View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.log4j.chainsaw.dnd;
18  
19  
20  import org.apache.log4j.Logger;
21  import java.awt.datatransfer.DataFlavor;
22  import java.awt.Color;
23  import java.awt.datatransfer.Transferable;
24  import java.awt.dnd.DnDConstants;
25  import java.awt.dnd.DropTarget;
26  import java.awt.dnd.DropTargetDragEvent;
27  import java.awt.dnd.DropTargetDropEvent;
28  import java.awt.dnd.DropTargetEvent;
29  import java.awt.dnd.DropTargetListener;
30  import java.beans.PropertyChangeListener;
31  import java.beans.PropertyChangeSupport;
32  import java.util.HashMap;
33  import java.util.List;
34  import java.util.Map;
35  
36  import javax.swing.BorderFactory;
37  import javax.swing.JComponent;
38  
39  /**
40   * This class provides all the functionality to work out when files are dragged onto
41   * a particular JComponent instance, and then notifies listeners via
42   * the standard PropertyChangesListener semantics to indicate that a list of 
43   * files have been dropped onto the target.
44   * 
45   * If you wish to know whan the files have been dropped, subscribe to the "fileList" property change.
46   * 
47   * @author psmith
48   *
49   */
50  public class FileDnDTarget implements DropTargetListener{
51      /**
52       * Logger for this class
53       */
54      private static final Logger LOG = Logger.getLogger(FileDnDTarget.class);
55  
56      protected int acceptableActions = DnDConstants.ACTION_COPY;
57  
58      private List fileList;
59  
60      private JComponent guiTarget;
61      private Map dropTargets = new HashMap();
62      
63      
64      private PropertyChangeSupport propertySupport = new PropertyChangeSupport(this);
65      /**
66       * 
67       */
68      public FileDnDTarget(JComponent c) {
69          this.guiTarget = c;
70      }
71      
72      public void addDropTargetToComponent(JComponent c){
73          dropTargets.put(c, new DropTarget(c, this));
74      }
75      
76      /**
77       * @param listener
78       */
79      public void addPropertyChangeListener(PropertyChangeListener listener) {
80          propertySupport.addPropertyChangeListener(listener);
81      }
82      /**
83       * @param propertyName
84       * @param listener
85       */
86      public void addPropertyChangeListener(String propertyName,
87              PropertyChangeListener listener) {
88          propertySupport.addPropertyChangeListener(propertyName, listener);
89      }
90  
91      /**
92       * 
93       */
94      private void decorateComponent() {
95  //        TODO work out a better way of decorating a component
96          guiTarget.setBorder(BorderFactory.createLineBorder(Color.black));
97      }
98  
99  
100     public void dragEnter(DropTargetDragEvent e) {
101         //LOG.debug(dtde);
102         if (isDragOk(e) == false) {
103             e.rejectDrag();
104             return;
105         }
106         decorateComponent();
107 
108         e.acceptDrag(acceptableActions);
109     }
110 
111 
112     public void dragExit(DropTargetEvent dte) {
113         removeComponentDecoration();
114     }
115 
116 
117     public void dragOver(DropTargetDragEvent e) {
118         //LOG.debug(dtde);
119 
120         if (isDragOk(e) == false) {
121             e.rejectDrag();
122             return;
123         }
124         e.acceptDrag(acceptableActions);
125     }
126 
127     public void drop(DropTargetDropEvent dtde) {
128         Transferable transferable = dtde.getTransferable();
129         LOG.debug(transferable);
130         dtde.acceptDrop(acceptableActions);
131         try {
132             List list = (List)transferable.getTransferData(DataFlavor.javaFileListFlavor);
133             LOG.debug(list);
134             setFileList(list);
135             dtde.getDropTargetContext().dropComplete(true);
136             removeComponentDecoration();
137 
138         } catch (Exception e) {
139             LOG.error("Error with DnD", e);
140         }
141         
142     }
143 
144     public void dropActionChanged(DropTargetDragEvent dtde) {
145         //LOG.debug(dtde);
146     }
147     /**
148      * @return Returns the fileList.
149      */
150     public final List getFileList() {
151         return fileList;
152     }
153 
154     private boolean isDragOk(DropTargetDragEvent e) {
155     	DataFlavor[] flavors = new DataFlavor[] { DataFlavor.javaFileListFlavor };
156     	DataFlavor chosen = null;
157     	for (int i = 0; i < flavors.length; i++) {
158     		if (e.isDataFlavorSupported(flavors[i])) {
159     			chosen = flavors[i];
160     			break;
161     		}
162     	}
163     	/*
164     	 * the src does not support any of the StringTransferable flavors
165     	 */
166     	if (chosen == null) {
167     		return false;
168     	}
169     	// the actions specified when the source
170     	// created the DragGestureRecognizer
171     	int sa = e.getSourceActions();
172     
173     	// we're saying that these actions are necessary
174     	if ((sa & acceptableActions) == 0)
175     		return false;
176     	return true;
177     }
178 
179     /**
180      * 
181      */
182     private void removeComponentDecoration() {
183         this.guiTarget.setBorder(null);
184     }
185     /**
186      * @param listener
187      */
188     public void removePropertyChangeListener(PropertyChangeListener listener) {
189         propertySupport.removePropertyChangeListener(listener);
190     }
191     /**
192      * @param propertyName
193      * @param listener
194      */
195     public void removePropertyChangeListener(String propertyName,
196             PropertyChangeListener listener) {
197         propertySupport.removePropertyChangeListener(propertyName, listener);
198     }
199     
200     /**
201      * @param fileList The fileList to set.
202      */
203     private  final void setFileList(List fileList) {
204         Object oldValue = this.fileList;
205         this.fileList = fileList;
206         propertySupport.firePropertyChange("fileList", oldValue, this.fileList);
207     }
208 }