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 }