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  
22  import javax.swing.*;
23  import java.awt.*;
24  import java.awt.datatransfer.DataFlavor;
25  import java.awt.datatransfer.Transferable;
26  import java.awt.dnd.*;
27  import java.beans.PropertyChangeListener;
28  import java.beans.PropertyChangeSupport;
29  import java.util.HashMap;
30  import java.util.List;
31  import java.util.Map;
32  
33  /**
34   * This class provides all the functionality to work out when files are dragged onto
35   * a particular JComponent instance, and then notifies listeners via
36   * the standard PropertyChangesListener semantics to indicate that a list of
37   * files have been dropped onto the target.
38   * <p>
39   * If you wish to know whan the files have been dropped, subscribe to the "fileList" property change.
40   *
41   * @author psmith
42   */
43  public class FileDnDTarget implements DropTargetListener {
44      /**
45       * Logger for this class
46       */
47      private static final Logger LOG = Logger.getLogger(FileDnDTarget.class);
48  
49      protected int acceptableActions = DnDConstants.ACTION_COPY;
50  
51      private List fileList;
52  
53      private JComponent guiTarget;
54      private Map<JComponent, DropTarget> dropTargets = new HashMap<>();
55  
56  
57      private PropertyChangeSupport propertySupport = new PropertyChangeSupport(this);
58  
59      /**
60       *
61       */
62      public FileDnDTarget(JComponent c) {
63          this.guiTarget = c;
64      }
65  
66      public void addDropTargetToComponent(JComponent c) {
67          dropTargets.put(c, new DropTarget(c, this));
68      }
69  
70      /**
71       * @param listener
72       */
73      public void addPropertyChangeListener(PropertyChangeListener listener) {
74          propertySupport.addPropertyChangeListener(listener);
75      }
76  
77      /**
78       * @param propertyName
79       * @param listener
80       */
81      public void addPropertyChangeListener(String propertyName,
82                                            PropertyChangeListener listener) {
83          propertySupport.addPropertyChangeListener(propertyName, listener);
84      }
85  
86      /**
87       *
88       */
89      private void decorateComponent() {
90  //        TODO work out a better way of decorating a component
91          guiTarget.setBorder(BorderFactory.createLineBorder(Color.black));
92      }
93  
94  
95      public void dragEnter(DropTargetDragEvent e) {
96          //LOG.debug(dtde);
97          if (isDragOk(e) == false) {
98              e.rejectDrag();
99              return;
100         }
101         decorateComponent();
102 
103         e.acceptDrag(acceptableActions);
104     }
105 
106 
107     public void dragExit(DropTargetEvent dte) {
108         removeComponentDecoration();
109     }
110 
111 
112     public void dragOver(DropTargetDragEvent e) {
113         //LOG.debug(dtde);
114 
115         if (isDragOk(e) == false) {
116             e.rejectDrag();
117             return;
118         }
119         e.acceptDrag(acceptableActions);
120     }
121 
122     public void drop(DropTargetDropEvent dtde) {
123         Transferable transferable = dtde.getTransferable();
124         LOG.debug(transferable);
125         dtde.acceptDrop(acceptableActions);
126         try {
127             List list = (List) transferable.getTransferData(DataFlavor.javaFileListFlavor);
128             LOG.debug(list);
129             setFileList(list);
130             dtde.getDropTargetContext().dropComplete(true);
131             removeComponentDecoration();
132 
133         } catch (Exception e) {
134             LOG.error("Error with DnD", e);
135         }
136 
137     }
138 
139     public void dropActionChanged(DropTargetDragEvent dtde) {
140         //LOG.debug(dtde);
141     }
142 
143     /**
144      * @return Returns the fileList.
145      */
146     public final List getFileList() {
147         return fileList;
148     }
149 
150     private boolean isDragOk(DropTargetDragEvent e) {
151         DataFlavor[] flavors = new DataFlavor[]{DataFlavor.javaFileListFlavor};
152         DataFlavor chosen = null;
153         for (DataFlavor flavor : flavors) {
154             if (e.isDataFlavorSupported(flavor)) {
155                 chosen = flavor;
156                 break;
157             }
158         }
159         /*
160          * the src does not support any of the StringTransferable flavors
161          */
162         if (chosen == null) {
163             return false;
164         }
165         // the actions specified when the source
166         // created the DragGestureRecognizer
167         int sa = e.getSourceActions();
168 
169         // we're saying that these actions are necessary
170         return (sa & acceptableActions) != 0;
171     }
172 
173     /**
174      *
175      */
176     private void removeComponentDecoration() {
177         this.guiTarget.setBorder(null);
178     }
179 
180     /**
181      * @param listener
182      */
183     public void removePropertyChangeListener(PropertyChangeListener listener) {
184         propertySupport.removePropertyChangeListener(listener);
185     }
186 
187     /**
188      * @param propertyName
189      * @param listener
190      */
191     public void removePropertyChangeListener(String propertyName,
192                                              PropertyChangeListener listener) {
193         propertySupport.removePropertyChangeListener(propertyName, listener);
194     }
195 
196     /**
197      * @param fileList The fileList to set.
198      */
199     private final void setFileList(List fileList) {
200         Object oldValue = this.fileList;
201         this.fileList = fileList;
202         propertySupport.firePropertyChange("fileList", oldValue, this.fileList);
203     }
204 }