Java Tutorial/Swing/Drag Drop

Материал из Java эксперт
Перейти к: навигация, поиск

Содержание

14. Basic drag and drop

/*
 * Copyright (c) 1995 - 2008 Sun Microsystems, Inc.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 *   - Neither the name of Sun Microsystems nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
/*
 * BasicDnD.java requires no other files.
 */
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.DefaultListModel;
import javax.swing.DropMode;
import javax.swing.JCheckBox;
import javax.swing.JColorChooser;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.TransferHandler;
import javax.swing.UIManager;
import javax.swing.table.DefaultTableModel;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeSelectionModel;
public class BasicDnD extends JPanel implements ActionListener {
  private static JFrame frame;
  private JTextArea textArea;
  private JTextField textField;
  private JList list;
  private JTable table;
  private JTree tree;
  private JColorChooser colorChooser;
  private JCheckBox toggleDnD;
  public BasicDnD() {
    super(new BorderLayout());
    JPanel leftPanel = createVerticalBoxPanel();
    JPanel rightPanel = createVerticalBoxPanel();
    // Create a table model.
    DefaultTableModel tm = new DefaultTableModel();
    tm.addColumn("Column 0");
    tm.addColumn("Column 1");
    tm.addColumn("Column 2");
    tm.addColumn("Column 3");
    tm.addRow(new String[] { "Table 00", "Table 01", "Table 02", "Table 03" });
    tm.addRow(new String[] { "Table 10", "Table 11", "Table 12", "Table 13" });
    tm.addRow(new String[] { "Table 20", "Table 21", "Table 22", "Table 23" });
    tm.addRow(new String[] { "Table 30", "Table 31", "Table 32", "Table 33" });
    // LEFT COLUMN
    // Use the table model to create a table.
    table = new JTable(tm);
    leftPanel.add(createPanelForComponent(table, "JTable"));
    // Create a color chooser.
    colorChooser = new JColorChooser();
    leftPanel.add(createPanelForComponent(colorChooser, "JColorChooser"));
    // RIGHT COLUMN
    // Create a textfield.
    textField = new JTextField(30);
    textField.setText("Favorite foods:\nPizza, Moussaka, Pot roast");
    rightPanel.add(createPanelForComponent(textField, "JTextField"));
    // Create a scrolled text area.
    textArea = new JTextArea(5, 30);
    textArea.setText("Favorite shows:\nBuffy, Alias, Angel");
    JScrollPane scrollPane = new JScrollPane(textArea);
    rightPanel.add(createPanelForComponent(scrollPane, "JTextArea"));
    // Create a list model and a list.
    DefaultListModel listModel = new DefaultListModel();
    listModel.addElement("Martha Washington");
    listModel.addElement("Abigail Adams");
    listModel.addElement("Martha Randolph");
    listModel.addElement("Dolley Madison");
    listModel.addElement("Elizabeth Monroe");
    listModel.addElement("Louisa Adams");
    listModel.addElement("Emily Donelson");
    list = new JList(listModel);
    list.setVisibleRowCount(-1);
    list.getSelectionModel().setSelectionMode(
        ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
    list.setTransferHandler(new TransferHandler() {
      public boolean canImport(TransferHandler.TransferSupport info) {
        // we only import Strings
        if (!info.isDataFlavorSupported(DataFlavor.stringFlavor)) {
          return false;
        }
        JList.DropLocation dl = (JList.DropLocation) info.getDropLocation();
        if (dl.getIndex() == -1) {
          return false;
        }
        return true;
      }
      public boolean importData(TransferHandler.TransferSupport info) {
        if (!info.isDrop()) {
          return false;
        }
        // Check for String flavor
        if (!info.isDataFlavorSupported(DataFlavor.stringFlavor)) {
          displayDropLocation("List doesn"t accept a drop of this type.");
          return false;
        }
        JList.DropLocation dl = (JList.DropLocation) info.getDropLocation();
        DefaultListModel listModel = (DefaultListModel) list.getModel();
        int index = dl.getIndex();
        boolean insert = dl.isInsert();
        // Get the current string under the drop.
        String value = (String) listModel.getElementAt(index);
        // Get the string that is being dropped.
        Transferable t = info.getTransferable();
        String data;
        try {
          data = (String) t.getTransferData(DataFlavor.stringFlavor);
        } catch (Exception e) {
          return false;
        }
        // Display a dialog with the drop information.
        String dropValue = "\"" + data + "\" dropped ";
        if (dl.isInsert()) {
          if (dl.getIndex() == 0) {
            displayDropLocation(dropValue + "at beginning of list");
          } else if (dl.getIndex() >= list.getModel().getSize()) {
            displayDropLocation(dropValue + "at end of list");
          } else {
            String value1 = (String) list.getModel().getElementAt(
                dl.getIndex() - 1);
            String value2 = (String) list.getModel()
                .getElementAt(dl.getIndex());
            displayDropLocation(dropValue + "between \"" + value1 + "\" and \""
                + value2 + "\"");
          }
        } else {
          displayDropLocation(dropValue + "on top of " + "\"" + value + "\"");
        }
        /**
         * This is commented out for the basicdemo.html tutorial page. * If you
         * add this code snippet back and delete the * "return false;" line, the
         * list will accept drops * of type string. // Perform the actual
         * import. if (insert) { listModel.add(index, data); } else {
         * listModel.set(index, data); } return true;
         */
        return false;
      }
      public int getSourceActions(JComponent c) {
        return COPY;
      }
      protected Transferable createTransferable(JComponent c) {
        JList list = (JList) c;
        Object[] values = list.getSelectedValues();
        StringBuffer buff = new StringBuffer();
        for (int i = 0; i < values.length; i++) {
          Object val = values[i];
          buff.append(val == null ? "" : val.toString());
          if (i != values.length - 1) {
            buff.append("\n");
          }
        }
        return new StringSelection(buff.toString());
      }
    });
    list.setDropMode(DropMode.ON_OR_INSERT);
    JScrollPane listView = new JScrollPane(list);
    listView.setPreferredSize(new Dimension(300, 100));
    rightPanel.add(createPanelForComponent(listView, "JList"));
    // Create a tree.
    DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode("Mia Familia");
    DefaultMutableTreeNode sharon = new DefaultMutableTreeNode("Sharon");
    rootNode.add(sharon);
    DefaultMutableTreeNode maya = new DefaultMutableTreeNode("Maya");
    sharon.add(maya);
    DefaultMutableTreeNode anya = new DefaultMutableTreeNode("Anya");
    sharon.add(anya);
    sharon.add(new DefaultMutableTreeNode("Bongo"));
    maya.add(new DefaultMutableTreeNode("Muffin"));
    anya.add(new DefaultMutableTreeNode("Winky"));
    DefaultTreeModel model = new DefaultTreeModel(rootNode);
    tree = new JTree(model);
    tree.getSelectionModel().setSelectionMode(
        TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
    JScrollPane treeView = new JScrollPane(tree);
    treeView.setPreferredSize(new Dimension(300, 100));
    rightPanel.add(createPanelForComponent(treeView, "JTree"));
    // Create the toggle button.
    toggleDnD = new JCheckBox("Turn on Drag and Drop");
    toggleDnD.setActionCommand("toggleDnD");
    toggleDnD.addActionListener(this);
    JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
        leftPanel, rightPanel);
    splitPane.setOneTouchExpandable(true);
    add(splitPane, BorderLayout.CENTER);
    add(toggleDnD, BorderLayout.PAGE_END);
    setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
  }
  protected JPanel createVerticalBoxPanel() {
    JPanel p = new JPanel();
    p.setLayout(new BoxLayout(p, BoxLayout.PAGE_AXIS));
    p.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
    return p;
  }
  public JPanel createPanelForComponent(JComponent comp, String title) {
    JPanel panel = new JPanel(new BorderLayout());
    panel.add(comp, BorderLayout.CENTER);
    if (title != null) {
      panel.setBorder(BorderFactory.createTitledBorder(title));
    }
    return panel;
  }
  private void displayDropLocation(final String string) {
    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        JOptionPane.showMessageDialog(null, string);
      }
    });
  }
  public void actionPerformed(ActionEvent e) {
    if ("toggleDnD".equals(e.getActionCommand())) {
      boolean toggle = toggleDnD.isSelected();
      textArea.setDragEnabled(toggle);
      textField.setDragEnabled(toggle);
      list.setDragEnabled(toggle);
      table.setDragEnabled(toggle);
      tree.setDragEnabled(toggle);
      colorChooser.setDragEnabled(toggle);
    }
  }
  /**
   * Create the GUI and show it. For thread safety, this method should be
   * invoked from the event-dispatching thread.
   */
  private static void createAndShowGUI() {
    // Create and set up the window.
    frame = new JFrame("BasicDnD");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    // Create and set up the content pane.
    JComponent newContentPane = new BasicDnD();
    newContentPane.setOpaque(true); // content panes must be opaque
    frame.setContentPane(newContentPane);
    // Display the window.
    frame.pack();
    frame.setVisible(true);
  }
  public static void main(String[] args) {
    // Schedule a job for the event-dispatching thread:
    // creating and showing this application"s GUI.
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        // Turn off metal"s use of bold fonts
        UIManager.put("swing.boldMetal", Boolean.FALSE);
        createAndShowGUI();
      }
    });
  }
}





14. Built-in drag and drop support: utilize a TransferHandler class

import java.awt.FlowLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.TransferHandler;
public class SimpleDnD {
  public static void main(String[] args) {
    JTextField field = new JTextField(10);
    JButton button = new JButton("Button");
    JFrame f = new JFrame();
    f.setTitle("Simple Drag & Drop");
    f.setLayout(new FlowLayout());
    f.add(button);
    f.add(field);
    field.setDragEnabled(true);
    button.setTransferHandler(new TransferHandler("text"));
    f.setSize(330, 150);
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.setLocationRelativeTo(null);
    f.setVisible(true);
  }
}





14. Choose Drop Action

/*
 * Copyright (c) 1995 - 2008 Sun Microsystems, Inc.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 *   - Neither the name of Sun Microsystems nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.DefaultListModel;
import javax.swing.DropMode;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.TransferHandler;
import javax.swing.UIManager;
public class ChooseDropActionDemo extends JFrame {
  DefaultListModel from = new DefaultListModel();
  DefaultListModel copy = new DefaultListModel();
  DefaultListModel move = new DefaultListModel();
  JList dragFrom;
  public ChooseDropActionDemo() {
    super("ChooseDropActionDemo");
    for (int i = 15; i >= 0; i--) {
      from.add(0, "Source item " + i);
    }
    for (int i = 2; i >= 0; i--) {
      copy.add(0, "Target item " + i);
      move.add(0, "Target item " + i);
    }
    JPanel p = new JPanel();
    p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
    dragFrom = new JList(from);
    dragFrom.setTransferHandler(new FromTransferHandler());
    dragFrom.setPrototypeCellValue("List Item WWWWWW");
    dragFrom.setDragEnabled(true);
    dragFrom.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    JLabel label = new JLabel("Drag from here:");
    label.setAlignmentX(0f);
    p.add(label);
    JScrollPane sp = new JScrollPane(dragFrom);
    sp.setAlignmentX(0f);
    p.add(sp);
    add(p, BorderLayout.WEST);
    JList moveTo = new JList(move);
    moveTo.setTransferHandler(new ToTransferHandler(TransferHandler.COPY));
    moveTo.setDropMode(DropMode.INSERT);
    JList copyTo = new JList(copy);
    copyTo.setTransferHandler(new ToTransferHandler(TransferHandler.MOVE));
    copyTo.setDropMode(DropMode.INSERT);
    p = new JPanel();
    p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
    label = new JLabel("Drop to COPY to here:");
    ;
    label.setAlignmentX(0f);
    p.add(label);
    sp = new JScrollPane(moveTo);
    sp.setAlignmentX(0f);
    p.add(sp);
    label = new JLabel("Drop to MOVE to here:");
    label.setAlignmentX(0f);
    p.add(label);
    sp = new JScrollPane(copyTo);
    sp.setAlignmentX(0f);
    p.add(sp);
    p.setBorder(BorderFactory.createEmptyBorder(0, 2, 0, 0));
    add(p, BorderLayout.CENTER);
    ((JPanel) getContentPane()).setBorder(BorderFactory.createEmptyBorder(2, 2,
        2, 2));
    getContentPane().setPreferredSize(new Dimension(320, 315));
  }
  private static void createAndShowGUI() {
    // Create and set up the window.
    ChooseDropActionDemo test = new ChooseDropActionDemo();
    test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    // Display the window.
    test.pack();
    test.setVisible(true);
  }
  public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        // Turn off metal"s use of bold fonts
        UIManager.put("swing.boldMetal", Boolean.FALSE);
        createAndShowGUI();
      }
    });
  }
  class FromTransferHandler extends TransferHandler {
    public int getSourceActions(JComponent comp) {
      return COPY_OR_MOVE;
    }
    private int index = 0;
    public Transferable createTransferable(JComponent comp) {
      index = dragFrom.getSelectedIndex();
      if (index < 0 || index >= from.getSize()) {
        return null;
      }
      return new StringSelection((String) dragFrom.getSelectedValue());
    }
    public void exportDone(JComponent comp, Transferable trans, int action) {
      if (action != MOVE) {
        return;
      }
      from.removeElementAt(index);
    }
  }
  class ToTransferHandler extends TransferHandler {
    int action;
    public ToTransferHandler(int action) {
      this.action = action;
    }
    public boolean canImport(TransferHandler.TransferSupport support) {
      // for the demo, we"ll only support drops (not clipboard paste)
      if (!support.isDrop()) {
        return false;
      }
      // we only import Strings
      if (!support.isDataFlavorSupported(DataFlavor.stringFlavor)) {
        return false;
      }
      boolean actionSupported = (action & support.getSourceDropActions()) == action;
      if (actionSupported) {
        support.setDropAction(action);
        return true;
      }
      return false;
    }
    public boolean importData(TransferHandler.TransferSupport support) {
      // if we can"t handle the import, say so
      if (!canImport(support)) {
        return false;
      }
      // fetch the drop location
      JList.DropLocation dl = (JList.DropLocation) support.getDropLocation();
      int index = dl.getIndex();
      // fetch the data and bail if this fails
      String data;
      try {
        data = (String) support.getTransferable().getTransferData(
            DataFlavor.stringFlavor);
      } catch (UnsupportedFlavorException e) {
        return false;
      } catch (java.io.IOException e) {
        return false;
      }
      JList list = (JList) support.getComponent();
      DefaultListModel model = (DefaultListModel) list.getModel();
      model.insertElementAt(data, index);
      Rectangle rect = list.getCellBounds(index, index);
      list.scrollRectToVisible(rect);
      list.setSelectedIndex(index);
      list.requestFocusInWindow();
      return true;
    }
  }
}





14. Create a drag source a drop target and a transferable object.

import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DragGestureEvent;
import java.awt.dnd.DragGestureListener;
import java.awt.dnd.DragSource;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetAdapter;
import java.awt.dnd.DropTargetDropEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class ComplexExample extends JFrame implements DragGestureListener {
  public ComplexExample() {
    JPanel left = new JPanel();
    left.setBackground(Color.red);
    JPanel right = new JPanel();
    right.setBackground(Color.white);
    new MyDropTargetListener(right);
    DragSource ds = new DragSource();
    ds.createDefaultDragGestureRecognizer(left, DnDConstants.ACTION_COPY, this);
    setLayout(new FlowLayout());
    add(left);
    add(right);
    setSize(40,50);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setLocationRelativeTo(null);
    setVisible(true);
  }
  public void dragGestureRecognized(DragGestureEvent event) {
    Cursor cursor = null;
    JPanel panel = (JPanel) event.getComponent();
    Color color = panel.getBackground();
    if (event.getDragAction() == DnDConstants.ACTION_COPY) {
      cursor = DragSource.DefaultCopyDrop;
    }
    event.startDrag(cursor, new TransferableColor(color));
  }
  class MyDropTargetListener extends DropTargetAdapter {
    private DropTarget dropTarget;
    private JPanel panel;
    public MyDropTargetListener(JPanel panel) {
      this.panel = panel;
      dropTarget = new DropTarget(panel, DnDConstants.ACTION_COPY, this, true, null);
    }
    public void drop(DropTargetDropEvent event) {
      try {
        Transferable tr = event.getTransferable();
        Color color = (Color) tr.getTransferData(TransferableColor.colorFlavor);
        if (event.isDataFlavorSupported(TransferableColor.colorFlavor)) {
          event.acceptDrop(DnDConstants.ACTION_COPY);
          this.panel.setBackground(color);
          event.dropComplete(true);
          return;
        }
        event.rejectDrop();
      } catch (Exception e) {
        e.printStackTrace();
        event.rejectDrop();
      }
    }
  }
  public static void main(String[] args) {
    new ComplexExample();
  }
}
class TransferableColor implements Transferable {
  protected static DataFlavor colorFlavor = new DataFlavor(Color.class, "A Color Object");
  protected static DataFlavor[] supportedFlavors = { colorFlavor };
  Color color;
  public TransferableColor(Color color) {
    this.color = color;
  }
  public DataFlavor[] getTransferDataFlavors() {
    return supportedFlavors;
  }
  public boolean isDataFlavorSupported(DataFlavor flavor) {
    if (flavor.equals(colorFlavor) || flavor.equals(DataFlavor.stringFlavor))
      return true;
    return false;
  }
  public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException {
    if (flavor.equals(colorFlavor))
      return color;
    else if (flavor.equals(DataFlavor.stringFlavor))
      return color.toString();
    else
      throw new UnsupportedFlavorException(flavor);
  }
}





14. Demonstrates how to add copy and drag support to a Swing component with TransferHandler

/*
 * Copyright (c) 2004 David Flanagan.  All rights reserved.
 * This code is from the book Java Examples in a Nutshell, 3nd Edition.
 * It is provided AS-IS, WITHOUT ANY WARRANTY either expressed or implied.
 * You may study, use, and modify it for any non-commercial purpose,
 * including teaching and use in open-source projects.
 * You may distribute it non-commercially as long as you retain this notice.
 * For a commercial use license, or to purchase the book, 
 * please visit http://www.davidflanagan.ru/javaexamples3.
 */
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.text.DateFormat;
import java.util.Date;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JLabel;
import javax.swing.KeyStroke;
import javax.swing.Timer;
import javax.swing.TransferHandler;
import javax.swing.border.LineBorder;
/**
 * A custom Swing component that displays a simple digital clock. Demonstrates
 * how to add copy and drag support to a Swing component with TransferHandler.
 */
public class DigitalClock extends JLabel {
  DateFormat format; // How to display the time in string form
  int updateFrequency; // How often to update the time (in milliseconds)
  Timer timer; // Triggers repeated updates to the clock
  public DigitalClock() {
    // Set default values for our properties
    setFormat(DateFormat.getTimeInstance(DateFormat.MEDIUM, getLocale()));
    setUpdateFrequency(1000); // Update once a second
    // Specify a Swing TransferHandler object to do the dirty work of
    // copy-and-paste and drag-and-drop for us. This one will transfer
    // the value of the "time" property. Since this property is read-only
    // it will allow drags but not drops.
    setTransferHandler(new TransferHandler("time"));
    // Since JLabel does not normally support drag-and-drop, we need an
    // event handler to detect a drag and start the transfer.
    addMouseMotionListener(new MouseMotionAdapter() {
      public void mouseDragged(MouseEvent e) {
        getTransferHandler().exportAsDrag(DigitalClock.this, e, TransferHandler.COPY);
      }
    });
    // Before we can have a keyboard binding for a Copy command,
    // the component needs to be able to accept keyboard focus.
    setFocusable(true);
    // Request focus when we"re clicked on
    addMouseListener(new MouseAdapter() {
      public void mouseClicked(MouseEvent e) {
        requestFocus();
      }
    });
    // Use a LineBorder to indicate when we"ve got the keyboard focus
    addFocusListener(new FocusListener() {
      public void focusGained(FocusEvent e) {
        setBorder(LineBorder.createBlackLineBorder());
      }
      public void focusLost(FocusEvent e) {
        setBorder(null);
      }
    });
    // Now bind the Ctrl-C keystroke to a "Copy" command.
    InputMap im = new InputMap();
    im.setParent(getInputMap(WHEN_FOCUSED));
    im.put(KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.CTRL_MASK), "Copy");
    setInputMap(WHEN_FOCUSED, im);
    // And bind the "Copy" command to a pre-defined Action that performs
    // a copy using the TransferHandler we"ve installed.
    ActionMap am = new ActionMap();
    am.setParent(getActionMap());
    am.put("Copy", TransferHandler.getCopyAction());
    setActionMap(am);
    // Create a javax.swing.Timer object that will generate ActionEvents
    // to tell us when to update the displayed time. Every updateFrequency
    // milliseconds, this timer will cause the actionPerformed() method
    // to be invoked. (For non-GUI applications, see java.util.Timer.)
    timer = new Timer(updateFrequency, new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        setText(getTime()); // set label to current time string
      }
    });
    timer.setInitialDelay(0); // Do the first update immediately
    timer.start(); // Start timing now!
  }
  // Return the current time as a String.
  // This is the property accessor method used by the TransferHandler.
  // Since there is a getter, but no setter, the TransferHandler will
  // reject any attempts to drop data on us.
  public String getTime() {
    // Use the DateFormat object to convert current time to a string
    return format.format(new Date());
  }
  // Here are two related property setter methods
  public void setFormat(DateFormat format) {
    this.format = format;
  }
  public void setUpdateFrequency(int ms) {
    this.updateFrequency = ms;
  }
}





14. Demonstration of the top-level TransferHandler support on JFrame

/*
 * Copyright (c) 1995 - 2008 Sun Microsystems, Inc.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 *   - Neither the name of Sun Microsystems nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */ 
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.awt.datatransfer.*;
import java.awt.dnd.*;
import java.util.*;
/**
 * Demonstration of the top-level {@code TransferHandler}
 * support on {@code JFrame}.
 *
 * @author Shannon Hickey
 */
public class TopLevelTransferHandlerDemo extends JFrame {
    
    private static boolean DEMO = false;
    private JDesktopPane dp = new JDesktopPane();
    private DefaultListModel listModel = new DefaultListModel();
    private JList list = new JList(listModel);
    private static int left;
    private static int top;
    private JCheckBoxMenuItem copyItem;
    private JCheckBoxMenuItem nullItem;
    private JCheckBoxMenuItem thItem;
    private class Doc extends InternalFrameAdapter implements ActionListener {
        String name;
        JInternalFrame frame;
        TransferHandler th;
        JTextArea area;
        public Doc(File file) {
            this.name = file.getName();
            try {
                init(file.toURI().toURL());
            } catch (MalformedURLException e) {
                e.printStackTrace();
            }
        }
        
        public Doc(String name) {
            this.name = name;
            init(getClass().getResource(name));
        }
        
        private void init(URL url) {
            frame = new JInternalFrame(name);
            frame.addInternalFrameListener(this);
            listModel.add(listModel.size(), this);
            area = new JTextArea();
            area.setMargin(new Insets(5, 5, 5, 5));
            try {
                BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()));
                String in;
                while ((in = reader.readLine()) != null) {
                    area.append(in);
                    area.append("\n");
                }
                reader.close();
            } catch (Exception e) {
                e.printStackTrace();
                return;
            }
            th = area.getTransferHandler();
            area.setFont(new Font("monospaced", Font.PLAIN, 12));
            area.setCaretPosition(0);
            area.setDragEnabled(true);
            area.setDropMode(DropMode.INSERT);
            frame.getContentPane().add(new JScrollPane(area));
            dp.add(frame);
            frame.show();
            if (DEMO) {
                frame.setSize(300, 200);
            } else {
                frame.setSize(400, 300);
            }
            frame.setResizable(true);
            frame.setClosable(true);
            frame.setIconifiable(true);
            frame.setMaximizable(true);
            frame.setLocation(left, top);
            incr();
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    select();
                }
            });
            nullItem.addActionListener(this);
            setNullTH();
        }
        public void internalFrameClosing(InternalFrameEvent event) {
            listModel.removeElement(this);
            nullItem.removeActionListener(this);
        }
        public void internalFrameOpened(InternalFrameEvent event) {
            int index = listModel.indexOf(this);
            list.getSelectionModel().setSelectionInterval(index, index);
        }
        public void internalFrameActivated(InternalFrameEvent event) {
            int index = listModel.indexOf(this);
            list.getSelectionModel().setSelectionInterval(index, index);
        }
        public String toString() {
            return name;
        }
        
        public void select() {
            try {
                frame.toFront();
                frame.setSelected(true);
            } catch (java.beans.PropertyVetoException e) {}
        }
        
        public void actionPerformed(ActionEvent ae) {
            setNullTH();
        }
        
        public void setNullTH() {
            if (nullItem.isSelected()) {
                area.setTransferHandler(null);
            } else {
                area.setTransferHandler(th);
            }
        }
    }
    private TransferHandler handler = new TransferHandler() {
        public boolean canImport(TransferHandler.TransferSupport support) {
            if (!support.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
                return false;
            }
            if (copyItem.isSelected()) {
                boolean copySupported = (COPY & support.getSourceDropActions()) == COPY;
                if (!copySupported) {
                    return false;
                }
                support.setDropAction(COPY);
            }
            return true;
        }
        public boolean importData(TransferHandler.TransferSupport support) {
            if (!canImport(support)) {
                return false;
            }
            
            Transferable t = support.getTransferable();
            try {
                java.util.List<File> l =
                    (java.util.List<File>)t.getTransferData(DataFlavor.javaFileListFlavor);
                for (File f : l) {
                    new Doc(f);
                }
            } catch (UnsupportedFlavorException e) {
                return false;
            } catch (IOException e) {
                return false;
            }
            return true;
        }
    };
    private static void incr() {
        left += 30;
        top += 30;
        if (top == 150) {
            top = 0;
        }
    }
    public TopLevelTransferHandlerDemo() {
        super("TopLevelTransferHandlerDemo");
        setJMenuBar(createDummyMenuBar());
        getContentPane().add(createDummyToolBar(), BorderLayout.NORTH);
        JSplitPane sp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, list, dp);
        sp.setDividerLocation(120);
        getContentPane().add(sp);
        //new Doc("sample.txt");
        //new Doc("sample.txt");
        //new Doc("sample.txt");
        list.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        list.addListSelectionListener(new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent e) {
                if (e.getValueIsAdjusting()) {
                    return;
                }
                
                Doc val = (Doc)list.getSelectedValue();
                if (val != null) {
                    val.select();
                }
             }
        });
        
        final TransferHandler th = list.getTransferHandler();
        nullItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                if (nullItem.isSelected()) {
                    list.setTransferHandler(null);
                } else {
                    list.setTransferHandler(th);
                }
            }
        });
        thItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                if (thItem.isSelected()) {
                    setTransferHandler(handler);
                } else {
                    setTransferHandler(null);
                }
            }
        });
        dp.setTransferHandler(handler);
    }
    private static void createAndShowGUI(String[] args) {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (Exception e) {
        }
        TopLevelTransferHandlerDemo test = new TopLevelTransferHandlerDemo();
        test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        if (DEMO) {
            test.setSize(493, 307);
        } else {
            test.setSize(800, 600);
        }
        test.setLocationRelativeTo(null);
        test.setVisible(true);
        test.list.requestFocus();
    }
    
    public static void main(final String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                //Turn off metal"s use of bold fonts
            UIManager.put("swing.boldMetal", Boolean.FALSE);
                createAndShowGUI(args);
            }
        });
    }
    
    private JToolBar createDummyToolBar() {
        JToolBar tb = new JToolBar();
        JButton b;
        b = new JButton("New");
        b.setRequestFocusEnabled(false);
        tb.add(b);
        b = new JButton("Open");
        b.setRequestFocusEnabled(false);
        tb.add(b);
        b = new JButton("Save");
        b.setRequestFocusEnabled(false);
        tb.add(b);
        b = new JButton("Print");
        b.setRequestFocusEnabled(false);
        tb.add(b);
        b = new JButton("Preview");
        b.setRequestFocusEnabled(false);
        tb.add(b);
        tb.setFloatable(false);
        return tb;
    }
    
    private JMenuBar createDummyMenuBar() {
        JMenuBar mb = new JMenuBar();
        mb.add(createDummyMenu("File"));
        mb.add(createDummyMenu("Edit"));
        mb.add(createDummyMenu("Search"));
        mb.add(createDummyMenu("View"));
        mb.add(createDummyMenu("Tools"));
        mb.add(createDummyMenu("Help"));
        
        JMenu demo = new JMenu("Demo");
        demo.setMnemonic(KeyEvent.VK_D);
        mb.add(demo);
        thItem = new JCheckBoxMenuItem("Use Top-Level TransferHandler");
        thItem.setMnemonic(KeyEvent.VK_T);
        demo.add(thItem);
        nullItem = new JCheckBoxMenuItem("Remove TransferHandler from List and Text");
        nullItem.setMnemonic(KeyEvent.VK_R);
        demo.add(nullItem);
        copyItem = new JCheckBoxMenuItem("Use COPY Action");
        copyItem.setMnemonic(KeyEvent.VK_C);
        demo.add(copyItem);
        return mb;
    }
    
    private JMenu createDummyMenu(String str) {
        JMenu menu = new JMenu(str);
        JMenuItem item = new JMenuItem("[Empty]");
        item.setEnabled(false);
        menu.add(item);
        return menu;
    }
}





14. Detect a drag initiating gesture in your application

import java.awt.BorderLayout;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DragGestureEvent;
import java.awt.dnd.DragGestureListener;
import java.awt.dnd.DragGestureRecognizer;
import java.awt.dnd.DragSource;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.ListSelectionModel;
public class Main extends JFrame implements DragGestureListener {
  String[] items = { "Java", "C", "C++", "Lisp", "Perl", "Python" };
  DragSource ds = new DragSource();
  JList jl = new JList(items);
  public Main() {
    setSize(200, 150);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    jl.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    getContentPane().add(new JScrollPane(jl), BorderLayout.CENTER);
    
    DragGestureRecognizer dgr = ds.createDefaultDragGestureRecognizer(jl, DnDConstants.ACTION_COPY,
        this);
    setVisible(true);
  }
  public void dragGestureRecognized(DragGestureEvent dge) {
    System.out.println("Drag Gesture Recognized!");
  }
  public static void main(String args[]) {
    new Main();
  }
}





14. DND Drag and drop List

/**
 * This is an example of a component, which serves as a DragSource as 
 * well as Drop Target.
 * To illustrate the concept, JList has been used as a droppable target
 * and a draggable source.
 * Any component can be used instead of a JList.
 * The code also contains debugging messages which can be used for 
 * diagnostics and understanding the flow of events.
 * 
 * @version 1.0
 */
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DragGestureEvent;
import java.awt.dnd.DragGestureListener;
import java.awt.dnd.DragSource;
import java.awt.dnd.DragSourceDragEvent;
import java.awt.dnd.DragSourceDropEvent;
import java.awt.dnd.DragSourceEvent;
import java.awt.dnd.DragSourceListener;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.dnd.DropTargetEvent;
import java.awt.dnd.DropTargetListener;
import javax.swing.DefaultListModel;
import javax.swing.JList;
import javax.swing.ListModel;

public class DNDList extends JList implements DropTargetListener, DragSourceListener, DragGestureListener
{
  /**
   * enables this component to be a dropTarget
   */
  DropTarget dropTarget = null;
  /**
   * enables this component to be a Drag Source
   */
  DragSource dragSource = null;
  /**
   * constructor - initializes the DropTarget and DragSource.
   */
  public DNDList( ListModel dataModel )
  {
    super( dataModel );
    dropTarget = new DropTarget( this, this );
    dragSource = new DragSource();
    dragSource.createDefaultDragGestureRecognizer( this, DnDConstants.ACTION_MOVE, this );
  }
  /**
   * is invoked when you are dragging over the DropSite
   * 
   */
  public void dragEnter( DropTargetDragEvent event )
  {
    // debug messages for diagnostics
    System.out.println( "dragEnter" );
    event.acceptDrag( DnDConstants.ACTION_MOVE );
  }
  /**
   * is invoked when you are exit the DropSite without dropping
   * 
   */
  public void dragExit( DropTargetEvent event )
  {
    System.out.println( "dragExit" );
  }
  /**
   * is invoked when a drag operation is going on
   * 
   */
  public void dragOver( DropTargetDragEvent event )
  {
    System.out.println( "dragOver" );
  }
  /**
   * a drop has occurred
   * 
   */
  public void drop( DropTargetDropEvent event )
  {
    try
    {
      Transferable transferable = event.getTransferable();
      // we accept only Strings
      if( transferable.isDataFlavorSupported( DataFlavor.stringFlavor ) )
      {
        event.acceptDrop( DnDConstants.ACTION_MOVE );
        String s = ( String )transferable.getTransferData( DataFlavor.stringFlavor );
        addElement( s );
        event.getDropTargetContext().dropComplete( true );
      }
      else
      {
        event.rejectDrop();
      }
    }
    catch( Exception exception )
    {
      System.err.println( "Exception" + exception.getMessage() );
      event.rejectDrop();
    }
  }
  /**
   * is invoked if the use modifies the current drop gesture
   * 
   */
  public void dropActionChanged( DropTargetDragEvent event )
  {
  }
  /**
   * a drag gesture has been initiated
   * 
   */
  public void dragGestureRecognized( DragGestureEvent event )
  {
    Object selected = getSelectedValue();
    if( selected != null )
    {
      StringSelection text = new StringSelection( selected.toString() );
      // as the name suggests, starts the dragging
      dragSource.startDrag( event, DragSource.DefaultMoveDrop, text, this );
    }
    else
    {
      System.out.println( "nothing was selected" );
    }
  }
  /**
   * this message goes to DragSourceListener, informing it that the dragging
   * has ended
   * 
   */
  public void dragDropEnd( DragSourceDropEvent event )
  {
    if( event.getDropSuccess() )
    {
      removeElement();
    }
  }
  /**
   * this message goes to DragSourceListener, informing it that the dragging
   * has entered the DropSite
   * 
   */
  public void dragEnter( DragSourceDragEvent event )
  {
    System.out.println( " dragEnter" );
  }
  /**
   * this message goes to DragSourceListener, informing it that the dragging
   * has exited the DropSite
   * 
   */
  public void dragExit( DragSourceEvent event )
  {
    System.out.println( "dragExit" );
  }
  /**
   * this message goes to DragSourceListener, informing it that the dragging is
   * currently ocurring over the DropSite
   * 
   */
  public void dragOver( DragSourceDragEvent event )
  {
    System.out.println( "dragExit" );
  }
  /**
   * is invoked when the user changes the dropAction
   * 
   */
  public void dropActionChanged( DragSourceDragEvent event )
  {
    System.out.println( "dropActionChanged" );
  }
  /**
   * adds elements to itself
   * 
   */
  public void addElement( Object s )
  {
    ( ( DefaultListModel )getModel() ).addElement( s.toString() );
  }
  /**
   * removes an element from itself
   */
  public void removeElement()
  {
    ( ( DefaultListModel )getModel() ).removeElement( getSelectedValue() );
  }
}





14. Drag and drop between JList and JTextField

import java.awt.BorderLayout;
import java.awt.Rectangle;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import javax.swing.DefaultListModel;
import javax.swing.DropMode;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.TransferHandler;
public class DnDDemo3 {
  public static void main(String[] args) {
    JPanel north = new JPanel();
    north.add(new JLabel("Drag from here:"));
    JTextField field = new JTextField(10);
    field.setDragEnabled(true); 
    north.add(field);
    final DefaultListModel listModel = new DefaultListModel();
    listModel.addElement("first");
    listModel.addElement("second");
    final JList list = new JList(listModel);
    list.setDragEnabled(true);
    list.setTransferHandler(new TransferHandler() {
      public boolean canImport(TransferHandler.TransferSupport support) {
        if (!support.isDataFlavorSupported(DataFlavor.stringFlavor)) {
          return false;
        }
        JList.DropLocation dl = (JList.DropLocation) support.getDropLocation();
        if (dl.getIndex() == -1) {
          return false;
        } else {
          return true;
        }
      }
      public boolean importData(TransferHandler.TransferSupport support) {
        if (!canImport(support)) {
          return false;
        }
        Transferable transferable = support.getTransferable();
        String data;
        try {
          data = (String) transferable.getTransferData(DataFlavor.stringFlavor);
        } catch (Exception e) {
          return false;
        }
        JList.DropLocation dl = (JList.DropLocation) support.getDropLocation();
        int index = dl.getIndex();
        if (dl.isInsert()) {
          listModel.add(index, data);
        } else {
          listModel.set(index, data);
        }
        Rectangle r = list.getCellBounds(index, index);
        list.scrollRectToVisible(r);
        return true;
      }
    });
    JScrollPane center = new JScrollPane();
    center.setViewportView(list);
    list.setDropMode(DropMode.USE_SELECTION);
    JPanel cp = new JPanel();
    cp.setLayout(new BorderLayout());
    cp.add(north, BorderLayout.NORTH);
    cp.add(center, BorderLayout.CENTER);
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setContentPane(cp);
    frame.pack();
    frame.setVisible(true);
  }
}





14. Drag and drop between JTextArea and JTextField

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class DnDBetweenJTextAreaAndJTextFieldDemo {
  public static void main(String[] args) {
    JFrame frame = new JFrame("Drag and Drop Demo");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setContentPane(new JPanel());
    JTextField textField = new JTextField(25);
    textField.setText("www.jexp.ru");
    frame.add(textField);
    JTextArea textArea = new JTextArea(4, 25);
    textArea.setText("Demonstrating\ndrag and drop");
    frame.getContentPane().add(new JScrollPane(textArea));
    textArea.setDragEnabled(true);
    textField.setDragEnabled(true);
    frame.pack();
    frame.setVisible(true);
  }
}





14. Drag-and-Drop customization: drag the foreground color from the first label and drop it as the background color into the second one

/*
 * Copyright (c) 2004 David Flanagan.  All rights reserved.
 * This code is from the book Java Examples in a Nutshell, 3nd Edition.
 * It is provided AS-IS, WITHOUT ANY WARRANTY either expressed or implied.
 * You may study, use, and modify it for any non-commercial purpose,
 * including teaching and use in open-source projects.
 * You may distribute it non-commercially as long as you retain this notice.
 * For a commercial use license, or to purchase the book, 
 * please visit http://www.davidflanagan.ru/javaexamples3.
 */
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.TransferHandler;
/**
 * Simple Drag-and-Drop customization: drag the foreground color from the first
 * label and drop it as the background color into the second one. Try it also
 * using the ShowBean program to display a JColorChooser component with
 * dragEnabled=true.
 */
public class ColorDrag {
  public static void main(String args[]) {
    // Create two JLabel objects
    final JLabel label1 = new JLabel("Drag here");
    JLabel label2 = new JLabel("Drop here");
    // Register TransferHandler objects on them: label1 transfers its
    // foreground color and label2 transfers its background color.
    label1.setTransferHandler(new TransferHandler("foreground"));
    label2.setTransferHandler(new TransferHandler("background"));
    // Give label1 a foreground color other than the default
    // Make label2 opaque so it displays its background color
    label1.setForeground(new Color(100, 100, 200));
    label2.setOpaque(true);
    // Now look for drag gestures over label1. When one occurs,
    // tell the TransferHandler to begin a drag.
    // Exercise: modify this gesture recognition so that the drag doesn"t
    // begin until the mouse has moved 4 pixels. This helps to keep
    // drags distinct from sloppy clicks. To do this, you"ll need both
    // a MouseListener and a MouseMotionListener.
    label1.addMouseMotionListener(new MouseMotionAdapter() {
      public void mouseDragged(MouseEvent e) {
        TransferHandler handler = label1.getTransferHandler();
        handler.exportAsDrag(label1, e, TransferHandler.COPY);
      }
    });
    // Create a window, add the labels, and make it all visible.
    JFrame f = new JFrame("ColorDrag");
    f.getContentPane().setLayout(new FlowLayout());
    f.getContentPane().add(label1);
    f.getContentPane().add(label2);
    f.pack();
    f.setVisible(true);
  }
}





14. Drag and drop icons: use an icon property.

import java.awt.FlowLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.TransferHandler;
class DragMouseAdapter extends MouseAdapter {
  public void mousePressed(MouseEvent e) {
    JComponent c = (JComponent) e.getSource();
    TransferHandler handler = c.getTransferHandler();
    handler.exportAsDrag(c, e, TransferHandler.COPY);
  }
}
public class IconDnD {
  public static void main(String[] args) {
    JFrame f = new JFrame("Icon Drag & Drop");
    ImageIcon icon1 = new ImageIcon("a.png");
    ImageIcon icon2 = new ImageIcon("b.png");
    ImageIcon icon3 = new ImageIcon("c.png");
    JButton button = new JButton(icon2);
    JLabel label1 = new JLabel(icon1, JLabel.CENTER);
    JLabel label2 = new JLabel(icon3, JLabel.CENTER);
    MouseListener listener = new DragMouseAdapter();
    label1.addMouseListener(listener);
    label2.addMouseListener(listener);
    label1.setTransferHandler(new TransferHandler("icon"));
    button.setTransferHandler(new TransferHandler("icon"));
    label2.setTransferHandler(new TransferHandler("icon"));
    f.setLayout(new FlowLayout());
    f.add(label1);
    f.add(button);
    f.add(label2);
    f.pack();
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.setVisible(true);
  }
}





14. Drag-and-Drop Support for Images

To transfer something other than a simple property, you need to create an implementation of the Transferable interface,



import java.awt.BorderLayout;
import java.awt.Image;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.IOException;
import javax.swing.AbstractButton;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.TransferHandler;
class ImageSelection extends TransferHandler implements Transferable {
  private static final DataFlavor flavors[] = { DataFlavor.imageFlavor };
  private Image image;
  public int getSourceActions(JComponent c) {
    return TransferHandler.COPY;
  }
  public boolean canImport(JComponent comp, DataFlavor flavor[]) {
    if (!(comp instanceof JLabel) && !(comp instanceof AbstractButton)) {
      return false;
    }
    for (int i = 0, n = flavor.length; i < n; i++) {
      for (int j = 0, m = flavors.length; j < m; j++) {
        if (flavor[i].equals(flavors[j])) {
          return true;
        }
      }
    }
    return false;
  }
  public Transferable createTransferable(JComponent comp) {
    // Clear
    image = null;
    if (comp instanceof JLabel) {
      JLabel label = (JLabel) comp;
      Icon icon = label.getIcon();
      if (icon instanceof ImageIcon) {
        image = ((ImageIcon) icon).getImage();
        return this;
      }
    } else if (comp instanceof AbstractButton) {
      AbstractButton button = (AbstractButton) comp;
      Icon icon = button.getIcon();
      if (icon instanceof ImageIcon) {
        image = ((ImageIcon) icon).getImage();
        return this;
      }
    }
    return null;
  }
  public boolean importData(JComponent comp, Transferable t) {
    if (comp instanceof JLabel) {
      JLabel label = (JLabel) comp;
      if (t.isDataFlavorSupported(flavors[0])) {
        try {
          image = (Image) t.getTransferData(flavors[0]);
          ImageIcon icon = new ImageIcon(image);
          label.setIcon(icon);
          return true;
        } catch (UnsupportedFlavorException ignored) {
        } catch (IOException ignored) {
        }
      }
    } else if (comp instanceof AbstractButton) {
      AbstractButton button = (AbstractButton) comp;
      if (t.isDataFlavorSupported(flavors[0])) {
        try {
          image = (Image) t.getTransferData(flavors[0]);
          ImageIcon icon = new ImageIcon(image);
          button.setIcon(icon);
          return true;
        } catch (UnsupportedFlavorException ignored) {
        } catch (IOException ignored) {
        }
      }
    }
    return false;
  }
  // Transferable
  public Object getTransferData(DataFlavor flavor) {
    if (isDataFlavorSupported(flavor)) {
      return image;
    }
    return null;
  }
  public DataFlavor[] getTransferDataFlavors() {
    return flavors;
  }
  public boolean isDataFlavorSupported(DataFlavor flavor) {
    return flavors[0].equals(flavor);
  }
}
public class DragImage {
  public static void main(String args[]) {
    JFrame frame = new JFrame("Drag Image");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    Icon icon = new ImageIcon("yourFile.gif");
    JLabel label = new JLabel(icon);
    label.setTransferHandler(new ImageSelection());
    MouseListener listener = new MouseAdapter() {
      public void mousePressed(MouseEvent me) {
        JComponent comp = (JComponent) me.getSource();
        TransferHandler handler = comp.getTransferHandler();
        handler.exportAsDrag(comp, me, TransferHandler.COPY);
      }
    };
    label.addMouseListener(listener);
    frame.add(new JScrollPane(label), BorderLayout.CENTER);
    frame.setSize(300, 150);
    frame.setVisible(true);
  }
}





14. Dragging and dropping text between a text area, a list, and a table

/*
 *
 * Copyright (c) 1998 Sun Microsystems, Inc. All Rights Reserved.
 *
 * Sun grants you ("Licensee") a non-exclusive, royalty free, license to use,
 * modify and redistribute this software in source and binary code form,
 * provided that i) this copyright notice and license appear on all copies of
 * the software; and ii) Licensee does not utilize the software in a manner
 * which is disparaging to Sun.
 *
 * This software is provided "AS IS," without a warranty of any kind. ALL
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
 * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
 * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
 * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
 * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
 * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
 * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
 * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
 * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES.
 *
 * This software is not designed or intended for use in on-line control of
 * aircraft, air traffic, aircraft navigation or aircraft communications; or in
 * the design, construction, operation or maintenance of any nuclear
 * facility. Licensee represents and warrants that it will not use or
 * redistribute the Software for such purposes.
 */
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;
import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.ListSelectionModel;
import javax.swing.TransferHandler;
import javax.swing.table.DefaultTableModel;
public class ExtendedDnDDemo extends JPanel {
    
    public ExtendedDnDDemo() {
        super(new GridLayout(3,1));
        add(createArea());
        add(createList());
        add(createTable());
    }
    
    private JPanel createList() {
        DefaultListModel listModel = new DefaultListModel();
        listModel.addElement("List 0");
        listModel.addElement("List 1");
        listModel.addElement("List 2");
        listModel.addElement("List 3");
        listModel.addElement("List 4");
        listModel.addElement("List 5");
        listModel.addElement("List 6");
        listModel.addElement("List 7");
        listModel.addElement("List 8");
        
        JList list = new JList(listModel);
        list.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
        JScrollPane scrollPane = new JScrollPane(list);
        scrollPane.setPreferredSize(new Dimension(400,100));
        
        list.setDragEnabled(true);
        list.setTransferHandler(new ListTransferHandler());
        
        JPanel panel = new JPanel(new BorderLayout());
        panel.add(scrollPane, BorderLayout.CENTER);
        panel.setBorder(BorderFactory.createTitledBorder("List"));
        return panel;
    }
    
    private JPanel createArea() {
        String text = "This is the text that I want to show.";
        
        JTextArea area = new JTextArea();
        area.setText(text);
        area.setDragEnabled(true);
        JScrollPane scrollPane = new JScrollPane(area);
        scrollPane.setPreferredSize(new Dimension(400,100));
        JPanel panel = new JPanel(new BorderLayout());
        panel.add(scrollPane, BorderLayout.CENTER);
        panel.setBorder(BorderFactory.createTitledBorder("Text Area"));
        return panel;
    }
    private JPanel createTable() {
        DefaultTableModel model = new DefaultTableModel();
        
        model.addColumn("Column 0");
        model.addColumn("Column 1");
        model.addColumn("Column 2");
        model.addColumn("Column 3");
        
        model.addRow(new String[]{"Table 00", "Table 01",
                                  "Table 02", "Table 03"});
        model.addRow(new String[]{"Table 10", "Table 11",
                                  "Table 12", "Table 13"});
        model.addRow(new String[]{"Table 20", "Table 21",
                                  "Table 22", "Table 23"});
        model.addRow(new String[]{"Table 30", "Table 31",
                                  "Table 32", "Table 33"});
        JTable table = new JTable(model);
        table.getTableHeader().setReorderingAllowed(false);
        table.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
        JScrollPane scrollPane = new JScrollPane(table);
        scrollPane.setPreferredSize(new Dimension(400,100));
        table.setDragEnabled(true);
        table.setTransferHandler(new TableTransferHandler());
        JPanel panel = new JPanel(new BorderLayout());
        panel.add(scrollPane, BorderLayout.CENTER);
        panel.setBorder(BorderFactory.createTitledBorder("Table"));
        return panel;
    }
    /**
     * Create the GUI and show it.  For thread safety,
     * this method should be invoked from the
     * event-dispatching thread.
     */
    private static void createAndShowGUI() {
        //Create and set up the window.
        JFrame frame = new JFrame("ExtendedDnDDemo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        //Create and set up the content pane.
        JComponent newContentPane = new ExtendedDnDDemo();
        newContentPane.setOpaque(true); //content panes must be opaque
        frame.setContentPane(newContentPane);
        //Display the window.
        frame.pack();
        frame.setVisible(true);
    }
    public static void main(String[] args) {
        //Schedule a job for the event-dispatching thread:
        //creating and showing this application"s GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }
}
abstract class StringTransferHandler extends TransferHandler {
    
    protected abstract String exportString(JComponent c);
    protected abstract void importString(JComponent c, String str);
    protected abstract void cleanup(JComponent c, boolean remove);
    
    protected Transferable createTransferable(JComponent c) {
        return new StringSelection(exportString(c));
    }
    
    public int getSourceActions(JComponent c) {
        return COPY_OR_MOVE;
    }
    
    public boolean importData(JComponent c, Transferable t) {
        if (canImport(c, t.getTransferDataFlavors())) {
            try {
                String str = (String)t.getTransferData(DataFlavor.stringFlavor);
                importString(c, str);
                return true;
            } catch (UnsupportedFlavorException ufe) {
            } catch (IOException ioe) {
            }
        }
        return false;
    }
    
    protected void exportDone(JComponent c, Transferable data, int action) {
        cleanup(c, action == MOVE);
    }
    
    public boolean canImport(JComponent c, DataFlavor[] flavors) {
        for (int i = 0; i < flavors.length; i++) {
            if (DataFlavor.stringFlavor.equals(flavors[i])) {
                return true;
            }
        }
        return false;
    }
}
class ListTransferHandler extends StringTransferHandler {
    private int[] indices = null;
    private int addIndex = -1; //Location where items were added
    private int addCount = 0;  //Number of items added.
            
    //Bundle up the selected items in the list
    //as a single string, for export.
    protected String exportString(JComponent c) {
        JList list = (JList)c;
        indices = list.getSelectedIndices();
        Object[] values = list.getSelectedValues();
        
        StringBuffer buff = new StringBuffer();
        for (int i = 0; i < values.length; i++) {
            Object val = values[i];
            buff.append(val == null ? "" : val.toString());
            if (i != values.length - 1) {
                buff.append("\n");
            }
        }
        
        return buff.toString();
    }
    //Take the incoming string and wherever there is a
    //newline, break it into a separate item in the list.
    protected void importString(JComponent c, String str) {
        JList target = (JList)c;
        DefaultListModel listModel = (DefaultListModel)target.getModel();
        int index = target.getSelectedIndex();
        //Prevent the user from dropping data back on itself.
        //For example, if the user is moving items #4,#5,#6 and #7 and
        //attempts to insert the items after item #5, this would
        //be problematic when removing the original items.
        //So this is not allowed.
        if (indices != null && index >= indices[0] - 1 &&
              index <= indices[indices.length - 1]) {
            indices = null;
            return;
        }
        int max = listModel.getSize();
        if (index < 0) {
            index = max;
        } else {
            index++;
            if (index > max) {
                index = max;
            }
        }
        addIndex = index;
        String[] values = str.split("\n");
        addCount = values.length;
        for (int i = 0; i < values.length; i++) {
            listModel.add(index++, values[i]);
        }
    }
    //If the remove argument is true, the drop has been
    //successful and it"s time to remove the selected items 
    //from the list. If the remove argument is false, it
    //was a Copy operation and the original list is left
    //intact.
    protected void cleanup(JComponent c, boolean remove) {
        if (remove && indices != null) {
            JList source = (JList)c;
            DefaultListModel model  = (DefaultListModel)source.getModel();
            //If we are moving items around in the same list, we
            //need to adjust the indices accordingly, since those
            //after the insertion point have moved.
            if (addCount > 0) {
                for (int i = 0; i < indices.length; i++) {
                    if (indices[i] > addIndex) {
                        indices[i] += addCount;
                    }
                }
            }
            for (int i = indices.length - 1; i >= 0; i--) {
                model.remove(indices[i]);
            }
        }
        indices = null;
        addCount = 0;
        addIndex = -1;
    }
}
class TableTransferHandler extends StringTransferHandler {
    private int[] rows = null;
    private int addIndex = -1; //Location where items were added
    private int addCount = 0;  //Number of items added.
    protected String exportString(JComponent c) {
        JTable table = (JTable)c;
        rows = table.getSelectedRows();
        int colCount = table.getColumnCount();
        
        StringBuffer buff = new StringBuffer();
        
        for (int i = 0; i < rows.length; i++) {
            for (int j = 0; j < colCount; j++) {
                Object val = table.getValueAt(rows[i], j);
                buff.append(val == null ? "" : val.toString());
                if (j != colCount - 1) {
                    buff.append(",");
                }
            }
            if (i != rows.length - 1) {
                buff.append("\n");
            }
        }
        
        return buff.toString();
    }
    protected void importString(JComponent c, String str) {
        JTable target = (JTable)c;
        DefaultTableModel model = (DefaultTableModel)target.getModel();
        int index = target.getSelectedRow();
        //Prevent the user from dropping data back on itself.
        //For example, if the user is moving rows #4,#5,#6 and #7 and
        //attempts to insert the rows after row #5, this would
        //be problematic when removing the original rows.
        //So this is not allowed.
        if (rows != null && index >= rows[0] - 1 &&
              index <= rows[rows.length - 1]) {
            rows = null;
            return;
        }
        int max = model.getRowCount();
        if (index < 0) {
            index = max;
        } else {
            index++;
            if (index > max) {
                index = max;
            }
        }
        addIndex = index;
        String[] values = str.split("\n");
        addCount = values.length;
        int colCount = target.getColumnCount();
        for (int i = 0; i < values.length && i < colCount; i++) {
            model.insertRow(index++, values[i].split(","));
        }
    }
    protected void cleanup(JComponent c, boolean remove) {
        JTable source = (JTable)c;
        if (remove && rows != null) {
            DefaultTableModel model =
                 (DefaultTableModel)source.getModel();
            //If we are moving items around in the same table, we
            //need to adjust the rows accordingly, since those
            //after the insertion point have moved.
            if (addCount > 0) {
                for (int i = 0; i < rows.length; i++) {
                    if (rows[i] > addIndex) {
                        rows[i] += addCount;
                    }
                }
            }
            for (int i = rows.length - 1; i >= 0; i--) {
                model.removeRow(rows[i]);
            }
        }
        rows = null;
        addCount = 0;
        addIndex = -1;
    }
}





14. Dragging Text from a JLabel

import java.awt.BorderLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.TransferHandler;
public class DragLabel {
  public static void main(String args[]) {
    JFrame frame = new JFrame("Drag Label");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    JLabel label = new JLabel("Hello, World");
    label.setTransferHandler(new TransferHandler("foreground"));
    MouseListener listener = new MouseAdapter() {
      public void mousePressed(MouseEvent me) {
        JComponent comp = (JComponent) me.getSource();
        TransferHandler handler = comp.getTransferHandler();
        handler.exportAsDrag(comp, me, TransferHandler.COPY);
      }
    };
    label.addMouseListener(listener);
    frame.add(label, BorderLayout.SOUTH);
    JTextField text = new JTextField();
    frame.add(text, BorderLayout.NORTH);
    frame.setSize(300, 150);
    frame.setVisible(true);
  }
}





14. DropMode.INSERT

import java.awt.BorderLayout;
import java.awt.Rectangle;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import javax.swing.DefaultListModel;
import javax.swing.DropMode;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.TransferHandler;
public class DropModeINSERT {
  public static void main(String[] args) {
    JPanel north = new JPanel();
    north.add(new JLabel("Drag from here:"));
    JTextField field = new JTextField(10);
    field.setDragEnabled(true); 
    north.add(field);
    final DefaultListModel listModel = new DefaultListModel();
    listModel.addElement("first");
    listModel.addElement("second");
    final JList list = new JList(listModel);
    list.setDragEnabled(true);
    list.setTransferHandler(new TransferHandler() {
      public boolean canImport(TransferHandler.TransferSupport support) {
        if (!support.isDataFlavorSupported(DataFlavor.stringFlavor)) {
          return false;
        }
        JList.DropLocation dl = (JList.DropLocation) support.getDropLocation();
        if (dl.getIndex() == -1) {
          return false;
        } else {
          return true;
        }
      }
      public boolean importData(TransferHandler.TransferSupport support) {
        if (!canImport(support)) {
          return false;
        }
        Transferable transferable = support.getTransferable();
        String data;
        try {
          data = (String) transferable.getTransferData(DataFlavor.stringFlavor);
        } catch (Exception e) {
          return false;
        }
        JList.DropLocation dl = (JList.DropLocation) support.getDropLocation();
        int index = dl.getIndex();
        if (dl.isInsert()) {
          listModel.add(index, data);
        } else {
          listModel.set(index, data);
        }
        // Scroll to display the element that was dropped
        Rectangle r = list.getCellBounds(index, index);
        list.scrollRectToVisible(r);
        return true;
      }
    });
    JScrollPane center = new JScrollPane();
    center.setViewportView(list);
    list.setDropMode(DropMode.INSERT);
    JPanel cp = new JPanel();
    cp.setLayout(new BorderLayout());
    cp.add(north, BorderLayout.NORTH);
    cp.add(center, BorderLayout.CENTER);
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setContentPane(cp);
    frame.pack();
    frame.setVisible(true);
  }
}





14. DropMode.ON

import java.awt.BorderLayout;
import java.awt.Rectangle;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import javax.swing.DefaultListModel;
import javax.swing.DropMode;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.TransferHandler;
public class DropModeON {
  public static void main(String[] args) {
    JPanel north = new JPanel();
    north.add(new JLabel("Drag from here:"));
    JTextField field = new JTextField(10);
    field.setDragEnabled(true); 
    north.add(field);
    final DefaultListModel listModel = new DefaultListModel();
    listModel.addElement("first");
    listModel.addElement("second");
    final JList list = new JList(listModel);
    list.setDragEnabled(true);
    list.setTransferHandler(new TransferHandler() {
      public boolean canImport(TransferHandler.TransferSupport support) {
        if (!support.isDataFlavorSupported(DataFlavor.stringFlavor)) {
          return false;
        }
        JList.DropLocation dl = (JList.DropLocation) support.getDropLocation();
        if (dl.getIndex() == -1) {
          return false;
        } else {
          return true;
        }
      }
      public boolean importData(TransferHandler.TransferSupport support) {
        if (!canImport(support)) {
          return false;
        }
        Transferable transferable = support.getTransferable();
        String data;
        try {
          data = (String) transferable.getTransferData(DataFlavor.stringFlavor);
        } catch (Exception e) {
          return false;
        }
        JList.DropLocation dl = (JList.DropLocation) support.getDropLocation();
        int index = dl.getIndex();
        if (dl.isInsert()) {
          listModel.add(index, data);
        } else {
          listModel.set(index, data);
        }
        // Scroll to display the element that was dropped
        Rectangle r = list.getCellBounds(index, index);
        list.scrollRectToVisible(r);
        return true;
      }
    });
    JScrollPane center = new JScrollPane();
    center.setViewportView(list);
    list.setDropMode(DropMode.ON);
    JPanel cp = new JPanel();
    cp.setLayout(new BorderLayout());
    cp.add(north, BorderLayout.NORTH);
    cp.add(center, BorderLayout.CENTER);
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setContentPane(cp);
    frame.pack();
    frame.setVisible(true);
  }
}





14. DropMode.ON_OR_INSERT

import java.awt.BorderLayout;
import java.awt.Rectangle;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import javax.swing.DefaultListModel;
import javax.swing.DropMode;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.TransferHandler;
public class DropModeON_OR_INSERT {
  public static void main(String[] args) {
    JPanel north = new JPanel();
    north.add(new JLabel("Drag from here:"));
    JTextField field = new JTextField(10);
    field.setDragEnabled(true); 
    north.add(field);
    final DefaultListModel listModel = new DefaultListModel();
    listModel.addElement("first");
    listModel.addElement("second");
    final JList list = new JList(listModel);
    list.setDragEnabled(true);
    list.setTransferHandler(new TransferHandler() {
      public boolean canImport(TransferHandler.TransferSupport support) {
        if (!support.isDataFlavorSupported(DataFlavor.stringFlavor)) {
          return false;
        }
        JList.DropLocation dl = (JList.DropLocation) support.getDropLocation();
        if (dl.getIndex() == -1) {
          return false;
        } else {
          return true;
        }
      }
      public boolean importData(TransferHandler.TransferSupport support) {
        if (!canImport(support)) {
          return false;
        }
        Transferable transferable = support.getTransferable();
        String data;
        try {
          data = (String) transferable.getTransferData(DataFlavor.stringFlavor);
        } catch (Exception e) {
          return false;
        }
        JList.DropLocation dl = (JList.DropLocation) support.getDropLocation();
        int index = dl.getIndex();
        if (dl.isInsert()) {
          listModel.add(index, data);
        } else {
          listModel.set(index, data);
        }
        // Scroll to display the element that was dropped
        Rectangle r = list.getCellBounds(index, index);
        list.scrollRectToVisible(r);
        return true;
      }
    });
    JScrollPane center = new JScrollPane();
    center.setViewportView(list);
    list.setDropMode(DropMode.ON_OR_INSERT);
    JPanel cp = new JPanel();
    cp.setLayout(new BorderLayout());
    cp.add(north, BorderLayout.NORTH);
    cp.add(center, BorderLayout.CENTER);
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setContentPane(cp);
    frame.pack();
    frame.setVisible(true);
  }
}





14. Illustrates cut, copy, paste and drag and drop using three instances of JList

/*
 * Copyright (c) 1995 - 2008 Sun Microsystems, Inc.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 *   - Neither the name of Sun Microsystems nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
/**
 * ListCutPaste.java requires the following files:
 *     ListTransferHandler.java
 *     TransferActionListener.java
 */
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.KeyboardFocusManager;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
import javax.swing.DropMode;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.KeyStroke;
import javax.swing.ListSelectionModel;
import javax.swing.TransferHandler;
import javax.swing.UIManager;
/**
 * The ListCutPaste example illustrates cut, copy, paste and drag and drop using
 * three instances of JList. The TransferActionListener class listens for one of
 * the CCP actions and, when one occurs, forwards the action to the component
 * which currently has the focus.
 */
public class ListCutPaste extends JPanel {
  ListTransferHandler lh;
  public ListCutPaste() {
    super(new BorderLayout());
    lh = new ListTransferHandler();
    JPanel panel = new JPanel(new GridLayout(1, 3));
    DefaultListModel list1Model = new DefaultListModel();
    list1Model.addElement("alpha");
    list1Model.addElement("beta");
    list1Model.addElement("gamma");
    list1Model.addElement("delta");
    list1Model.addElement("epsilon");
    list1Model.addElement("zeta");
    JList list1 = new JList(list1Model);
    list1.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    JScrollPane sp1 = new JScrollPane(list1);
    sp1.setPreferredSize(new Dimension(400, 100));
    list1.setDragEnabled(true);
    list1.setTransferHandler(lh);
    list1.setDropMode(DropMode.ON_OR_INSERT);
    setMappings(list1);
    JPanel pan1 = new JPanel(new BorderLayout());
    pan1.add(sp1, BorderLayout.CENTER);
    pan1.setBorder(BorderFactory.createTitledBorder("Greek Alphabet"));
    panel.add(pan1);
    DefaultListModel list2Model = new DefaultListModel();
    list2Model.addElement("uma");
    list2Model.addElement("dois");
    list2Model.addElement("tres");
    list2Model.addElement("quatro");
    list2Model.addElement("cinco");
    list2Model.addElement("seis");
    JList list2 = new JList(list2Model);
    list2.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    list2.setDragEnabled(true);
    JScrollPane sp2 = new JScrollPane(list2);
    sp2.setPreferredSize(new Dimension(400, 100));
    list2.setTransferHandler(lh);
    list2.setDropMode(DropMode.INSERT);
    setMappings(list2);
    JPanel pan2 = new JPanel(new BorderLayout());
    pan2.add(sp2, BorderLayout.CENTER);
    pan2.setBorder(BorderFactory.createTitledBorder("Portuguese Numbers"));
    panel.add(pan2);
    DefaultListModel list3Model = new DefaultListModel();
    list3Model.addElement("adeen");
    list3Model.addElement("dva");
    list3Model.addElement("tri");
    list3Model.addElement("chyetirye");
    list3Model.addElement("pyat");
    list3Model.addElement("shest");
    JList list3 = new JList(list3Model);
    list3.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    list3.setDragEnabled(true);
    JScrollPane sp3 = new JScrollPane(list3);
    sp3.setPreferredSize(new Dimension(400, 100));
    list3.setTransferHandler(lh);
    list3.setDropMode(DropMode.ON);
    setMappings(list3);
    JPanel pan3 = new JPanel(new BorderLayout());
    pan3.add(sp3, BorderLayout.CENTER);
    pan3.setBorder(BorderFactory.createTitledBorder("Russian Numbers"));
    panel.add(pan3);
    setPreferredSize(new Dimension(500, 200));
    add(panel, BorderLayout.CENTER);
  }
  /**
   * Create an Edit menu to support cut/copy/paste.
   */
  public JMenuBar createMenuBar() {
    JMenuItem menuItem = null;
    JMenuBar menuBar = new JMenuBar();
    JMenu mainMenu = new JMenu("Edit");
    mainMenu.setMnemonic(KeyEvent.VK_E);
    TransferActionListener actionListener = new TransferActionListener();
    menuItem = new JMenuItem("Cut");
    menuItem.setActionCommand((String) TransferHandler.getCutAction().getValue(
        Action.NAME));
    menuItem.addActionListener(actionListener);
    menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X,
        ActionEvent.CTRL_MASK));
    menuItem.setMnemonic(KeyEvent.VK_T);
    mainMenu.add(menuItem);
    menuItem = new JMenuItem("Copy");
    menuItem.setActionCommand((String) TransferHandler.getCopyAction()
        .getValue(Action.NAME));
    menuItem.addActionListener(actionListener);
    menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C,
        ActionEvent.CTRL_MASK));
    menuItem.setMnemonic(KeyEvent.VK_C);
    mainMenu.add(menuItem);
    menuItem = new JMenuItem("Paste");
    menuItem.setActionCommand((String) TransferHandler.getPasteAction()
        .getValue(Action.NAME));
    menuItem.addActionListener(actionListener);
    menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V,
        ActionEvent.CTRL_MASK));
    menuItem.setMnemonic(KeyEvent.VK_P);
    mainMenu.add(menuItem);
    menuBar.add(mainMenu);
    return menuBar;
  }
  /**
   * Add the cut/copy/paste actions to the action map.
   */
  private void setMappings(JList list) {
    ActionMap map = list.getActionMap();
    map.put(TransferHandler.getCutAction().getValue(Action.NAME),
        TransferHandler.getCutAction());
    map.put(TransferHandler.getCopyAction().getValue(Action.NAME),
        TransferHandler.getCopyAction());
    map.put(TransferHandler.getPasteAction().getValue(Action.NAME),
        TransferHandler.getPasteAction());
  }
  /**
   * Create the GUI and show it. For thread safety, this method should be
   * invoked from the event-dispatching thread.
   */
  private static void createAndShowGUI() {
    // Create and set up the window.
    JFrame frame = new JFrame("ListCutPaste");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    // Create and set up the menu bar and content pane.
    ListCutPaste demo = new ListCutPaste();
    frame.setJMenuBar(demo.createMenuBar());
    demo.setOpaque(true); // content panes must be opaque
    frame.setContentPane(demo);
    // Display the window.
    frame.pack();
    frame.setVisible(true);
  }
  public static void main(String[] args) {
    // Schedule a job for the event-dispatching thread:
    // creating and showing this application"s GUI.
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        // Turn off metal"s use of bold fonts
        UIManager.put("swing.boldMetal", Boolean.FALSE);
        createAndShowGUI();
      }
    });
  }
}/*
   * Copyright (c) 1995 - 2008 Sun Microsystems, Inc. All rights reserved.
   * 
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions are met:
   *  - Redistributions of source code must retain the above copyright notice,
   * this list of conditions and the following disclaimer.
   *  - Redistributions in binary form must reproduce the above copyright
   * notice, this list of conditions and the following disclaimer in the
   * documentation and/or other materials provided with the distribution.
   *  - Neither the name of Sun Microsystems nor the names of its contributors
   * may be used to endorse or promote products derived from this software
   * without specific prior written permission.
   * 
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   * POSSIBILITY OF SUCH DAMAGE.
   */
/*
 * ListTransferHandler.java is used by the ListCutPaste example.
 */
class ListTransferHandler extends TransferHandler {
  /**
   * Perform the actual data import.
   */
  public boolean importData(TransferHandler.TransferSupport info) {
    String data = null;
    // If we can"t handle the import, bail now.
    if (!canImport(info)) {
      return false;
    }
    JList list = (JList) info.getComponent();
    DefaultListModel model = (DefaultListModel) list.getModel();
    // Fetch the data -- bail if this fails
    try {
      data = (String) info.getTransferable().getTransferData(
          DataFlavor.stringFlavor);
    } catch (UnsupportedFlavorException ufe) {
      System.out.println("importData: unsupported data flavor");
      return false;
    } catch (IOException ioe) {
      System.out.println("importData: I/O exception");
      return false;
    }
    if (info.isDrop()) { // This is a drop
      JList.DropLocation dl = (JList.DropLocation) info.getDropLocation();
      int index = dl.getIndex();
      if (dl.isInsert()) {
        model.add(index, data);
        return true;
      } else {
        model.set(index, data);
        return true;
      }
    } else { // This is a paste
      int index = list.getSelectedIndex();
      // if there is a valid selection,
      // insert data after the selection
      if (index >= 0) {
        model.add(list.getSelectedIndex() + 1, data);
        // else append to the end of the list
      } else {
        model.addElement(data);
      }
      return true;
    }
  }
  /**
   * Bundle up the data for export.
   */
  protected Transferable createTransferable(JComponent c) {
    JList list = (JList) c;
    int index = list.getSelectedIndex();
    String value = (String) list.getSelectedValue();
    return new StringSelection(value);
  }
  /**
   * The list handles both copy and move actions.
   */
  public int getSourceActions(JComponent c) {
    return COPY_OR_MOVE;
  }
  /**
   * When the export is complete, remove the old list entry if the action was a
   * move.
   */
  protected void exportDone(JComponent c, Transferable data, int action) {
    if (action != MOVE) {
      return;
    }
    JList list = (JList) c;
    DefaultListModel model = (DefaultListModel) list.getModel();
    int index = list.getSelectedIndex();
    model.remove(index);
  }
  /**
   * We only support importing strings.
   */
  public boolean canImport(TransferHandler.TransferSupport support) {
    // we only import Strings
    if (!support.isDataFlavorSupported(DataFlavor.stringFlavor)) {
      return false;
    }
    return true;
  }
}
/*
 * Copyright (c) 1995 - 2008 Sun Microsystems, Inc. All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *  - Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *  - Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *  - Neither the name of Sun Microsystems nor the names of its contributors may
 * be used to endorse or promote products derived from this software without
 * specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
/*
 * TransferActionListener.java is used by the ListCutPaste example.
 */
/**
 * A class that tracks the focused component. This is necessary to delegate the
 * menu cut/copy/paste commands to the right component. An instance of this
 * class is listening and when the user fires one of these commands, it calls
 * the appropriate action on the currently focused component.
 */
class TransferActionListener implements ActionListener, PropertyChangeListener {
  private JComponent focusOwner = null;
  public TransferActionListener() {
    KeyboardFocusManager manager = KeyboardFocusManager
        .getCurrentKeyboardFocusManager();
    manager.addPropertyChangeListener("permanentFocusOwner", this);
  }
  public void propertyChange(PropertyChangeEvent e) {
    Object o = e.getNewValue();
    if (o instanceof JComponent) {
      focusOwner = (JComponent) o;
    } else {
      focusOwner = null;
    }
  }
  public void actionPerformed(ActionEvent e) {
    if (focusOwner == null)
      return;
    String action = (String) e.getActionCommand();
    Action a = focusOwner.getActionMap().get(action);
    if (a != null) {
      a.actionPerformed(new ActionEvent(focusOwner,
          ActionEvent.ACTION_PERFORMED, null));
    }
  }
}





14. implements DragGestureListener, Transferable

import java.awt.Cursor;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DragGestureEvent;
import java.awt.dnd.DragGestureListener;
import java.awt.dnd.DragSource;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class DragGesture extends JFrame implements DragGestureListener, Transferable {
  public DragGesture() {
    setTitle("Drag Gesture");
    JLabel left = new JLabel("text");
    DragSource ds = new DragSource();
    ds.createDefaultDragGestureRecognizer(left, DnDConstants.ACTION_COPY, this);
    add(left);
    pack();
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setVisible(true);
  }
  public void dragGestureRecognized(DragGestureEvent event) {
    Cursor cursor = null;
    if (event.getDragAction() == DnDConstants.ACTION_COPY) {
      cursor = DragSource.DefaultCopyDrop;
    }
    event.startDrag(cursor, this);
  }
  public Object getTransferData(DataFlavor flavor) {
    return null;
  }
  public DataFlavor[] getTransferDataFlavors() {
    return new DataFlavor[0];
  }
  public boolean isDataFlavorSupported(DataFlavor flavor) {
    return false;
  }
  public static void main(String[] args) {
    new DragGesture();
  }
}





14. JTable drag and drop

/*
 * Copyright (c) 1995 - 2008 Sun Microsystems, Inc.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 *   - Neither the name of Sun Microsystems nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.DefaultListModel;
import javax.swing.DropMode;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.TransferHandler;
import javax.swing.UIManager;
import javax.swing.table.DefaultTableModel;
public class FillViewportHeightDemo extends JFrame implements ActionListener {
  private DefaultListModel model = new DefaultListModel();
  private int count = 0;
  private JTable table;
  private JCheckBoxMenuItem fillBox;
  private DefaultTableModel tableModel;
  private static String getNextString(int count) {
    StringBuffer buf = new StringBuffer();
    for (int i = 0; i < 5; i++) {
      buf.append(String.valueOf(count));
      buf.append(",");
    }
    // remove last newline
    buf.deleteCharAt(buf.length() - 1);
    return buf.toString();
  }
  private static DefaultTableModel getDefaultTableModel() {
    String[] cols = { "Foo", "Toto", "Kala", "Pippo", "Boing" };
    return new DefaultTableModel(null, cols);
  }
  public FillViewportHeightDemo() {
    super("Empty Table DnD Demo");
    tableModel = getDefaultTableModel();
    table = new JTable(tableModel);
    table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
    table.setDropMode(DropMode.INSERT_ROWS);
    table.setTransferHandler(new TransferHandler() {
      public boolean canImport(TransferSupport support) {
        // for the demo, we"ll only support drops (not clipboard paste)
        if (!support.isDrop()) {
          return false;
        }
        // we only import Strings
        if (!support.isDataFlavorSupported(DataFlavor.stringFlavor)) {
          return false;
        }
        return true;
      }
      public boolean importData(TransferSupport support) {
        // if we can"t handle the import, say so
        if (!canImport(support)) {
          return false;
        }
        // fetch the drop location
        JTable.DropLocation dl = (JTable.DropLocation) support
            .getDropLocation();
        int row = dl.getRow();
        // fetch the data and bail if this fails
        String data;
        try {
          data = (String) support.getTransferable().getTransferData(
              DataFlavor.stringFlavor);
        } catch (UnsupportedFlavorException e) {
          return false;
        } catch (IOException e) {
          return false;
        }
        String[] rowData = data.split(",");
        tableModel.insertRow(row, rowData);
        Rectangle rect = table.getCellRect(row, 0, false);
        if (rect != null) {
          table.scrollRectToVisible(rect);
        }
        // demo stuff - remove for blog
        model.removeAllElements();
        model.insertElementAt(getNextString(count++), 0);
        // end demo stuff
        return true;
      }
    });
    JList dragFrom = new JList(model);
    dragFrom.setFocusable(false);
    dragFrom.setPrototypeCellValue(getNextString(100));
    model.insertElementAt(getNextString(count++), 0);
    dragFrom.setDragEnabled(true);
    dragFrom.setBorder(BorderFactory.createLoweredBevelBorder());
    dragFrom.addMouseListener(new MouseAdapter() {
      public void mouseClicked(MouseEvent me) {
        if (SwingUtilities.isLeftMouseButton(me) && me.getClickCount() % 2 == 0) {
          String text = (String) model.getElementAt(0);
          String[] rowData = text.split(",");
          tableModel.insertRow(table.getRowCount(), rowData);
          model.removeAllElements();
          model.insertElementAt(getNextString(count++), 0);
        }
      }
    });
    JPanel p = new JPanel();
    p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS));
    JPanel wrap = new JPanel();
    wrap.add(new JLabel("Drag from here:"));
    wrap.add(dragFrom);
    p.add(Box.createHorizontalStrut(4));
    p.add(Box.createGlue());
    p.add(wrap);
    p.add(Box.createGlue());
    p.add(Box.createHorizontalStrut(4));
    getContentPane().add(p, BorderLayout.NORTH);
    JScrollPane sp = new JScrollPane(table);
    getContentPane().add(sp, BorderLayout.CENTER);
    fillBox = new JCheckBoxMenuItem("Fill Viewport Height");
    fillBox.addActionListener(this);
    JMenuBar mb = new JMenuBar();
    JMenu options = new JMenu("Options");
    mb.add(options);
    setJMenuBar(mb);
    JMenuItem clear = new JMenuItem("Reset");
    clear.addActionListener(this);
    options.add(clear);
    options.add(fillBox);
    getContentPane().setPreferredSize(new Dimension(260, 180));
  }
  public void actionPerformed(ActionEvent ae) {
    if (ae.getSource() == fillBox) {
      table.setFillsViewportHeight(fillBox.isSelected());
    } else {
      tableModel.setRowCount(0);
      count = 0;
      model.removeAllElements();
      model.insertElementAt(getNextString(count++), 0);
    }
  }
  private static void createAndShowGUI() {
    // Create and set up the window.
    FillViewportHeightDemo test = new FillViewportHeightDemo();
    test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    // Display the window.
    test.pack();
    test.setVisible(true);
  }
  public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        // Turn off metal"s use of bold fonts
        UIManager.put("swing.boldMetal", Boolean.FALSE);
        createAndShowGUI();
      }
    });
  }
}





14. Location sensitive drag and drop

/*
 * Copyright (c) 1995 - 2008 Sun Microsystems, Inc.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 *   - Neither the name of Sun Microsystems nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.DefaultListModel;
import javax.swing.DropMode;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.TransferHandler;
import javax.swing.UIManager;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
public class LocationSensitiveDemo extends JFrame {
  private DefaultListModel model = new DefaultListModel();
  private int count = 0;
  private JTree tree;
  private JComboBox indicateCombo;
  private DefaultTreeModel treeModel;
  private TreePath namesPath;
  private static DefaultTreeModel getDefaultTreeModel() {
    DefaultMutableTreeNode root = new DefaultMutableTreeNode("things");
    DefaultMutableTreeNode parent;
    DefaultMutableTreeNode nparent;
    parent = new DefaultMutableTreeNode("colors");
    root.add(parent);
    parent.add(new DefaultMutableTreeNode("red"));
    parent.add(new DefaultMutableTreeNode("yellow"));
    parent.add(new DefaultMutableTreeNode("green"));
    parent.add(new DefaultMutableTreeNode("blue"));
    parent.add(new DefaultMutableTreeNode("purple"));
    parent = new DefaultMutableTreeNode("names");
    root.add(parent);
    nparent = new DefaultMutableTreeNode("men");
    nparent.add(new DefaultMutableTreeNode("jack"));
    nparent.add(new DefaultMutableTreeNode("kieran"));
    nparent.add(new DefaultMutableTreeNode("william"));
    nparent.add(new DefaultMutableTreeNode("jose"));
    parent.add(nparent);
    nparent = new DefaultMutableTreeNode("women");
    nparent.add(new DefaultMutableTreeNode("jennifer"));
    nparent.add(new DefaultMutableTreeNode("holly"));
    nparent.add(new DefaultMutableTreeNode("danielle"));
    nparent.add(new DefaultMutableTreeNode("tara"));
    parent.add(nparent);
    parent = new DefaultMutableTreeNode("sports");
    root.add(parent);
    parent.add(new DefaultMutableTreeNode("basketball"));
    parent.add(new DefaultMutableTreeNode("soccer"));
    parent.add(new DefaultMutableTreeNode("football"));
    nparent = new DefaultMutableTreeNode("hockey");
    parent.add(nparent);
    nparent.add(new DefaultMutableTreeNode("ice hockey"));
    nparent.add(new DefaultMutableTreeNode("roller hockey"));
    nparent.add(new DefaultMutableTreeNode("floor hockey"));
    nparent.add(new DefaultMutableTreeNode("road hockey"));
    parent = new DefaultMutableTreeNode("food");
    root.add(parent);
    parent.add(new DefaultMutableTreeNode("pizza"));
    parent.add(new DefaultMutableTreeNode("wings"));
    parent.add(new DefaultMutableTreeNode("pasta"));
    nparent = new DefaultMutableTreeNode("fruit");
    parent.add(nparent);
    nparent.add(new DefaultMutableTreeNode("bananas"));
    nparent.add(new DefaultMutableTreeNode("apples"));
    nparent.add(new DefaultMutableTreeNode("grapes"));
    nparent.add(new DefaultMutableTreeNode("pears"));
    return new DefaultTreeModel(root);
  }
  public LocationSensitiveDemo() {
    super("Location Sensitive Drag and Drop Demo");
    treeModel = getDefaultTreeModel();
    tree = new JTree(treeModel);
    tree.setBorder(BorderFactory.createEmptyBorder(2, 4, 2, 4));
    tree.getSelectionModel().setSelectionMode(
        TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
    tree.setDropMode(DropMode.ON);
    namesPath = tree.getPathForRow(2);
    tree.expandRow(2);
    tree.expandRow(1);
    tree.setRowHeight(0);
    tree.setTransferHandler(new TransferHandler() {
      public boolean canImport(TransferHandler.TransferSupport info) {
        // for the demo, we"ll only support drops (not clipboard paste)
        if (!info.isDrop()) {
          return false;
        }
        String item = (String) indicateCombo.getSelectedItem();
        if (item.equals("Always")) {
          info.setShowDropLocation(true);
        } else if (item.equals("Never")) {
          info.setShowDropLocation(false);
        }
        // we only import Strings
        if (!info.isDataFlavorSupported(DataFlavor.stringFlavor)) {
          return false;
        }
        // fetch the drop location
        JTree.DropLocation dl = (JTree.DropLocation) info.getDropLocation();
        TreePath path = dl.getPath();
        // we don"t support invalid paths or descendants of the names folder
        if (path == null || namesPath.isDescendant(path)) {
          return false;
        }
        return true;
      }
      public boolean importData(TransferHandler.TransferSupport info) {
        // if we can"t handle the import, say so
        if (!canImport(info)) {
          return false;
        }
        // fetch the drop location
        JTree.DropLocation dl = (JTree.DropLocation) info.getDropLocation();
        // fetch the path and child index from the drop location
        TreePath path = dl.getPath();
        int childIndex = dl.getChildIndex();
        // fetch the data and bail if this fails
        String data;
        try {
          data = (String) info.getTransferable().getTransferData(
              DataFlavor.stringFlavor);
        } catch (UnsupportedFlavorException e) {
          return false;
        } catch (IOException e) {
          return false;
        }
        // if child index is -1, the drop was on top of the path, so we"ll
        // treat it as inserting at the end of that path"s list of children
        if (childIndex == -1) {
          childIndex = tree.getModel().getChildCount(
              path.getLastPathComponent());
        }
        // create a new node to represent the data and insert it into the model
        DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(data);
        DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) path
            .getLastPathComponent();
        treeModel.insertNodeInto(newNode, parentNode, childIndex);
        // make the new node visible and scroll so that it"s visible
        tree.makeVisible(path.pathByAddingChild(newNode));
        tree.scrollRectToVisible(tree.getPathBounds(path
            .pathByAddingChild(newNode)));
        // demo stuff - remove for blog
        model.removeAllElements();
        model.insertElementAt("String " + (++count), 0);
        // end demo stuff
        return true;
      }
    });
    JList dragFrom = new JList(model);
    dragFrom.setFocusable(false);
    dragFrom.setPrototypeCellValue("String 0123456789");
    model.insertElementAt("String " + count, 0);
    dragFrom.setDragEnabled(true);
    dragFrom.setBorder(BorderFactory.createLoweredBevelBorder());
    JPanel p = new JPanel();
    p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS));
    JPanel wrap = new JPanel();
    wrap.add(new JLabel("Drag from here:"));
    wrap.add(dragFrom);
    p.add(Box.createHorizontalStrut(4));
    p.add(Box.createGlue());
    p.add(wrap);
    p.add(Box.createGlue());
    p.add(Box.createHorizontalStrut(4));
    getContentPane().add(p, BorderLayout.NORTH);
    getContentPane().add(new JScrollPane(tree), BorderLayout.CENTER);
    indicateCombo = new JComboBox(new String[] { "Default", "Always", "Never" });
    indicateCombo.setSelectedItem("INSERT");
    p = new JPanel();
    p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS));
    wrap = new JPanel();
    wrap.add(new JLabel("Show drop location:"));
    wrap.add(indicateCombo);
    p.add(Box.createHorizontalStrut(4));
    p.add(Box.createGlue());
    p.add(wrap);
    p.add(Box.createGlue());
    p.add(Box.createHorizontalStrut(4));
    getContentPane().add(p, BorderLayout.SOUTH);
    getContentPane().setPreferredSize(new Dimension(400, 450));
  }
  private static void increaseFont(String type) {
    Font font = UIManager.getFont(type);
    font = font.deriveFont(font.getSize() + 4f);
    UIManager.put(type, font);
  }
  private static void createAndShowGUI() {
    // Create and set up the window.
    LocationSensitiveDemo test = new LocationSensitiveDemo();
    test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    // Display the window.
    test.pack();
    test.setVisible(true);
  }
  public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        try {
          UIManager
              .setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
          increaseFont("Tree.font");
          increaseFont("Label.font");
          increaseFont("ComboBox.font");
          increaseFont("List.font");
        } catch (Exception e) {
        }
        // Turn off metal"s use of bold fonts
        UIManager.put("swing.boldMetal", Boolean.FALSE);
        createAndShowGUI();
      }
    });
  }
}





14. Making a Component Draggable

import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DragGestureEvent;
import java.awt.dnd.DragGestureListener;
import java.awt.dnd.DragSource;
import java.awt.dnd.DragSourceDragEvent;
import java.awt.dnd.DragSourceDropEvent;
import java.awt.dnd.DragSourceEvent;
import java.awt.dnd.DragSourceListener;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class Main {
  public static void main(String[] argv) throws Exception {
    JComponent com = new DraggableComponent();
    JFrame f = new JFrame();
    f.add(com);
    f.setSize(300, 300);
    f.setVisible(true);
  }
}
class DraggableComponent extends JComponent implements DragGestureListener, DragSourceListener {
  DragSource dragSource;
  public DraggableComponent() {
    dragSource = new DragSource();
    dragSource.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_COPY_OR_MOVE, this);
  }
  public void dragGestureRecognized(DragGestureEvent evt) {
    Transferable t = new StringSelection("aString");
    dragSource.startDrag(evt, DragSource.DefaultCopyDrop, t, this);
  }
  public void dragEnter(DragSourceDragEvent evt) {
    System.out.println("enters");
  }
  public void dragOver(DragSourceDragEvent evt) {
    System.out.println("over");
  }
  public void dragExit(DragSourceEvent evt) {
    System.out.println("leaves");
  }
  public void dropActionChanged(DragSourceDragEvent evt) {
    System.out.println("changes the drag action between copy or move");
  }
  public void dragDropEnd(DragSourceDropEvent evt) {
    System.out.println("finishes or cancels the drag operation");
  }
}





14. ScribblePane allows individual PolyLine lines to be selected, cut, copied, pasted, dragged, and dropped

/*
 * Copyright (c) 2004 David Flanagan.  All rights reserved.
 * This code is from the book Java Examples in a Nutshell, 3nd Edition.
 * It is provided AS-IS, WITHOUT ANY WARRANTY either expressed or implied.
 * You may study, use, and modify it for any non-commercial purpose,
 * including teaching and use in open-source projects.
 * You may distribute it non-commercially as long as you retain this notice.
 * For a commercial use license, or to purchase the book, 
 * please visit http://www.davidflanagan.ru/javaexamples3.
 */
import java.awt.AWTEvent;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.ClipboardOwner;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DragGestureEvent;
import java.awt.dnd.DragGestureListener;
import java.awt.dnd.DragSource;
import java.awt.dnd.DragSourceDragEvent;
import java.awt.dnd.DragSourceDropEvent;
import java.awt.dnd.DragSourceEvent;
import java.awt.dnd.DragSourceListener;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.dnd.DropTargetEvent;
import java.awt.dnd.DropTargetListener;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.Externalizable;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.border.BevelBorder;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;
/**
 * This rewrite of ScribblePane allows individual PolyLine lines to be selected,
 * cut, copied, pasted, dragged, and dropped.
 */
public class TransferableScribblePane extends JComponent {
  List lines; // The PolyLines that comprise this scribble
  PolyLine currentLine; // The line currently being drawn
  PolyLine selectedLine; // The line that is current selected
  boolean canDragImage; // Can we drag an image of the line?
  // Lines are 3 pixels wide, and the selected line is drawn dashed
  static Stroke stroke = new BasicStroke(3.0f);
  static Stroke selectedStroke = new BasicStroke(3, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND,
      0f, new float[] { 3f, 3f, }, 0f);
  // Different borders indicate receptivity to drops
  static Border normalBorder = new LineBorder(Color.black, 3);
  static Border canDropBorder = new BevelBorder(BevelBorder.LOWERED);
  public static void main(String args[]) {
    JFrame f = new JFrame("ColorDrag");
    f.getContentPane().setLayout(new FlowLayout());
    f.getContentPane().add(new TransferableScribblePane());
    f.getContentPane().add(new TransferableScribblePane());
    f.pack();
    f.setVisible(true);
  }
  // The constructor method
  public TransferableScribblePane() {
    setPreferredSize(new Dimension(450, 200)); // We need a default size
    setBorder(normalBorder); // and a border.
    lines = new ArrayList(); // Start with an empty list of lines
    // Register interest in mouse button and mouse motion events.
    enableEvents(AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK);
    // Enable drag-and-drop by specifying a listener that will be
    // notified when a drag begins. dragGestureListener is defined later.
    DragSource dragSource = DragSource.getDefaultDragSource();
    dragSource.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_COPY_OR_MOVE,
        dragGestureListener);
    // Enable drops on this component by registering a listener to
    // be notified when something is dragged or dropped over us.
    this.setDropTarget(new DropTarget(this, dropTargetListener));
    // Check whether the system allows us to drag an image of the line
    canDragImage = dragSource.isDragImageSupported();
  }
  /** We override this method to draw ourselves. */
  public void paintComponent(Graphics g) {
    // Let the superclass do its painting first
    super.paintComponent(g);
    // Make a copy of the Graphics context so we can modify it
    Graphics2D g2 = (Graphics2D) (g.create());
    // Our superclass doesn"t paint the background, so do this ourselves.
    g2.setColor(getBackground());
    g2.fillRect(0, 0, getWidth(), getHeight());
    // Set the line width and color to use for the foreground
    g2.setStroke(stroke);
    g2.setColor(this.getForeground());
    // Now loop through the PolyLine shapes and draw them all
    int numlines = lines.size();
    for (int i = 0; i < numlines; i++) {
      PolyLine line = (PolyLine) lines.get(i);
      if (line == selectedLine) { // If it is the selected line
        g2.setStroke(selectedStroke); // Set dash pattern
        g2.draw(line); // Draw the line
        g2.setStroke(stroke); // Revert to solid lines
      } else
        g2.draw(line); // Otherwise just draw the line
    }
  }
  /**
   * This method is called on mouse button events. It begins a new line or tries
   * to select an existing line.
   */
  public void processMouseEvent(MouseEvent e) {
    if (e.getButton() == MouseEvent.BUTTON1) { // Left mouse button
      if (e.getID() == MouseEvent.MOUSE_PRESSED) { // Pressed down
        if (e.isShiftDown()) { // with Shift key
          // If the shift key is down, try to select a line
          int x = e.getX();
          int y = e.getY();
          // Loop through the lines checking to see if we hit one
          PolyLine selection = null;
          int numlines = lines.size();
          for (int i = 0; i < numlines; i++) {
            PolyLine line = (PolyLine) lines.get(i);
            if (line.intersects(x - 2, y - 2, 4, 4)) {
              selection = line;
              e.consume();
              break;
            }
          }
          // If we found an intersecting line, save it and repaint
          if (selection != selectedLine) { // If selection changed
            selectedLine = selection; // remember which is selected
            repaint(); // will make selection dashed
          }
        } else if (!e.isControlDown()) { // no shift key or ctrl key
          // Start a new line on mouse down without shift or ctrl
          currentLine = new PolyLine(e.getX(), e.getY());
          lines.add(currentLine);
          e.consume();
        }
      } else if (e.getID() == MouseEvent.MOUSE_RELEASED) {// Left Button Up
        // End the line on mouse up
        if (currentLine != null) {
          currentLine = null;
          e.consume();
        }
      }
    }
    // The superclass method dispatches to registered event listeners
    super.processMouseEvent(e);
  }
  /**
   * This method is called for mouse motion events. We don"t have to detect
   * gestures that initiate a drag in this method. That is the job of the
   * DragGestureRecognizer we created in the constructor: it will notify the
   * DragGestureListener defined below.
   */
  public void processMouseMotionEvent(MouseEvent e) {
    if (e.getID() == MouseEvent.MOUSE_DRAGGED && // If we"re dragging
        currentLine != null) { // and a line exists
      currentLine.addSegment(e.getX(), e.getY()); // Add a line segment
      e.consume(); // Eat the event
      repaint(); // Redisplay all lines
    }
    super.processMouseMotionEvent(e); // Invoke any listeners
  }
  /** Copy the selected line to the clipboard, then delete it */
  public void cut() {
    if (selectedLine == null)
      return; // Only works if a line is selected
    copy(); // Do a Copy operation...
    lines.remove(selectedLine); // and then erase the selected line
    selectedLine = null;
    repaint(); // Repaint because a line was removed
  }
  /** Copy the selected line to the clipboard */
  public void copy() {
    if (selectedLine == null)
      return; // Only works if a line is selected
    // Get the system Clipboard object.
    Clipboard c = this.getToolkit().getSystemClipboard();
    // Wrap the selected line in a TransferablePolyLine object
    // and pass it to the clipboard, with an object to receive notification
    // when some other application takes ownership of the clipboard
    c.setContents(new TransferablePolyLine((PolyLine) selectedLine.clone()), new ClipboardOwner() {
      public void lostOwnership(Clipboard c, Transferable t) {
        // This method is called when something else
        // is copied to the clipboard. We could use it
        // to deselect the selected line, if we wanted.
      }
    });
  }
  /** Get a PolyLine from the clipboard, if one exists, and display it */
  public void paste() {
    // Get the system Clipboard and ask for its Transferable contents
    Clipboard c = this.getToolkit().getSystemClipboard();
    Transferable t = c.getContents(this);
    // See if we can extract a PolyLine from the Transferable object
    PolyLine line;
    try {
      line = (PolyLine) t.getTransferData(TransferablePolyLine.FLAVOR);
    } catch (Exception e) { // UnsupportedFlavorException or IOException
      // If we get here, the clipboard doesn"t hold a PolyLine we can use
      getToolkit().beep(); // So beep to indicate the error
      return;
    }
    lines.add(line); // We got a line from the clipboard, so add it to list
    repaint(); // And repaint to make the line appear
  }
  /** Erase all lines and repaint. */
  public void clear() {
    lines.clear();
    repaint();
  }
  /**
   * This DragGestureListener is notified when the user initiates a drag. We
   * passed it to the DragGestureRecognizer we created in the constructor.
   */
  public DragGestureListener dragGestureListener = new DragGestureListener() {
    public void dragGestureRecognized(DragGestureEvent e) {
      // Don"t start a drag if there isn"t a selected line
      if (selectedLine == null)
        return;
      // Find out where the drag began
      MouseEvent trigger = (MouseEvent) e.getTriggerEvent();
      int x = trigger.getX();
      int y = trigger.getY();
      // Don"t do anything if the drag was not near the selected line
      if (!selectedLine.intersects(x - 4, y - 4, 8, 8))
        return;
      // Make a copy of the selected line, adjust the copy so that
      // the point under the mouse is (0,0), and wrap the copy in a
      // Tranferable wrapper.
      PolyLine copy = (PolyLine) selectedLine.clone();
      copy.translate(-x, -y);
      Transferable t = new TransferablePolyLine(copy);
      // If the system allows custom images to be dragged, make
      // an image of the line on a transparent background
      Image dragImage = null;
      Point hotspot = null;
      if (canDragImage) {
        Rectangle box = copy.getBounds();
        dragImage = createImage(box.width, box.height);
        Graphics2D g = (Graphics2D) dragImage.getGraphics();
        g.setColor(new Color(0, 0, 0, 0)); // transparent bg
        g.fillRect(0, 0, box.width, box.height);
        g.setColor(getForeground());
        g.setStroke(selectedStroke);
        g.translate(-box.x, -box.y);
        g.draw(copy);
        hotspot = new Point(-box.x, -box.y);
      }
      // Now begin dragging the line, specifying the listener
      // object to receive notifications about the progress of
      // the operation. Note: the startDrag() method is defined by
      // the event object, which is unusual.
      e.startDrag(null, // Use default drag-and-drop cursors
          dragImage, // Use the image, if supported
          hotspot, // Ditto for the image hotspot
          t, // Drag this object
          dragSourceListener); // Send notifications here
    }
  };
  /**
   * If this component is the source of a drag, then this DragSourceListener
   * will receive notifications about the progress of the drag. The only one we
   * use here is dragDropEnd() which is called after a drop occurs. We could use
   * the other methods to change cursors or perform other "drag over effects"
   */
  public DragSourceListener dragSourceListener = new DragSourceListener() {
    // Invoked when dragging stops
    public void dragDropEnd(DragSourceDropEvent e) {
      if (!e.getDropSuccess())
        return; // Ignore failed drops
      // If the drop was a move, then delete the selected line
      if (e.getDropAction() == DnDConstants.ACTION_MOVE) {
        lines.remove(selectedLine);
        selectedLine = null;
        repaint();
      }
    }
    // The following methods are unused here. We could implement them
    // to change custom cursors or perform other "drag over effects".
    public void dragEnter(DragSourceDragEvent e) {
    }
    public void dragExit(DragSourceEvent e) {
    }
    public void dragOver(DragSourceDragEvent e) {
    }
    public void dropActionChanged(DragSourceDragEvent e) {
    }
  };
  /**
   * This DropTargetListener is notified when something is dragged over this
   * component.
   */
  public DropTargetListener dropTargetListener = new DropTargetListener() {
    // This method is called when something is dragged over us.
    // If we understand what is being dragged, then tell the system
    // we can accept it, and change our border to provide extra
    // "drag under" visual feedback to the user to indicate our
    // receptivity to a drop.
    public void dragEnter(DropTargetDragEvent e) {
      if (e.isDataFlavorSupported(TransferablePolyLine.FLAVOR)) {
        e.acceptDrag(e.getDropAction());
        setBorder(canDropBorder);
      }
    }
    // Revert to our normal border if the drag moves off us.
    public void dragExit(DropTargetEvent e) {
      setBorder(normalBorder);
    }
    // This method is called when something is dropped on us.
    public void drop(DropTargetDropEvent e) {
      // If a PolyLine is dropped, accept either a COPY or a MOVE
      if (e.isDataFlavorSupported(TransferablePolyLine.FLAVOR))
        e.acceptDrop(e.getDropAction());
      else { // Otherwise, reject the drop and return
        e.rejectDrop();
        return;
      }
      // Get the dropped object and extract a PolyLine from it
      Transferable t = e.getTransferable();
      PolyLine line;
      try {
        line = (PolyLine) t.getTransferData(TransferablePolyLine.FLAVOR);
      } catch (Exception ex) { // UnsupportedFlavor or IOException
        getToolkit().beep(); // Something went wrong, so beep
        e.dropComplete(false); // Tell the system we failed
        return;
      }
      // Figure out where the drop occurred, and translate so the
      // point that was formerly (0,0) is now at that point.
      Point p = e.getLocation();
      line.translate((float) p.getX(), (float) p.getY());
      // Add the line to our list, and repaint
      lines.add(line);
      repaint();
      // Tell the system that we successfully completed the transfer.
      // This means it is safe for the initiating component to delete
      // its copy of the line
      e.dropComplete(true);
    }
    // We could provide additional drag under effects with this method.
    public void dragOver(DropTargetDragEvent e) {
    }
    // If we used custom cursors, we would update them here.
    public void dropActionChanged(DropTargetDragEvent e) {
    }
  };
}
/**
 * This Shape implementation represents a series of connected line segments. It
 * is like a Polygon, but is not closed. This class is used by the ScribblePane
 * class of the GUI chapter. It implements the Cloneable and Externalizable
 * interfaces so it can be used in the Drag-and-Drop examples in the Data
 * Transfer chapter.
 */
class PolyLine implements Shape, Cloneable, Externalizable {
  float x0, y0; // The starting point of the polyline.
  float[] coords; // The x and y coordinates of the end point of each line
  // segment packed into a single array for simplicity:
  // [x1,y1,x2,y2,...] Note that these are relative to x0,y0
  int numsegs; // How many line segments in this PolyLine
  // Coordinates of our bounding box, relative to (x0, y0);
  float xmin = 0f, xmax = 0f, ymin = 0f, ymax = 0f;
  // No arg constructor assumes an origin of (0,0)
  // A no-arg constructor is required for the Externalizable interface
  public PolyLine() {
    this(0f, 0f);
  }
  // The constructor.
  public PolyLine(float x0, float y0) {
    setOrigin(x0, y0); // Record the starting point.
    numsegs = 0; // Note that we have no line segments, so far
  }
  /** Set the origin of the PolyLine. Useful when moving it */
  public void setOrigin(float x0, float y0) {
    this.x0 = x0;
    this.y0 = y0;
  }
  /** Add dx and dy to the origin */
  public void translate(float dx, float dy) {
    this.x0 += dx;
    this.y0 += dy;
  }
  /**
   * Add a line segment to the PolyLine. Note that x and y are absolute
   * coordinates, even though the implementation stores them relative to x0, y0;
   */
  public void addSegment(float x, float y) {
    // Allocate or reallocate the coords[] array when necessary
    if (coords == null)
      coords = new float[32];
    if (numsegs * 2 >= coords.length) {
      float[] newcoords = new float[coords.length * 2];
      System.arraycopy(coords, 0, newcoords, 0, coords.length);
      coords = newcoords;
    }
    // Convert from absolute to relative coordinates
    x = x - x0;
    y = y - y0;
    // Store the data
    coords[numsegs * 2] = x;
    coords[numsegs * 2 + 1] = y;
    numsegs++;
    // Enlarge the bounding box, if necessary
    if (x > xmax)
      xmax = x;
    else if (x < xmin)
      xmin = x;
    if (y > ymax)
      ymax = y;
    else if (y < ymin)
      ymin = y;
  }
  /*------------------ The Shape Interface --------------------- */
  // Return floating-point bounding box
  public Rectangle2D getBounds2D() {
    return new Rectangle2D.Float(x0 + xmin, y0 + ymin, xmax - xmin, ymax - ymin);
  }
  // Return integer bounding box, rounded to outermost pixels.
  public Rectangle getBounds() {
    return new Rectangle((int) (x0 + xmin - 0.5f), // x0
        (int) (y0 + ymin - 0.5f), // y0
        (int) (xmax - xmin + 0.5f), // width
        (int) (ymax - ymin + 0.5f)); // height
  }
  // PolyLine shapes are open curves, with no interior.
  // The Shape interface says that open curves should be implicitly closed
  // for the purposes of insideness testing. For our purposes, however,
  // we define PolyLine shapes to have no interior, and the contains()
  // methods always return false.
  public boolean contains(Point2D p) {
    return false;
  }
  public boolean contains(Rectangle2D r) {
    return false;
  }
  public boolean contains(double x, double y) {
    return false;
  }
  public boolean contains(double x, double y, double w, double h) {
    return false;
  }
  // The intersects methods simply test whether any of the line segments
  // within a polyline intersects the given rectangle. Strictly speaking,
  // the Shape interface requires us to also check whether the rectangle
  // is entirely contained within the shape as well. But the contains()
  // methods for this class alwasy return false.
  // We might improve the efficiency of this method by first checking for
  // intersection with the overall bounding box to rule out cases that
  // aren"t even close.
  public boolean intersects(Rectangle2D r) {
    if (numsegs < 1)
      return false;
    float lastx = x0, lasty = y0;
    for (int i = 0; i < numsegs; i++) { // loop through the segments
      float x = coords[i * 2] + x0;
      float y = coords[i * 2 + 1] + y0;
      // See if this line segment intersects the rectangle
      if (r.intersectsLine(x, y, lastx, lasty))
        return true;
      // Otherwise move on to the next segment
      lastx = x;
      lasty = y;
    }
    return false; // No line segment intersected the rectangle
  }
  // This variant method is just defined in terms of the last.
  public boolean intersects(double x, double y, double w, double h) {
    return intersects(new Rectangle2D.Double(x, y, w, h));
  }
  // This is the key to the Shape interface; it tells Java2D how to draw
  // the shape as a series of lines and curves. We use only lines
  public PathIterator getPathIterator(final AffineTransform transform) {
    return new PathIterator() {
      int curseg = -1; // current segment
      // Copy the current segment for thread-safety, so we don"t
      // mess up of a segment is added while we"re iterating
      int numsegs = PolyLine.this.numsegs;
      public boolean isDone() {
        return curseg >= numsegs;
      }
      public void next() {
        curseg++;
      }
      // Get coordinates and type of current segment as floats
      public int currentSegment(float[] data) {
        int segtype;
        if (curseg == -1) { // First time we"re called
          data[0] = x0; // Data is the origin point
          data[1] = y0;
          segtype = SEG_MOVETO; // Returned as a moveto segment
        } else { // Otherwise, the data is a segment endpoint
          data[0] = x0 + coords[curseg * 2];
          data[1] = y0 + coords[curseg * 2 + 1];
          segtype = SEG_LINETO; // Returned as a lineto segment
        }
        // If a tranform was specified, transform point in place
        if (transform != null)
          transform.transform(data, 0, data, 0, 1);
        return segtype;
      }
      // Same as last method, but use doubles
      public int currentSegment(double[] data) {
        int segtype;
        if (curseg == -1) {
          data[0] = x0;
          data[1] = y0;
          segtype = SEG_MOVETO;
        } else {
          data[0] = x0 + coords[curseg * 2];
          data[1] = y0 + coords[curseg * 2 + 1];
          segtype = SEG_LINETO;
        }
        if (transform != null)
          transform.transform(data, 0, data, 0, 1);
        return segtype;
      }
      // This only matters for closed shapes
      public int getWindingRule() {
        return WIND_NON_ZERO;
      }
    };
  }
  // PolyLines never contain curves, so we can ignore the flatness limit
  // and implement this method in terms of the one above.
  public PathIterator getPathIterator(AffineTransform at, double flatness) {
    return getPathIterator(at);
  }
  /*------------------ Externalizable --------------------- */
  /**
   * The following two methods implement the Externalizable interface. We use
   * Externalizable instead of Seralizable so we have full control over the data
   * format, and only write out the defined coordinates
   */
  public void writeExternal(java.io.ObjectOutput out) throws java.io.IOException {
    out.writeFloat(x0);
    out.writeFloat(y0);
    out.writeInt(numsegs);
    for (int i = 0; i < numsegs * 2; i++)
      out.writeFloat(coords[i]);
  }
  public void readExternal(java.io.ObjectInput in) throws java.io.IOException,
      ClassNotFoundException {
    this.x0 = in.readFloat();
    this.y0 = in.readFloat();
    this.numsegs = in.readInt();
    this.coords = new float[numsegs * 2];
    for (int i = 0; i < numsegs * 2; i++)
      coords[i] = in.readFloat();
  }
  /*------------------ Cloneable --------------------- */
  /**
   * Override the Object.clone() method so that the array gets cloned, too.
   */
  public Object clone() {
    try {
      PolyLine copy = (PolyLine) super.clone();
      if (coords != null)
        copy.coords = (float[]) this.coords.clone();
      return copy;
    } catch (CloneNotSupportedException e) {
      throw new AssertionError(); // This should never happen
    }
  }
}
/*
 * Copyright (c) 2004 David Flanagan. All rights reserved. This code is from the
 * book Java Examples in a Nutshell, 3nd Edition. It is provided AS-IS, WITHOUT
 * ANY WARRANTY either expressed or implied. You may study, use, and modify it
 * for any non-commercial purpose, including teaching and use in open-source
 * projects. You may distribute it non-commercially as long as you retain this
 * notice. For a commercial use license, or to purchase the book, please visit
 * http://www.davidflanagan.ru/javaexamples3.
 */
/**
 * This class implements the Transferable interface for PolyLine objects. It
 * also defines a DataFlavor used to describe this data type.
 */
class TransferablePolyLine implements Transferable {
  public static DataFlavor FLAVOR = new DataFlavor(PolyLine.class, "PolyLine");
  static DataFlavor[] FLAVORS = new DataFlavor[] { FLAVOR };
  PolyLine line; // This is the PolyLine we wrap.
  public TransferablePolyLine(PolyLine line) {
    this.line = line;
  }
  /** Return the supported flavor */
  public DataFlavor[] getTransferDataFlavors() {
    return FLAVORS;
  }
  /** Check for the one flavor we support */
  public boolean isDataFlavorSupported(DataFlavor f) {
    return f.equals(FLAVOR);
  }
  /** Return the wrapped PolyLine, if the flavor is right */
  public Object getTransferData(DataFlavor f) throws UnsupportedFlavorException {
    if (!f.equals(FLAVOR))
      throw new UnsupportedFlavorException(f);
    return line;
  }
}





14. Set tree drag mode to DropMode.INSERT

import java.awt.BorderLayout;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import javax.swing.DropMode;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.TransferHandler;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
public class DndTree {
  public static void main(String args[]) {
    JFrame f = new JFrame();
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    JPanel top = new JPanel(new BorderLayout());
    JLabel dragLabel = new JLabel("Drag me:");
    JTextField text = new JTextField();
    text.setDragEnabled(true);
    top.add(dragLabel, BorderLayout.WEST);
    top.add(text, BorderLayout.CENTER);
    f.add(top, BorderLayout.NORTH);
    final JTree tree = new JTree();
    final DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
    tree.setTransferHandler(new TransferHandler() {
      public boolean canImport(TransferHandler.TransferSupport support) {
        if (!support.isDataFlavorSupported(DataFlavor.stringFlavor) || !support.isDrop()) {
          return false;
        }
        JTree.DropLocation dropLocation = (JTree.DropLocation) support.getDropLocation();
        return dropLocation.getPath() != null;
      }
      public boolean importData(TransferHandler.TransferSupport support) {
        if (!canImport(support)) {
          return false;
        }
        JTree.DropLocation dropLocation = (JTree.DropLocation) support.getDropLocation();
        TreePath path = dropLocation.getPath();
        Transferable transferable = support.getTransferable();
        String transferData;
        try {
          transferData = (String) transferable.getTransferData(DataFlavor.stringFlavor);
        } catch (IOException e) {
          return false;
        } catch (UnsupportedFlavorException e) {
          return false;
        }
        int childIndex = dropLocation.getChildIndex();
        if (childIndex == -1) {
          childIndex = model.getChildCount(path.getLastPathComponent());
        }
        DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(transferData);
        DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) path.getLastPathComponent();
        model.insertNodeInto(newNode, parentNode, childIndex);
        TreePath newPath = path.pathByAddingChild(newNode);
        tree.makeVisible(newPath);
        tree.scrollRectToVisible(tree.getPathBounds(newPath));
        return true;
      }
    });
    JScrollPane pane = new JScrollPane(tree);
    f.add(pane, BorderLayout.CENTER);
    tree.setDropMode(DropMode.INSERT);
    f.setSize(300, 400);
    f.setVisible(true);
  }
}





14. Set tree drag mode to DropMode.ON

import java.awt.BorderLayout;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import javax.swing.DropMode;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.TransferHandler;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
public class DndTree {
  public static void main(String args[]) {
    JFrame f = new JFrame();
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    JPanel top = new JPanel(new BorderLayout());
    JLabel dragLabel = new JLabel("Drag me:");
    JTextField text = new JTextField();
    text.setDragEnabled(true);
    top.add(dragLabel, BorderLayout.WEST);
    top.add(text, BorderLayout.CENTER);
    f.add(top, BorderLayout.NORTH);
    final JTree tree = new JTree();
    final DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
    tree.setTransferHandler(new TransferHandler() {
      public boolean canImport(TransferHandler.TransferSupport support) {
        if (!support.isDataFlavorSupported(DataFlavor.stringFlavor) || !support.isDrop()) {
          return false;
        }
        JTree.DropLocation dropLocation = (JTree.DropLocation) support.getDropLocation();
        return dropLocation.getPath() != null;
      }
      public boolean importData(TransferHandler.TransferSupport support) {
        if (!canImport(support)) {
          return false;
        }
        JTree.DropLocation dropLocation = (JTree.DropLocation) support.getDropLocation();
        TreePath path = dropLocation.getPath();
        Transferable transferable = support.getTransferable();
        String transferData;
        try {
          transferData = (String) transferable.getTransferData(DataFlavor.stringFlavor);
        } catch (IOException e) {
          return false;
        } catch (UnsupportedFlavorException e) {
          return false;
        }
        int childIndex = dropLocation.getChildIndex();
        if (childIndex == -1) {
          childIndex = model.getChildCount(path.getLastPathComponent());
        }
        DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(transferData);
        DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) path.getLastPathComponent();
        model.insertNodeInto(newNode, parentNode, childIndex);
        TreePath newPath = path.pathByAddingChild(newNode);
        tree.makeVisible(newPath);
        tree.scrollRectToVisible(tree.getPathBounds(newPath));
        return true;
      }
    });
    JScrollPane pane = new JScrollPane(tree);
    f.add(pane, BorderLayout.CENTER);
    tree.setDropMode(DropMode.ON);
    f.setSize(300, 400);
    f.setVisible(true);
  }
}





14. Set tree drag mode to DropMode.ON_OR_INSERT

import java.awt.BorderLayout;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import javax.swing.DropMode;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.TransferHandler;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
public class DndTree {
  public static void main(String args[]) {
    JFrame f = new JFrame();
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    JPanel top = new JPanel(new BorderLayout());
    JLabel dragLabel = new JLabel("Drag me:");
    JTextField text = new JTextField();
    text.setDragEnabled(true);
    top.add(dragLabel, BorderLayout.WEST);
    top.add(text, BorderLayout.CENTER);
    f.add(top, BorderLayout.NORTH);
    final JTree tree = new JTree();
    final DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
    tree.setTransferHandler(new TransferHandler() {
      public boolean canImport(TransferHandler.TransferSupport support) {
        if (!support.isDataFlavorSupported(DataFlavor.stringFlavor) || !support.isDrop()) {
          return false;
        }
        JTree.DropLocation dropLocation = (JTree.DropLocation) support.getDropLocation();
        return dropLocation.getPath() != null;
      }
      public boolean importData(TransferHandler.TransferSupport support) {
        if (!canImport(support)) {
          return false;
        }
        JTree.DropLocation dropLocation = (JTree.DropLocation) support.getDropLocation();
        TreePath path = dropLocation.getPath();
        Transferable transferable = support.getTransferable();
        String transferData;
        try {
          transferData = (String) transferable.getTransferData(DataFlavor.stringFlavor);
        } catch (IOException e) {
          return false;
        } catch (UnsupportedFlavorException e) {
          return false;
        }
        int childIndex = dropLocation.getChildIndex();
        if (childIndex == -1) {
          childIndex = model.getChildCount(path.getLastPathComponent());
        }
        DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(transferData);
        DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) path.getLastPathComponent();
        model.insertNodeInto(newNode, parentNode, childIndex);
        TreePath newPath = path.pathByAddingChild(newNode);
        tree.makeVisible(newPath);
        tree.scrollRectToVisible(tree.getPathBounds(newPath));
        return true;
      }
    });
    JScrollPane pane = new JScrollPane(tree);
    f.add(pane, BorderLayout.CENTER);
    tree.setDropMode(DropMode.ON_OR_INSERT);
    f.setSize(300, 400);
    f.setVisible(true);
  }
}





14. Set tree DropMode to DropMode.USE_SELECTION

import java.awt.BorderLayout;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import javax.swing.DropMode;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.TransferHandler;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
public class DndTree {
  public static void main(String args[]) {
    JFrame f = new JFrame();
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    JPanel top = new JPanel(new BorderLayout());
    JLabel dragLabel = new JLabel("Drag me:");
    JTextField text = new JTextField();
    text.setDragEnabled(true);
    top.add(dragLabel, BorderLayout.WEST);
    top.add(text, BorderLayout.CENTER);
    f.add(top, BorderLayout.NORTH);
    final JTree tree = new JTree();
    final DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
    tree.setTransferHandler(new TransferHandler() {
      public boolean canImport(TransferHandler.TransferSupport support) {
        if (!support.isDataFlavorSupported(DataFlavor.stringFlavor) || !support.isDrop()) {
          return false;
        }
        JTree.DropLocation dropLocation = (JTree.DropLocation) support.getDropLocation();
        return dropLocation.getPath() != null;
      }
      public boolean importData(TransferHandler.TransferSupport support) {
        if (!canImport(support)) {
          return false;
        }
        JTree.DropLocation dropLocation = (JTree.DropLocation) support.getDropLocation();
        TreePath path = dropLocation.getPath();
        Transferable transferable = support.getTransferable();
        String transferData;
        try {
          transferData = (String) transferable.getTransferData(DataFlavor.stringFlavor);
        } catch (IOException e) {
          return false;
        } catch (UnsupportedFlavorException e) {
          return false;
        }
        int childIndex = dropLocation.getChildIndex();
        if (childIndex == -1) {
          childIndex = model.getChildCount(path.getLastPathComponent());
        }
        DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(transferData);
        DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) path.getLastPathComponent();
        model.insertNodeInto(newNode, parentNode, childIndex);
        TreePath newPath = path.pathByAddingChild(newNode);
        tree.makeVisible(newPath);
        tree.scrollRectToVisible(tree.getPathBounds(newPath));
        return true;
      }
    });
    JScrollPane pane = new JScrollPane(tree);
    f.add(pane, BorderLayout.CENTER);
    tree.setDropMode(DropMode.USE_SELECTION);
    f.setSize(300, 400);
    f.setVisible(true);
  }
}





14. Transfer both Text and Color between JTextField and JTextArea

import java.awt.Color;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.TransferHandler;
import javax.swing.text.JTextComponent;
public class DnDDemo2 {
  public static void main(String[] args) {
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setContentPane(new JPanel());
    JTextField textField = new JTextField(25);
    textField.setText("Let"s swing higher");
    frame.add(textField);
    JTextArea textArea = new JTextArea("Demonstrating\ndrag and drop");
    textArea.setForeground(Color.red);
    frame.add(new JScrollPane(textArea));
    textArea.setDragEnabled(true);
    textField.setDragEnabled(true);
    TextColorTransferHandler transferHandler = new TextColorTransferHandler();
    textArea.setTransferHandler(transferHandler);
    textField.setTransferHandler(transferHandler);
    frame.pack();
    frame.setVisible(true);
  }
}
class TextColorTransferHandler extends TransferHandler {
  public int getSourceActions(JComponent c) {
    return COPY_OR_MOVE;
  }
  protected Transferable createTransferable(JComponent component) {
    String text = ((JTextComponent) component).getText();
    Color color = component.getForeground();
    TextColor transferable = new TextColor(text, color);
    return transferable;
  }
  public boolean canImport(JComponent c, DataFlavor[] flavors) {
    return true;
  }
  public boolean importData(JComponent component, Transferable transferable) {
    String colorMimeType = DataFlavor.javaJVMLocalObjectMimeType + ";class=java.awt.Color";
    JTextComponent textComponent = (JTextComponent) component;
    try {
      DataFlavor colorFlavor = new DataFlavor(colorMimeType);
      Color color = (Color) transferable.getTransferData(colorFlavor);
      String text = (String) transferable.getTransferData(DataFlavor.stringFlavor);
      textComponent.setForeground(color);
      textComponent.setText(text);
    } catch (Exception e) {
      e.printStackTrace();
    }
    return true;
  }
}
class TextColor implements Transferable {
  private String text;
  private Color color;
  private DataFlavor[] flavors;
  public TextColor(String text, Color color) {
    String colorMimeType = DataFlavor.javaJVMLocalObjectMimeType + ";class=java.awt.Color";
    DataFlavor colorFlavor = null;
    try {
      colorFlavor = new DataFlavor(colorMimeType);
    } catch (ClassNotFoundException e) {
    }
    flavors = new DataFlavor[2];
    flavors[0] = DataFlavor.stringFlavor;
    flavors[1] = colorFlavor;
    this.text = text;
    this.color = color;
  }
  public DataFlavor[] getTransferDataFlavors() {
    return (DataFlavor[]) flavors.clone();
  }
  public boolean isDataFlavorSupported(DataFlavor flavor) {
    for (int i = 0; i < flavors.length; i++) {
      if (flavor.equals(flavors[i])) {
        return true;
      }
    }
    return false;
  }
  public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
    if (flavor.equals(flavors[0])) {
      return text;
    } else if (flavor.equals(flavors[1])) {
      return color;
    } else {
      throw new UnsupportedFlavorException(flavor);
    }
  }
}
//Reference:
//Java 6 New Features: A Tutorial
//by Budi Kurniawan 
//Brainy Software Corp. 2006
//Chapter 4 - Networking
//# ISBN-10: 0975212885
//# ISBN-13: 978-0975212882





14. Various drop actions

/*
 * Copyright (c) 1995 - 2008 Sun Microsystems, Inc.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 *   - Neither the name of Sun Microsystems nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */ 

/*
 * DropDemo.java requires the following file:
 *     ListTransferHandler.java
 */
import javax.swing.*;
import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.event.*;

public class DropDemo extends JPanel implements ActionListener {
    private JComboBox dropCombo;
    private JList list;
    
    public DropDemo() {
        super(new GridLayout(2,1));
        add(createArea());
        add(createList());
    }
    
    private JPanel createList() {
        DefaultListModel listModel = new DefaultListModel();
            
        for (int i = 0; i < 10; i++) {
            listModel.addElement("List Item " + i);
        }
        
        list = new JList(listModel);
        list.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
        JScrollPane scrollPane = new JScrollPane(list);
        scrollPane.setPreferredSize(new Dimension(400,100));
        
        list.setDragEnabled(true);
        list.setTransferHandler(new ListTransferHandler());
        
        dropCombo = new JComboBox(new String[] {"USE_SELECTION", "ON", "INSERT", "ON_OR_INSERT"});
        dropCombo.addActionListener(this);
        JPanel dropPanel = new JPanel();
        dropPanel.add(new JLabel("List Drop Mode:"));
        dropPanel.add(dropCombo);
        
        JPanel panel = new JPanel(new BorderLayout());
        panel.add(scrollPane, BorderLayout.CENTER);
        panel.add(dropPanel, BorderLayout.SOUTH);
        panel.setBorder(BorderFactory.createTitledBorder("List"));
        return panel;
    }
    
    private JPanel createArea() {
        String text = "Drag from or drop into this area.\nThe default action is MOVE;\nhold the Control key to COPY.";
        
        JTextArea area = new JTextArea();
        area.setText(text);
        area.setDragEnabled(true);
        JScrollPane scrollPane = new JScrollPane(area);
        scrollPane.setPreferredSize(new Dimension(400,100));
        JPanel panel = new JPanel(new BorderLayout());
        panel.add(scrollPane, BorderLayout.CENTER);
        panel.setBorder(BorderFactory.createTitledBorder("Text Area"));
        return panel;
    }
    public void actionPerformed(ActionEvent ae) {
        Object val = dropCombo.getSelectedItem();
        if (val == "USE_SELECTION") {
            list.setDropMode(DropMode.USE_SELECTION);
        } else if (val == "ON") {
            list.setDropMode(DropMode.ON);
        } else if (val == "INSERT") {
            list.setDropMode(DropMode.INSERT);
        } else if (val == "ON_OR_INSERT") {
            list.setDropMode(DropMode.ON_OR_INSERT);
        }
    }
    /**
     * Create the GUI and show it.  For thread safety,
     * this method should be invoked from the
     * event-dispatching thread.
     */
    private static void createAndShowGUI() {
        //Create and set up the window.
        JFrame frame = new JFrame("DropDemo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        //Create and set up the content pane.
        JComponent newContentPane = new DropDemo();
        newContentPane.setOpaque(true); //content panes must be opaque
        frame.setContentPane(newContentPane);
        //Display the window.
        frame.pack();
        frame.setVisible(true);
    }
    public static void main(String[] args) {
        //Schedule a job for the event-dispatching thread:
        //creating and showing this application"s GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                //Turn off metal"s use of bold fonts
            UIManager.put("swing.boldMetal", Boolean.FALSE);
                createAndShowGUI();
            }
        });
    }
}
/*
 * Copyright (c) 1995 - 2008 Sun Microsystems, Inc.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 *   - Neither the name of Sun Microsystems nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
/*
 * ListTransferHandler.java is used by the DropDemo example.
 */

class ListTransferHandler extends TransferHandler {
  private int[] indices = null;
  private int addIndex = -1; // Location where items were added
  private int addCount = 0; // Number of items added.
  public boolean canImport(TransferHandler.TransferSupport info) {
    // Check for String flavor
    if (!info.isDataFlavorSupported(DataFlavor.stringFlavor)) {
      return false;
    }
    return true;
  }
  protected Transferable createTransferable(JComponent c) {
    return new StringSelection(exportString(c));
  }
  public int getSourceActions(JComponent c) {
    return TransferHandler.COPY_OR_MOVE;
  }
  public boolean importData(TransferHandler.TransferSupport info) {
    if (!info.isDrop()) {
      return false;
    }
    JList list = (JList) info.getComponent();
    DefaultListModel listModel = (DefaultListModel) list.getModel();
    JList.DropLocation dl = (JList.DropLocation) info.getDropLocation();
    int index = dl.getIndex();
    boolean insert = dl.isInsert();
    // Get the string that is being dropped.
    Transferable t = info.getTransferable();
    String data;
    try {
      data = (String) t.getTransferData(DataFlavor.stringFlavor);
    } catch (Exception e) {
      return false;
    }
    // Perform the actual import.
    if (insert) {
      listModel.add(index, data);
    } else {
      listModel.set(index, data);
    }
    return true;
  }
  protected void exportDone(JComponent c, Transferable data, int action) {
    cleanup(c, action == TransferHandler.MOVE);
  }
  // Bundle up the selected items in the list
  // as a single string, for export.
  protected String exportString(JComponent c) {
    JList list = (JList) c;
    indices = list.getSelectedIndices();
    Object[] values = list.getSelectedValues();
    StringBuffer buff = new StringBuffer();
    for (int i = 0; i < values.length; i++) {
      Object val = values[i];
      buff.append(val == null ? "" : val.toString());
      if (i != values.length - 1) {
        buff.append("\n");
      }
    }
    return buff.toString();
  }
  // Take the incoming string and wherever there is a
  // newline, break it into a separate item in the list.
  protected void importString(JComponent c, String str) {
    JList target = (JList) c;
    DefaultListModel listModel = (DefaultListModel) target.getModel();
    int index = target.getSelectedIndex();
    // Prevent the user from dropping data back on itself.
    // For example, if the user is moving items #4,#5,#6 and #7 and
    // attempts to insert the items after item #5, this would
    // be problematic when removing the original items.
    // So this is not allowed.
    if (indices != null && index >= indices[0] - 1
        && index <= indices[indices.length - 1]) {
      indices = null;
      return;
    }
    int max = listModel.getSize();
    if (index < 0) {
      index = max;
    } else {
      index++;
      if (index > max) {
        index = max;
      }
    }
    addIndex = index;
    String[] values = str.split("\n");
    addCount = values.length;
    for (int i = 0; i < values.length; i++) {
      listModel.add(index++, values[i]);
    }
  }
  // If the remove argument is true, the drop has been
  // successful and it"s time to remove the selected items
  // from the list. If the remove argument is false, it
  // was a Copy operation and the original list is left
  // intact.
  protected void cleanup(JComponent c, boolean remove) {
    if (remove && indices != null) {
      JList source = (JList) c;
      DefaultListModel model = (DefaultListModel) source.getModel();
      // If we are moving items around in the same list, we
      // need to adjust the indices accordingly, since those
      // after the insertion point have moved.
      if (addCount > 0) {
        for (int i = 0; i < indices.length; i++) {
          if (indices[i] > addIndex) {
            indices[i] += addCount;
          }
        }
      }
      for (int i = indices.length - 1; i >= 0; i--) {
        model.remove(indices[i]);
      }
    }
    indices = null;
    addCount = 0;
    addIndex = -1;
  }
}