Java/Swing JFC/Drag Drop
Содержание
- 1 Adding Image-Dragging Behavior
- 2 A simple drop tester application for JDK 1.4 Swing components
- 3 BasicDnD (Drag and Drop)
- 4 Built-in drag and drop support: utilize a TransferHandler class
- 5 Color Drag Source
- 6 Comma separated text will be inserted into two or more rows.
- 7 Create a drag source a drop target and a transferable object.
- 8 Demonstrate various aspects of Swing data transfer
- 9 Detect a drag initiating gesture in your application
- 10 Drag and drop
- 11 Drag and drop icons: use an icon property.
- 12 Drag and drop: TextArea
- 13 Drag capabilities: JList
- 14 Drag Color Demo
- 15 Drag Color TextField Demo
- 16 Drag Drop Tree Example
- 17 Drag File Demo
- 18 Drag List Demo
- 19 Drag Picture Demo
- 20 Drag Picture Demo 2
- 21 Dropper - show File Drop Target from Drag-n-Drop
- 22 Editor Drop Target
- 23 Editor Drop Target 2
- 24 Editor Drop Target 3
- 25 Editor Drop Target 4
- 26 Extended DnD (Drag and Drop) Demo
- 27 File Tree Drag Source
- 28 File Tree Drop Target
- 29 Getting and Setting Text on the System Clipboard
- 30 Implement drag & drop functionality in your application
- 31 implements DragGestureListener, Transferable
- 32 JLabel Drag Source
- 33 JTextArea subclass allows TransferableColor objects to
- 34 LabelDnD2 allows dropping color onto the foreground of the JLabel
- 35 Label DnD (Drag and Drop)
- 36 Making a Component Draggable
- 37 Panel Drop Target
- 38 Setting text drag in a JTextArea
- 39 Test of the DragGesture classes and JList to see if we
- 40 Transferable Color
- 41 TransferHandler subclass wraps another TransferHandler and delegates most of its operations to the wrapped handler
- 42 Use drag and drop to reorder a list
Adding Image-Dragging Behavior
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Image;
import java.awt.datatransfer.Clipboard;
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.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.IOException;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.TransferHandler;
public class DragImage {
public static void main(String args[]) {
JFrame frame = new JFrame("Clip Image");
Container contentPane = frame.getContentPane();
final Clipboard clipboard = frame.getToolkit().getSystemClipboard();
Icon icon = new ImageIcon("jaeger.jpg");
final JLabel label = new JLabel(icon);
label.setTransferHandler(new ImageSelection());
MouseListener mouseListener = new MouseAdapter() {
public void mousePressed(MouseEvent e) {
JComponent comp = (JComponent) e.getSource();
TransferHandler handler = comp.getTransferHandler();
handler.exportAsDrag(comp, e, TransferHandler.COPY);
}
};
label.addMouseListener(mouseListener);
JScrollPane pane = new JScrollPane(label);
contentPane.add(pane, BorderLayout.CENTER);
JButton copy = new JButton("Copy");
copy.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
TransferHandler handler = label.getTransferHandler();
handler.exportToClipboard(label, clipboard,
TransferHandler.COPY);
}
});
JButton clear = new JButton("Clear");
clear.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
label.setIcon(null);
}
});
clear.setTransferHandler(new TransferHandler("text"));
mouseListener = new MouseAdapter() {
public void mousePressed(MouseEvent e) {
JComponent comp = (JComponent) e.getSource();
TransferHandler handler = comp.getTransferHandler();
handler.exportAsDrag(comp, e, TransferHandler.COPY);
}
};
clear.addMouseListener(mouseListener);
JButton paste = new JButton("Paste");
paste.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
Transferable clipData = clipboard.getContents(clipboard);
if (clipData != null) {
if (clipData.isDataFlavorSupported(DataFlavor.imageFlavor)) {
TransferHandler handler = label.getTransferHandler();
handler.importData(label, clipData);
}
}
}
});
JPanel p = new JPanel();
p.add(copy);
p.add(clear);
p.add(paste);
contentPane.add(p, BorderLayout.SOUTH);
JTextField tf = new JTextField();
tf.setDragEnabled(true);
contentPane.add(tf, BorderLayout.NORTH);
frame.setSize(300, 300);
frame.show();
}
}
class ImageSelection extends TransferHandler implements Transferable {
private static final DataFlavor flavors[] = { DataFlavor.imageFlavor };
private JLabel source;
private Image image;
public int getSourceActions(JComponent c) {
return TransferHandler.COPY;
}
public boolean canImport(JComponent comp, DataFlavor flavor[]) {
if (!(comp instanceof JLabel)) {
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
source = null;
image = null;
if (comp instanceof JLabel) {
JLabel label = (JLabel) comp;
Icon icon = label.getIcon();
if (icon instanceof ImageIcon) {
image = ((ImageIcon) icon).getImage();
source = label;
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) {
}
}
}
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 flavor.equals(DataFlavor.imageFlavor);
}
}
A simple drop tester application for JDK 1.4 Swing components
import java.awt.BorderLayout;
import java.awt.Color;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextArea;
public class DropTest14 extends JFrame {
JTextArea ta;
public DropTest14() {
super("Drop Test 1.4");
setSize(300, 300);
setDefaultCloseOperation(EXIT_ON_CLOSE);
getContentPane().add(
new JLabel("Drop the choice from your JList here:"),
BorderLayout.NORTH);
ta = new JTextArea();
ta.setBackground(Color.white);
getContentPane().add(ta, BorderLayout.CENTER);
setVisible(true);
}
public static void main(String args[]) {
new DropTest14();
}
}
BasicDnD (Drag and Drop)
/* From http://java.sun.ru/docs/books/tutorial/index.html */
/*
* Copyright (c) 2006 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:
*
* -Redistribution of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* -Redistribution 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, Inc. or the names of contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* 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 MIDROSYSTEMS, INC. ("SUN")
* AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
* AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS 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 THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed, licensed or intended
* for use in the design, construction, operation or maintenance of any
* nuclear facility.
*/
/*
* BasicDnD.java is a 1.4 example that requires no other files.
*/
import java.awt.BorderLayout;
import java.awt.Dimension;
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.JCheckBox;
import javax.swing.JColorChooser;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JList;
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.table.DefaultTableModel;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeSelectionModel;
public class BasicDnD extends JPanel implements ActionListener {
static JFrame frame;
JTextArea textArea;
JTextField textField;
JList list;
JTable table;
JTree tree;
JColorChooser colorChooser;
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.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
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;
}
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() {
//Make sure we have nice window decorations.
JFrame.setDefaultLookAndFeelDecorated(true);
//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() {
createAndShowGUI();
}
});
}
}
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);
}
}
Color Drag Source
/*
* This example is from the book "Java Foundation Classes in a Nutshell".
* Written by David Flanagan. Copyright (c) 1999 by O"Reilly & Associates.
* You may distribute this source code for non-commercial purposes only.
* You may study, modify, and use this example for any purpose, as long as
* this notice is retained. Note that this example is provided "as is",
* WITHOUT WARRANTY of any kind either expressed or implied.
*/
import java.awt.*;
import java.awt.event.*;
import java.awt.datatransfer.*;
import java.awt.dnd.*;
import javax.swing.*;
import javax.swing.border.*;
import java.io.*;
/**
* This simple component displays a solid color, and allows that color
* to be dragged. Also, it copies the color to the clipboard when the
* user clicks on it.
*/
public class ColorSource extends JComponent
implements ClipboardOwner, DragGestureListener, DragSourceListener
{
Color color; // The color to display
TransferableColor tcolor; // The color, encapsulated for data transfer
DragSource dragSource; // We need this object for drag-and-drop
/** A ColorSource normally displays itself with this border */
protected static Border defaultBorder = new BevelBorder(BevelBorder.LOWERED);
/** When we are the clipboard owner, uses this border */
protected static Border highlightBorder =
new CompoundBorder(defaultBorder, new LineBorder(Color.black, 2));
/** Create a new ColorSource object that displays the speciifed color */
public ColorSource(Color color) {
// Save the color. Encapsulate it in a Transferable object so that
// it can be used with cut-and-paste and drag-and-drop
this.color = color;
this.tcolor = new TransferableColor(color);
// Set our default border
this.setBorder(defaultBorder);
// Listen for mouse clicks, and copy the color to the clipboard.
this.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) { copy(); }
});
// Set up a DragGestureRecognizer that will detect when the user
// begins a drag. When it detects one, it will notify us by calling
// the dragGestureRecognized() method of the DragGestureListener
// interface we implement below
this.dragSource = DragSource.getDefaultDragSource();
dragSource.createDefaultDragGestureRecognizer(this, // Look for drags on us
DnDConstants.ACTION_COPY_OR_MOVE, // Recognize these types
this); // Tell us when recognized
}
// These are component methods that make this class work as a component.
// They specify how big the component is, and what it it looks like.
protected static Dimension mysize = new Dimension(25, 25);
public Dimension getMinimumSize() { return mysize; }
public Dimension getPreferredSize() { return mysize; }
public void paintComponent(Graphics g) {
g.setColor(color);
Dimension s = this.getSize();
Insets i = this.getInsets();
g.fillRect(i.left, i.top,
s.width-i.left-i.right, s.height-i.top-i.bottom);
}
// The methods below support cut-and-paste
/** This method copies the color to the clipboard. */
public void copy() {
// Get system clipboard
Clipboard c = this.getToolkit().getSystemClipboard();
// Put our TransferableColor object on the clipboard.
// Also, we"ll get notification when we no longer own the clipboard
c.setContents(tcolor, this);
// Set a special border on ourselves that indicates that we"re the
// current color available for pasting.
this.setBorder(highlightBorder);
}
// This ClipboardOwner method is called when something else is
// placed on the clipboard. It means that our color is no longer
// available for pasting, and we should not display the highlight border
public void lostOwnership(Clipboard clipboard, Transferable contents) {
this.setBorder(defaultBorder);
}
// The methods below support drag-and-drop
// This DragGestureListener method is called when the DragGestureRecognizer
// detects that the user has dragged the mouse. It is responsible
// for beginning the drag-and-drop process.
public void dragGestureRecognized(DragGestureEvent e) {
// Create an image we can drag along with us.
// Not all systems support this, but it doesn"t hurt to try.
Image colorblock = this.createImage(25,25);
Graphics g = colorblock.getGraphics();
g.setColor(color);
g.fillRect(0,0,25,25);
// Start dragging our transferable color object.
e.startDrag(DragSource.DefaultMoveDrop, // The initial drag cursor
colorblock, new Point(0,0), // The image to drag
tcolor, // The data being dragged
this); // Who to notify during drag
}
// These methods implement DragSourceListener.
// Since we passed this object to startDrag, these methods will be
// called at interesting points during the drag. We could use them,
// for example to implement custom cursors or other "drag over" effects
public void dragEnter(DragSourceDragEvent e) {}
public void dragExit(DragSourceEvent e) {}
public void dragDropEnd(DragSourceDropEvent e) {}
public void dragOver(DragSourceDragEvent e) {}
public void dropActionChanged(DragSourceDragEvent e) {}
}
Comma separated text will be inserted into two or more rows.
import java.awt.FlowLayout;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import javax.swing.DefaultListModel;
import javax.swing.DropMode;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.TransferHandler;
public class ListDrop {
class ListHandler extends TransferHandler {
public boolean canImport(TransferSupport support) {
if (!support.isDrop()) {
return false;
}
return support.isDataFlavorSupported(DataFlavor.stringFlavor);
}
public boolean importData(TransferSupport support) {
if (!canImport(support)) {
return false;
}
Transferable transferable = support.getTransferable();
String line;
try {
line = (String) transferable.getTransferData(DataFlavor.stringFlavor);
} catch (Exception e) {
return false;
}
JList.DropLocation dl = (JList.DropLocation) support.getDropLocation();
int index = dl.getIndex();
model.add(index++, line);
return true;
}
}
JTextField field = new JTextField(20);
DefaultListModel model = new DefaultListModel();
public ListDrop() {
JFrame f = new JFrame();
JList list = new JList(model);
list.setDropMode(DropMode.INSERT);
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
list.setTransferHandler(new ListHandler());
field.setDragEnabled(true);
f.setLayout(new FlowLayout());
f.add(new JScrollPane(list));
f.add(field);
f.pack();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
public static void main(String[] args) {
new ListDrop();
}
}
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);
}
}
Demonstrate various aspects of Swing data transfer
/*
* Copyright (c) Ian F. Darwin, http://www.darwinsys.ru/, 1996-2002.
* All rights reserved. Software written by Ian F. Darwin and others.
* $Id: LICENSE,v 1.8 2004/02/09 03:33:38 ian Exp $
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*
* Java, the Duke mascot, and all variants of Sun"s Java "steaming coffee
* cup" logo are trademarks of Sun Microsystems. Sun"s, and James Gosling"s,
* pioneering role in inventing and promulgating (and standardizing) the Java
* language and environment is gratefully acknowledged.
*
* The pioneering role of Dennis Ritchie and Bjarne Stroustrup, of AT&T, for
* inventing predecessor languages C and C++ is also gratefully acknowledged.
*/
import java.awt.Color;
import java.awt.Container;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.TransferHandler;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
/**
* Demonstrate various aspects of Swing "data transfer".
*
* @author Ian Darwin, http://www.darwinsys.ru
* @author Jonathan Fuerth, http://www.SQLPower.ca
*/
public class Transfer extends JFrame {
public static void main(String[] args) {
new Transfer().setVisible(true);
}
private JTextField tf;
private JLabel l;
private JComboBox propertyComboBox;
public Transfer() {
// Establish the GUI
Container cp = new Box(BoxLayout.X_AXIS);
setContentPane(cp);
JPanel firstPanel = new JPanel();
propertyComboBox = new JComboBox();
propertyComboBox.addItem("text");
propertyComboBox.addItem("font");
propertyComboBox.addItem("background");
propertyComboBox.addItem("foreground");
firstPanel.add(propertyComboBox);
cp.add(firstPanel);
cp.add(Box.createGlue());
tf = new JTextField("Hello");
tf.setForeground(Color.RED);
tf.setDragEnabled(true);
cp.add(tf);
cp.add(Box.createGlue());
l = new JLabel("Hello");
l.setBackground(Color.YELLOW);
cp.add(l);
cp.add(Box.createGlue());
JSlider stryder = new JSlider(SwingConstants.VERTICAL);
stryder.setMinimum(10);
stryder.setValue(14);
stryder.setMaximum(72);
stryder.setMajorTickSpacing(10);
stryder.setPaintTicks(true);
cp.add(stryder);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(500, 300);
// Add Listeners and Converters
setMyTransferHandlers((String) propertyComboBox.getSelectedItem());
// Mousing in the Label starts a Drag.
MouseListener myDragListener = new MouseAdapter() {
public void mousePressed(MouseEvent e) {
JComponent c = (JComponent) e.getSource();
TransferHandler handler = c.getTransferHandler();
handler.exportAsDrag(c, e, TransferHandler.COPY);
}
};
l.addMouseListener(myDragListener);
// Selecting in the ComboBox makes that the property that is xfered.
propertyComboBox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ce) {
JComboBox bx = (JComboBox) ce.getSource();
String prop = (String) bx.getSelectedItem();
setMyTransferHandlers(prop);
}
});
// Typing a word and pressing enter in the TextField tries
// to set that as the font name.
tf.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
JTextField jtf = (JTextField) evt.getSource();
String fontName = jtf.getText();
Font font = new Font(fontName, Font.BOLD, 18);
tf.setFont(font);
}
});
// Setting the Slider sets that font into the textfield.
stryder.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent evt) {
JSlider sl = (JSlider) evt.getSource();
Font oldf = tf.getFont();
Font newf = oldf.deriveFont((float) sl.getValue());
tf.setFont(newf);
}
});
}
private void setMyTransferHandlers(String s) {
TransferHandler th = new TransferHandler(s);
tf.setTransferHandler(th);
l.setTransferHandler(th);
}
}
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();
}
}
Drag and drop
/*
* Copyright (c) 2000 David Flanagan. All rights reserved.
* This code is from the book Java Examples in a Nutshell, 2nd 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.
* You may distribute it non-commercially as long as you retain this notice.
* For a commercial use license, or to purchase the book (recommended),
* visit http://www.davidflanagan.ru/javaexamples2.
*/
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
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.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.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.StringTokenizer;
import javax.swing.ButtonGroup;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JToggleButton;
import javax.swing.JToolBar;
import javax.swing.border.BevelBorder;
import javax.swing.border.Border;
/**
* This component can operate in two modes. In "draw mode", it allows the user
* to scribble with the mouse. In "drag mode", it allows the user to drag
* scribbles with the mouse. Regardless of the mode, it always allows scribbles
* to be dropped on it from other applications.
*/
public class ScribbleDragAndDrop extends JComponent implements
DragGestureListener, // For recognizing the start of drags
DragSourceListener, // For processing drag source events
DropTargetListener, // For processing drop target events
MouseListener, // For processing mouse clicks
MouseMotionListener // For processing mouse drags
{
ArrayList scribbles = new ArrayList(); // A list of Scribbles to draw
Scribble currentScribble; // The scribble in progress
Scribble beingDragged; // The scribble being dragged
DragSource dragSource; // A central DnD object
boolean dragMode; // Are we dragging or scribbling?
// These are some constants we use
static final int LINEWIDTH = 3;
static final BasicStroke linestyle = new BasicStroke(LINEWIDTH);
static final Border normalBorder = new BevelBorder(BevelBorder.LOWERED);
static final Border dropBorder = new BevelBorder(BevelBorder.RAISED);
/** The constructor: set up drag-and-drop stuff */
public ScribbleDragAndDrop() {
// Give ourselves a nice default border.
// We"ll change this border during drag-and-drop.
setBorder(normalBorder);
// Register listeners to handle drawing
addMouseListener(this);
addMouseMotionListener(this);
// Create a DragSource and DragGestureRecognizer to listen for drags
// The DragGestureRecognizer will notify the DragGestureListener
// when the user tries to drag an object
dragSource = DragSource.getDefaultDragSource();
dragSource.createDefaultDragGestureRecognizer(this, // What component
DnDConstants.ACTION_COPY_OR_MOVE, // What drag types?
this);// the listener
// Create and set up a DropTarget that will listen for drags and
// drops over this component, and will notify the DropTargetListener
DropTarget dropTarget = new DropTarget(this, // component to monitor
this); // listener to notify
this.setDropTarget(dropTarget); // Tell the component about it.
}
/**
* The component draws itself by drawing each of the Scribble objects.
*/
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setStroke(linestyle); // Specify wide lines
int numScribbles = scribbles.size();
for (int i = 0; i < numScribbles; i++) {
Scribble s = (Scribble) scribbles.get(i);
g2.draw(s); // Draw the scribble
}
}
public void setDragMode(boolean dragMode) {
this.dragMode = dragMode;
}
public boolean getDragMode() {
return dragMode;
}
/**
* This method, and the following four methods are from the MouseListener
* interface. If we"re in drawing mode, this method handles mouse down
* events and starts a new scribble.
*/
public void mousePressed(MouseEvent e) {
if (dragMode)
return;
currentScribble = new Scribble();
scribbles.add(currentScribble);
currentScribble.moveto(e.getX(), e.getY());
}
public void mouseReleased(MouseEvent e) {
}
public void mouseClicked(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
/**
* This method and mouseMoved() below are from the MouseMotionListener
* interface. If we"re in drawing mode, this method adds a new point to the
* current scribble and requests a redraw
*/
public void mouseDragged(MouseEvent e) {
if (dragMode)
return;
currentScribble.lineto(e.getX(), e.getY());
repaint();
}
public void mouseMoved(MouseEvent e) {
}
/**
* This method implements the DragGestureListener interface. It will be
* invoked when the DragGestureRecognizer thinks that the user has initiated
* a drag. If we"re not in drawing mode, then this method will try to figure
* out which Scribble object is being dragged, and will initiate a drag on
* that object.
*/
public void dragGestureRecognized(DragGestureEvent e) {
// Don"t drag if we"re not in drag mode
if (!dragMode)
return;
// Figure out where the drag started
MouseEvent inputEvent = (MouseEvent) e.getTriggerEvent();
int x = inputEvent.getX();
int y = inputEvent.getY();
// Figure out which scribble was clicked on, if any by creating a
// small rectangle around the point and testing for intersection.
Rectangle r = new Rectangle(x - LINEWIDTH, y - LINEWIDTH,
LINEWIDTH * 2, LINEWIDTH * 2);
int numScribbles = scribbles.size();
for (int i = 0; i < numScribbles; i++) { // Loop through the scribbles
Scribble s = (Scribble) scribbles.get(i);
if (s.intersects(r)) {
// The user started the drag on top of this scribble, so
// start to drag it.
// First, remember which scribble is being dragged, so we can
// delete it later (if this is a move rather than a copy)
beingDragged = s;
// Next, create a copy that will be the one dragged
Scribble dragScribble = (Scribble) s.clone();
// Adjust the origin to the point the user clicked on.
dragScribble.translate(-x, -y);
// Choose a cursor based on the type of drag the user initiated
Cursor cursor;
switch (e.getDragAction()) {
case DnDConstants.ACTION_COPY:
cursor = DragSource.DefaultCopyDrop;
break;
case DnDConstants.ACTION_MOVE:
cursor = DragSource.DefaultMoveDrop;
break;
default:
return; // We only support move and copys
}
// Some systems allow us to drag an image along with the
// cursor. If so, create an image of the scribble to drag
if (dragSource.isDragImageSupported()) {
Rectangle scribbleBox = dragScribble.getBounds();
Image dragImage = this.createImage(scribbleBox.width,
scribbleBox.height);
Graphics2D g = (Graphics2D) dragImage.getGraphics();
g.setColor(new Color(0, 0, 0, 0)); // transparent background
g.fillRect(0, 0, scribbleBox.width, scribbleBox.height);
g.setColor(Color.black);
g.setStroke(linestyle);
g.translate(-scribbleBox.x, -scribbleBox.y);
g.draw(dragScribble);
Point hotspot = new Point(-scribbleBox.x, -scribbleBox.y);
// Now start dragging, using the image.
e.startDrag(cursor, dragImage, hotspot, dragScribble, this);
} else {
// Or start the drag without an image
e.startDrag(cursor, dragScribble, this);
}
// After we"ve started dragging one scribble, stop looking
return;
}
}
}
/**
* This method, and the four unused methods that follow it implement the
* DragSourceListener interface. dragDropEnd() is invoked when the user
* drops the scribble she was dragging. If the drop was successful, and if
* the user did a "move" rather than a "copy", then we delete the dragged
* scribble from the list of scribbles to draw.
*/
public void dragDropEnd(DragSourceDropEvent e) {
if (!e.getDropSuccess())
return;
int action = e.getDropAction();
if (action == DnDConstants.ACTION_MOVE) {
scribbles.remove(beingDragged);
beingDragged = null;
repaint();
}
}
// These methods are also part of DragSourceListener.
// They are invoked at interesting points during the drag, and can be
// used to perform "drag over" effects, such as changing the drag cursor
// or drag image.
public void dragEnter(DragSourceDragEvent e) {
}
public void dragExit(DragSourceEvent e) {
}
public void dropActionChanged(DragSourceDragEvent e) {
}
public void dragOver(DragSourceDragEvent e) {
}
// The next five methods implement DropTargetListener
/**
* This method is invoked when the user first drags something over us. If we
* understand the data type being dragged, then call acceptDrag() to tell
* the system that we"re receptive. Also, we change our border as a "drag
* under" effect to signal that we can accept the drop.
*/
public void dragEnter(DropTargetDragEvent e) {
if (e.isDataFlavorSupported(Scribble.scribbleDataFlavor)
|| e.isDataFlavorSupported(DataFlavor.stringFlavor)) {
e.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE);
this.setBorder(dropBorder);
}
}
/** The user is no longer dragging over us, so restore the border */
public void dragExit(DropTargetEvent e) {
this.setBorder(normalBorder);
}
/**
* This is the key method of DropTargetListener. It is invoked when the user
* drops something on us.
*/
public void drop(DropTargetDropEvent e) {
this.setBorder(normalBorder); // Restore the default border
// First, check whether we understand the data that was dropped.
// If we supports our data flavors, accept the drop, otherwise reject.
if (e.isDataFlavorSupported(Scribble.scribbleDataFlavor)
|| e.isDataFlavorSupported(DataFlavor.stringFlavor)) {
e.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
} else {
e.rejectDrop();
return;
}
// We"ve accepted the drop, so now we attempt to get the dropped data
// from the Transferable object.
Transferable t = e.getTransferable(); // Holds the dropped data
Scribble droppedScribble; // This will hold the Scribble object
// First, try to get the data directly as a scribble object
try {
droppedScribble = (Scribble) t
.getTransferData(Scribble.scribbleDataFlavor);
} catch (Exception ex) { // unsupported flavor, IO exception, etc.
// If that doesn"t work, try to get it as a String and parse it
try {
String s = (String) t.getTransferData(DataFlavor.stringFlavor);
droppedScribble = Scribble.parse(s);
} catch (Exception ex2) {
// If we still couldn"t get the data, tell the system we failed
e.dropComplete(false);
return;
}
}
// If we get here, we"ve got the Scribble object
Point p = e.getLocation(); // Where did the drop happen?
droppedScribble.translate(p.getX(), p.getY()); // Move it there
scribbles.add(droppedScribble); // add to display list
repaint(); // ask for redraw
e.dropComplete(true); // signal success!
}
// These are unused DropTargetListener methods
public void dragOver(DropTargetDragEvent e) {
}
public void dropActionChanged(DropTargetDragEvent e) {
}
/**
* The main method. Creates a simple application using this class. Note the
* buttons for switching between draw mode and drag mode.
*/
public static void main(String[] args) {
// Create a frame and put a scribble pane in it
JFrame frame = new JFrame("ScribbleDragAndDrop");
final ScribbleDragAndDrop scribblePane = new ScribbleDragAndDrop();
frame.getContentPane().add(scribblePane, BorderLayout.CENTER);
// Create two buttons for switching modes
JToolBar toolbar = new JToolBar();
ButtonGroup group = new ButtonGroup();
JToggleButton draw = new JToggleButton("Draw");
JToggleButton drag = new JToggleButton("Drag");
draw.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
scribblePane.setDragMode(false);
}
});
drag.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
scribblePane.setDragMode(true);
}
});
group.add(draw);
group.add(drag);
toolbar.add(draw);
toolbar.add(drag);
frame.getContentPane().add(toolbar, BorderLayout.NORTH);
// Start off in drawing mode
draw.setSelected(true);
scribblePane.setDragMode(false);
// Pop up the window
frame.setSize(400, 400);
frame.setVisible(true);
}
}
class Scribble implements Shape, Transferable, Serializable, Cloneable {
protected double[] points = new double[64]; // The scribble data
protected int numPoints = 0; // The current number of points
double maxX = Double.NEGATIVE_INFINITY; // The bounding box
double maxY = Double.NEGATIVE_INFINITY;
double minX = Double.POSITIVE_INFINITY;
double minY = Double.POSITIVE_INFINITY;
/**
* Begin a new polyline at (x,y). Note the use of Double.NaN in the points
* array to mark the beginning of a new polyline
*/
public void moveto(double x, double y) {
if (numPoints + 3 > points.length)
reallocate();
// Mark this as the beginning of a new line
points[numPoints++] = Double.NaN;
// The rest of this method is just like lineto();
lineto(x, y);
}
/**
* Add the point (x,y) to the end of the current polyline
*/
public void lineto(double x, double y) {
if (numPoints + 2 > points.length)
reallocate();
points[numPoints++] = x;
points[numPoints++] = y;
// See if the point enlarges our bounding box
if (x > maxX)
maxX = x;
if (x < minX)
minX = x;
if (y > maxY)
maxY = y;
if (y < minY)
minY = y;
}
/**
* Append the Scribble s to this Scribble
*/
public void append(Scribble s) {
int n = numPoints + s.numPoints;
double[] newpoints = new double[n];
System.arraycopy(points, 0, newpoints, 0, numPoints);
System.arraycopy(s.points, 0, newpoints, numPoints, s.numPoints);
points = newpoints;
numPoints = n;
minX = Math.min(minX, s.minX);
maxX = Math.max(maxX, s.maxX);
minY = Math.min(minY, s.minY);
maxY = Math.max(maxY, s.maxY);
}
/**
* Translate the coordinates of all points in the Scribble by x,y
*/
public void translate(double x, double y) {
for (int i = 0; i < numPoints; i++) {
if (Double.isNaN(points[i]))
continue;
points[i++] += x;
points[i] += y;
}
minX += x;
maxX += x;
minY += y;
maxY += y;
}
/** An internal method to make more room in the data array */
protected void reallocate() {
double[] newpoints = new double[points.length * 2];
System.arraycopy(points, 0, newpoints, 0, numPoints);
points = newpoints;
}
/** Clone a Scribble object and its internal array of data */
public Object clone() {
try {
Scribble s = (Scribble) super.clone(); // make a copy of all fields
s.points = (double[]) points.clone(); // copy the entire array
return s;
} catch (CloneNotSupportedException e) { // This should never happen
return this;
}
}
/** Convert the scribble data to a textual format */
public String toString() {
StringBuffer b = new StringBuffer();
for (int i = 0; i < numPoints; i++) {
if (Double.isNaN(points[i])) {
b.append("m ");
} else {
b.append(points[i]);
b.append(" ");
}
}
return b.toString();
}
/**
* Create a new Scribble object and initialize it by parsing a string of
* coordinate data in the format produced by toString()
*/
public static Scribble parse(String s) throws NumberFormatException {
StringTokenizer st = new StringTokenizer(s);
Scribble scribble = new Scribble();
while (st.hasMoreTokens()) {
String t = st.nextToken();
if (t.charAt(0) == "m") {
scribble.moveto(Double.parseDouble(st.nextToken()), Double
.parseDouble(st.nextToken()));
} else {
scribble.lineto(Double.parseDouble(t), Double.parseDouble(st
.nextToken()));
}
}
return scribble;
}
// ========= The following methods implement the Shape interface ========
/** Return the bounding box of the Shape */
public Rectangle getBounds() {
return new Rectangle((int) (minX - 0.5f), (int) (minY - 0.5f),
(int) (maxX - minX + 0.5f), (int) (maxY - minY + 0.5f));
}
/** Return the bounding box of the Shape */
public Rectangle2D getBounds2D() {
return new Rectangle2D.Double(minX, minY, maxX - minX, maxY - minY);
}
/** Our shape is an open curve, so it never contains anything */
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;
}
/**
* Determine if the scribble intersects the specified rectangle by testing
* each line segment individually
*/
public boolean intersects(Rectangle2D r) {
if (numPoints < 4)
return false;
int i = 0;
double x1, y1, x2 = 0.0, y2 = 0.0;
while (i < numPoints) {
if (Double.isNaN(points[i])) { // If we"re beginning a new line
i++; // Skip the NaN
x2 = points[i++];
y2 = points[i++];
} else {
x1 = x2;
y1 = y2;
x2 = points[i++];
y2 = points[i++];
if (r.intersectsLine(x1, y1, x2, y2))
return true;
}
}
return false;
}
/** Test for intersection by invoking the method above */
public boolean intersects(double x, double y, double w, double h) {
return intersects(new Rectangle2D.Double(x, y, w, h));
}
/**
* Return a PathIterator object that tells Java2D how to draw this scribble
*/
public PathIterator getPathIterator(AffineTransform at) {
return new ScribbleIterator(at);
}
/**
* Return a PathIterator that doesn"t include curves. Ours never does.
*/
public PathIterator getPathIterator(AffineTransform at, double flatness) {
return getPathIterator(at);
}
/**
* This inner class implements the PathIterator interface to describe the
* shape of a scribble. Since a Scribble is composed of arbitrary movetos
* and linetos, we simply return their coordinates
*/
public class ScribbleIterator implements PathIterator {
protected int i = 0; // Position in array
protected AffineTransform transform;
public ScribbleIterator(AffineTransform transform) {
this.transform = transform;
}
/** How to determine insideness and outsideness for this shape */
public int getWindingRule() {
return PathIterator.WIND_NON_ZERO;
}
/** Have we reached the end of the scribble path yet? */
public boolean isDone() {
return i >= numPoints;
}
/** Move on to the next segment of the path */
public void next() {
if (Double.isNaN(points[i]))
i += 3;
else
i += 2;
}
/**
* Get the coordinates of the current moveto or lineto as floats
*/
public int currentSegment(float[] coords) {
int retval;
if (Double.isNaN(points[i])) { // If its a moveto
coords[0] = (float) points[i + 1];
coords[1] = (float) points[i + 2];
retval = SEG_MOVETO;
} else {
coords[0] = (float) points[i];
coords[1] = (float) points[i + 1];
retval = SEG_LINETO;
}
// If a transform was specified, use it on the coordinates
if (transform != null)
transform.transform(coords, 0, coords, 0, 1);
return retval;
}
/**
* Get the coordinates of the current moveto or lineto as doubles
*/
public int currentSegment(double[] coords) {
int retval;
if (Double.isNaN(points[i])) {
coords[0] = points[i + 1];
coords[1] = points[i + 2];
retval = SEG_MOVETO;
} else {
coords[0] = points[i];
coords[1] = points[i + 1];
retval = SEG_LINETO;
}
if (transform != null)
transform.transform(coords, 0, coords, 0, 1);
return retval;
}
}
//====== The following methods implement the Transferable interface =====
// This is the custom DataFlavor for Scribble objects
public static DataFlavor scribbleDataFlavor = new DataFlavor(
Scribble.class, "Scribble");
// This is a list of the flavors we know how to work with
public static DataFlavor[] supportedFlavors = { scribbleDataFlavor,
DataFlavor.stringFlavor };
/** Return the data formats or "flavors" we know how to transfer */
public DataFlavor[] getTransferDataFlavors() {
return (DataFlavor[]) supportedFlavors.clone();
}
/** Check whether we support a given flavor */
public boolean isDataFlavorSupported(DataFlavor flavor) {
return (flavor.equals(scribbleDataFlavor) || flavor
.equals(DataFlavor.stringFlavor));
}
/**
* Return the scribble data in the requested format, or throw an exception
* if we don"t support the requested format
*/
public Object getTransferData(DataFlavor flavor)
throws UnsupportedFlavorException {
if (flavor.equals(scribbleDataFlavor)) {
return this;
} else if (flavor.equals(DataFlavor.stringFlavor)) {
return toString();
} else
throw new UnsupportedFlavorException(flavor);
}
}
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);
}
}
Drag and drop: TextArea
/*
Java Swing, 2nd Edition
By Marc Loy, Robert Eckstein, Dave Wood, James Elliott, Brian Cole
ISBN: 0-596-00408-7
Publisher: O"Reilly
*/
// DropTest2.java
//Another simple drag & drop tester application.
//
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.dnd.DnDConstants;
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.io.InputStream;
import java.io.InputStreamReader;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextArea;
public class DropTest2 extends JFrame implements DropTargetListener {
DropTarget dt;
JTextArea ta;
public DropTest2() {
super("Drop Test");
setSize(300, 300);
getContentPane().add(
new JLabel("Drop a list from your file chooser here:"),
BorderLayout.NORTH);
ta = new JTextArea();
ta.setBackground(Color.white);
getContentPane().add(ta, BorderLayout.CENTER);
// Set up our text area to recieve drops...
// This class will handle drop events
dt = new DropTarget(ta, this);
setVisible(true);
}
public void dragEnter(DropTargetDragEvent dtde) {
System.out.println("Drag Enter");
}
public void dragExit(DropTargetEvent dte) {
System.out.println("Drag Exit");
}
public void dragOver(DropTargetDragEvent dtde) {
System.out.println("Drag Over");
}
public void dropActionChanged(DropTargetDragEvent dtde) {
System.out.println("Drop Action Changed");
}
public void drop(DropTargetDropEvent dtde) {
try {
// Ok, get the dropped object and try to figure out what it is
Transferable tr = dtde.getTransferable();
DataFlavor[] flavors = tr.getTransferDataFlavors();
for (int i = 0; i < flavors.length; i++) {
System.out.println("Possible flavor: "
+ flavors[i].getMimeType());
// Check for file lists specifically
if (flavors[i].isFlavorJavaFileListType()) {
// Great! Accept copy drops...
dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
ta.setText("Successful file list drop.\n\n");
// And add the list of file names to our text area
java.util.List list = (java.util.List) tr
.getTransferData(flavors[i]);
for (int j = 0; j < list.size(); j++) {
ta.append(list.get(j) + "\n");
}
// If we made it this far, everything worked.
dtde.dropComplete(true);
return;
}
// Ok, is it another Java object?
else if (flavors[i].isFlavorSerializedObjectType()) {
dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
ta.setText("Successful text drop.\n\n");
Object o = tr.getTransferData(flavors[i]);
ta.append("Object: " + o);
dtde.dropComplete(true);
return;
}
// How about an input stream?
else if (flavors[i].isRepresentationClassInputStream()) {
dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
ta.setText("Successful text drop.\n\n");
ta.read(new InputStreamReader((InputStream) tr
.getTransferData(flavors[i])),
"from system clipboard");
dtde.dropComplete(true);
return;
}
}
// Hmm, the user must not have dropped a file list
System.out.println("Drop failed: " + dtde);
dtde.rejectDrop();
} catch (Exception e) {
e.printStackTrace();
dtde.rejectDrop();
}
}
public static void main(String args[]) {
new DropTest2();
}
}
Drag capabilities: JList
import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.ListSelectionModel;
public class DragTest14 extends JFrame {
JList jl;
String[] items = { "Java", "C", "C++", "Lisp", "Perl", "Python" };
public DragTest14() {
super("Drag Test 1.4");
setSize(200, 150);
setDefaultCloseOperation(EXIT_ON_CLOSE);
jl = new JList(items);
jl.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
jl.setDragEnabled(true);
getContentPane().add(new JScrollPane(jl), BorderLayout.CENTER);
setVisible(true);
}
public static void main(String args[]) {
new DragTest14();
}
}
Drag Color Demo
/* From http://java.sun.ru/docs/books/tutorial/index.html */
/*
* Copyright (c) 2006 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:
*
* -Redistribution of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* -Redistribution 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, Inc. or the names of contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* 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 MIDROSYSTEMS, INC. ("SUN")
* AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
* AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS 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 THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed, licensed or intended
* for use in the design, construction, operation or maintenance of any
* nuclear facility.
*/
/*
* DragColorDemo.java is a 1.4 example that requires
* the following file:
* ColorTransferHandler.java
*/
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
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.BorderFactory;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JColorChooser;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.TransferHandler;
/**
* Example code that shows any JComponent can be customized to allow dropping of
* a color.
*/
public class DragColorDemo extends JPanel implements ActionListener {
JCheckBox toggleForeground;
ColorTransferHandler colorHandler;
public DragColorDemo() {
super(new BorderLayout());
setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
JColorChooser chooser = new JColorChooser();
chooser.setDragEnabled(true);
add(chooser, BorderLayout.PAGE_START);
//Create the color transfer handler.
colorHandler = new ColorTransferHandler();
//Create a matrix of 9 buttons.
JPanel buttonPanel = new JPanel(new GridLayout(3, 3));
for (int i = 0; i < 9; i++) {
JButton tmp = new JButton("Button " + i);
tmp.setTransferHandler(colorHandler);
buttonPanel.add(tmp);
}
add(buttonPanel, BorderLayout.CENTER);
//Create a check box.
toggleForeground = new JCheckBox("Change the foreground color.");
toggleForeground.setSelected(true);
toggleForeground.addActionListener(this);
JPanel textPanel = new JPanel(new BorderLayout());
textPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
textPanel.add(toggleForeground, BorderLayout.PAGE_START);
//Create a label.
JLabel label = new JLabel(
"Change the color of any button or this label by dropping a color.");
label.setTransferHandler(colorHandler);
label.setOpaque(true); //So the background color can be changed.
textPanel.add(label, BorderLayout.PAGE_END);
add(textPanel, BorderLayout.PAGE_END);
}
public void actionPerformed(ActionEvent e) {
colorHandler.setChangesForegroundColor(toggleForeground.isSelected());
}
/**
* Create the GUI and show it. For thread safety, this method should be
* invoked from the event-dispatching thread.
*/
private static void createAndShowGUI() {
//Make sure we have nice window decorations.
JFrame.setDefaultLookAndFeelDecorated(true);
//Create and set up the window.
JFrame frame = new JFrame("DragColorDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Create and setup the content pane.
JComponent newContentPane = new DragColorDemo();
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();
}
});
}
}
/*
* ColorTransferHandler.java is used by the 1.4 DragColorDemo.java and
* DragColorTextFieldDemo examples.
*/
/**
* An implementation of TransferHandler that adds support for dropping colors.
* Dropping a color on a component having this TransferHandler changes the
* foreground or the background of the component to the dropped color, according
* to the value of the changesForegroundColor property.
*/
class ColorTransferHandler extends TransferHandler {
//The data type exported from JColorChooser.
String mimeType = DataFlavor.javaJVMLocalObjectMimeType
+ ";class=java.awt.Color";
DataFlavor colorFlavor;
private boolean changesForegroundColor = true;
ColorTransferHandler() {
//Try to create a DataFlavor for color.
try {
colorFlavor = new DataFlavor(mimeType);
} catch (ClassNotFoundException e) {
}
}
/**
* Overridden to import a Color if it is available.
* getChangesForegroundColor is used to determine whether the foreground or
* the background color is changed.
*/
public boolean importData(JComponent c, Transferable t) {
if (hasColorFlavor(t.getTransferDataFlavors())) {
try {
Color col = (Color) t.getTransferData(colorFlavor);
if (getChangesForegroundColor()) {
c.setForeground(col);
} else {
c.setBackground(col);
}
return true;
} catch (UnsupportedFlavorException ufe) {
System.out.println("importData: unsupported data flavor");
} catch (IOException ioe) {
System.out.println("importData: I/O exception");
}
}
return false;
}
/**
* Does the flavor list have a Color flavor?
*/
protected boolean hasColorFlavor(DataFlavor[] flavors) {
if (colorFlavor == null) {
return false;
}
for (int i = 0; i < flavors.length; i++) {
if (colorFlavor.equals(flavors[i])) {
return true;
}
}
return false;
}
/**
* Overridden to include a check for a color flavor.
*/
public boolean canImport(JComponent c, DataFlavor[] flavors) {
return hasColorFlavor(flavors);
}
protected void setChangesForegroundColor(boolean flag) {
changesForegroundColor = flag;
}
protected boolean getChangesForegroundColor() {
return changesForegroundColor;
}
}
Drag Color TextField Demo
/* From http://java.sun.ru/docs/books/tutorial/index.html */
/*
* Copyright (c) 2006 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:
*
* -Redistribution of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* -Redistribution 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, Inc. or the names of contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* 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 MIDROSYSTEMS, INC. ("SUN")
* AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
* AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS 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 THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed, licensed or intended
* for use in the design, construction, operation or maintenance of any
* nuclear facility.
*/
/*
* DragColorTextFieldDemo.java is a 1.4 example that requires
* the following files:
* ColorTransferHandler.java
* ColorAndTextTransferHandler.java
*/
import java.awt.BorderLayout;
import java.awt.Color;
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.awt.event.KeyEvent;
import java.io.IOException;
import javax.swing.BorderFactory;
import javax.swing.JCheckBox;
import javax.swing.JColorChooser;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.TransferHandler;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultEditorKit;
import javax.swing.text.Document;
import javax.swing.text.JTextComponent;
import javax.swing.text.Position;
/**
* Example code that shows a text component that both accepts color (by changing
* its foreground) and also exports simple text.
*/
public class DragColorTextFieldDemo extends JPanel {
JCheckBox toggleForeground;
ColorAndTextTransferHandler colorHandler;
public DragColorTextFieldDemo() {
super(new BorderLayout());
JTextField textField;
setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
JColorChooser chooser = new JColorChooser();
chooser.setDragEnabled(true);
add(chooser, BorderLayout.PAGE_START);
//Create the color transfer handler.
colorHandler = new ColorAndTextTransferHandler();
//Create some text fields.
JPanel buttonPanel = new JPanel(new GridLayout(3, 1));
textField = new JTextField("I can accept color/text and drag text.");
textField.setTransferHandler(colorHandler);
textField.setDragEnabled(true);
buttonPanel.add(textField);
textField = new JTextField("Me too!");
textField.setTransferHandler(colorHandler);
textField.setDragEnabled(true);
buttonPanel.add(textField);
textField = new JTextField("Me three!");
textField.setTransferHandler(colorHandler);
textField.setDragEnabled(true);
buttonPanel.add(textField);
add(buttonPanel, 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);
menuItem = new JMenuItem(new DefaultEditorKit.CutAction());
menuItem.setText("Cut");
menuItem.setMnemonic(KeyEvent.VK_T);
mainMenu.add(menuItem);
menuItem = new JMenuItem(new DefaultEditorKit.CopyAction());
menuItem.setText("Copy");
menuItem.setMnemonic(KeyEvent.VK_C);
mainMenu.add(menuItem);
menuItem = new JMenuItem(new DefaultEditorKit.PasteAction());
menuItem.setText("Paste");
menuItem.setMnemonic(KeyEvent.VK_P);
mainMenu.add(menuItem);
menuBar.add(mainMenu);
return menuBar;
}
/**
* Create the GUI and show it. For thread safety, this method should be
* invoked from the event-dispatching thread.
*/
private static void createAndShowGUI() {
//Make sure we have nice window decorations.
JFrame.setDefaultLookAndFeelDecorated(true);
//Create and set up the window.
JFrame frame = new JFrame("DragColorTextFieldDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Create and set up the menu bar and content pane.
DragColorTextFieldDemo demo = new DragColorTextFieldDemo();
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() {
createAndShowGUI();
}
});
}
}
/*
* ColorAndTextTransferHandler.java is used by the 1.4 DragColorDemo.java
* example.
*/
/**
* An implementation of TransferHandler that adds support for the import of
* color and the import and export of text. Dropping a color on a component
* having this TransferHandler changes the foreground of the component to the
* imported color.
*/
class ColorAndTextTransferHandler extends ColorTransferHandler {
private DataFlavor stringFlavor = DataFlavor.stringFlavor;
private JTextComponent source;
private boolean shouldRemove;
//Start and end position in the source text.
//We need this information when performing a MOVE
//in order to remove the dragged text from the source.
Position p0 = null, p1 = null;
//Get the flavors from the Transferable.
//Is there a color flavor? If so, set the foreground color.
//Is there a string flavor? If so, set the text property.
public boolean importData(JComponent c, Transferable t) {
JTextComponent tc = (JTextComponent) c;
if (!canImport(c, t.getTransferDataFlavors())) {
return false;
}
if (tc.equals(source) && (tc.getCaretPosition() >= p0.getOffset())
&& (tc.getCaretPosition() <= p1.getOffset())) {
shouldRemove = false;
return true;
}
if (hasStringFlavor(t.getTransferDataFlavors())) {
try {
String str = (String) t.getTransferData(stringFlavor);
tc.replaceSelection(str);
return true;
} catch (UnsupportedFlavorException ufe) {
System.out.println("importData: unsupported data flavor");
} catch (IOException ioe) {
System.out.println("importData: I/O exception");
}
}
//The ColorTransferHandler superclass handles color.
return super.importData(c, t);
}
//Create a Transferable implementation that contains the
//selected text.
protected Transferable createTransferable(JComponent c) {
source = (JTextComponent) c;
int start = source.getSelectionStart();
int end = source.getSelectionEnd();
Document doc = source.getDocument();
if (start == end) {
return null;
}
try {
p0 = doc.createPosition(start);
p1 = doc.createPosition(end);
} catch (BadLocationException e) {
System.out
.println("Can"t create position - unable to remove text from source.");
}
shouldRemove = true;
String data = source.getSelectedText();
return new StringSelection(data);
}
public int getSourceActions(JComponent c) {
return COPY_OR_MOVE;
}
//Remove the old text if the action is a MOVE.
//However, we do not allow dropping on top of the selected text,
//so in that case do nothing.
protected void exportDone(JComponent c, Transferable data, int action) {
if (shouldRemove && (action == MOVE)) {
if ((p0 != null) && (p1 != null)
&& (p0.getOffset() != p1.getOffset())) {
try {
JTextComponent tc = (JTextComponent) c;
tc.getDocument().remove(p0.getOffset(),
p1.getOffset() - p0.getOffset());
} catch (BadLocationException e) {
System.out.println("Can"t remove text from source.");
}
}
}
source = null;
}
/**
* Does flavors contain a color or string Transferable?
*/
public boolean canImport(JComponent c, DataFlavor[] flavors) {
if (hasStringFlavor(flavors)) {
return true;
}
return super.canImport(c, flavors);
}
/**
* Does the flavor list have a string flavor?
*/
protected boolean hasStringFlavor(DataFlavor[] flavors) {
for (int i = 0; i < flavors.length; i++) {
if (stringFlavor.equals(flavors[i])) {
return true;
}
}
return false;
}
}
/*
* ColorTransferHandler.java is used by the 1.4 DragColorDemo.java and
* DragColorTextFieldDemo examples.
*/
/**
* An implementation of TransferHandler that adds support for dropping colors.
* Dropping a color on a component having this TransferHandler changes the
* foreground or the background of the component to the dropped color, according
* to the value of the changesForegroundColor property.
*/
class ColorTransferHandler extends TransferHandler {
//The data type exported from JColorChooser.
String mimeType = DataFlavor.javaJVMLocalObjectMimeType
+ ";class=java.awt.Color";
DataFlavor colorFlavor;
private boolean changesForegroundColor = true;
ColorTransferHandler() {
//Try to create a DataFlavor for color.
try {
colorFlavor = new DataFlavor(mimeType);
} catch (ClassNotFoundException e) {
}
}
/**
* Overridden to import a Color if it is available.
* getChangesForegroundColor is used to determine whether the foreground or
* the background color is changed.
*/
public boolean importData(JComponent c, Transferable t) {
if (hasColorFlavor(t.getTransferDataFlavors())) {
try {
Color col = (Color) t.getTransferData(colorFlavor);
if (getChangesForegroundColor()) {
c.setForeground(col);
} else {
c.setBackground(col);
}
return true;
} catch (UnsupportedFlavorException ufe) {
System.out.println("importData: unsupported data flavor");
} catch (IOException ioe) {
System.out.println("importData: I/O exception");
}
}
return false;
}
/**
* Does the flavor list have a Color flavor?
*/
protected boolean hasColorFlavor(DataFlavor[] flavors) {
if (colorFlavor == null) {
return false;
}
for (int i = 0; i < flavors.length; i++) {
if (colorFlavor.equals(flavors[i])) {
return true;
}
}
return false;
}
/**
* Overridden to include a check for a color flavor.
*/
public boolean canImport(JComponent c, DataFlavor[] flavors) {
return hasColorFlavor(flavors);
}
protected void setChangesForegroundColor(boolean flag) {
changesForegroundColor = flag;
}
protected boolean getChangesForegroundColor() {
return changesForegroundColor;
}
}
Drag Drop Tree Example
/*
Core SWING Advanced Programming
By Kim Topley
ISBN: 0 13 083292 8
Publisher: Prentice Hall
*/
import java.awt.BorderLayout;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.Autoscroll;
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.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.ruparator;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeExpansionListener;
import javax.swing.plaf.basic.BasicTreeUI.TreeExpansionHandler;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
public class DragDropTreeExample {
public static void main(String[] args) {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch (Exception evt) {}
final JFrame f = new JFrame("FileTree Drop and Drop Example");
try {
final FileTree tree = new FileTree("D:\\");
// Add a drop target to the FileTree
FileTreeDropTarget target = new FileTreeDropTarget(tree);
// Add a drag source to the FileTree
FileTreeDragSource source = new FileTreeDragSource(tree);
tree.setEditable(true);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent evt) {
System.exit(0);
}
});
JPanel panel = new JPanel();
final JCheckBox editable = new JCheckBox("Editable");
editable.setSelected(true);
panel.add(editable);
editable.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
tree.setEditable(editable.isSelected());
}
});
final JCheckBox enabled = new JCheckBox("Enabled");
enabled.setSelected(true);
panel.add(enabled);
enabled.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
tree.setEnabled(enabled.isSelected());
}
});
f.getContentPane().add(new JScrollPane(tree), BorderLayout.CENTER);
f.getContentPane().add(panel, BorderLayout.SOUTH);
f.setSize(500, 400);
f.setVisible(true);
} catch (Exception e) {
System.out.println("Failed to build GUI: " + e);
}
}
}
class FileTree extends JTree implements Autoscroll {
public static final Insets defaultScrollInsets = new Insets(8, 8, 8, 8);
protected Insets scrollInsets = defaultScrollInsets;
public FileTree(String path) throws FileNotFoundException,
SecurityException {
super((TreeModel) null); // Create the JTree itself
// Use horizontal and vertical lines
putClientProperty("JTree.lineStyle", "Angled");
// Create the first node
FileTreeNode rootNode = new FileTreeNode(null, path);
// Populate the root node with its subdirectories
boolean addedNodes = rootNode.populateDirectories(true);
setModel(new DefaultTreeModel(rootNode));
// Listen for Tree Selection Events
addTreeExpansionListener(new TreeExpansionHandler());
}
// Returns the full pathname for a path, or null if not a known path
public String getPathName(TreePath path) {
Object o = path.getLastPathComponent();
if (o instanceof FileTreeNode) {
return ((FileTreeNode) o).fullName;
}
return null;
}
// Adds a new node to the tree after construction.
// Returns the inserted node, or null if the parent
// directory has not been expanded.
public FileTreeNode addNode(FileTreeNode parent, String name) {
int index = parent.addNode(name);
if (index != -1) {
((DefaultTreeModel) getModel()).nodesWereInserted(parent,
new int[] { index });
return (FileTreeNode) parent.getChildAt(index);
}
// No node was created
return null;
}
// Autoscrolling support
public void setScrollInsets(Insets insets) {
this.scrollInsets = insets;
}
public Insets getScrollInsets() {
return scrollInsets;
}
// Implementation of Autoscroll interface
public Insets getAutoscrollInsets() {
Rectangle r = getVisibleRect();
Dimension size = getSize();
Insets i = new Insets(r.y + scrollInsets.top, r.x + scrollInsets.left,
size.height - r.y - r.height + scrollInsets.bottom, size.width
- r.x - r.width + scrollInsets.right);
return i;
}
public void autoscroll(Point location) {
JScrollPane scroller = (JScrollPane) SwingUtilities.getAncestorOfClass(
JScrollPane.class, this);
if (scroller != null) {
JScrollBar hBar = scroller.getHorizontalScrollBar();
JScrollBar vBar = scroller.getVerticalScrollBar();
Rectangle r = getVisibleRect();
if (location.x <= r.x + scrollInsets.left) {
// Need to scroll left
hBar.setValue(hBar.getValue() - hBar.getUnitIncrement(-1));
}
if (location.y <= r.y + scrollInsets.top) {
// Need to scroll up
vBar.setValue(vBar.getValue() - vBar.getUnitIncrement(-1));
}
if (location.x >= r.x + r.width - scrollInsets.right) {
// Need to scroll right
hBar.setValue(hBar.getValue() + hBar.getUnitIncrement(1));
}
if (location.y >= r.y + r.height - scrollInsets.bottom) {
// Need to scroll down
vBar.setValue(vBar.getValue() + vBar.getUnitIncrement(1));
}
}
}
// Inner class that represents a node in this file system tree
public static class FileTreeNode extends DefaultMutableTreeNode {
public FileTreeNode(String parent, String name)
throws SecurityException, FileNotFoundException {
this.name = name;
// See if this node exists and whether it is a directory
fullName = parent == null ? name : parent + File.separator + name;
File f = new File(fullName);
if (f.exists() == false) {
throw new FileNotFoundException("File " + fullName
+ " does not exist");
}
isDir = f.isDirectory();
// Hack for Windows which doesn"t consider a drive to be a
// directory!
if (isDir == false && f.isFile() == false) {
isDir = true;
}
}
// Override isLeaf to check whether this is a directory
public boolean isLeaf() {
return !isDir;
}
// Override getAllowsChildren to check whether this is a directory
public boolean getAllowsChildren() {
return isDir;
}
// Return whether this is a directory
public boolean isDir() {
return isDir;
}
// Get full path
public String getFullName() {
return fullName;
}
// For display purposes, we return our own name
public String toString() {
return name;
}
// If we are a directory, scan our contents and populate
// with children. In addition, populate those children
// if the "descend" flag is true. We only descend once,
// to avoid recursing the whole subtree.
// Returns true if some nodes were added
boolean populateDirectories(boolean descend) {
boolean addedNodes = false;
// Do this only once
if (populated == false) {
File f;
try {
f = new File(fullName);
} catch (SecurityException e) {
populated = true;
return false;
}
if (interim == true) {
// We have had a quick look here before:
// remove the dummy node that we added last time
removeAllChildren();
interim = false;
}
String[] names = f.list(); // Get list of contents
// Process the contents
ArrayList list = new ArrayList();
for (int i = 0; i < names.length; i++) {
String name = names[i];
File d = new File(fullName, name);
try {
FileTreeNode node = new FileTreeNode(fullName, name);
list.add(node);
if (descend && d.isDirectory()) {
node.populateDirectories(false);
}
addedNodes = true;
if (descend == false) {
// Only add one node if not descending
break;
}
} catch (Throwable t) {
// Ignore phantoms or access problems
}
}
if (addedNodes == true) {
// Now sort the list of contained files and directories
Object[] nodes = list.toArray();
Arrays.sort(nodes, new Comparator() {
public boolean equals(Object o) {
return false;
}
public int compare(Object o1, Object o2) {
FileTreeNode node1 = (FileTreeNode) o1;
FileTreeNode node2 = (FileTreeNode) o2;
// Directories come first
if (node1.isDir != node2.isDir) {
return node1.isDir ? -1 : +1;
}
// Both directories or both files -
// compare based on pathname
return node1.fullName.rupareTo(node2.fullName);
}
});
// Add sorted items as children of this node
for (int j = 0; j < nodes.length; j++) {
this.add((FileTreeNode) nodes[j]);
}
}
// If we were scanning to get all subdirectories,
// or if we found no content, there is no
// reason to look at this directory again, so
// set populated to true. Otherwise, we set interim
// so that we look again in the future if we need to
if (descend == true || addedNodes == false) {
populated = true;
} else {
// Just set interim state
interim = true;
}
}
return addedNodes;
}
// Adding a new file or directory after
// constructing the FileTree. Returns
// the index of the inserted node.
public int addNode(String name) {
// If not populated yet, do nothing
if (populated == true) {
// Do not add a new node if
// the required node is already there
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
FileTreeNode node = (FileTreeNode) getChildAt(i);
if (node.name.equals(name)) {
// Already exists - ensure
// we repopulate
if (node.isDir()) {
node.interim = true;
node.populated = false;
}
return -1;
}
}
// Add a new node
try {
FileTreeNode node = new FileTreeNode(fullName, name);
add(node);
return childCount;
} catch (Exception e) {
}
}
return -1;
}
protected String name; // Name of this component
protected String fullName; // Full pathname
protected boolean populated;// true if we have been populated
protected boolean interim; // true if we are in interim state
protected boolean isDir; // true if this is a directory
}
// Inner class that handles Tree Expansion Events
protected class TreeExpansionHandler implements TreeExpansionListener {
public void treeExpanded(TreeExpansionEvent evt) {
TreePath path = evt.getPath(); // The expanded path
JTree tree = (JTree) evt.getSource(); // The tree
// Get the last component of the path and
// arrange to have it fully populated.
FileTreeNode node = (FileTreeNode) path.getLastPathComponent();
if (node.populateDirectories(true)) {
((DefaultTreeModel) tree.getModel()).nodeStructureChanged(node);
}
}
public void treeCollapsed(TreeExpansionEvent evt) {
// Nothing to do
}
}
}
class FileTreeDropTarget implements DropTargetListener, PropertyChangeListener {
public FileTreeDropTarget(FileTree tree) {
this.tree = tree;
// Listen for changes in the enabled property
tree.addPropertyChangeListener(this);
// Create the DropTarget and register
// it with the FileTree.
dropTarget = new DropTarget(tree, DnDConstants.ACTION_COPY_OR_MOVE,
this, tree.isEnabled(), null);
}
// Implementation of the DropTargetListener interface
public void dragEnter(DropTargetDragEvent dtde) {
DnDUtils.debugPrintln("dragEnter, drop action = "
+ DnDUtils.showActions(dtde.getDropAction()));
// Save the list of selected items
saveTreeSelection();
// Get the type of object being transferred and determine
// whether it is appropriate.
checkTransferType(dtde);
// Accept or reject the drag.
boolean acceptedDrag = acceptOrRejectDrag(dtde);
// Do drag-under feedback
dragUnderFeedback(dtde, acceptedDrag);
}
public void dragExit(DropTargetEvent dte) {
DnDUtils.debugPrintln("DropTarget dragExit");
// Do drag-under feedback
dragUnderFeedback(null, false);
// Restore the original selections
restoreTreeSelection();
}
public void dragOver(DropTargetDragEvent dtde) {
DnDUtils.debugPrintln("DropTarget dragOver, drop action = "
+ DnDUtils.showActions(dtde.getDropAction()));
// Accept or reject the drag
boolean acceptedDrag = acceptOrRejectDrag(dtde);
// Do drag-under feedback
dragUnderFeedback(dtde, acceptedDrag);
}
public void dropActionChanged(DropTargetDragEvent dtde) {
DnDUtils.debugPrintln("DropTarget dropActionChanged, drop action = "
+ DnDUtils.showActions(dtde.getDropAction()));
// Accept or reject the drag
boolean acceptedDrag = acceptOrRejectDrag(dtde);
// Do drag-under feedback
dragUnderFeedback(dtde, acceptedDrag);
}
public void drop(DropTargetDropEvent dtde) {
DnDUtils.debugPrintln("DropTarget drop, drop action = "
+ DnDUtils.showActions(dtde.getDropAction()));
// Check the drop action
if ((dtde.getDropAction() & DnDConstants.ACTION_COPY_OR_MOVE) != 0) {
// Accept the drop and get the transfer data
dtde.acceptDrop(dtde.getDropAction());
Transferable transferable = dtde.getTransferable();
boolean dropSucceeded = false;
try {
tree.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
// Save the user"s selections
saveTreeSelection();
dropSucceeded = dropFile(dtde.getDropAction(), transferable,
dtde.getLocation());
DnDUtils.debugPrintln("Drop completed, success: "
+ dropSucceeded);
} catch (Exception e) {
DnDUtils.debugPrintln("Exception while handling drop " + e);
} finally {
tree.setCursor(Cursor.getDefaultCursor());
// Restore the user"s selections
restoreTreeSelection();
dtde.dropComplete(dropSucceeded);
}
} else {
DnDUtils.debugPrintln("Drop target rejected drop");
dtde.dropComplete(false);
}
}
// PropertyChangeListener interface
public void propertyChange(PropertyChangeEvent evt) {
String propertyName = evt.getPropertyName();
if (propertyName.equals("enabled")) {
// Enable the drop target if the FileTree is enabled
// and vice versa.
dropTarget.setActive(tree.isEnabled());
}
}
// Internal methods start here
protected boolean acceptOrRejectDrag(DropTargetDragEvent dtde) {
int dropAction = dtde.getDropAction();
int sourceActions = dtde.getSourceActions();
boolean acceptedDrag = false;
DnDUtils.debugPrintln("\tSource actions are "
+ DnDUtils.showActions(sourceActions) + ", drop action is "
+ DnDUtils.showActions(dropAction));
Point location = dtde.getLocation();
boolean acceptableDropLocation = isAcceptableDropLocation(location);
// Reject if the object being transferred
// or the operations available are not acceptable.
if (!acceptableType
|| (sourceActions & DnDConstants.ACTION_COPY_OR_MOVE) == 0) {
DnDUtils.debugPrintln("Drop target rejecting drag");
dtde.rejectDrag();
} else if (!tree.isEditable()) {
// Can"t drag to a read-only FileTree
DnDUtils.debugPrintln("Drop target rejecting drag");
dtde.rejectDrag();
} else if (!acceptableDropLocation) {
// Can only drag to writable directory
DnDUtils.debugPrintln("Drop target rejecting drag");
dtde.rejectDrag();
} else if ((dropAction & DnDConstants.ACTION_COPY_OR_MOVE) == 0) {
// Not offering copy or move - suggest a copy
DnDUtils.debugPrintln("Drop target offering COPY");
dtde.acceptDrag(DnDConstants.ACTION_COPY);
acceptedDrag = true;
} else {
// Offering an acceptable operation: accept
DnDUtils.debugPrintln("Drop target accepting drag");
dtde.acceptDrag(dropAction);
acceptedDrag = true;
}
return acceptedDrag;
}
protected void dragUnderFeedback(DropTargetDragEvent dtde,
boolean acceptedDrag) {
if (dtde != null && acceptedDrag) {
Point location = dtde.getLocation();
if (isAcceptableDropLocation(location)) {
tree.setSelectionRow(tree.getRowForLocation(location.x,
location.y));
} else {
tree.clearSelection();
}
} else {
tree.clearSelection();
}
}
protected void checkTransferType(DropTargetDragEvent dtde) {
// Accept a list of files
acceptableType = false;
if (dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
acceptableType = true;
}
DnDUtils.debugPrintln("Data type acceptable - " + acceptableType);
}
// This method handles a drop for a list of files
protected boolean dropFile(int action, Transferable transferable,
Point location) throws IOException, UnsupportedFlavorException,
MalformedURLException {
List files = (List) transferable
.getTransferData(DataFlavor.javaFileListFlavor);
TreePath treePath = tree.getPathForLocation(location.x, location.y);
File targetDirectory = findTargetDirectory(location);
if (treePath == null || targetDirectory == null) {
return false;
}
FileTree.FileTreeNode node = (FileTree.FileTreeNode) treePath
.getLastPathComponent();
// Highlight the drop location while we perform the drop
tree.setSelectionPath(treePath);
// Get File objects for all files being
// transferred, eliminating duplicates.
File[] fileList = getFileList(files);
// Don"t overwrite files by default
copyOverExistingFiles = false;
// Copy or move each source object to the target
for (int i = 0; i < fileList.length; i++) {
File f = fileList[i];
if (f.isDirectory()) {
transferDirectory(action, f, targetDirectory, node);
} else {
try {
transferFile(action, fileList[i], targetDirectory, node);
} catch (IllegalStateException e) {
// Cancelled by user
return false;
}
}
}
return true;
}
protected File findTargetDirectory(Point location) {
TreePath treePath = tree.getPathForLocation(location.x, location.y);
if (treePath != null) {
FileTree.FileTreeNode node = (FileTree.FileTreeNode) treePath
.getLastPathComponent();
// Only allow a drop on a writable directory
if (node.isDir()) {
try {
File f = new File(node.getFullName());
if (f.canWrite()) {
return f;
}
} catch (Exception e) {
}
}
}
return null;
}
protected boolean isAcceptableDropLocation(Point location) {
return findTargetDirectory(location) != null;
}
protected void saveTreeSelection() {
selections = tree.getSelectionPaths();
leadSelection = tree.getLeadSelectionPath();
tree.clearSelection();
}
protected void restoreTreeSelection() {
tree.setSelectionPaths(selections);
// Restore the lead selection
if (leadSelection != null) {
tree.removeSelectionPath(leadSelection);
tree.addSelectionPath(leadSelection);
}
}
// Get the list of files being transferred and
// remove any duplicates. For example, if the
// list contains /a/b/c and /a/b/c/d, the
// second entry is removed.
protected File[] getFileList(List files) {
int size = files.size();
// Get the files into an array for sorting
File[] f = new File[size];
Iterator iter = files.iterator();
int count = 0;
while (iter.hasNext()) {
f[count++] = (File) iter.next();
}
// Sort the files into alphabetical order
// based on pathnames.
Arrays.sort(f, new Comparator() {
public boolean equals(Object o1) {
return false;
}
public int compare(Object o1, Object o2) {
return ((File) o1).getAbsolutePath().rupareTo(
((File) o2).getAbsolutePath());
}
});
// Remove duplicates, retaining the results in a Vector
Vector v = new Vector();
char separator = System.getProperty("file.separator").charAt(0);
outer: for (int i = f.length - 1; i >= 0; i--) {
String secondPath = f[i].getAbsolutePath();
int secondLength = secondPath.length();
for (int j = i - 1; j >= 0; j--) {
String firstPath = f[j].getAbsolutePath();
int firstLength = firstPath.length();
if (secondPath.startsWith(firstPath)
&& firstLength != secondLength
&& secondPath.charAt(firstLength) == separator) {
continue outer;
}
}
v.add(f[i]);
}
// Copy the retained files into an array
f = new File[v.size()];
v.copyInto(f);
return f;
}
// Copy or move a file
protected void transferFile(int action, File srcFile, File targetDirectory,
FileTree.FileTreeNode targetNode) {
DnDUtils.debugPrintln((action == DnDConstants.ACTION_COPY ? "Copy"
: "Move")
+ " file "
+ srcFile.getAbsolutePath()
+ " to "
+ targetDirectory.getAbsolutePath());
// Create a File entry for the target
String name = srcFile.getName();
File newFile = new File(targetDirectory, name);
if (newFile.exists()) {
// Already exists - is it the same file?
if (newFile.equals(srcFile)) {
// Exactly the same file - ignore
return;
}
// File of this name exists in this directory
if (copyOverExistingFiles == false) {
int res = JOptionPane.showOptionDialog(tree,
"A file called\n " + name
+ "\nalready exists in the directory\n "
+ targetDirectory.getAbsolutePath()
+ "\nOverwrite it?", "File Exists",
JOptionPane.DEFAULT_OPTION,
JOptionPane.QUESTION_MESSAGE, null, new String[] {
"Yes", "Yes to All", "No", "Cancel" }, "No");
switch (res) {
case 1: // Yes to all
copyOverExistingFiles = true;
case 0: // Yes
break;
case 2: // No
return;
default: // Cancel
throw new IllegalStateException("Cancelled");
}
}
} else {
// New file - create it
try {
newFile.createNewFile();
} catch (IOException e) {
JOptionPane.showMessageDialog(tree,
"Failed to create new file\n "
+ newFile.getAbsolutePath(),
"File Creation Failed", JOptionPane.ERROR_MESSAGE);
return;
}
}
// Copy the data and close file.
BufferedInputStream is = null;
BufferedOutputStream os = null;
try {
is = new BufferedInputStream(new FileInputStream(srcFile));
os = new BufferedOutputStream(new FileOutputStream(newFile));
int size = 4096;
byte[] buffer = new byte[size];
int len;
while ((len = is.read(buffer, 0, size)) > 0) {
os.write(buffer, 0, len);
}
} catch (IOException e) {
JOptionPane.showMessageDialog(tree, "Failed to copy file\n "
+ name + "\nto directory\n "
+ targetDirectory.getAbsolutePath(), "File Copy Failed",
JOptionPane.ERROR_MESSAGE);
return;
} finally {
try {
if (is != null) {
is.close();
}
if (os != null) {
os.close();
}
} catch (IOException e) {
}
}
// Remove the source if this is a move operation.
if (action == DnDConstants.ACTION_MOVE
&& System.getProperty("DnDExamples.allowRemove") != null) {
srcFile.delete();
}
// Update the tree display
if (targetNode != null) {
tree.addNode(targetNode, name);
}
}
protected void transferDirectory(int action, File srcDir,
File targetDirectory, FileTree.FileTreeNode targetNode) {
DnDUtils.debugPrintln((action == DnDConstants.ACTION_COPY ? "Copy"
: "Move")
+ " directory "
+ srcDir.getAbsolutePath()
+ " to "
+ targetDirectory.getAbsolutePath());
// Do not copy a directory into itself or
// a subdirectory of itself.
File parentDir = targetDirectory;
while (parentDir != null) {
if (parentDir.equals(srcDir)) {
DnDUtils.debugPrintln("-- SUPPRESSED");
return;
}
parentDir = parentDir.getParentFile();
}
// Copy the directory itself, then its contents
// Create a File entry for the target
String name = srcDir.getName();
File newDir = new File(targetDirectory, name);
if (newDir.exists()) {
// Already exists - is it the same directory?
if (newDir.equals(srcDir)) {
// Exactly the same file - ignore
return;
}
} else {
// Directory does not exist - create it
if (newDir.mkdir() == false) {
// Failed to create - abandon this directory
JOptionPane.showMessageDialog(tree,
"Failed to create target directory\n "
+ newDir.getAbsolutePath(),
"Directory creation Failed", JOptionPane.ERROR_MESSAGE);
return;
}
}
// Add a node for the new directory
if (targetNode != null) {
targetNode = tree.addNode(targetNode, name);
}
// Now copy the directory content.
File[] files = srcDir.listFiles();
for (int i = 0; i < files.length; i++) {
File f = files[i];
if (f.isFile()) {
transferFile(action, f, newDir, targetNode);
} else if (f.isDirectory()) {
transferDirectory(action, f, newDir, targetNode);
}
}
// Remove the source directory after moving
if (action == DnDConstants.ACTION_MOVE
&& System.getProperty("DnDExamples.allowRemove") != null) {
srcDir.delete();
}
}
public static void main(String[] args) {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch (Exception evt) {}
final JFrame f = new JFrame("FileTree Drop Target Example");
try {
final FileTree tree = new FileTree("D:\\");
// Add a drop target to the FileTree
FileTreeDropTarget target = new FileTreeDropTarget(tree);
tree.setEditable(true);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent evt) {
System.exit(0);
}
});
JPanel panel = new JPanel();
final JCheckBox editable = new JCheckBox("Editable");
editable.setSelected(true);
panel.add(editable);
editable.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
tree.setEditable(editable.isSelected());
}
});
final JCheckBox enabled = new JCheckBox("Enabled");
enabled.setSelected(true);
panel.add(enabled);
enabled.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
tree.setEnabled(enabled.isSelected());
}
});
f.getContentPane().add(new JScrollPane(tree), BorderLayout.CENTER);
f.getContentPane().add(panel, BorderLayout.SOUTH);
f.setSize(500, 400);
f.setVisible(true);
} catch (Exception e) {
System.out.println("Failed to build GUI: " + e);
}
}
protected FileTree tree;
protected DropTarget dropTarget;
protected boolean acceptableType; // Indicates whether data is acceptable
TreePath[] selections; // Initially selected rows
TreePath leadSelection; // Initial lead selection
boolean copyOverExistingFiles;
}
class DnDUtils {
public static String showActions(int action) {
String actions = "";
if ((action & (DnDConstants.ACTION_LINK | DnDConstants.ACTION_COPY_OR_MOVE)) == 0) {
return "None";
}
if ((action & DnDConstants.ACTION_COPY) != 0) {
actions += "Copy ";
}
if ((action & DnDConstants.ACTION_MOVE) != 0) {
actions += "Move ";
}
if ((action & DnDConstants.ACTION_LINK) != 0) {
actions += "Link";
}
return actions;
}
public static boolean isDebugEnabled() {
return debugEnabled;
}
public static void debugPrintln(String s) {
if (debugEnabled) {
System.out.println(s);
}
}
private static boolean debugEnabled = (System
.getProperty("DnDExamples.debug") != null);
}
class FileTreeDragSource implements DragGestureListener, DragSourceListener {
public FileTreeDragSource(FileTree tree) {
this.tree = tree;
// Use the default DragSource
DragSource dragSource = DragSource.getDefaultDragSource();
// Create a DragGestureRecognizer and
// register as the listener
dragSource.createDefaultDragGestureRecognizer(tree,
DnDConstants.ACTION_COPY_OR_MOVE, this);
}
// Implementation of DragGestureListener interface.
public void dragGestureRecognized(DragGestureEvent dge) {
// Get the mouse location and convert it to
// a location within the tree.
Point location = dge.getDragOrigin();
TreePath dragPath = tree.getPathForLocation(location.x, location.y);
if (dragPath != null && tree.isPathSelected(dragPath)) {
// Get the list of selected files and create a Transferable
// The list of files and the is saved for use when
// the drop completes.
paths = tree.getSelectionPaths();
if (paths != null && paths.length > 0) {
dragFiles = new File[paths.length];
for (int i = 0; i < paths.length; i++) {
String pathName = tree.getPathName(paths[i]);
dragFiles[i] = new File(pathName);
}
Transferable transferable = new FileListTransferable(dragFiles);
dge.startDrag(null, transferable, this);
}
}
}
// Implementation of DragSourceListener interface
public void dragEnter(DragSourceDragEvent dsde) {
DnDUtils.debugPrintln("Drag Source: dragEnter, drop action = "
+ DnDUtils.showActions(dsde.getDropAction()));
}
public void dragOver(DragSourceDragEvent dsde) {
DnDUtils.debugPrintln("Drag Source: dragOver, drop action = "
+ DnDUtils.showActions(dsde.getDropAction()));
}
public void dragExit(DragSourceEvent dse) {
DnDUtils.debugPrintln("Drag Source: dragExit");
}
public void dropActionChanged(DragSourceDragEvent dsde) {
DnDUtils.debugPrintln("Drag Source: dropActionChanged, drop action = "
+ DnDUtils.showActions(dsde.getDropAction()));
}
public void dragDropEnd(DragSourceDropEvent dsde) {
DnDUtils.debugPrintln("Drag Source: drop completed, drop action = "
+ DnDUtils.showActions(dsde.getDropAction()) + ", success: "
+ dsde.getDropSuccess());
// If the drop action was ACTION_MOVE,
// the tree might need to be updated.
if (dsde.getDropAction() == DnDConstants.ACTION_MOVE) {
final File[] draggedFiles = dragFiles;
final TreePath[] draggedPaths = paths;
Timer tm = new Timer(200, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
// Check whether each of the dragged files exists.
// If it does not, we need to remove the node
// that represents it from the tree.
for (int i = 0; i < draggedFiles.length; i++) {
if (draggedFiles[i].exists() == false) {
// Remove this node
DefaultMutableTreeNode node = (DefaultMutableTreeNode) draggedPaths[i]
.getLastPathComponent();
((DefaultTreeModel) tree.getModel())
.removeNodeFromParent(node);
}
}
}
});
tm.setRepeats(false);
tm.start();
}
}
public static void main(String[] args) {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch (Exception evt) {}
JFrame f = new JFrame("Draggable File Tree");
try {
FileTree tree = new FileTree("D:\\");
f.getContentPane().add(new JScrollPane(tree));
// Attach the drag source
FileTreeDragSource dragSource = new FileTreeDragSource(tree);
} catch (Exception e) {
}
f.pack();
f.setVisible(true);
}
protected FileTree tree; // The associated tree
protected File[] dragFiles; // Dragged files
protected TreePath[] paths; // Dragged paths
}
class FileListTransferable implements Transferable {
public FileListTransferable(File[] files) {
fileList = new ArrayList();
for (int i = 0; i < files.length; i++) {
fileList.add(files[i]);
}
}
// Implementation of the Transferable interface
public DataFlavor[] getTransferDataFlavors() {
return new DataFlavor[] { DataFlavor.javaFileListFlavor };
}
public boolean isDataFlavorSupported(DataFlavor fl) {
return fl.equals(DataFlavor.javaFileListFlavor);
}
public Object getTransferData(DataFlavor fl) {
if (!isDataFlavorSupported(fl)) {
return null;
}
return fileList;
}
List fileList; // The list of files
}
Drag File Demo
/* From http://java.sun.ru/docs/books/tutorial/index.html */
/*
* Copyright (c) 2006 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:
*
* -Redistribution of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* -Redistribution 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, Inc. or the names of contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* 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 MIDROSYSTEMS, INC. ("SUN")
* AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
* AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS 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 THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed, licensed or intended
* for use in the design, construction, operation or maintenance of any
* nuclear facility.
*/
/*
* DragFileDemo.java is a 1.4 example that requires the following file:
* FileAndTextTransferHandler.java TabbedPaneController.java
*/
import java.awt.BorderLayout;
import java.awt.ruponent;
import java.awt.Dimension;
import java.awt.Insets;
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.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextArea;
import javax.swing.TransferHandler;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.JTextComponent;
import javax.swing.text.Position;
public class DragFileDemo extends JPanel implements ActionListener {
JTextArea fileArea;
JFileChooser fc;
JButton clear;
TabbedPaneController tpc;
public DragFileDemo() {
super(new BorderLayout());
fc = new JFileChooser();
;
fc.setMultiSelectionEnabled(true);
fc.setDragEnabled(true);
fc.setControlButtonsAreShown(false);
JPanel fcPanel = new JPanel(new BorderLayout());
fcPanel.add(fc, BorderLayout.CENTER);
clear = new JButton("Clear All");
clear.addActionListener(this);
JPanel buttonPanel = new JPanel(new BorderLayout());
buttonPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
buttonPanel.add(clear, BorderLayout.LINE_END);
JPanel upperPanel = new JPanel(new BorderLayout());
upperPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
upperPanel.add(fcPanel, BorderLayout.CENTER);
upperPanel.add(buttonPanel, BorderLayout.PAGE_END);
//The TabbedPaneController manages the panel that
//contains the tabbed pane. When there are no files
//the panel contains a plain text area. Then, as
//files are dropped onto the area, the tabbed panel
//replaces the file area.
JTabbedPane tabbedPane = new JTabbedPane();
JPanel tabPanel = new JPanel(new BorderLayout());
tabPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
tpc = new TabbedPaneController(tabbedPane, tabPanel);
JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
upperPanel, tabPanel);
splitPane.setDividerLocation(400);
splitPane.setPreferredSize(new Dimension(530, 650));
add(splitPane, BorderLayout.CENTER);
}
public void setDefaultButton() {
getRootPane().setDefaultButton(clear);
}
public void actionPerformed(ActionEvent e) {
if (e.getSource() == clear) {
tpc.clearAll();
}
}
/**
* Create the GUI and show it. For thread safety, this method should be
* invoked from the event-dispatching thread.
*/
private static void createAndShowGUI() {
//Make sure we have nice window decorations.
JFrame.setDefaultLookAndFeelDecorated(true);
//Create and set up the window.
JFrame frame = new JFrame("DragFileDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Create and set up the menu bar and content pane.
DragFileDemo demo = new DragFileDemo();
demo.setOpaque(true); //content panes must be opaque
frame.setContentPane(demo);
//Display the window.
frame.pack();
frame.setVisible(true);
demo.setDefaultButton();
}
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();
}
});
}
}
/*
* TabbedPaneController.java is used by the 1.4 DragFileDemo.java example.
*/
/*
* Class that manages area where the contents of files are displayed. When no
* files are present, there is a simple JTextArea instructing users to drop a
* file. As soon as a file is dropped, a JTabbedPane is placed into the window
* and each file is displayed under its own tab. When all the files are removed,
* the JTabbedPane is removed from the window and the simple JTextArea is again
* displayed.
*/
class TabbedPaneController {
JPanel tabbedPanel = null;
JTabbedPane tabbedPane;
JPanel emptyFilePanel = null;
JTextArea emptyFileArea = null;
FileAndTextTransferHandler transferHandler;
boolean noFiles = true;
String fileSeparator;
public TabbedPaneController(JTabbedPane tb, JPanel tp) {
tabbedPane = tb;
tabbedPanel = tp;
transferHandler = new FileAndTextTransferHandler(this);
fileSeparator = System.getProperty("file.separator");
//The split method in the String class uses
//regular expressions to define the text used for
//the split. The forward slash "\" is a special
//character and must be escaped. Some look and feels,
//such as Microsoft Windows, use the forward slash to
//delimit the path.
if ("\\".equals(fileSeparator)) {
fileSeparator = "\\\\";
}
init();
}
public JTextArea addTab(String filename) {
if (noFiles) {
tabbedPanel.remove(emptyFilePanel);
tabbedPanel.add(tabbedPane, BorderLayout.CENTER);
noFiles = false;
}
String[] str = filename.split(fileSeparator);
return makeTextPanel(str[str.length - 1], filename);
}
//Remove all tabs and their components, then put the default
//file area back.
public void clearAll() {
if (noFiles == false) {
tabbedPane.removeAll();
tabbedPanel.remove(tabbedPane);
}
init();
}
private void init() {
String defaultText = "Select one or more files from the file chooser and drop here...";
noFiles = true;
if (emptyFilePanel == null) {
emptyFileArea = new JTextArea(20, 15);
emptyFileArea.setEditable(false);
emptyFileArea.setDragEnabled(true);
emptyFileArea.setTransferHandler(transferHandler);
emptyFileArea.setMargin(new Insets(5, 5, 5, 5));
JScrollPane fileScrollPane = new JScrollPane(emptyFileArea);
emptyFilePanel = new JPanel(new BorderLayout(), false);
emptyFilePanel.add(fileScrollPane, BorderLayout.CENTER);
}
tabbedPanel.add(emptyFilePanel, BorderLayout.CENTER);
tabbedPanel.repaint();
emptyFileArea.setText(defaultText);
}
protected JTextArea makeTextPanel(String name, String toolTip) {
JTextArea fileArea = new JTextArea(20, 15);
fileArea.setDragEnabled(true);
fileArea.setTransferHandler(transferHandler);
fileArea.setMargin(new Insets(5, 5, 5, 5));
JScrollPane fileScrollPane = new JScrollPane(fileArea);
tabbedPane.addTab(name, null, (Component) fileScrollPane, toolTip);
tabbedPane.setSelectedComponent((Component) fileScrollPane);
return fileArea;
}
}
/*
* FileAndTextTransferHandler.java is used by the 1.4 DragFileDemo.java example.
*/
class FileAndTextTransferHandler extends TransferHandler {
private DataFlavor fileFlavor, stringFlavor;
private TabbedPaneController tpc;
private JTextArea source;
private boolean shouldRemove;
protected String newline = "\n";
//Start and end position in the source text.
//We need this information when performing a MOVE
//in order to remove the dragged text from the source.
Position p0 = null, p1 = null;
FileAndTextTransferHandler(TabbedPaneController t) {
tpc = t;
fileFlavor = DataFlavor.javaFileListFlavor;
stringFlavor = DataFlavor.stringFlavor;
}
public boolean importData(JComponent c, Transferable t) {
JTextArea tc;
if (!canImport(c, t.getTransferDataFlavors())) {
return false;
}
//A real application would load the file in another
//thread in order to not block the UI. This step
//was omitted here to simplify the code.
try {
if (hasFileFlavor(t.getTransferDataFlavors())) {
String str = null;
java.util.List files = (java.util.List) t
.getTransferData(fileFlavor);
for (int i = 0; i < files.size(); i++) {
File file = (File) files.get(i);
//Tell the tabbedpane controller to add
//a new tab with the name of this file
//on the tab. The text area that will
//display the contents of the file is returned.
tc = tpc.addTab(file.toString());
BufferedReader in = null;
try {
in = new BufferedReader(new FileReader(file));
while ((str = in.readLine()) != null) {
tc.append(str + newline);
}
} catch (IOException ioe) {
System.out
.println("importData: Unable to read from file "
+ file.toString());
} finally {
if (in != null) {
try {
in.close();
} catch (IOException ioe) {
System.out
.println("importData: Unable to close file "
+ file.toString());
}
}
}
}
return true;
} else if (hasStringFlavor(t.getTransferDataFlavors())) {
tc = (JTextArea) c;
if (tc.equals(source)
&& (tc.getCaretPosition() >= p0.getOffset())
&& (tc.getCaretPosition() <= p1.getOffset())) {
shouldRemove = false;
return true;
}
String str = (String) t.getTransferData(stringFlavor);
tc.replaceSelection(str);
return true;
}
} catch (UnsupportedFlavorException ufe) {
System.out.println("importData: unsupported data flavor");
} catch (IOException ieo) {
System.out.println("importData: I/O exception");
}
return false;
}
protected Transferable createTransferable(JComponent c) {
source = (JTextArea) c;
int start = source.getSelectionStart();
int end = source.getSelectionEnd();
Document doc = source.getDocument();
if (start == end) {
return null;
}
try {
p0 = doc.createPosition(start);
p1 = doc.createPosition(end);
} catch (BadLocationException e) {
System.out
.println("Can"t create position - unable to remove text from source.");
}
shouldRemove = true;
String data = source.getSelectedText();
return new StringSelection(data);
}
public int getSourceActions(JComponent c) {
return COPY_OR_MOVE;
}
//Remove the old text if the action is a MOVE.
//However, we do not allow dropping on top of the selected text,
//so in that case do nothing.
protected void exportDone(JComponent c, Transferable data, int action) {
if (shouldRemove && (action == MOVE)) {
if ((p0 != null) && (p1 != null)
&& (p0.getOffset() != p1.getOffset())) {
try {
JTextComponent tc = (JTextComponent) c;
tc.getDocument().remove(p0.getOffset(),
p1.getOffset() - p0.getOffset());
} catch (BadLocationException e) {
System.out.println("Can"t remove text from source.");
}
}
}
source = null;
}
public boolean canImport(JComponent c, DataFlavor[] flavors) {
if (hasFileFlavor(flavors)) {
return true;
}
if (hasStringFlavor(flavors)) {
return true;
}
return false;
}
private boolean hasFileFlavor(DataFlavor[] flavors) {
for (int i = 0; i < flavors.length; i++) {
if (fileFlavor.equals(flavors[i])) {
return true;
}
}
return false;
}
private boolean hasStringFlavor(DataFlavor[] flavors) {
for (int i = 0; i < flavors.length; i++) {
if (stringFlavor.equals(flavors[i])) {
return true;
}
}
return false;
}
}
Drag List Demo
/* From http://java.sun.ru/docs/books/tutorial/index.html */
/*
* Copyright (c) 2006 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:
*
* -Redistribution of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* -Redistribution 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, Inc. or the names of contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* 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 MIDROSYSTEMS, INC. ("SUN")
* AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
* AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS 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 THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed, licensed or intended
* for use in the design, construction, operation or maintenance of any
* nuclear facility.
*/
/*
* DragListDemo.java is a 1.4 example that requires the following file:
* ArrayListTransferHandler.java
*/
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;
import java.util.ArrayList;
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.ListSelectionModel;
import javax.swing.TransferHandler;
public class DragListDemo extends JPanel {
ArrayListTransferHandler arrayListHandler;
public DragListDemo() {
arrayListHandler = new ArrayListTransferHandler();
JList list1, list2;
DefaultListModel list1Model = new DefaultListModel();
list1Model.addElement("0 (list 1)");
list1Model.addElement("1 (list 1)");
list1Model.addElement("2 (list 1)");
list1Model.addElement("3 (list 1)");
list1Model.addElement("4 (list 1)");
list1Model.addElement("5 (list 1)");
list1Model.addElement("6 (list 1)");
list1 = new JList(list1Model);
list1.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
list1.setTransferHandler(arrayListHandler);
list1.setDragEnabled(true);
JScrollPane list1View = new JScrollPane(list1);
list1View.setPreferredSize(new Dimension(200, 100));
JPanel panel1 = new JPanel();
panel1.setLayout(new BorderLayout());
panel1.add(list1View, BorderLayout.CENTER);
panel1.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
DefaultListModel list2Model = new DefaultListModel();
list2Model.addElement("0 (list 2)");
list2Model.addElement("1 (list 2)");
list2Model.addElement("2 (list 2)");
list2Model.addElement("3 (list 2)");
list2Model.addElement("4 (list 2)");
list2Model.addElement("5 (list 2)");
list2Model.addElement("6 (list 2)");
list2 = new JList(list2Model);
list2.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
list2.setTransferHandler(arrayListHandler);
list2.setDragEnabled(true);
JScrollPane list2View = new JScrollPane(list2);
list2View.setPreferredSize(new Dimension(200, 100));
JPanel panel2 = new JPanel();
panel2.setLayout(new BorderLayout());
panel2.add(list2View, BorderLayout.CENTER);
panel2.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
setLayout(new BorderLayout());
add(panel1, BorderLayout.LINE_START);
add(panel2, BorderLayout.LINE_END);
setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
}
/**
* Create the GUI and show it. For thread safety, this method should be
* invoked from the event-dispatching thread.
*/
private static void createAndShowGUI() {
//Make sure we have nice window decorations.
JFrame.setDefaultLookAndFeelDecorated(true);
//Create and set up the window.
JFrame frame = new JFrame("DragListDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Create and set up the content pane.
DragListDemo demo = new DragListDemo();
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() {
createAndShowGUI();
}
});
}
}
/*
* ArrayListTransferHandler.java is used by the 1.4 DragListDemo.java example.
*/
class ArrayListTransferHandler extends TransferHandler {
DataFlavor localArrayListFlavor, serialArrayListFlavor;
String localArrayListType = DataFlavor.javaJVMLocalObjectMimeType
+ ";class=java.util.ArrayList";
JList source = null;
int[] indices = null;
int addIndex = -1; //Location where items were added
int addCount = 0; //Number of items added
public ArrayListTransferHandler() {
try {
localArrayListFlavor = new DataFlavor(localArrayListType);
} catch (ClassNotFoundException e) {
System.out
.println("ArrayListTransferHandler: unable to create data flavor");
}
serialArrayListFlavor = new DataFlavor(ArrayList.class, "ArrayList");
}
public boolean importData(JComponent c, Transferable t) {
JList target = null;
ArrayList alist = null;
if (!canImport(c, t.getTransferDataFlavors())) {
return false;
}
try {
target = (JList) c;
if (hasLocalArrayListFlavor(t.getTransferDataFlavors())) {
alist = (ArrayList) t.getTransferData(localArrayListFlavor);
} else if (hasSerialArrayListFlavor(t.getTransferDataFlavors())) {
alist = (ArrayList) t.getTransferData(serialArrayListFlavor);
} else {
return false;
}
} catch (UnsupportedFlavorException ufe) {
System.out.println("importData: unsupported data flavor");
return false;
} catch (IOException ioe) {
System.out.println("importData: I/O exception");
return false;
}
//At this point we use the same code to retrieve the data
//locally or serially.
//We"ll drop at the current selected index.
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.
//This is interpreted as dropping the same data on itself
//and has no effect.
if (source.equals(target)) {
if (indices != null && index >= indices[0] - 1
&& index <= indices[indices.length - 1]) {
indices = null;
return true;
}
}
DefaultListModel listModel = (DefaultListModel) target.getModel();
int max = listModel.getSize();
if (index < 0) {
index = max;
} else {
index++;
if (index > max) {
index = max;
}
}
addIndex = index;
addCount = alist.size();
for (int i = 0; i < alist.size(); i++) {
listModel.add(index++, alist.get(i));
}
return true;
}
protected void exportDone(JComponent c, Transferable data, int action) {
if ((action == MOVE) && (indices != null)) {
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;
addIndex = -1;
addCount = 0;
}
private boolean hasLocalArrayListFlavor(DataFlavor[] flavors) {
if (localArrayListFlavor == null) {
return false;
}
for (int i = 0; i < flavors.length; i++) {
if (flavors[i].equals(localArrayListFlavor)) {
return true;
}
}
return false;
}
private boolean hasSerialArrayListFlavor(DataFlavor[] flavors) {
if (serialArrayListFlavor == null) {
return false;
}
for (int i = 0; i < flavors.length; i++) {
if (flavors[i].equals(serialArrayListFlavor)) {
return true;
}
}
return false;
}
public boolean canImport(JComponent c, DataFlavor[] flavors) {
if (hasLocalArrayListFlavor(flavors)) {
return true;
}
if (hasSerialArrayListFlavor(flavors)) {
return true;
}
return false;
}
protected Transferable createTransferable(JComponent c) {
if (c instanceof JList) {
source = (JList) c;
indices = source.getSelectedIndices();
Object[] values = source.getSelectedValues();
if (values == null || values.length == 0) {
return null;
}
ArrayList alist = new ArrayList(values.length);
for (int i = 0; i < values.length; i++) {
Object o = values[i];
String str = o.toString();
if (str == null)
str = "";
alist.add(str);
}
return new ArrayListTransferable(alist);
}
return null;
}
public int getSourceActions(JComponent c) {
return COPY_OR_MOVE;
}
public class ArrayListTransferable implements Transferable {
ArrayList data;
public ArrayListTransferable(ArrayList alist) {
data = alist;
}
public Object getTransferData(DataFlavor flavor)
throws UnsupportedFlavorException {
if (!isDataFlavorSupported(flavor)) {
throw new UnsupportedFlavorException(flavor);
}
return data;
}
public DataFlavor[] getTransferDataFlavors() {
return new DataFlavor[] { localArrayListFlavor,
serialArrayListFlavor };
}
public boolean isDataFlavorSupported(DataFlavor flavor) {
if (localArrayListFlavor.equals(flavor)) {
return true;
}
if (serialArrayListFlavor.equals(flavor)) {
return true;
}
return false;
}
}
}
Drag Picture Demo
/* From http://java.sun.ru/docs/books/tutorial/index.html */
/*
* Copyright (c) 2006 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:
*
* -Redistribution of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* -Redistribution 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, Inc. or the names of contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* 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 MIDROSYSTEMS, INC. ("SUN")
* AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
* AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS 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 THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed, licensed or intended
* for use in the design, construction, operation or maintenance of any
* nuclear facility.
*/
/*
* DragPictureDemo.java is a 1.4 example that requires the following files:
* Picture.java DTPicture.java PictureTransferHandler.java images/Maya.jpg
* images/Anya.jpg images/Laine.jpg images/Cosmo.jpg images/Adele.jpg
* images/Alexi.jpg
*/
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.io.IOException;
import javax.accessibility.Accessible;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.TransferHandler;
public class DragPictureDemo extends JPanel {
DTPicture pic1, pic2, pic3, pic4, pic5, pic6, pic7, pic8, pic9, pic10,
pic11, pic12;
static String mayaString = "Maya";
static String anyaString = "Anya";
static String laineString = "Laine";
static String cosmoString = "Cosmo";
static String adeleString = "Adele";
static String alexiString = "Alexi";
PictureTransferHandler picHandler;
public DragPictureDemo() {
super(new BorderLayout());
picHandler = new PictureTransferHandler();
JPanel mugshots = new JPanel(new GridLayout(4, 3));
pic1 = new DTPicture(createImageIcon("images/" + mayaString + ".jpg",
mayaString).getImage());
pic1.setTransferHandler(picHandler);
mugshots.add(pic1);
pic2 = new DTPicture(createImageIcon("images/" + anyaString + ".jpg",
anyaString).getImage());
pic2.setTransferHandler(picHandler);
mugshots.add(pic2);
pic3 = new DTPicture(createImageIcon("images/" + laineString + ".jpg",
laineString).getImage());
pic3.setTransferHandler(picHandler);
mugshots.add(pic3);
pic4 = new DTPicture(createImageIcon("images/" + cosmoString + ".jpg",
cosmoString).getImage());
pic4.setTransferHandler(picHandler);
mugshots.add(pic4);
pic5 = new DTPicture(createImageIcon("images/" + adeleString + ".jpg",
adeleString).getImage());
pic5.setTransferHandler(picHandler);
mugshots.add(pic5);
pic6 = new DTPicture(createImageIcon("images/" + alexiString + ".jpg",
alexiString).getImage());
pic6.setTransferHandler(picHandler);
mugshots.add(pic6);
//These six components with no pictures provide handy
//drop targets.
pic7 = new DTPicture(null);
pic7.setTransferHandler(picHandler);
mugshots.add(pic7);
pic8 = new DTPicture(null);
pic8.setTransferHandler(picHandler);
mugshots.add(pic8);
pic9 = new DTPicture(null);
pic9.setTransferHandler(picHandler);
mugshots.add(pic9);
pic10 = new DTPicture(null);
pic10.setTransferHandler(picHandler);
mugshots.add(pic10);
pic11 = new DTPicture(null);
pic11.setTransferHandler(picHandler);
mugshots.add(pic11);
pic12 = new DTPicture(null);
pic12.setTransferHandler(picHandler);
mugshots.add(pic12);
setPreferredSize(new Dimension(450, 630));
add(mugshots, BorderLayout.CENTER);
setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
}
/** Returns an ImageIcon, or null if the path was invalid. */
protected static ImageIcon createImageIcon(String path, String description) {
java.net.URL imageURL = DragPictureDemo.class.getResource(path);
if (imageURL == null) {
System.err.println("Resource not found: " + path);
return null;
} else {
return new ImageIcon(imageURL, description);
}
}
/**
* Create the GUI and show it. For thread safety, this method should be
* invoked from the event-dispatching thread.
*/
private static void createAndShowGUI() {
//Make sure we have nice window decorations.
JFrame.setDefaultLookAndFeelDecorated(true);
//Create and set up the window.
JFrame frame = new JFrame("DragPictureDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Create and set up the menu bar and content pane.
DragPictureDemo demo = new DragPictureDemo();
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() {
createAndShowGUI();
}
});
}
}
/*
* PictureTransferHandler.java is used by the 1.4 DragPictureDemo.java example.
*/
class PictureTransferHandler extends TransferHandler {
DataFlavor pictureFlavor = DataFlavor.imageFlavor;
DTPicture sourcePic;
boolean shouldRemove;
public boolean importData(JComponent c, Transferable t) {
Image image;
if (canImport(c, t.getTransferDataFlavors())) {
DTPicture pic = (DTPicture) c;
//Don"t drop on myself.
if (sourcePic == pic) {
shouldRemove = false;
return true;
}
try {
image = (Image) t.getTransferData(pictureFlavor);
//Set the component to the new picture.
pic.setImage(image);
return true;
} catch (UnsupportedFlavorException ufe) {
System.out.println("importData: unsupported data flavor");
} catch (IOException ioe) {
System.out.println("importData: I/O exception");
}
}
return false;
}
protected Transferable createTransferable(JComponent c) {
sourcePic = (DTPicture) c;
shouldRemove = true;
return new PictureTransferable(sourcePic);
}
public int getSourceActions(JComponent c) {
return COPY_OR_MOVE;
}
protected void exportDone(JComponent c, Transferable data, int action) {
if (shouldRemove && (action == MOVE)) {
sourcePic.setImage(null);
}
sourcePic = null;
}
public boolean canImport(JComponent c, DataFlavor[] flavors) {
for (int i = 0; i < flavors.length; i++) {
if (pictureFlavor.equals(flavors[i])) {
return true;
}
}
return false;
}
class PictureTransferable implements Transferable {
private Image image;
PictureTransferable(DTPicture pic) {
image = pic.image;
}
public Object getTransferData(DataFlavor flavor)
throws UnsupportedFlavorException {
if (!isDataFlavorSupported(flavor)) {
throw new UnsupportedFlavorException(flavor);
}
return image;
}
public DataFlavor[] getTransferDataFlavors() {
return new DataFlavor[] { pictureFlavor };
}
public boolean isDataFlavorSupported(DataFlavor flavor) {
return pictureFlavor.equals(flavor);
}
}
}
/*
* DTPicture.java is used by the 1.4 DragPictureDemo.java example.
*/
//A subclass of Picture that supports Data Transfer.
class DTPicture extends Picture implements MouseMotionListener {
private MouseEvent firstMouseEvent = null;
private static boolean installInputMapBindings = true;
public DTPicture(Image image) {
super(image);
addMouseMotionListener(this);
//Add the cut/copy/paste key bindings to the input map.
//Note that this step is redundant if you are installing
//menu accelerators that cause these actions to be invoked.
//DragPictureDemo does not use menu accelerators and, since
//the default value of installInputMapBindings is true,
//the bindings are installed. DragPictureDemo2 does use
//menu accelerators and so calls setInstallInputMapBindings
//with a value of false. Your program would do one or the
//other, but not both.
if (installInputMapBindings) {
InputMap imap = this.getInputMap();
imap.put(KeyStroke.getKeyStroke("ctrl X"), TransferHandler
.getCutAction().getValue(Action.NAME));
imap.put(KeyStroke.getKeyStroke("ctrl C"), TransferHandler
.getCopyAction().getValue(Action.NAME));
imap.put(KeyStroke.getKeyStroke("ctrl V"), TransferHandler
.getPasteAction().getValue(Action.NAME));
}
//Add the cut/copy/paste actions to the action map.
//This step is necessary because the menu"s action listener
//looks for these actions to fire.
ActionMap map = this.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());
}
public void setImage(Image image) {
this.image = image;
this.repaint();
}
public void mousePressed(MouseEvent e) {
//Don"t bother to drag if there is no image.
if (image == null)
return;
firstMouseEvent = e;
e.consume();
}
public void mouseDragged(MouseEvent e) {
//Don"t bother to drag if the component displays no image.
if (image == null)
return;
if (firstMouseEvent != null) {
e.consume();
//If they are holding down the control key, COPY rather than MOVE
int ctrlMask = InputEvent.CTRL_DOWN_MASK;
int action = ((e.getModifiersEx() & ctrlMask) == ctrlMask) ? TransferHandler.COPY
: TransferHandler.MOVE;
int dx = Math.abs(e.getX() - firstMouseEvent.getX());
int dy = Math.abs(e.getY() - firstMouseEvent.getY());
//Arbitrarily define a 5-pixel shift as the
//official beginning of a drag.
if (dx > 5 || dy > 5) {
//This is a drag, not a click.
JComponent c = (JComponent) e.getSource();
TransferHandler handler = c.getTransferHandler();
//Tell the transfer handler to initiate the drag.
handler.exportAsDrag(c, firstMouseEvent, action);
firstMouseEvent = null;
}
}
}
public void mouseReleased(MouseEvent e) {
firstMouseEvent = null;
}
public void mouseMoved(MouseEvent e) {
}
//This method is necessary because DragPictureDemo and
//DragPictureDemo2 both use this class and DragPictureDemo
//needs to have the input map bindings installed for
//cut/copy/paste. DragPictureDemo2 uses menu accelerators
//and does not need to have the input map bindings installed.
//Your program would use one approach or the other, but not
//both. The default for installInputMapBindings is true.
public static void setInstallInputMapBindings(boolean flag) {
installInputMapBindings = flag;
}
public static boolean getInstallInputMapBindingds() { //for completeness
return installInputMapBindings;
}
}
/*
* Picture.java is used by the 1.4 TrackFocusDemo.java and DragPictureDemo.java
* examples.
*/
class Picture extends JComponent implements MouseListener, FocusListener,
Accessible {
Image image;
public Picture(Image image) {
this.image = image;
setFocusable(true);
addMouseListener(this);
addFocusListener(this);
}
public void mouseClicked(MouseEvent e) {
//Since the user clicked on us, let"s get focus!
requestFocusInWindow();
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
public void focusGained(FocusEvent e) {
//Draw the component with a red border
//indicating that it has focus.
this.repaint();
}
public void focusLost(FocusEvent e) {
//Draw the component with a black border
//indicating that it doesn"t have focus.
this.repaint();
}
protected void paintComponent(Graphics graphics) {
Graphics g = graphics.create();
//Draw in our entire space, even if isOpaque is false.
g.setColor(Color.WHITE);
g.fillRect(0, 0, image == null ? 125 : image.getWidth(this),
image == null ? 125 : image.getHeight(this));
if (image != null) {
//Draw image at its natural size of 125x125.
g.drawImage(image, 0, 0, this);
}
//Add a border, red if picture currently has focus
if (isFocusOwner()) {
g.setColor(Color.RED);
} else {
g.setColor(Color.BLACK);
}
g.drawRect(0, 0, image == null ? 125 : image.getWidth(this),
image == null ? 125 : image.getHeight(this));
g.dispose();
}
}
Drag Picture Demo 2
/* From http://java.sun.ru/docs/books/tutorial/index.html */
/*
* Copyright (c) 2006 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:
*
* -Redistribution of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* -Redistribution 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, Inc. or the names of contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* 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 MIDROSYSTEMS, INC. ("SUN")
* AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
* AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS 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 THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed, licensed or intended
* for use in the design, construction, operation or maintenance of any
* nuclear facility.
*/
/*
* DragPictureDemo2.java is a 1.4 example that requires the following files:
* Picture.java DTPicture.java PictureTransferHandler.java
* TransferActionListener.java images/Maya.jpg images/Anya.jpg images/Laine.jpg
* images/Cosmo.jpg images/Adele.jpg images/Alexi.jpg
*/
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.KeyboardFocusManager;
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.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import javax.accessibility.Accessible;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.TransferHandler;
//A version of DragPictureDemo that creates an
//Edit menu with cut/copy/paste actions.
//This demo adds a class called TransferActionDemo
//that transfers the cut/copy/paste menu action
//to the currently focused component.
public class DragPictureDemo2 extends JPanel {
DTPicture pic1, pic2, pic3, pic4, pic5, pic6, pic7, pic8, pic9, pic10,
pic11, pic12;
static String mayaString = "Maya";
static String anyaString = "Anya";
static String laineString = "Laine";
static String cosmoString = "Cosmo";
static String adeleString = "Adele";
static String alexiString = "Alexi";
PictureTransferHandler picHandler;
public DragPictureDemo2() {
super(new BorderLayout());
picHandler = new PictureTransferHandler();
//Since we are using keyboard accelerators, we don"t
//need the component to install its own input map
//bindings.
DTPicture.setInstallInputMapBindings(false);
JPanel mugshots = new JPanel(new GridLayout(4, 3));
pic1 = new DTPicture(createImageIcon("images/" + mayaString + ".jpg",
mayaString).getImage());
pic1.setTransferHandler(picHandler);
mugshots.add(pic1);
pic2 = new DTPicture(createImageIcon("images/" + anyaString + ".jpg",
anyaString).getImage());
pic2.setTransferHandler(picHandler);
mugshots.add(pic2);
pic3 = new DTPicture(createImageIcon("images/" + laineString + ".jpg",
laineString).getImage());
pic3.setTransferHandler(picHandler);
mugshots.add(pic3);
pic4 = new DTPicture(createImageIcon("images/" + cosmoString + ".jpg",
cosmoString).getImage());
pic4.setTransferHandler(picHandler);
mugshots.add(pic4);
pic5 = new DTPicture(createImageIcon("images/" + adeleString + ".jpg",
adeleString).getImage());
pic5.setTransferHandler(picHandler);
mugshots.add(pic5);
pic6 = new DTPicture(createImageIcon("images/" + alexiString + ".jpg",
alexiString).getImage());
pic6.setTransferHandler(picHandler);
mugshots.add(pic6);
//These six components with no pictures provide handy
//drop targets.
pic7 = new DTPicture(null);
pic7.setTransferHandler(picHandler);
mugshots.add(pic7);
pic8 = new DTPicture(null);
pic8.setTransferHandler(picHandler);
mugshots.add(pic8);
pic9 = new DTPicture(null);
pic9.setTransferHandler(picHandler);
mugshots.add(pic9);
pic10 = new DTPicture(null);
pic10.setTransferHandler(picHandler);
mugshots.add(pic10);
pic11 = new DTPicture(null);
pic11.setTransferHandler(picHandler);
mugshots.add(pic11);
pic12 = new DTPicture(null);
pic12.setTransferHandler(picHandler);
mugshots.add(pic12);
setPreferredSize(new Dimension(450, 630));
add(mugshots, BorderLayout.CENTER);
setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
}
//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;
}
/** Returns an ImageIcon, or null if the path was invalid. */
protected static ImageIcon createImageIcon(String path, String description) {
java.net.URL imageURL = DragPictureDemo2.class.getResource(path);
if (imageURL == null) {
System.err.println("Resource not found: " + path);
return null;
} else {
return new ImageIcon(imageURL, description);
}
}
/**
* Create the GUI and show it. For thread safety, this method should be
* invoked from the event-dispatching thread.
*/
private static void createAndShowGUI() {
//Make sure we have nice window decorations.
JFrame.setDefaultLookAndFeelDecorated(true);
//Create and set up the window.
JFrame frame = new JFrame("DragPictureDemo2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Create and set up the menu bar and content pane.
DragPictureDemo2 demo = new DragPictureDemo2();
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() {
createAndShowGUI();
}
});
}
}
/*
* DTPicture.java is used by the 1.4 DragPictureDemo.java example.
*/
//A subclass of Picture that supports Data Transfer.
class DTPicture extends Picture implements MouseMotionListener {
private MouseEvent firstMouseEvent = null;
private static boolean installInputMapBindings = true;
public DTPicture(Image image) {
super(image);
addMouseMotionListener(this);
//Add the cut/copy/paste key bindings to the input map.
//Note that this step is redundant if you are installing
//menu accelerators that cause these actions to be invoked.
//DragPictureDemo does not use menu accelerators and, since
//the default value of installInputMapBindings is true,
//the bindings are installed. DragPictureDemo2 does use
//menu accelerators and so calls setInstallInputMapBindings
//with a value of false. Your program would do one or the
//other, but not both.
if (installInputMapBindings) {
InputMap imap = this.getInputMap();
imap.put(KeyStroke.getKeyStroke("ctrl X"), TransferHandler
.getCutAction().getValue(Action.NAME));
imap.put(KeyStroke.getKeyStroke("ctrl C"), TransferHandler
.getCopyAction().getValue(Action.NAME));
imap.put(KeyStroke.getKeyStroke("ctrl V"), TransferHandler
.getPasteAction().getValue(Action.NAME));
}
//Add the cut/copy/paste actions to the action map.
//This step is necessary because the menu"s action listener
//looks for these actions to fire.
ActionMap map = this.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());
}
public void setImage(Image image) {
this.image = image;
this.repaint();
}
public void mousePressed(MouseEvent e) {
//Don"t bother to drag if there is no image.
if (image == null)
return;
firstMouseEvent = e;
e.consume();
}
public void mouseDragged(MouseEvent e) {
//Don"t bother to drag if the component displays no image.
if (image == null)
return;
if (firstMouseEvent != null) {
e.consume();
//If they are holding down the control key, COPY rather than MOVE
int ctrlMask = InputEvent.CTRL_DOWN_MASK;
int action = ((e.getModifiersEx() & ctrlMask) == ctrlMask) ? TransferHandler.COPY
: TransferHandler.MOVE;
int dx = Math.abs(e.getX() - firstMouseEvent.getX());
int dy = Math.abs(e.getY() - firstMouseEvent.getY());
//Arbitrarily define a 5-pixel shift as the
//official beginning of a drag.
if (dx > 5 || dy > 5) {
//This is a drag, not a click.
JComponent c = (JComponent) e.getSource();
TransferHandler handler = c.getTransferHandler();
//Tell the transfer handler to initiate the drag.
handler.exportAsDrag(c, firstMouseEvent, action);
firstMouseEvent = null;
}
}
}
public void mouseReleased(MouseEvent e) {
firstMouseEvent = null;
}
public void mouseMoved(MouseEvent e) {
}
//This method is necessary because DragPictureDemo and
//DragPictureDemo2 both use this class and DragPictureDemo
//needs to have the input map bindings installed for
//cut/copy/paste. DragPictureDemo2 uses menu accelerators
//and does not need to have the input map bindings installed.
//Your program would use one approach or the other, but not
//both. The default for installInputMapBindings is true.
public static void setInstallInputMapBindings(boolean flag) {
installInputMapBindings = flag;
}
public static boolean getInstallInputMapBindingds() { //for completeness
return installInputMapBindings;
}
}
/*
* Picture.java is used by the 1.4 TrackFocusDemo.java and DragPictureDemo.java
* examples.
*/
class Picture extends JComponent implements MouseListener, FocusListener,
Accessible {
Image image;
public Picture(Image image) {
this.image = image;
setFocusable(true);
addMouseListener(this);
addFocusListener(this);
}
public void mouseClicked(MouseEvent e) {
//Since the user clicked on us, let"s get focus!
requestFocusInWindow();
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
public void focusGained(FocusEvent e) {
//Draw the component with a red border
//indicating that it has focus.
this.repaint();
}
public void focusLost(FocusEvent e) {
//Draw the component with a black border
//indicating that it doesn"t have focus.
this.repaint();
}
protected void paintComponent(Graphics graphics) {
Graphics g = graphics.create();
//Draw in our entire space, even if isOpaque is false.
g.setColor(Color.WHITE);
g.fillRect(0, 0, image == null ? 125 : image.getWidth(this),
image == null ? 125 : image.getHeight(this));
if (image != null) {
//Draw image at its natural size of 125x125.
g.drawImage(image, 0, 0, this);
}
//Add a border, red if picture currently has focus
if (isFocusOwner()) {
g.setColor(Color.RED);
} else {
g.setColor(Color.BLACK);
}
g.drawRect(0, 0, image == null ? 125 : image.getWidth(this),
image == null ? 125 : image.getHeight(this));
g.dispose();
}
}
/*
* PictureTransferHandler.java is used by the 1.4 DragPictureDemo.java example.
*/
class PictureTransferHandler extends TransferHandler {
DataFlavor pictureFlavor = DataFlavor.imageFlavor;
DTPicture sourcePic;
boolean shouldRemove;
public boolean importData(JComponent c, Transferable t) {
Image image;
if (canImport(c, t.getTransferDataFlavors())) {
DTPicture pic = (DTPicture) c;
//Don"t drop on myself.
if (sourcePic == pic) {
shouldRemove = false;
return true;
}
try {
image = (Image) t.getTransferData(pictureFlavor);
//Set the component to the new picture.
pic.setImage(image);
return true;
} catch (UnsupportedFlavorException ufe) {
System.out.println("importData: unsupported data flavor");
} catch (IOException ioe) {
System.out.println("importData: I/O exception");
}
}
return false;
}
protected Transferable createTransferable(JComponent c) {
sourcePic = (DTPicture) c;
shouldRemove = true;
return new PictureTransferable(sourcePic);
}
public int getSourceActions(JComponent c) {
return COPY_OR_MOVE;
}
protected void exportDone(JComponent c, Transferable data, int action) {
if (shouldRemove && (action == MOVE)) {
sourcePic.setImage(null);
}
sourcePic = null;
}
public boolean canImport(JComponent c, DataFlavor[] flavors) {
for (int i = 0; i < flavors.length; i++) {
if (pictureFlavor.equals(flavors[i])) {
return true;
}
}
return false;
}
class PictureTransferable implements Transferable {
private Image image;
PictureTransferable(DTPicture pic) {
image = pic.image;
}
public Object getTransferData(DataFlavor flavor)
throws UnsupportedFlavorException {
if (!isDataFlavorSupported(flavor)) {
throw new UnsupportedFlavorException(flavor);
}
return image;
}
public DataFlavor[] getTransferDataFlavors() {
return new DataFlavor[] { pictureFlavor };
}
public boolean isDataFlavorSupported(DataFlavor flavor) {
return pictureFlavor.equals(flavor);
}
}
}
/*
* TransferActionListener.java is used by the 1.4 DragPictureDemo.java 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));
}
}
}
Dropper - show File Drop Target from Drag-n-Drop
/*
* Copyright (c) Ian F. Darwin, http://www.darwinsys.ru/, 1996-2002.
* All rights reserved. Software written by Ian F. Darwin and others.
* $Id: LICENSE,v 1.8 2004/02/09 03:33:38 ian Exp $
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*
* Java, the Duke mascot, and all variants of Sun"s Java "steaming coffee
* cup" logo are trademarks of Sun Microsystems. Sun"s, and James Gosling"s,
* pioneering role in inventing and promulgating (and standardizing) the Java
* language and environment is gratefully acknowledged.
*
* The pioneering role of Dennis Ritchie and Bjarne Stroustrup, of AT&T, for
* inventing predecessor languages C and C++ is also gratefully acknowledged.
*/
import java.awt.Toolkit;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Iterator;
import java.util.List;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.TransferHandler;
/**
* Dropper - show File Drop Target from Drag-n-Drop
*
* @version $Id: Dropper.java,v 1.1 2004/04/10 00:12:25 ian Exp $
*/
public class Dropper extends JFrame {
/**
* Construct trivial GUI and connect a TransferHandler to it.
*/
public Dropper() {
super("Drop Target");
JComponent cp = (JComponent) getContentPane();
cp.setTransferHandler(new MyFileTransferHandler()); // see below
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(150, 150);
}
/** Instantiate and show the GUI */
public static void main(String[] args) {
new Dropper().setVisible(true);
}
}
/** Non-public class to handle filename drops */
class MyFileTransferHandler extends TransferHandler {
/**
* @see javax.swing.TransferHandler#canImport(javax.swing.JComponent,
* java.awt.datatransfer.DataFlavor[])
*/
public boolean canImport(JComponent arg0, DataFlavor[] arg1) {
for (int i = 0; i < arg1.length; i++) {
DataFlavor flavor = arg1[i];
if (flavor.equals(DataFlavor.javaFileListFlavor)) {
System.out.println("canImport: JavaFileList FLAVOR: " + flavor);
return true;
}
if (flavor.equals(DataFlavor.stringFlavor)) {
System.out.println("canImport: String FLAVOR: " + flavor);
return true;
}
System.err.println("canImport: Rejected Flavor: " + flavor);
}
// Didn"t find any that match, so:
return false;
}
/**
* Do the actual import.
*
* @see javax.swing.TransferHandler#importData(javax.swing.JComponent,
* java.awt.datatransfer.Transferable)
*/
public boolean importData(JComponent comp, Transferable t) {
DataFlavor[] flavors = t.getTransferDataFlavors();
System.out.println("Trying to import:" + t);
System.out.println("... which has " + flavors.length + " flavors.");
for (int i = 0; i < flavors.length; i++) {
DataFlavor flavor = flavors[i];
try {
if (flavor.equals(DataFlavor.javaFileListFlavor)) {
System.out.println("importData: FileListFlavor");
List l = (List) t
.getTransferData(DataFlavor.javaFileListFlavor);
Iterator iter = l.iterator();
while (iter.hasNext()) {
File file = (File) iter.next();
System.out.println("GOT FILE: "
+ file.getCanonicalPath());
// Now do something with the file...
}
return true;
} else if (flavor.equals(DataFlavor.stringFlavor)) {
System.out.println("importData: String Flavor");
String fileOrURL = (String) t.getTransferData(flavor);
System.out.println("GOT STRING: " + fileOrURL);
try {
URL url = new URL(fileOrURL);
System.out.println("Valid URL: " + url.toString());
// Do something with the contents...
return true;
} catch (MalformedURLException ex) {
System.err.println("Not a valid URL");
return false;
}
// now do something with the String.
} else {
System.out.println("importData rejected: " + flavor);
// Don"t return; try next flavor.
}
} catch (IOException ex) {
System.err.println("IOError getting data: " + ex);
} catch (UnsupportedFlavorException e) {
System.err.println("Unsupported Flavor: " + e);
}
}
// If you get here, I didn"t like the flavor.
Toolkit.getDefaultToolkit().beep();
return false;
}
}
Editor Drop Target
/*
Core SWING Advanced Programming
By Kim Topley
ISBN: 0 13 083292 8
Publisher: Prentice Hall
*/
import java.awt.BorderLayout;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.DnDConstants;
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.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.UIManager;
public class EditorDropTarget implements DropTargetListener {
public EditorDropTarget(JEditorPane pane) {
this.pane = pane;
// Create the DropTarget and register
// it with the JEditorPane.
dropTarget = new DropTarget(pane, DnDConstants.ACTION_COPY_OR_MOVE,
this, true, null);
}
// Implementation of the DropTargetListener interface
public void dragEnter(DropTargetDragEvent dtde) {
DnDUtils.debugPrintln("dragEnter, drop action = "
+ DnDUtils.showActions(dtde.getDropAction()));
// Get the type of object being transferred and determine
// whether it is appropriate.
checkTransferType(dtde);
// Accept or reject the drag.
acceptOrRejectDrag(dtde);
}
public void dragExit(DropTargetEvent dte) {
DnDUtils.debugPrintln("DropTarget dragExit");
}
public void dragOver(DropTargetDragEvent dtde) {
DnDUtils.debugPrintln("DropTarget dragOver, drop action = "
+ DnDUtils.showActions(dtde.getDropAction()));
// Accept or reject the drag
acceptOrRejectDrag(dtde);
}
public void dropActionChanged(DropTargetDragEvent dtde) {
DnDUtils.debugPrintln("DropTarget dropActionChanged, drop action = "
+ DnDUtils.showActions(dtde.getDropAction()));
// Accept or reject the drag
acceptOrRejectDrag(dtde);
}
public void drop(DropTargetDropEvent dtde) {
DnDUtils.debugPrintln("DropTarget drop, drop action = "
+ DnDUtils.showActions(dtde.getDropAction()));
// Check the drop action
if ((dtde.getDropAction() & DnDConstants.ACTION_COPY_OR_MOVE) != 0) {
// Accept the drop and get the transfer data
dtde.acceptDrop(dtde.getDropAction());
Transferable transferable = dtde.getTransferable();
try {
boolean result = dropFile(transferable);
dtde.dropComplete(result);
DnDUtils.debugPrintln("Drop completed, success: " + result);
} catch (Exception e) {
DnDUtils.debugPrintln("Exception while handling drop " + e);
dtde.dropComplete(false);
}
} else {
DnDUtils.debugPrintln("Drop target rejected drop");
dtde.rejectDrop();
}
}
// Internal methods start here
protected boolean acceptOrRejectDrag(DropTargetDragEvent dtde) {
int dropAction = dtde.getDropAction();
int sourceActions = dtde.getSourceActions();
boolean acceptedDrag = false;
DnDUtils.debugPrintln("\tSource actions are "
+ DnDUtils.showActions(sourceActions) + ", drop action is "
+ DnDUtils.showActions(dropAction));
// Reject if the object being transferred
// or the operations available are not acceptable.
if (!acceptableType
|| (sourceActions & DnDConstants.ACTION_COPY_OR_MOVE) == 0) {
DnDUtils.debugPrintln("Drop target rejecting drag");
dtde.rejectDrag();
} else if ((dropAction & DnDConstants.ACTION_COPY_OR_MOVE) == 0) {
// Not offering copy or move - suggest a copy
DnDUtils.debugPrintln("Drop target offering COPY");
dtde.acceptDrag(DnDConstants.ACTION_COPY);
acceptedDrag = true;
} else {
// Offering an acceptable operation: accept
DnDUtils.debugPrintln("Drop target accepting drag");
dtde.acceptDrag(dropAction);
acceptedDrag = true;
}
return acceptedDrag;
}
protected void checkTransferType(DropTargetDragEvent dtde) {
// Only accept a list of files
acceptableType = dtde
.isDataFlavorSupported(DataFlavor.javaFileListFlavor);
DnDUtils.debugPrintln("File type acceptable - " + acceptableType);
}
// This method handles a drop for a list of files
protected boolean dropFile(Transferable transferable) throws IOException,
UnsupportedFlavorException, MalformedURLException {
List fileList = (List) transferable
.getTransferData(DataFlavor.javaFileListFlavor);
File transferFile = (File) fileList.get(0);
final URL transferURL = transferFile.toURL();
DnDUtils.debugPrintln("File URL is " + transferURL);
pane.setPage(transferURL);
return true;
}
public static void main(String[] args) {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch (Exception evt) {}
final JFrame f = new JFrame("JEditor Pane Drop Target Example 1");
JEditorPane pane = new JEditorPane();
// Add a drop target to the JEditorPane
EditorDropTarget target = new EditorDropTarget(pane);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent evt) {
System.exit(0);
}
});
f.getContentPane().add(new JScrollPane(pane), BorderLayout.CENTER);
f.setSize(500, 400);
f.setVisible(true);
}
protected JEditorPane pane;
protected DropTarget dropTarget;
protected boolean acceptableType; // Indicates whether data is acceptable
}
class DnDUtils {
public static String showActions(int action) {
String actions = "";
if ((action & (DnDConstants.ACTION_LINK | DnDConstants.ACTION_COPY_OR_MOVE)) == 0) {
return "None";
}
if ((action & DnDConstants.ACTION_COPY) != 0) {
actions += "Copy ";
}
if ((action & DnDConstants.ACTION_MOVE) != 0) {
actions += "Move ";
}
if ((action & DnDConstants.ACTION_LINK) != 0) {
actions += "Link";
}
return actions;
}
public static boolean isDebugEnabled() {
return debugEnabled;
}
public static void debugPrintln(String s) {
if (debugEnabled) {
System.out.println(s);
}
}
private static boolean debugEnabled = (System
.getProperty("DnDExamples.debug") != null);
}
Editor Drop Target 2
/*
Core SWING Advanced Programming
By Kim Topley
ISBN: 0 13 083292 8
Publisher: Prentice Hall
*/
import java.awt.BorderLayout;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.DnDConstants;
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.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import javax.swing.JCheckBox;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.UIManager;
public class EditorDropTarget2 implements DropTargetListener {
public EditorDropTarget2(JEditorPane pane) {
this.pane = pane;
// Create the DropTarget and register
// it with the JEditorPane.
dropTarget = new DropTarget(pane, DnDConstants.ACTION_COPY_OR_MOVE,
this, true, null);
}
// Implementation of the DropTargetListener interface
public void dragEnter(DropTargetDragEvent dtde) {
DnDUtils.debugPrintln("dragEnter, drop action = "
+ DnDUtils.showActions(dtde.getDropAction()));
// Get the type of object being transferred and determine
// whether it is appropriate.
checkTransferType(dtde);
// Accept or reject the drag.
acceptOrRejectDrag(dtde);
}
public void dragExit(DropTargetEvent dte) {
DnDUtils.debugPrintln("DropTarget dragExit");
}
public void dragOver(DropTargetDragEvent dtde) {
DnDUtils.debugPrintln("DropTarget dragOver, drop action = "
+ DnDUtils.showActions(dtde.getDropAction()));
// Accept or reject the drag
acceptOrRejectDrag(dtde);
}
public void dropActionChanged(DropTargetDragEvent dtde) {
DnDUtils.debugPrintln("DropTarget dropActionChanged, drop action = "
+ DnDUtils.showActions(dtde.getDropAction()));
// Accept or reject the drag
acceptOrRejectDrag(dtde);
}
public void drop(DropTargetDropEvent dtde) {
DnDUtils.debugPrintln("DropTarget drop, drop action = "
+ DnDUtils.showActions(dtde.getDropAction()));
// Check the drop action
if ((dtde.getDropAction() & DnDConstants.ACTION_COPY_OR_MOVE) != 0) {
// Accept the drop and get the transfer data
dtde.acceptDrop(dtde.getDropAction());
Transferable transferable = dtde.getTransferable();
try {
boolean result = false;
if (draggingFile) {
result = dropFile(transferable);
} else {
result = dropContent(transferable, dtde);
}
dtde.dropComplete(result);
DnDUtils.debugPrintln("Drop completed, success: " + result);
} catch (Exception e) {
DnDUtils.debugPrintln("Exception while handling drop " + e);
dtde.dropComplete(false);
}
} else {
DnDUtils.debugPrintln("Drop target rejected drop");
dtde.rejectDrop();
}
}
// Internal methods start here
protected boolean acceptOrRejectDrag(DropTargetDragEvent dtde) {
int dropAction = dtde.getDropAction();
int sourceActions = dtde.getSourceActions();
boolean acceptedDrag = false;
DnDUtils.debugPrintln("\tSource actions are "
+ DnDUtils.showActions(sourceActions) + ", drop action is "
+ DnDUtils.showActions(dropAction));
// Reject if the object being transferred
// or the operations available are not acceptable
if (!acceptableType
|| (sourceActions & DnDConstants.ACTION_COPY_OR_MOVE) == 0) {
DnDUtils.debugPrintln("Drop target rejecting drag");
dtde.rejectDrag();
} else if (!draggingFile && !pane.isEditable()) {
// Can"t drag text to a read-only JEditorPane
DnDUtils.debugPrintln("Drop target rejecting drag");
dtde.rejectDrag();
} else if ((dropAction & DnDConstants.ACTION_COPY_OR_MOVE) == 0) {
// Not offering copy or move - suggest a copy
DnDUtils.debugPrintln("Drop target offering COPY");
dtde.acceptDrag(DnDConstants.ACTION_COPY);
acceptedDrag = true;
} else {
// Offering an acceptable operation: accept
DnDUtils.debugPrintln("Drop target accepting drag");
dtde.acceptDrag(dropAction);
acceptedDrag = true;
}
return acceptedDrag;
}
protected void checkTransferType(DropTargetDragEvent dtde) {
// Accept a list of files, or data content that
// amounts to plain text or a Unicode text string
acceptableType = false;
draggingFile = false;
if (DnDUtils.isDebugEnabled()) {
DataFlavor[] flavors = dtde.getCurrentDataFlavors();
for (int i = 0; i < flavors.length; i++) {
DataFlavor flavor = flavors[i];
DnDUtils.debugPrintln("Drop MIME type " + flavor.getMimeType()
+ " is available");
}
}
if (dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
acceptableType = true;
draggingFile = true;
} else if (dtde.isDataFlavorSupported(DataFlavor.plainTextFlavor)
|| dtde.isDataFlavorSupported(DataFlavor.stringFlavor)) {
acceptableType = true;
}
DnDUtils.debugPrintln("File type acceptable - " + acceptableType);
}
// This method handles a drop for a list of files
protected boolean dropFile(Transferable transferable) throws IOException,
UnsupportedFlavorException, MalformedURLException {
List fileList = (List) transferable
.getTransferData(DataFlavor.javaFileListFlavor);
File transferFile = (File) fileList.get(0);
final URL transferURL = transferFile.toURL();
DnDUtils.debugPrintln("File URL is " + transferURL);
pane.setPage(transferURL);
return true;
}
// This method handles a drop with data content
protected boolean dropContent(Transferable transferable,
DropTargetDropEvent dtde) {
if (!pane.isEditable()) {
// Can"t drop content on a read-only text control
return false;
}
try {
// Check for a match with the current content type
DataFlavor[] flavors = dtde.getCurrentDataFlavors();
DataFlavor selectedFlavor = null;
// Look for either plain text or a String.
for (int i = 0; i < flavors.length; i++) {
DataFlavor flavor = flavors[i];
if (flavor.equals(DataFlavor.plainTextFlavor)
|| flavor.equals(DataFlavor.stringFlavor)) {
selectedFlavor = flavor;
break;
}
}
if (selectedFlavor == null) {
// No compatible flavor - should never happen
return false;
}
DnDUtils.debugPrintln("Selected flavor is "
+ selectedFlavor.getHumanPresentableName());
// Get the transferable and then obtain the data
Object data = transferable.getTransferData(selectedFlavor);
DnDUtils.debugPrintln("Transfer data type is "
+ data.getClass().getName());
String insertData = null;
if (data instanceof InputStream) {
// Plain text flavor
String charSet = selectedFlavor.getParameter("charset");
InputStream is = (InputStream) data;
byte[] bytes = new byte[is.available()];
is.read(bytes);
try {
insertData = new String(bytes, charSet);
} catch (UnsupportedEncodingException e) {
// Use the platform default encoding
insertData = new String(bytes);
}
} else if (data instanceof String) {
// String flavor
insertData = (String) data;
}
if (insertData != null) {
int selectionStart = pane.getCaretPosition();
pane.replaceSelection(insertData);
pane.select(selectionStart, selectionStart
+ insertData.length());
return true;
}
return false;
} catch (Exception e) {
return false;
}
}
public static void main(String[] args) {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch (Exception evt) {}
final JFrame f = new JFrame("JEditor Pane Drop Target Example 2");
final JEditorPane pane = new JEditorPane();
// Add a drop target to the JEditorPane
EditorDropTarget2 target = new EditorDropTarget2(pane);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent evt) {
System.exit(0);
}
});
JPanel panel = new JPanel();
final JCheckBox editable = new JCheckBox("Editable");
editable.setSelected(true);
panel.add(editable);
editable.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
pane.setEditable(editable.isSelected());
}
});
f.getContentPane().add(new JScrollPane(pane), BorderLayout.CENTER);
f.getContentPane().add(panel, BorderLayout.SOUTH);
f.setSize(500, 400);
f.setVisible(true);
}
protected JEditorPane pane;
protected DropTarget dropTarget;
protected boolean acceptableType; // Indicates whether data is acceptable
protected boolean draggingFile; // True if dragging an entire file
}
class DnDUtils {
public static String showActions(int action) {
String actions = "";
if ((action & (DnDConstants.ACTION_LINK | DnDConstants.ACTION_COPY_OR_MOVE)) == 0) {
return "None";
}
if ((action & DnDConstants.ACTION_COPY) != 0) {
actions += "Copy ";
}
if ((action & DnDConstants.ACTION_MOVE) != 0) {
actions += "Move ";
}
if ((action & DnDConstants.ACTION_LINK) != 0) {
actions += "Link";
}
return actions;
}
public static boolean isDebugEnabled() {
return debugEnabled;
}
public static void debugPrintln(String s) {
if (debugEnabled) {
System.out.println(s);
}
}
private static boolean debugEnabled = (System
.getProperty("DnDExamples.debug") != null);
}
Editor Drop Target 3
/*
Core SWING Advanced Programming
By Kim Topley
ISBN: 0 13 083292 8
Publisher: Prentice Hall
*/
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Point;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.DnDConstants;
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.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import javax.swing.JCheckBox;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.UIManager;
public class EditorDropTarget3 implements DropTargetListener,
PropertyChangeListener {
public EditorDropTarget3(JEditorPane pane) {
this.pane = pane;
// Listen for changes in the enabled property
pane.addPropertyChangeListener(this);
// Save the JEditorPane"s background color
backgroundColor = pane.getBackground();
// Create the DropTarget and register
// it with the JEditorPane.
dropTarget = new DropTarget(pane, DnDConstants.ACTION_COPY_OR_MOVE,
this, pane.isEnabled(), null);
}
// Implementation of the DropTargetListener interface
public void dragEnter(DropTargetDragEvent dtde) {
DnDUtils.debugPrintln("dragEnter, drop action = "
+ DnDUtils.showActions(dtde.getDropAction()));
// Get the type of object being transferred and determine
// whether it is appropriate.
checkTransferType(dtde);
// Accept or reject the drag.
boolean acceptedDrag = acceptOrRejectDrag(dtde);
// Do drag-under feedback
dragUnderFeedback(dtde, acceptedDrag);
}
public void dragExit(DropTargetEvent dte) {
DnDUtils.debugPrintln("DropTarget dragExit");
// Do drag-under feedback
dragUnderFeedback(null, false);
}
public void dragOver(DropTargetDragEvent dtde) {
DnDUtils.debugPrintln("DropTarget dragOver, drop action = "
+ DnDUtils.showActions(dtde.getDropAction()));
// Accept or reject the drag
boolean acceptedDrag = acceptOrRejectDrag(dtde);
// Do drag-under feedback
dragUnderFeedback(dtde, acceptedDrag);
}
public void dropActionChanged(DropTargetDragEvent dtde) {
DnDUtils.debugPrintln("DropTarget dropActionChanged, drop action = "
+ DnDUtils.showActions(dtde.getDropAction()));
// Accept or reject the drag
boolean acceptedDrag = acceptOrRejectDrag(dtde);
// Do drag-under feedback
dragUnderFeedback(dtde, acceptedDrag);
}
public void drop(DropTargetDropEvent dtde) {
DnDUtils.debugPrintln("DropTarget drop, drop action = "
+ DnDUtils.showActions(dtde.getDropAction()));
// Check the drop action
if ((dtde.getDropAction() & DnDConstants.ACTION_COPY_OR_MOVE) != 0) {
// Accept the drop and get the transfer data
dtde.acceptDrop(dtde.getDropAction());
Transferable transferable = dtde.getTransferable();
try {
boolean result = false;
if (draggingFile) {
result = dropFile(transferable);
} else {
result = dropContent(transferable, dtde);
}
dtde.dropComplete(result);
DnDUtils.debugPrintln("Drop completed, success: " + result);
} catch (Exception e) {
DnDUtils.debugPrintln("Exception while handling drop " + e);
dtde.dropComplete(false);
}
} else {
DnDUtils.debugPrintln("Drop target rejected drop");
dtde.rejectDrop();
}
}
// PropertyChangeListener interface
public void propertyChange(PropertyChangeEvent evt) {
String propertyName = evt.getPropertyName();
if (propertyName.equals("enabled")) {
// Enable the drop target if the JEditorPane is enabled
// and vice versa.
dropTarget.setActive(pane.isEnabled());
} else if (!changingBackground && propertyName.equals("background")) {
backgroundColor = pane.getBackground();
}
}
// Internal methods start here
protected boolean acceptOrRejectDrag(DropTargetDragEvent dtde) {
int dropAction = dtde.getDropAction();
int sourceActions = dtde.getSourceActions();
boolean acceptedDrag = false;
DnDUtils.debugPrintln("\tSource actions are "
+ DnDUtils.showActions(sourceActions) + ", drop action is "
+ DnDUtils.showActions(dropAction));
// Reject if the object being transferred
// or the operations available are not acceptable.
if (!acceptableType
|| (sourceActions & DnDConstants.ACTION_COPY_OR_MOVE) == 0) {
DnDUtils.debugPrintln("Drop target rejecting drag");
dtde.rejectDrag();
} else if (!draggingFile && !pane.isEditable()) {
// Can"t drag text to a read-only JEditorPane
DnDUtils.debugPrintln("Drop target rejecting drag");
dtde.rejectDrag();
} else if ((dropAction & DnDConstants.ACTION_COPY_OR_MOVE) == 0) {
// Not offering copy or move - suggest a copy
DnDUtils.debugPrintln("Drop target offering COPY");
dtde.acceptDrag(DnDConstants.ACTION_COPY);
acceptedDrag = true;
} else {
// Offering an acceptable operation: accept
DnDUtils.debugPrintln("Drop target accepting drag");
dtde.acceptDrag(dropAction);
acceptedDrag = true;
}
return acceptedDrag;
}
protected void dragUnderFeedback(DropTargetDragEvent dtde,
boolean acceptedDrag) {
if (draggingFile) {
// When dragging a file, change the background color
Color newColor = (dtde != null && acceptedDrag ? feedbackColor
: backgroundColor);
if (newColor.equals(pane.getBackground()) == false) {
changingBackground = true;
pane.setBackground(newColor);
changingBackground = false;
pane.repaint();
}
} else {
if (dtde != null && acceptedDrag) {
// Dragging text - move the insertion cursor
Point location = dtde.getLocation();
pane.getCaret().setVisible(true);
pane.setCaretPosition(pane.viewToModel(location));
} else {
pane.getCaret().setVisible(false);
}
}
}
protected void checkTransferType(DropTargetDragEvent dtde) {
// Accept a list of files, or data content that
// amounts to plain text or a Unicode text string
acceptableType = false;
draggingFile = false;
if (dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
acceptableType = true;
draggingFile = true;
} else if (dtde.isDataFlavorSupported(DataFlavor.plainTextFlavor)
|| dtde.isDataFlavorSupported(DataFlavor.stringFlavor)) {
acceptableType = true;
}
DnDUtils.debugPrintln("File type acceptable - " + acceptableType);
DnDUtils.debugPrintln("Dragging a file - " + draggingFile);
}
// This method handles a drop for a list of files
protected boolean dropFile(Transferable transferable) throws IOException,
UnsupportedFlavorException, MalformedURLException {
List fileList = (List) transferable
.getTransferData(DataFlavor.javaFileListFlavor);
File transferFile = (File) fileList.get(0);
final URL transferURL = transferFile.toURL();
DnDUtils.debugPrintln("File URL is " + transferURL);
pane.setPage(transferURL);
return true;
}
// This method handles a drop with data content
protected boolean dropContent(Transferable transferable,
DropTargetDropEvent dtde) {
if (!pane.isEditable()) {
// Can"t drop content on a read-only text control
return false;
}
try {
// Check for a match with the current content type
DataFlavor[] flavors = dtde.getCurrentDataFlavors();
DataFlavor selectedFlavor = null;
// Look for either plain text or a String.
for (int i = 0; i < flavors.length; i++) {
DataFlavor flavor = flavors[i];
DnDUtils.debugPrintln("Drop MIME type " + flavor.getMimeType()
+ " is available");
if (flavor.equals(DataFlavor.plainTextFlavor)
|| flavor.equals(DataFlavor.stringFlavor)) {
selectedFlavor = flavor;
break;
}
}
if (selectedFlavor == null) {
// No compatible flavor - should never happen
return false;
}
DnDUtils.debugPrintln("Selected flavor is "
+ selectedFlavor.getHumanPresentableName());
// Get the transferable and then obtain the data
Object data = transferable.getTransferData(selectedFlavor);
DnDUtils.debugPrintln("Transfer data type is "
+ data.getClass().getName());
String insertData = null;
if (data instanceof InputStream) {
// Plain text flavor
String charSet = selectedFlavor.getParameter("charset");
InputStream is = (InputStream) data;
byte[] bytes = new byte[is.available()];
is.read(bytes);
try {
insertData = new String(bytes, charSet);
} catch (UnsupportedEncodingException e) {
// Use the platform default encoding
insertData = new String(bytes);
}
} else if (data instanceof String) {
// String flavor
insertData = (String) data;
}
if (insertData != null) {
int selectionStart = pane.getCaretPosition();
pane.replaceSelection(insertData);
pane.select(selectionStart, selectionStart
+ insertData.length());
return true;
}
return false;
} catch (Exception e) {
return false;
}
}
public static void main(String[] args) {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch (Exception evt) {}
final JFrame f = new JFrame("JEditor Pane Drop Target Example 3");
final JEditorPane pane = new JEditorPane();
// Add a drop target to the JEditorPane
EditorDropTarget3 target = new EditorDropTarget3(pane);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent evt) {
System.exit(0);
}
});
JPanel panel = new JPanel();
final JCheckBox editable = new JCheckBox("Editable");
editable.setSelected(true);
panel.add(editable);
editable.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
pane.setEditable(editable.isSelected());
}
});
final JCheckBox enabled = new JCheckBox("Enabled");
enabled.setSelected(true);
panel.add(enabled);
enabled.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
pane.setEnabled(enabled.isSelected());
}
});
f.getContentPane().add(new JScrollPane(pane), BorderLayout.CENTER);
f.getContentPane().add(panel, BorderLayout.SOUTH);
f.setSize(500, 400);
f.setVisible(true);
}
protected JEditorPane pane;
protected DropTarget dropTarget;
protected boolean acceptableType; // Indicates whether data is acceptable
protected boolean draggingFile; // True if dragging an entire file
protected Color backgroundColor; // Original background color of JEditorPane
protected boolean changingBackground;
protected static final Color feedbackColor = Color.gray;
}
class DnDUtils {
public static String showActions(int action) {
String actions = "";
if ((action & (DnDConstants.ACTION_LINK | DnDConstants.ACTION_COPY_OR_MOVE)) == 0) {
return "None";
}
if ((action & DnDConstants.ACTION_COPY) != 0) {
actions += "Copy ";
}
if ((action & DnDConstants.ACTION_MOVE) != 0) {
actions += "Move ";
}
if ((action & DnDConstants.ACTION_LINK) != 0) {
actions += "Link";
}
return actions;
}
public static boolean isDebugEnabled() {
return debugEnabled;
}
public static void debugPrintln(String s) {
if (debugEnabled) {
System.out.println(s);
}
}
private static boolean debugEnabled = (System
.getProperty("DnDExamples.debug") != null);
}
Editor Drop Target 4
/*
Core SWING Advanced Programming
By Kim Topley
ISBN: 0 13 083292 8
Publisher: Prentice Hall
*/
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.Autoscroll;
import java.awt.dnd.DnDConstants;
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.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import javax.swing.JCheckBox;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
public class EditorDropTarget4 implements DropTargetListener,
PropertyChangeListener {
public EditorDropTarget4(JEditorPane pane) {
this.pane = pane;
// Listen for changes in the enabled property
pane.addPropertyChangeListener(this);
// Save the JEditorPane"s background color
backgroundColor = pane.getBackground();
// Create the DropTarget and register
// it with the JEditorPane.
dropTarget = new DropTarget(pane, DnDConstants.ACTION_COPY_OR_MOVE,
this, pane.isEnabled(), null);
}
// Implementation of the DropTargetListener interface
public void dragEnter(DropTargetDragEvent dtde) {
DnDUtils.debugPrintln("dragEnter, drop action = "
+ DnDUtils.showActions(dtde.getDropAction()));
// Get the type of object being transferred and determine
// whether it is appropriate.
checkTransferType(dtde);
// Accept or reject the drag.
boolean acceptedDrag = acceptOrRejectDrag(dtde);
// Do drag-under feedback
dragUnderFeedback(dtde, acceptedDrag);
}
public void dragExit(DropTargetEvent dte) {
DnDUtils.debugPrintln("DropTarget dragExit");
// Do drag-under feedback
dragUnderFeedback(null, false);
}
public void dragOver(DropTargetDragEvent dtde) {
DnDUtils.debugPrintln("DropTarget dragOver, drop action = "
+ DnDUtils.showActions(dtde.getDropAction()));
// Accept or reject the drag
boolean acceptedDrag = acceptOrRejectDrag(dtde);
// Do drag-under feedback
dragUnderFeedback(dtde, acceptedDrag);
}
public void dropActionChanged(DropTargetDragEvent dtde) {
DnDUtils.debugPrintln("DropTarget dropActionChanged, drop action = "
+ DnDUtils.showActions(dtde.getDropAction()));
// Accept or reject the drag
boolean acceptedDrag = acceptOrRejectDrag(dtde);
// Do drag-under feedback
dragUnderFeedback(dtde, acceptedDrag);
}
public void drop(DropTargetDropEvent dtde) {
DnDUtils.debugPrintln("DropTarget drop, drop action = "
+ DnDUtils.showActions(dtde.getDropAction()));
// Check the drop action
if ((dtde.getDropAction() & DnDConstants.ACTION_COPY_OR_MOVE) != 0) {
// Accept the drop and get the transfer data
dtde.acceptDrop(dtde.getDropAction());
Transferable transferable = dtde.getTransferable();
try {
boolean result = false;
if (draggingFile) {
result = dropFile(transferable);
} else {
result = dropContent(transferable, dtde);
}
dtde.dropComplete(result);
DnDUtils.debugPrintln("Drop completed, success: " + result);
} catch (Exception e) {
DnDUtils.debugPrintln("Exception while handling drop " + e);
dtde.rejectDrop();
}
} else {
DnDUtils.debugPrintln("Drop target rejected drop");
dtde.dropComplete(false);
}
}
// PropertyChangeListener interface
public void propertyChange(PropertyChangeEvent evt) {
String propertyName = evt.getPropertyName();
if (propertyName.equals("enabled")) {
// Enable the drop target if the JEditorPane is enabled
// and vice versa.
dropTarget.setActive(pane.isEnabled());
} else if (!changingBackground && propertyName.equals("background")) {
backgroundColor = pane.getBackground();
}
}
// Internal methods start here
protected boolean acceptOrRejectDrag(DropTargetDragEvent dtde) {
int dropAction = dtde.getDropAction();
int sourceActions = dtde.getSourceActions();
boolean acceptedDrag = false;
DnDUtils.debugPrintln("\tSource actions are "
+ DnDUtils.showActions(sourceActions) + ", drop action is "
+ DnDUtils.showActions(dropAction));
// Reject if the object being transferred
// or the operations available are not acceptable.
if (!acceptableType
|| (sourceActions & DnDConstants.ACTION_COPY_OR_MOVE) == 0) {
DnDUtils.debugPrintln("Drop target rejecting drag");
dtde.rejectDrag();
} else if (!draggingFile && !pane.isEditable()) {
// Can"t drag text to a read-only JEditorPane
DnDUtils.debugPrintln("Drop target rejecting drag");
dtde.rejectDrag();
} else if ((dropAction & DnDConstants.ACTION_COPY_OR_MOVE) == 0) {
// Not offering copy or move - suggest a copy
DnDUtils.debugPrintln("Drop target offering COPY");
dtde.acceptDrag(DnDConstants.ACTION_COPY);
acceptedDrag = true;
} else {
// Offering an acceptable operation: accept
DnDUtils.debugPrintln("Drop target accepting drag");
dtde.acceptDrag(dropAction);
acceptedDrag = true;
}
return acceptedDrag;
}
protected void dragUnderFeedback(DropTargetDragEvent dtde,
boolean acceptedDrag) {
if (draggingFile) {
// When dragging a file, change the background color
Color newColor = (dtde != null && acceptedDrag ? feedbackColor
: backgroundColor);
if (newColor.equals(pane.getBackground()) == false) {
changingBackground = true;
pane.setBackground(newColor);
changingBackground = false;
pane.repaint();
}
} else {
if (dtde != null && acceptedDrag) {
// Dragging text - move the insertion cursor
Point location = dtde.getLocation();
pane.getCaret().setVisible(true);
pane.setCaretPosition(pane.viewToModel(location));
} else {
pane.getCaret().setVisible(false);
}
}
}
protected void checkTransferType(DropTargetDragEvent dtde) {
// Accept a list of files, or data content that
// amounts to plain text or a Unicode text string
acceptableType = false;
draggingFile = false;
if (dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
acceptableType = true;
draggingFile = true;
} else if (dtde.isDataFlavorSupported(DataFlavor.plainTextFlavor)
|| dtde.isDataFlavorSupported(DataFlavor.stringFlavor)) {
acceptableType = true;
}
DnDUtils.debugPrintln("File type acceptable - " + acceptableType);
DnDUtils.debugPrintln("Dragging a file - " + draggingFile);
}
// This method handles a drop for a list of files
protected boolean dropFile(Transferable transferable) throws IOException,
UnsupportedFlavorException, MalformedURLException {
List fileList = (List) transferable
.getTransferData(DataFlavor.javaFileListFlavor);
File transferFile = (File) fileList.get(0);
final URL transferURL = transferFile.toURL();
DnDUtils.debugPrintln("File URL is " + transferURL);
pane.setPage(transferURL);
return true;
}
// This method handles a drop with data content
protected boolean dropContent(Transferable transferable,
DropTargetDropEvent dtde) {
if (!pane.isEditable()) {
// Can"t drop content on a read-only text control
return false;
}
try {
// Check for a match with the current content type
DataFlavor[] flavors = dtde.getCurrentDataFlavors();
DataFlavor selectedFlavor = null;
// Look for either plain text or a String.
for (int i = 0; i < flavors.length; i++) {
DataFlavor flavor = flavors[i];
DnDUtils.debugPrintln("Drop MIME type " + flavor.getMimeType()
+ " is available");
if (flavor.equals(DataFlavor.plainTextFlavor)
|| flavor.equals(DataFlavor.stringFlavor)) {
selectedFlavor = flavor;
break;
}
}
if (selectedFlavor == null) {
// No compatible flavor - should never happen
return false;
}
DnDUtils.debugPrintln("Selected flavor is "
+ selectedFlavor.getHumanPresentableName());
// Get the transferable and then obtain the data
Object data = transferable.getTransferData(selectedFlavor);
DnDUtils.debugPrintln("Transfer data type is "
+ data.getClass().getName());
String insertData = null;
if (data instanceof InputStream) {
// Plain text flavor
String charSet = selectedFlavor.getParameter("charset");
InputStream is = (InputStream) data;
byte[] bytes = new byte[is.available()];
is.read(bytes);
try {
insertData = new String(bytes, charSet);
} catch (UnsupportedEncodingException e) {
// Use the platform default encoding
insertData = new String(bytes);
}
} else if (data instanceof String) {
// String flavor
insertData = (String) data;
}
if (insertData != null) {
int selectionStart = pane.getCaretPosition();
pane.replaceSelection(insertData);
pane.select(selectionStart, selectionStart
+ insertData.length());
return true;
}
return false;
} catch (Exception e) {
return false;
}
}
public static void main(String[] args) {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch (Exception evt) {}
final JFrame f = new JFrame("JEditor Pane Drop Target Example 4");
// Create an editor with autoscrolling support
final JEditorPane pane = new AutoScrollingEditorPane();
// Add a drop target to the JEditorPane
EditorDropTarget4 target = new EditorDropTarget4(pane);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent evt) {
System.exit(0);
}
});
JPanel panel = new JPanel();
final JCheckBox editable = new JCheckBox("Editable");
editable.setSelected(true);
panel.add(editable);
editable.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
pane.setEditable(editable.isSelected());
}
});
final JCheckBox enabled = new JCheckBox("Enabled");
enabled.setSelected(true);
panel.add(enabled);
enabled.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
pane.setEnabled(enabled.isSelected());
}
});
f.getContentPane().add(new JScrollPane(pane), BorderLayout.CENTER);
f.getContentPane().add(panel, BorderLayout.SOUTH);
f.setSize(500, 400);
f.setVisible(true);
}
protected JEditorPane pane;
protected DropTarget dropTarget;
protected boolean acceptableType; // Indicates whether data is acceptable
protected boolean draggingFile; // True if dragging an entire file
protected Color backgroundColor; // Original background color of JEditorPane
protected boolean changingBackground;
protected static final Color feedbackColor = Color.gray;
}
class DnDUtils {
public static String showActions(int action) {
String actions = "";
if ((action & (DnDConstants.ACTION_LINK | DnDConstants.ACTION_COPY_OR_MOVE)) == 0) {
return "None";
}
if ((action & DnDConstants.ACTION_COPY) != 0) {
actions += "Copy ";
}
if ((action & DnDConstants.ACTION_MOVE) != 0) {
actions += "Move ";
}
if ((action & DnDConstants.ACTION_LINK) != 0) {
actions += "Link";
}
return actions;
}
public static boolean isDebugEnabled() {
return debugEnabled;
}
public static void debugPrintln(String s) {
if (debugEnabled) {
System.out.println(s);
}
}
private static boolean debugEnabled = (System
.getProperty("DnDExamples.debug") != null);
}
class AutoScrollingEditorPane extends JEditorPane implements Autoscroll {
public static final Insets defaultScrollInsets = new Insets(8, 8, 8, 8);
protected Insets scrollInsets = defaultScrollInsets;
public AutoScrollingEditorPane() {
}
public void setScrollInsets(Insets insets) {
this.scrollInsets = insets;
}
public Insets getScrollInsets() {
return scrollInsets;
}
// Implementation of Autoscroll interface
public Insets getAutoscrollInsets() {
Rectangle r = getVisibleRect();
Dimension size = getSize();
Insets i = new Insets(r.y + scrollInsets.top, r.x + scrollInsets.left,
size.height - r.y - r.height + scrollInsets.bottom, size.width
- r.x - r.width + scrollInsets.right);
return i;
}
public void autoscroll(Point location) {
JScrollPane scroller = (JScrollPane) SwingUtilities.getAncestorOfClass(
JScrollPane.class, this);
if (scroller != null) {
JScrollBar hBar = scroller.getHorizontalScrollBar();
JScrollBar vBar = scroller.getVerticalScrollBar();
Rectangle r = getVisibleRect();
if (location.x <= r.x + scrollInsets.left) {
// Need to scroll left
hBar.setValue(hBar.getValue() - hBar.getUnitIncrement(-1));
}
if (location.y <= r.y + scrollInsets.top) {
// Need to scroll up
vBar.setValue(vBar.getValue() - vBar.getUnitIncrement(-1));
}
if (location.x >= r.x + r.width - scrollInsets.right) {
// Need to scroll right
hBar.setValue(hBar.getValue() + hBar.getUnitIncrement(1));
}
if (location.y >= r.y + r.height - scrollInsets.bottom) {
// Need to scroll down
vBar.setValue(vBar.getValue() + vBar.getUnitIncrement(1));
}
}
}
}
Extended DnD (Drag and Drop) Demo
/* From http://java.sun.ru/docs/books/tutorial/index.html */
/*
* Copyright (c) 2006 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:
*
* -Redistribution of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* -Redistribution 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, Inc. or the names of contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* 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 MIDROSYSTEMS, INC. ("SUN")
* AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
* AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS 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 THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed, licensed or intended
* for use in the design, construction, operation or maintenance of any
* nuclear facility.
*/
/*
* ExtendedDnDDemo.java is a 1.4 example that requires the following files:
* StringTransferHandler.java ListTransferHandler.java TableTransferHandler.java
*/
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() {
//Make sure we have nice window decorations.
JFrame.setDefaultLookAndFeelDecorated(true);
//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();
}
});
}
}
/*
* ListTransferHandler.java is used by the 1.4 ExtendedDnDDemo.java example.
*/
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;
}
}
/*
* StringTransferHandler.java is used by the 1.4 ExtendedDnDDemo.java example.
*/
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;
}
}
/*
* TableTransferHandler.java is used by the 1.4 ExtendedDnDDemo.java example.
*/
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;
}
}
File Tree Drag Source
/*
Core SWING Advanced Programming
By Kim Topley
ISBN: 0 13 083292 8
Publisher: Prentice Hall
*/
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.dnd.Autoscroll;
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.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.ruparator;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeExpansionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
public class FileTreeDragSource implements DragGestureListener,
DragSourceListener {
public FileTreeDragSource(FileTree tree) {
this.tree = tree;
// Use the default DragSource
DragSource dragSource = DragSource.getDefaultDragSource();
// Create a DragGestureRecognizer and
// register as the listener
dragSource.createDefaultDragGestureRecognizer(tree,
DnDConstants.ACTION_COPY_OR_MOVE, this);
}
// Implementation of DragGestureListener interface.
public void dragGestureRecognized(DragGestureEvent dge) {
// Get the mouse location and convert it to
// a location within the tree.
Point location = dge.getDragOrigin();
TreePath dragPath = tree.getPathForLocation(location.x, location.y);
if (dragPath != null && tree.isPathSelected(dragPath)) {
// Get the list of selected files and create a Transferable
// The list of files and the is saved for use when
// the drop completes.
paths = tree.getSelectionPaths();
if (paths != null && paths.length > 0) {
dragFiles = new File[paths.length];
for (int i = 0; i < paths.length; i++) {
String pathName = tree.getPathName(paths[i]);
dragFiles[i] = new File(pathName);
}
Transferable transferable = new FileListTransferable(dragFiles);
dge.startDrag(null, transferable, this);
}
}
}
// Implementation of DragSourceListener interface
public void dragEnter(DragSourceDragEvent dsde) {
DnDUtils.debugPrintln("Drag Source: dragEnter, drop action = "
+ DnDUtils.showActions(dsde.getDropAction()));
}
public void dragOver(DragSourceDragEvent dsde) {
DnDUtils.debugPrintln("Drag Source: dragOver, drop action = "
+ DnDUtils.showActions(dsde.getDropAction()));
}
public void dragExit(DragSourceEvent dse) {
DnDUtils.debugPrintln("Drag Source: dragExit");
}
public void dropActionChanged(DragSourceDragEvent dsde) {
DnDUtils.debugPrintln("Drag Source: dropActionChanged, drop action = "
+ DnDUtils.showActions(dsde.getDropAction()));
}
public void dragDropEnd(DragSourceDropEvent dsde) {
DnDUtils.debugPrintln("Drag Source: drop completed, drop action = "
+ DnDUtils.showActions(dsde.getDropAction()) + ", success: "
+ dsde.getDropSuccess());
// If the drop action was ACTION_MOVE,
// the tree might need to be updated.
if (dsde.getDropAction() == DnDConstants.ACTION_MOVE) {
final File[] draggedFiles = dragFiles;
final TreePath[] draggedPaths = paths;
Timer tm = new Timer(200, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
// Check whether each of the dragged files exists.
// If it does not, we need to remove the node
// that represents it from the tree.
for (int i = 0; i < draggedFiles.length; i++) {
if (draggedFiles[i].exists() == false) {
// Remove this node
DefaultMutableTreeNode node = (DefaultMutableTreeNode) draggedPaths[i]
.getLastPathComponent();
((DefaultTreeModel) tree.getModel())
.removeNodeFromParent(node);
}
}
}
});
tm.setRepeats(false);
tm.start();
}
}
public static void main(String[] args) {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch (Exception evt) {}
JFrame f = new JFrame("Draggable File Tree");
try {
FileTree tree = new FileTree("D:\\");
f.getContentPane().add(new JScrollPane(tree));
// Attach the drag source
FileTreeDragSource dragSource = new FileTreeDragSource(tree);
} catch (Exception e) {
}
f.pack();
f.setVisible(true);
}
protected FileTree tree; // The associated tree
protected File[] dragFiles; // Dragged files
protected TreePath[] paths; // Dragged paths
}
class FileTree extends JTree implements Autoscroll {
public static final Insets defaultScrollInsets = new Insets(8, 8, 8, 8);
protected Insets scrollInsets = defaultScrollInsets;
public FileTree(String path) throws FileNotFoundException,
SecurityException {
super((TreeModel) null); // Create the JTree itself
// Use horizontal and vertical lines
putClientProperty("JTree.lineStyle", "Angled");
// Create the first node
FileTreeNode rootNode = new FileTreeNode(null, path);
// Populate the root node with its subdirectories
boolean addedNodes = rootNode.populateDirectories(true);
setModel(new DefaultTreeModel(rootNode));
// Listen for Tree Selection Events
addTreeExpansionListener(new TreeExpansionHandler());
}
// Returns the full pathname for a path, or null if not a known path
public String getPathName(TreePath path) {
Object o = path.getLastPathComponent();
if (o instanceof FileTreeNode) {
return ((FileTreeNode) o).fullName;
}
return null;
}
// Adds a new node to the tree after construction.
// Returns the inserted node, or null if the parent
// directory has not been expanded.
public FileTreeNode addNode(FileTreeNode parent, String name) {
int index = parent.addNode(name);
if (index != -1) {
((DefaultTreeModel) getModel()).nodesWereInserted(parent,
new int[] { index });
return (FileTreeNode) parent.getChildAt(index);
}
// No node was created
return null;
}
// Autoscrolling support
public void setScrollInsets(Insets insets) {
this.scrollInsets = insets;
}
public Insets getScrollInsets() {
return scrollInsets;
}
// Implementation of Autoscroll interface
public Insets getAutoscrollInsets() {
Rectangle r = getVisibleRect();
Dimension size = getSize();
Insets i = new Insets(r.y + scrollInsets.top, r.x + scrollInsets.left,
size.height - r.y - r.height + scrollInsets.bottom, size.width
- r.x - r.width + scrollInsets.right);
return i;
}
public void autoscroll(Point location) {
JScrollPane scroller = (JScrollPane) SwingUtilities.getAncestorOfClass(
JScrollPane.class, this);
if (scroller != null) {
JScrollBar hBar = scroller.getHorizontalScrollBar();
JScrollBar vBar = scroller.getVerticalScrollBar();
Rectangle r = getVisibleRect();
if (location.x <= r.x + scrollInsets.left) {
// Need to scroll left
hBar.setValue(hBar.getValue() - hBar.getUnitIncrement(-1));
}
if (location.y <= r.y + scrollInsets.top) {
// Need to scroll up
vBar.setValue(vBar.getValue() - vBar.getUnitIncrement(-1));
}
if (location.x >= r.x + r.width - scrollInsets.right) {
// Need to scroll right
hBar.setValue(hBar.getValue() + hBar.getUnitIncrement(1));
}
if (location.y >= r.y + r.height - scrollInsets.bottom) {
// Need to scroll down
vBar.setValue(vBar.getValue() + vBar.getUnitIncrement(1));
}
}
}
// Inner class that represents a node in this file system tree
public static class FileTreeNode extends DefaultMutableTreeNode {
public FileTreeNode(String parent, String name)
throws SecurityException, FileNotFoundException {
this.name = name;
// See if this node exists and whether it is a directory
fullName = parent == null ? name : parent + File.separator + name;
File f = new File(fullName);
if (f.exists() == false) {
throw new FileNotFoundException("File " + fullName
+ " does not exist");
}
isDir = f.isDirectory();
// Hack for Windows which doesn"t consider a drive to be a
// directory!
if (isDir == false && f.isFile() == false) {
isDir = true;
}
}
// Override isLeaf to check whether this is a directory
public boolean isLeaf() {
return !isDir;
}
// Override getAllowsChildren to check whether this is a directory
public boolean getAllowsChildren() {
return isDir;
}
// Return whether this is a directory
public boolean isDir() {
return isDir;
}
// Get full path
public String getFullName() {
return fullName;
}
// For display purposes, we return our own name
public String toString() {
return name;
}
// If we are a directory, scan our contents and populate
// with children. In addition, populate those children
// if the "descend" flag is true. We only descend once,
// to avoid recursing the whole subtree.
// Returns true if some nodes were added
boolean populateDirectories(boolean descend) {
boolean addedNodes = false;
// Do this only once
if (populated == false) {
File f;
try {
f = new File(fullName);
} catch (SecurityException e) {
populated = true;
return false;
}
if (interim == true) {
// We have had a quick look here before:
// remove the dummy node that we added last time
removeAllChildren();
interim = false;
}
String[] names = f.list(); // Get list of contents
// Process the contents
ArrayList list = new ArrayList();
for (int i = 0; i < names.length; i++) {
String name = names[i];
File d = new File(fullName, name);
try {
FileTreeNode node = new FileTreeNode(fullName, name);
list.add(node);
if (descend && d.isDirectory()) {
node.populateDirectories(false);
}
addedNodes = true;
if (descend == false) {
// Only add one node if not descending
break;
}
} catch (Throwable t) {
// Ignore phantoms or access problems
}
}
if (addedNodes == true) {
// Now sort the list of contained files and directories
Object[] nodes = list.toArray();
Arrays.sort(nodes, new Comparator() {
public boolean equals(Object o) {
return false;
}
public int compare(Object o1, Object o2) {
FileTreeNode node1 = (FileTreeNode) o1;
FileTreeNode node2 = (FileTreeNode) o2;
// Directories come first
if (node1.isDir != node2.isDir) {
return node1.isDir ? -1 : +1;
}
// Both directories or both files -
// compare based on pathname
return node1.fullName.rupareTo(node2.fullName);
}
});
// Add sorted items as children of this node
for (int j = 0; j < nodes.length; j++) {
this.add((FileTreeNode) nodes[j]);
}
}
// If we were scanning to get all subdirectories,
// or if we found no content, there is no
// reason to look at this directory again, so
// set populated to true. Otherwise, we set interim
// so that we look again in the future if we need to
if (descend == true || addedNodes == false) {
populated = true;
} else {
// Just set interim state
interim = true;
}
}
return addedNodes;
}
// Adding a new file or directory after
// constructing the FileTree. Returns
// the index of the inserted node.
public int addNode(String name) {
// If not populated yet, do nothing
if (populated == true) {
// Do not add a new node if
// the required node is already there
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
FileTreeNode node = (FileTreeNode) getChildAt(i);
if (node.name.equals(name)) {
// Already exists - ensure
// we repopulate
if (node.isDir()) {
node.interim = true;
node.populated = false;
}
return -1;
}
}
// Add a new node
try {
FileTreeNode node = new FileTreeNode(fullName, name);
add(node);
return childCount;
} catch (Exception e) {
}
}
return -1;
}
protected String name; // Name of this component
protected String fullName; // Full pathname
protected boolean populated;// true if we have been populated
protected boolean interim; // true if we are in interim state
protected boolean isDir; // true if this is a directory
}
// Inner class that handles Tree Expansion Events
protected class TreeExpansionHandler implements TreeExpansionListener {
public void treeExpanded(TreeExpansionEvent evt) {
TreePath path = evt.getPath(); // The expanded path
JTree tree = (JTree) evt.getSource(); // The tree
// Get the last component of the path and
// arrange to have it fully populated.
FileTreeNode node = (FileTreeNode) path.getLastPathComponent();
if (node.populateDirectories(true)) {
((DefaultTreeModel) tree.getModel()).nodeStructureChanged(node);
}
}
public void treeCollapsed(TreeExpansionEvent evt) {
// Nothing to do
}
}
}
class FileListTransferable implements Transferable {
public FileListTransferable(File[] files) {
fileList = new ArrayList();
for (int i = 0; i < files.length; i++) {
fileList.add(files[i]);
}
}
// Implementation of the Transferable interface
public DataFlavor[] getTransferDataFlavors() {
return new DataFlavor[] { DataFlavor.javaFileListFlavor };
}
public boolean isDataFlavorSupported(DataFlavor fl) {
return fl.equals(DataFlavor.javaFileListFlavor);
}
public Object getTransferData(DataFlavor fl) {
if (!isDataFlavorSupported(fl)) {
return null;
}
return fileList;
}
List fileList; // The list of files
}
class DnDUtils {
public static String showActions(int action) {
String actions = "";
if ((action & (DnDConstants.ACTION_LINK|DnDConstants.ACTION_COPY_OR_MOVE)) == 0) {
return "None";
}
if ((action & DnDConstants.ACTION_COPY) != 0) {
actions += "Copy ";
}
if ((action & DnDConstants.ACTION_MOVE) != 0) {
actions += "Move ";
}
if ((action & DnDConstants.ACTION_LINK) != 0) {
actions += "Link";
}
return actions;
}
public static boolean isDebugEnabled() {
return debugEnabled;
}
public static void debugPrintln(String s) {
if (debugEnabled) {
System.out.println(s);
}
}
private static boolean debugEnabled =
(System.getProperty("DnDExamples.debug") != null);
}
File Tree Drop Target
/*
Core SWING Advanced Programming
By Kim Topley
ISBN: 0 13 083292 8
Publisher: Prentice Hall
*/
import java.awt.BorderLayout;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.Autoscroll;
import java.awt.dnd.DnDConstants;
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.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.ruparator;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeExpansionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
public class FileTreeDropTarget implements DropTargetListener,
PropertyChangeListener {
public FileTreeDropTarget(FileTree tree) {
this.tree = tree;
// Listen for changes in the enabled property
tree.addPropertyChangeListener(this);
// Create the DropTarget and register
// it with the FileTree.
dropTarget = new DropTarget(tree,
DnDConstants.ACTION_COPY_OR_MOVE,
this,
tree.isEnabled(), null);
}
// Implementation of the DropTargetListener interface
public void dragEnter(DropTargetDragEvent dtde) {
DnDUtils.debugPrintln("dragEnter, drop action = "
+ DnDUtils.showActions(dtde.getDropAction()));
// Save the list of selected items
saveTreeSelection();
// Get the type of object being transferred and determine
// whether it is appropriate.
checkTransferType(dtde);
// Accept or reject the drag.
boolean acceptedDrag = acceptOrRejectDrag(dtde);
// Do drag-under feedback
dragUnderFeedback(dtde, acceptedDrag);
}
public void dragExit(DropTargetEvent dte) {
DnDUtils.debugPrintln("DropTarget dragExit");
// Do drag-under feedback
dragUnderFeedback(null, false);
// Restore the original selections
restoreTreeSelection();
}
public void dragOver(DropTargetDragEvent dtde) {
DnDUtils.debugPrintln("DropTarget dragOver, drop action = "
+ DnDUtils.showActions(dtde.getDropAction()));
// Accept or reject the drag
boolean acceptedDrag = acceptOrRejectDrag(dtde);
// Do drag-under feedback
dragUnderFeedback(dtde, acceptedDrag);
}
public void dropActionChanged(DropTargetDragEvent dtde) {
DnDUtils.debugPrintln("DropTarget dropActionChanged, drop action = "
+ DnDUtils.showActions(dtde.getDropAction()));
// Accept or reject the drag
boolean acceptedDrag = acceptOrRejectDrag(dtde);
// Do drag-under feedback
dragUnderFeedback(dtde, acceptedDrag);
}
public void drop(DropTargetDropEvent dtde) {
DnDUtils.debugPrintln("DropTarget drop, drop action = "
+ DnDUtils.showActions(dtde.getDropAction()));
// Check the drop action
if ((dtde.getDropAction() & DnDConstants.ACTION_COPY_OR_MOVE) != 0) {
// Accept the drop and get the transfer data
dtde.acceptDrop(dtde.getDropAction());
Transferable transferable = dtde.getTransferable();
boolean dropSucceeded = false;
try {
tree.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
// Save the user"s selections
saveTreeSelection();
dropSucceeded = dropFile(dtde.getDropAction(),
transferable, dtde.getLocation());
DnDUtils.debugPrintln("Drop completed, success: "
+ dropSucceeded);
} catch (Exception e) {
DnDUtils.debugPrintln("Exception while handling drop " + e);
} finally {
tree.setCursor(Cursor.getDefaultCursor());
// Restore the user"s selections
restoreTreeSelection();
dtde.dropComplete(dropSucceeded);
}
} else {
DnDUtils.debugPrintln("Drop target rejected drop");
dtde.dropComplete(false);
}
}
// PropertyChangeListener interface
public void propertyChange(PropertyChangeEvent evt) {
String propertyName = evt.getPropertyName();
if (propertyName.equals("enabled")) {
// Enable the drop target if the FileTree is enabled
// and vice versa.
dropTarget.setActive(tree.isEnabled());
}
}
// Internal methods start here
protected boolean acceptOrRejectDrag(DropTargetDragEvent dtde) {
int dropAction = dtde.getDropAction();
int sourceActions = dtde.getSourceActions();
boolean acceptedDrag = false;
DnDUtils.debugPrintln("\tSource actions are " +
DnDUtils.showActions(sourceActions) +
", drop action is " +
DnDUtils.showActions(dropAction));
Point location = dtde.getLocation();
boolean acceptableDropLocation = isAcceptableDropLocation(location);
// Reject if the object being transferred
// or the operations available are not acceptable.
if (!acceptableType ||
(sourceActions & DnDConstants.ACTION_COPY_OR_MOVE) == 0) {
DnDUtils.debugPrintln("Drop target rejecting drag");
dtde.rejectDrag();
} else if (!tree.isEditable()) {
// Can"t drag to a read-only FileTree
DnDUtils.debugPrintln("Drop target rejecting drag");
dtde.rejectDrag();
} else if (!acceptableDropLocation) {
// Can only drag to writable directory
DnDUtils.debugPrintln("Drop target rejecting drag");
dtde.rejectDrag();
} else if ((dropAction & DnDConstants.ACTION_COPY_OR_MOVE) == 0) {
// Not offering copy or move - suggest a copy
DnDUtils.debugPrintln("Drop target offering COPY");
dtde.acceptDrag(DnDConstants.ACTION_COPY);
acceptedDrag = true;
} else {
// Offering an acceptable operation: accept
DnDUtils.debugPrintln("Drop target accepting drag");
dtde.acceptDrag(dropAction);
acceptedDrag = true;
}
return acceptedDrag;
}
protected void dragUnderFeedback(DropTargetDragEvent dtde,
boolean acceptedDrag) {
if (dtde != null && acceptedDrag) {
Point location = dtde.getLocation();
if (isAcceptableDropLocation(location)) {
tree.setSelectionRow(
tree.getRowForLocation(location.x, location.y));
} else {
tree.clearSelection();
}
} else {
tree.clearSelection();
}
}
protected void checkTransferType(DropTargetDragEvent dtde) {
// Accept a list of files
acceptableType = false;
if (dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
acceptableType = true;
}
DnDUtils.debugPrintln("Data type acceptable - " + acceptableType);
}
// This method handles a drop for a list of files
protected boolean dropFile(int action,
Transferable transferable, Point location)
throws IOException, UnsupportedFlavorException,
MalformedURLException {
List files = (List)transferable.getTransferData(
DataFlavor.javaFileListFlavor);
TreePath treePath = tree.getPathForLocation(
location.x, location.y);
File targetDirectory = findTargetDirectory(location);
if (treePath == null || targetDirectory == null) {
return false;
}
FileTree.FileTreeNode node =
(FileTree.FileTreeNode)treePath.getLastPathComponent();
// Highlight the drop location while we perform the drop
tree.setSelectionPath(treePath);
// Get File objects for all files being
// transferred, eliminating duplicates.
File[] fileList = getFileList(files);
// Don"t overwrite files by default
copyOverExistingFiles = false;
// Copy or move each source object to the target
for (int i = 0; i < fileList.length; i++) {
File f = fileList[i];
if (f.isDirectory()) {
transferDirectory(action, f, targetDirectory, node);
} else {
try {
transferFile(action, fileList[i],
targetDirectory, node);
} catch (IllegalStateException e) {
// Cancelled by user
return false;
}
}
}
return true;
}
protected File findTargetDirectory(Point location) {
TreePath treePath = tree.getPathForLocation(location.x, location.y);
if(treePath != null) {
FileTree.FileTreeNode node =
(FileTree.FileTreeNode)treePath.getLastPathComponent();
// Only allow a drop on a writable directory
if (node.isDir()) {
try {
File f = new File(node.getFullName());
if (f.canWrite()) {
return f;
}
} catch (Exception e) {
}
}
}
return null;
}
protected boolean isAcceptableDropLocation(Point location) {
return findTargetDirectory(location) != null;
}
protected void saveTreeSelection() {
selections = tree.getSelectionPaths();
leadSelection = tree.getLeadSelectionPath();
tree.clearSelection();
}
protected void restoreTreeSelection() {
tree.setSelectionPaths(selections);
// Restore the lead selection
if (leadSelection != null) {
tree.removeSelectionPath(leadSelection);
tree.addSelectionPath(leadSelection);
}
}
// Get the list of files being transferred and
// remove any duplicates. For example, if the
// list contains /a/b/c and /a/b/c/d, the
// second entry is removed.
protected File[] getFileList(List files) {
int size = files.size();
// Get the files into an array for sorting
File[] f = new File[size];
Iterator iter = files.iterator();
int count = 0;
while (iter.hasNext()) {
f[count++] = (File)iter.next();
}
// Sort the files into alphabetical order
// based on pathnames.
Arrays.sort(f, new Comparator() {
public boolean equals(Object o1) {
return false;
}
public int compare(Object o1, Object o2) {
return ((File)o1).getAbsolutePath().rupareTo(
((File)o2).getAbsolutePath());
}
});
// Remove duplicates, retaining the results in a Vector
Vector v = new Vector();
char separator = System.getProperty("file.separator").charAt(0);
outer:
for (int i = f.length - 1 ; i >= 0; i--) {
String secondPath = f[i].getAbsolutePath();
int secondLength = secondPath.length();
for (int j = i - 1 ; j >= 0; j--) {
String firstPath = f[j].getAbsolutePath();
int firstLength = firstPath.length();
if (secondPath.startsWith(firstPath)
&& firstLength != secondLength
&& secondPath.charAt(firstLength) == separator) {
continue outer;
}
}
v.add(f[i]);
}
// Copy the retained files into an array
f = new File[v.size()];
v.copyInto(f);
return f;
}
// Copy or move a file
protected void transferFile(int action, File srcFile,
File targetDirectory,
FileTree.FileTreeNode targetNode) {
DnDUtils.debugPrintln(
(action == DnDConstants.ACTION_COPY ? "Copy" : "Move") +
" file " + srcFile.getAbsolutePath() +
" to " + targetDirectory.getAbsolutePath());
// Create a File entry for the target
String name = srcFile.getName();
File newFile = new File(targetDirectory, name);
if (newFile.exists()) {
// Already exists - is it the same file?
if (newFile.equals(srcFile)) {
// Exactly the same file - ignore
return;
}
// File of this name exists in this directory
if (copyOverExistingFiles == false) {
int res = JOptionPane.showOptionDialog(tree,
"A file called\n " + name +
"\nalready exists in the directory\n " +
targetDirectory.getAbsolutePath() +
"\nOverwrite it?",
"File Exists",
JOptionPane.DEFAULT_OPTION,
JOptionPane.QUESTION_MESSAGE,
null, new String[] {
"Yes", "Yes to All", "No", "Cancel"
},
"No");
switch (res) {
case 1: // Yes to all
copyOverExistingFiles = true;
case 0: // Yes
break;
case 2: // No
return;
default: // Cancel
throw new IllegalStateException("Cancelled");
}
}
} else {
// New file - create it
try {
newFile.createNewFile();
} catch (IOException e) {
JOptionPane.showMessageDialog(tree,
"Failed to create new file\n " +
newFile.getAbsolutePath(),
"File Creation Failed",
JOptionPane.ERROR_MESSAGE);
return;
}
}
// Copy the data and close file.
BufferedInputStream is = null;
BufferedOutputStream os = null;
try {
is = new BufferedInputStream(
new FileInputStream(srcFile));
os = new BufferedOutputStream(
new FileOutputStream(newFile));
int size = 4096;
byte[] buffer = new byte[size];
int len;
while ((len = is.read(buffer, 0, size)) > 0) {
os.write(buffer, 0, len);
}
} catch (IOException e) {
JOptionPane.showMessageDialog(tree,
"Failed to copy file\n " +
name + "\nto directory\n " +
targetDirectory.getAbsolutePath(),
"File Copy Failed",
JOptionPane.ERROR_MESSAGE);
return;
} finally {
try {
if (is != null) {
is.close();
}
if (os != null) {
os.close();
}
} catch (IOException e) {
}
}
// Remove the source if this is a move operation.
if (action == DnDConstants.ACTION_MOVE &&
System.getProperty("DnDExamples.allowRemove") != null) {
srcFile.delete();
}
// Update the tree display
if (targetNode != null) {
tree.addNode(targetNode, name);
}
}
protected void transferDirectory(int action, File srcDir,
File targetDirectory,
FileTree.FileTreeNode targetNode) {
DnDUtils.debugPrintln(
(action == DnDConstants.ACTION_COPY ? "Copy" : "Move") +
" directory " + srcDir.getAbsolutePath() +
" to " + targetDirectory.getAbsolutePath());
// Do not copy a directory into itself or
// a subdirectory of itself.
File parentDir = targetDirectory;
while (parentDir != null) {
if (parentDir.equals(srcDir)) {
DnDUtils.debugPrintln("-- SUPPRESSED");
return;
}
parentDir = parentDir.getParentFile();
}
// Copy the directory itself, then its contents
// Create a File entry for the target
String name = srcDir.getName();
File newDir = new File(targetDirectory, name);
if (newDir.exists()) {
// Already exists - is it the same directory?
if (newDir.equals(srcDir)) {
// Exactly the same file - ignore
return;
}
} else {
// Directory does not exist - create it
if (newDir.mkdir() == false) {
// Failed to create - abandon this directory
JOptionPane.showMessageDialog(tree,
"Failed to create target directory\n " +
newDir.getAbsolutePath(),
"Directory creation Failed",
JOptionPane.ERROR_MESSAGE);
return;
}
}
// Add a node for the new directory
if (targetNode != null) {
targetNode = tree.addNode(targetNode, name);
}
// Now copy the directory content.
File[] files = srcDir.listFiles();
for (int i = 0; i < files.length; i++) {
File f = files[i];
if (f.isFile()) {
transferFile(action, f, newDir, targetNode);
} else if (f.isDirectory()) {
transferDirectory(action, f, newDir, targetNode);
}
}
// Remove the source directory after moving
if (action == DnDConstants.ACTION_MOVE &&
System.getProperty("DnDExamples.allowRemove") != null) {
srcDir.delete();
}
}
public static void main(String[] args) {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch (Exception evt) {}
final JFrame f = new JFrame("FileTree Drop Target Example");
try {
final FileTree tree = new FileTree("D:\\");
// Add a drop target to the FileTree
FileTreeDropTarget target = new FileTreeDropTarget(tree);
tree.setEditable(true);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent evt) {
System.exit(0);
}
});
JPanel panel = new JPanel();
final JCheckBox editable = new JCheckBox("Editable");
editable.setSelected(true);
panel.add(editable);
editable.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
tree.setEditable(editable.isSelected());
}
});
final JCheckBox enabled = new JCheckBox("Enabled");
enabled.setSelected(true);
panel.add(enabled);
enabled.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
tree.setEnabled(enabled.isSelected());
}
});
f.getContentPane().add(new JScrollPane(tree), BorderLayout.CENTER);
f.getContentPane().add(panel, BorderLayout.SOUTH);
f.setSize(500, 400);
f.setVisible(true);
} catch (Exception e) {
System.out.println("Failed to build GUI: " + e);
}
}
protected FileTree tree;
protected DropTarget dropTarget;
protected boolean acceptableType; // Indicates whether data is acceptable
TreePath[] selections; // Initially selected rows
TreePath leadSelection; // Initial lead selection
boolean copyOverExistingFiles;
}
class FileTree extends JTree implements Autoscroll {
public static final Insets defaultScrollInsets = new Insets(8, 8, 8, 8);
protected Insets scrollInsets = defaultScrollInsets;
public FileTree(String path) throws FileNotFoundException, SecurityException {
super((TreeModel)null); // Create the JTree itself
// Use horizontal and vertical lines
putClientProperty("JTree.lineStyle", "Angled");
// Create the first node
FileTreeNode rootNode = new FileTreeNode(null, path);
// Populate the root node with its subdirectories
boolean addedNodes = rootNode.populateDirectories(true);
setModel(new DefaultTreeModel(rootNode));
// Listen for Tree Selection Events
addTreeExpansionListener(new TreeExpansionHandler());
}
// Returns the full pathname for a path, or null if not a known path
public String getPathName(TreePath path) {
Object o = path.getLastPathComponent();
if (o instanceof FileTreeNode) {
return ((FileTreeNode)o).fullName;
}
return null;
}
// Adds a new node to the tree after construction.
// Returns the inserted node, or null if the parent
// directory has not been expanded.
public FileTreeNode addNode(FileTreeNode parent, String name) {
int index = parent.addNode(name);
if (index != -1) {
((DefaultTreeModel)getModel()).nodesWereInserted(
parent, new int[] { index });
return (FileTreeNode)parent.getChildAt(index);
}
// No node was created
return null;
}
// Autoscrolling support
public void setScrollInsets(Insets insets) {
this.scrollInsets = insets;
}
public Insets getScrollInsets() {
return scrollInsets;
}
// Implementation of Autoscroll interface
public Insets getAutoscrollInsets() {
Rectangle r = getVisibleRect();
Dimension size = getSize();
Insets i = new Insets(r.y + scrollInsets.top, r.x + scrollInsets.left,
size.height - r.y - r.height + scrollInsets.bottom,
size.width - r.x - r.width + scrollInsets.right);
return i;
}
public void autoscroll(Point location) {
JScrollPane scroller =
(JScrollPane)SwingUtilities.getAncestorOfClass(JScrollPane.class, this);
if (scroller != null) {
JScrollBar hBar = scroller.getHorizontalScrollBar();
JScrollBar vBar = scroller.getVerticalScrollBar();
Rectangle r = getVisibleRect();
if (location.x <= r.x + scrollInsets.left) {
// Need to scroll left
hBar.setValue(hBar.getValue() - hBar.getUnitIncrement(-1));
}
if (location.y <= r.y + scrollInsets.top) {
// Need to scroll up
vBar.setValue(vBar.getValue() - vBar.getUnitIncrement(-1));
}
if (location.x >= r.x + r.width - scrollInsets.right) {
// Need to scroll right
hBar.setValue(hBar.getValue() + hBar.getUnitIncrement(1));
}
if (location.y >= r.y + r.height - scrollInsets.bottom) {
// Need to scroll down
vBar.setValue(vBar.getValue() + vBar.getUnitIncrement(1));
}
}
}
// Inner class that represents a node in this file system tree
public static class FileTreeNode extends DefaultMutableTreeNode {
public FileTreeNode(String parent, String name) throws SecurityException,
FileNotFoundException {
this.name = name;
// See if this node exists and whether it is a directory
fullName = parent == null ? name : parent + File.separator + name;
File f = new File(fullName);
if (f.exists() == false) {
throw new FileNotFoundException("File " + fullName + " does not exist");
}
isDir = f.isDirectory();
// Hack for Windows which doesn"t consider a drive to be a directory!
if (isDir == false && f.isFile() == false) {
isDir = true;
}
}
// Override isLeaf to check whether this is a directory
public boolean isLeaf() {
return !isDir;
}
// Override getAllowsChildren to check whether this is a directory
public boolean getAllowsChildren() {
return isDir;
}
// Return whether this is a directory
public boolean isDir() {
return isDir;
}
// Get full path
public String getFullName() {
return fullName;
}
// For display purposes, we return our own name
public String toString() {
return name;
}
// If we are a directory, scan our contents and populate
// with children. In addition, populate those children
// if the "descend" flag is true. We only descend once,
// to avoid recursing the whole subtree.
// Returns true if some nodes were added
boolean populateDirectories(boolean descend) {
boolean addedNodes = false;
// Do this only once
if (populated == false) {
File f;
try {
f = new File(fullName);
} catch (SecurityException e) {
populated = true;
return false;
}
if (interim == true) {
// We have had a quick look here before:
// remove the dummy node that we added last time
removeAllChildren();
interim = false;
}
String[] names = f.list(); // Get list of contents
// Process the contents
ArrayList list = new ArrayList();
for (int i = 0; i < names.length; i++) {
String name = names[i];
File d = new File(fullName, name);
try {
FileTreeNode node = new FileTreeNode(fullName, name);
list.add(node);
if (descend && d.isDirectory()) {
node.populateDirectories(false);
}
addedNodes = true;
if (descend == false) {
// Only add one node if not descending
break;
}
} catch (Throwable t) {
// Ignore phantoms or access problems
}
}
if (addedNodes == true) {
// Now sort the list of contained files and directories
Object[] nodes = list.toArray();
Arrays.sort(nodes, new Comparator() {
public boolean equals(Object o) {
return false;
}
public int compare(Object o1, Object o2) {
FileTreeNode node1 = (FileTreeNode)o1;
FileTreeNode node2 = (FileTreeNode)o2;
// Directories come first
if (node1.isDir != node2.isDir) {
return node1.isDir ? -1 : +1;
}
// Both directories or both files -
// compare based on pathname
return node1.fullName.rupareTo(node2.fullName);
}
});
// Add sorted items as children of this node
for (int j = 0; j < nodes.length; j++) {
this.add((FileTreeNode)nodes[j]);
}
}
// If we were scanning to get all subdirectories,
// or if we found no content, there is no
// reason to look at this directory again, so
// set populated to true. Otherwise, we set interim
// so that we look again in the future if we need to
if (descend == true || addedNodes == false) {
populated = true;
} else {
// Just set interim state
interim = true;
}
}
return addedNodes;
}
// Adding a new file or directory after
// constructing the FileTree. Returns
// the index of the inserted node.
public int addNode(String name) {
// If not populated yet, do nothing
if (populated == true) {
// Do not add a new node if
// the required node is already there
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
FileTreeNode node = (FileTreeNode)getChildAt(i);
if (node.name.equals(name)) {
// Already exists - ensure
// we repopulate
if (node.isDir()) {
node.interim = true;
node.populated = false;
}
return -1;
}
}
// Add a new node
try {
FileTreeNode node = new FileTreeNode(fullName, name);
add(node);
return childCount;
} catch (Exception e) {
}
}
return -1;
}
protected String name; // Name of this component
protected String fullName; // Full pathname
protected boolean populated;// true if we have been populated
protected boolean interim; // true if we are in interim state
protected boolean isDir; // true if this is a directory
}
// Inner class that handles Tree Expansion Events
protected class TreeExpansionHandler implements TreeExpansionListener {
public void treeExpanded(TreeExpansionEvent evt) {
TreePath path = evt.getPath(); // The expanded path
JTree tree = (JTree)evt.getSource(); // The tree
// Get the last component of the path and
// arrange to have it fully populated.
FileTreeNode node = (FileTreeNode)path.getLastPathComponent();
if (node.populateDirectories(true)) {
((DefaultTreeModel)tree.getModel()).nodeStructureChanged(node);
}
}
public void treeCollapsed(TreeExpansionEvent evt) {
// Nothing to do
}
}
}
class DnDUtils {
public static String showActions(int action) {
String actions = "";
if ((action & (DnDConstants.ACTION_LINK|DnDConstants.ACTION_COPY_OR_MOVE)) == 0) {
return "None";
}
if ((action & DnDConstants.ACTION_COPY) != 0) {
actions += "Copy ";
}
if ((action & DnDConstants.ACTION_MOVE) != 0) {
actions += "Move ";
}
if ((action & DnDConstants.ACTION_LINK) != 0) {
actions += "Link";
}
return actions;
}
public static boolean isDebugEnabled() {
return debugEnabled;
}
public static void debugPrintln(String s) {
if (debugEnabled) {
System.out.println(s);
}
}
private static boolean debugEnabled =
(System.getProperty("DnDExamples.debug") != null);
}
Getting and Setting Text on the System Clipboard
import java.awt.Toolkit;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
public class Main {
public static void main(String[] argv) throws Exception {
Transferable t = Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null);
if (t != null && t.isDataFlavorSupported(DataFlavor.stringFlavor)) {
String text = (String) t.getTransferData(DataFlavor.stringFlavor);
System.out.println(text);
}
}
}
Implement drag & drop functionality in your application
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.dnd.DnDConstants;
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.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextArea;
public class Main extends JFrame implements DropTargetListener {
DropTarget dt;
JTextArea ta = new JTextArea();
public Main() {
super("Drop Test");
setSize(300, 300);
getContentPane()
.add(new JLabel("Drop something here:"), BorderLayout.NORTH);
ta.setBackground(Color.white);
getContentPane().add(ta, BorderLayout.CENTER);
dt = new DropTarget(ta, this);
setVisible(true);
}
public void dragEnter(DropTargetDragEvent dtde) {
System.out.println("Drag Enter");
}
public void dragExit(DropTargetEvent dte) {
System.out.println("Drag Exit");
}
public void dragOver(DropTargetDragEvent dtde) {
System.out.println("Drag Over");
}
public void dropActionChanged(DropTargetDragEvent dtde) {
System.out.println("Drop Action Changed");
}
public void drop(DropTargetDropEvent dtde) {
try {
Transferable tr = dtde.getTransferable();
DataFlavor[] flavors = tr.getTransferDataFlavors();
for (int i = 0; i < flavors.length; i++) {
if (flavors[i].isFlavorJavaFileListType()) {
dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
List list = (List) tr.getTransferData(flavors[i]);
for (int j = 0; j < list.size(); j++) {
ta.append(list.get(j) + "\n");
}
dtde.dropComplete(true);
return;
} else if (flavors[i].isFlavorSerializedObjectType()) {
dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
Object o = tr.getTransferData(flavors[i]);
ta.append("Object: " + o);
dtde.dropComplete(true);
return;
} else if (flavors[i].isRepresentationClassInputStream()) {
dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
ta.read(new InputStreamReader((InputStream) tr.getTransferData(flavors[i])),
"from system clipboard");
dtde.dropComplete(true);
return;
}
}
dtde.rejectDrop();
} catch (Exception e) {
e.printStackTrace();
dtde.rejectDrop();
}
}
public static void main(String args[]) {
new Main();
}
}
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();
}
}
JLabel Drag Source
/*
Core SWING Advanced Programming
By Kim Topley
ISBN: 0 13 083292 8
Publisher: Prentice Hall
*/
import java.awt.Font;
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 java.awt.dnd.DragSourceDragEvent;
import java.awt.dnd.DragSourceDropEvent;
import java.awt.dnd.DragSourceEvent;
import java.awt.dnd.DragSourceListener;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.Iterator;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.UIManager;
public class JLabelDragSource implements DragGestureListener,
DragSourceListener {
public JLabelDragSource(JLabel label) {
this.label = label;
// Use the default DragSource
DragSource dragSource = DragSource.getDefaultDragSource();
// Create a DragGestureRecognizer and
// register as the listener
dragSource.createDefaultDragGestureRecognizer(label,
DnDConstants.ACTION_COPY_OR_MOVE, this);
}
// Implementation of DragGestureListener interface.
public void dragGestureRecognized(DragGestureEvent dge) {
if (DnDUtils.isDebugEnabled()) {
DnDUtils.debugPrintln("Initiating event is "
+ dge.getTriggerEvent());
DnDUtils.debugPrintln("Complete event set is:");
Iterator iter = dge.iterator();
while (iter.hasNext()) {
DnDUtils.debugPrintln("\t" + iter.next());
}
}
Transferable transferable = new JLabelTransferable(label);
dge.startDrag(null, transferable, this);
}
// Implementation of DragSourceListener interface
public void dragEnter(DragSourceDragEvent dsde) {
DnDUtils.debugPrintln("Drag Source: dragEnter, drop action = "
+ DnDUtils.showActions(dsde.getDropAction()));
}
public void dragOver(DragSourceDragEvent dsde) {
DnDUtils.debugPrintln("Drag Source: dragOver, drop action = "
+ DnDUtils.showActions(dsde.getDropAction()));
}
public void dragExit(DragSourceEvent dse) {
DnDUtils.debugPrintln("Drag Source: dragExit");
}
public void dropActionChanged(DragSourceDragEvent dsde) {
DnDUtils.debugPrintln("Drag Source: dropActionChanged, drop action = "
+ DnDUtils.showActions(dsde.getDropAction()));
}
public void dragDropEnd(DragSourceDropEvent dsde) {
DnDUtils.debugPrintln("Drag Source: drop completed, drop action = "
+ DnDUtils.showActions(dsde.getDropAction()) + ", success: "
+ dsde.getDropSuccess());
}
public static void main(String[] args) {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch (Exception evt) {}
JFrame f = new JFrame("Draggable JLabel");
JLabel label = new JLabel("Drag this text", JLabel.CENTER);
label.setFont(new Font("Serif", Font.BOLD, 32));
f.getContentPane().add(label);
f.pack();
f.setVisible(true);
// Attach the drag source
JLabelDragSource dragSource = new JLabelDragSource(label);
}
protected JLabel label; // The associated JLabel
}
class DnDUtils {
public static String showActions(int action) {
String actions = "";
if ((action & (DnDConstants.ACTION_LINK | DnDConstants.ACTION_COPY_OR_MOVE)) == 0) {
return "None";
}
if ((action & DnDConstants.ACTION_COPY) != 0) {
actions += "Copy ";
}
if ((action & DnDConstants.ACTION_MOVE) != 0) {
actions += "Move ";
}
if ((action & DnDConstants.ACTION_LINK) != 0) {
actions += "Link";
}
return actions;
}
public static boolean isDebugEnabled() {
return debugEnabled;
}
public static void debugPrintln(String s) {
if (debugEnabled) {
System.out.println(s);
}
}
private static boolean debugEnabled = (System
.getProperty("DnDExamples.debug") != null);
}
class JLabelTransferable implements Transferable {
public JLabelTransferable(JLabel label) {
this.label = label;
}
// Implementation of the Transferable interface
public DataFlavor[] getTransferDataFlavors() {
return flavors;
}
public boolean isDataFlavorSupported(DataFlavor fl) {
for (int i = 0; i < flavors.length; i++) {
if (fl.equals(flavors[i])) {
return true;
}
}
return false;
}
public Object getTransferData(DataFlavor fl) {
if (!isDataFlavorSupported(fl)) {
return null;
}
if (fl.equals(DataFlavor.stringFlavor)) {
// String - return the text as a String
return label.getText() + " (DataFlavor.stringFlavor)";
} else if (fl.equals(jLabelFlavor)) {
// The JLabel itself - just return the label.
return label;
} else {
// Plain text - return an InputStream
try {
String targetText = label.getText() + " (plain text flavor)";
int length = targetText.length();
ByteArrayOutputStream os = new ByteArrayOutputStream();
OutputStreamWriter w = new OutputStreamWriter(os);
w.write(targetText, 0, length);
w.flush();
byte[] bytes = os.toByteArray();
w.close();
return new ByteArrayInputStream(bytes);
} catch (IOException e) {
return null;
}
}
}
// A flavor that transfers a copy of the JLabel
public static final DataFlavor jLabelFlavor = new DataFlavor(JLabel.class,
"Swing JLabel");
private JLabel label; // The label being transferred
private static final DataFlavor[] flavors = new DataFlavor[] {
DataFlavor.stringFlavor,
new DataFlavor("text/plain; charset=ascii", "ASCII text"),
jLabelFlavor };
}
JTextArea subclass allows TransferableColor objects to
/*
* This example is from the book "Java Foundation Classes in a Nutshell".
* Written by David Flanagan. Copyright (c) 1999 by O"Reilly & Associates.
* You may distribute this source code for non-commercial purposes only.
* You may study, modify, and use this example for any purpose, as long as
* this notice is retained. Note that this example is provided "as is",
* WITHOUT WARRANTY of any kind either expressed or implied.
*/
import java.awt.*;
import java.awt.event.*;
import java.awt.datatransfer.*;
import java.awt.dnd.*;
import javax.swing.*;
import javax.swing.border.*;
import java.io.*;
import java.util.List;
/**
* This simple JTextArea subclass allows TransferableColor objects to
* be pasted or dropped into it. It also supports the pasting of
* text, and the dropping of File objects.
*/
public class ColorSink extends JTextArea implements DropTargetListener {
/** Create a new ColorSink object */
public ColorSink() {
// Listen for double clicks. Use them to trigger a paste action.
addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2) { pastecolor(); e.consume(); }
}
});
// We have to create a DropTarget object to support Drag-and-Drop
// It will listen for drops on top of us, and notify our DropTargetListener
// methods when drag-and-drop related events occur.
setDropTarget(new DropTarget(this, this));
}
// This method is invoked when the user double-clicks on us. It attempts
// to paste a color or text. Note that the JTextArea we extend
// already supports cut-and-paste of text through the Ctrl-V keystroke.
// This adds a different kind of cut-and-paste for demonstration purposes.
public void pastecolor() {
// Get the clipboard, and read its contents
Clipboard c = this.getToolkit().getSystemClipboard();
Transferable t = c.getContents(this);
if (t == null) { // If nothing to paste
this.getToolkit().beep(); // then beep and do nothing
return;
}
try {
// If the clipboard contained a color, use it as the background color
if (t.isDataFlavorSupported(TransferableColor.colorFlavor)) {
Color color = (Color) t.getTransferData(TransferableColor.colorFlavor);
this.setBackground(color);
}
// If the clipboard contained text, insert it.
else if (t.isDataFlavorSupported(DataFlavor.stringFlavor)) {
String s = (String) t.getTransferData(DataFlavor.stringFlavor);
this.replaceSelection(s);
}
// Otherwise, we don"t know how to paste the data, so just beep.
else this.getToolkit().beep();
}
catch (UnsupportedFlavorException ex) { this.getToolkit().beep(); }
catch (IOException ex) { this.getToolkit().beep(); }
}
// The methods below are the methods of DropTargetListener.
// They are invoked at various times when something is being
// dragged over us, and allow us an opportunity to respond to the drag
// This is the border we display when the user is dragging over us.
protected static Border dropBorder = new BevelBorder(BevelBorder.LOWERED);
// Something is being dragged over us. If we can support this data type
// tell the drag-and-drop system that we are interested, and display
// a special border to tell the user that we"re intereted.
public void dragEnter(DropTargetDragEvent e) {
if (e.isDataFlavorSupported(TransferableColor.colorFlavor) ||
e.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
e.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE);
this.setBorder(dropBorder);
}
}
/** The user is no longer dragging over us, so restore the default border */
public void dragExit(DropTargetEvent e) { this.setBorder(null); }
/** This method is invoked when the user drops something on us */
public void drop(DropTargetDropEvent e){
this.setBorder(null); // Restore the default border
Transferable t = e.getTransferable(); // Get the data that was dropped
// Check for types of data that we support
if (t.isDataFlavorSupported(TransferableColor.colorFlavor)) {
// If it was a color, accept it, and use it as the background color
e.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
try {
Color c = (Color) t.getTransferData(TransferableColor.colorFlavor);
this.setBackground(c);
e.dropComplete(true);
}
catch (Exception ex) { e.dropComplete(false); }
}
else if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
// If it was a file list, accept it, read the first file in the list
// and display the file contents
e.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
try {
List files = (List) t.getTransferData(DataFlavor.javaFileListFlavor);
File f = (File) files.get(0);
BufferedReader in = new BufferedReader(new FileReader(f));
String s;
this.setText("");
while((s = in.readLine()) != null) this.append(s);
e.dropComplete(true);
}
catch (Exception ex) { e.dropComplete(false); }
}
else { // If it wasn"t a color or a file list, reject it.
e.rejectDrop();
return;
}
}
// These are unused DropTargetListener methods
public void dragOver(DropTargetDragEvent e) {}
public void dropActionChanged(DropTargetDragEvent e) {}
/** This is a simple test program for ColorSource and ColorSink */
public static void main(String[] args) {
// Create a window
JFrame f = new JFrame("ColorSourceTest");
f.getContentPane().setLayout(new BorderLayout());
// Add some ColorSources
JPanel panel = new JPanel();
f.getContentPane().add(panel, BorderLayout.NORTH);
panel.add(new ColorSource(Color.yellow));
panel.add(new ColorSource(Color.pink));
panel.add(new ColorSource(Color.white));
panel.add(new ColorSource(Color.gray));
// Add a ColorSink
ColorSink sink = new ColorSink();
f.getContentPane().add(sink, BorderLayout.CENTER);
// Pop it all up
f.setSize(400, 300);
f.show();
}
}
LabelDnD2 allows dropping color onto the foreground of the JLabel
/* From http://java.sun.ru/docs/books/tutorial/index.html */
/*
* Copyright (c) 2006 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:
*
* -Redistribution of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* -Redistribution 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, Inc. or the names of contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* 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 MIDROSYSTEMS, INC. ("SUN")
* AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
* AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS 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 THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed, licensed or intended
* for use in the design, construction, operation or maintenance of any
* nuclear facility.
*/
/*
* LabelDnD2.java is a 1.4 example that requires no other files.
*/
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.BorderFactory;
import javax.swing.JColorChooser;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.TransferHandler;
import javax.swing.border.TitledBorder;
//LabelDnD2 allows dropping color onto the foreground
//of the JLabel.
public class LabelDnD2 extends JPanel {
JTextField textField;
JLabel label;
public LabelDnD2() {
super(new BorderLayout());
JColorChooser chooser = new JColorChooser();
chooser.setDragEnabled(true);
label = new JLabel("I"m a Label and I accept color!",
SwingConstants.LEADING);
label.setTransferHandler(new TransferHandler("foreground"));
MouseListener listener = new DragMouseAdapter();
label.addMouseListener(listener);
JPanel lpanel = new JPanel(new GridLayout(1, 1));
TitledBorder t2 = BorderFactory
.createTitledBorder("JLabel: drop color onto the label");
lpanel.add(label);
lpanel.setBorder(t2);
add(chooser, BorderLayout.CENTER);
add(lpanel, BorderLayout.PAGE_END);
setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
}
private class DragMouseAdapter extends MouseAdapter {
public void mousePressed(MouseEvent e) {
JComponent c = (JComponent) e.getSource();
TransferHandler handler = c.getTransferHandler();
handler.exportAsDrag(c, e, TransferHandler.COPY);
}
}
/**
* Create the GUI and show it. For thread safety, this method should be
* invoked from the event-dispatching thread.
*/
private static void createAndShowGUI() {
//Make sure we have nice window decorations.
JFrame.setDefaultLookAndFeelDecorated(true);
//Create and set up the window.
JFrame frame = new JFrame("LabelDnD2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Create and set up the content pane.
JComponent newContentPane = new LabelDnD2();
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();
}
});
}
}
Label DnD (Drag and Drop)
/* From http://java.sun.ru/docs/books/tutorial/index.html */
/*
* Copyright (c) 2006 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:
*
* -Redistribution of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* -Redistribution 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, Inc. or the names of contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* 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 MIDROSYSTEMS, INC. ("SUN")
* AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
* AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS 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 THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed, licensed or intended
* for use in the design, construction, operation or maintenance of any
* nuclear facility.
*/
/*
* LabelDnD.java is a 1.4 example that requires no other files.
*/
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.TransferHandler;
import javax.swing.border.TitledBorder;
public class LabelDnD extends JPanel {
JTextField textField;
JLabel label;
public LabelDnD() {
super(new GridLayout(2, 1));
textField = new JTextField(40);
textField.setDragEnabled(true);
JPanel tfpanel = new JPanel(new GridLayout(1, 1));
TitledBorder t1 = BorderFactory
.createTitledBorder("JTextField: drag and drop is enabled");
tfpanel.add(textField);
tfpanel.setBorder(t1);
label = new JLabel("I"m a Label!", SwingConstants.LEADING);
label.setTransferHandler(new TransferHandler("text"));
MouseListener listener = new DragMouseAdapter();
label.addMouseListener(listener);
JPanel lpanel = new JPanel(new GridLayout(1, 1));
TitledBorder t2 = BorderFactory
.createTitledBorder("JLabel: drag from or drop to this label");
lpanel.add(label);
lpanel.setBorder(t2);
add(tfpanel);
add(lpanel);
setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
}
private class DragMouseAdapter extends MouseAdapter {
public void mousePressed(MouseEvent e) {
JComponent c = (JComponent) e.getSource();
TransferHandler handler = c.getTransferHandler();
handler.exportAsDrag(c, e, TransferHandler.COPY);
}
}
/**
* Create the GUI and show it. For thread safety, this method should be
* invoked from the event-dispatching thread.
*/
private static void createAndShowGUI() {
//Make sure we have nice window decorations.
JFrame.setDefaultLookAndFeelDecorated(true);
//Create and set up the window.
JFrame frame = new JFrame("LabelDnD");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Create and set up the content pane.
JComponent newContentPane = new LabelDnD();
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();
}
});
}
}
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");
}
}
Panel Drop Target
/*
Core SWING Advanced Programming
By Kim Topley
ISBN: 0 13 083292 8
Publisher: Prentice Hall
*/
import java.awt.BorderLayout;
import java.awt.ruponent;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.DnDConstants;
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.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.UIManager;
public class PanelDropTarget implements DropTargetListener {
public PanelDropTarget(JPanel pane) {
this.pane = pane;
// Create the DropTarget and register
// it with the JPanel.
dropTarget = new DropTarget(pane, DnDConstants.ACTION_COPY_OR_MOVE,
this, true, null);
}
// Implementation of the DropTargetListener interface
public void dragEnter(DropTargetDragEvent dtde) {
DnDUtils.debugPrintln("dragEnter, drop action = "
+ DnDUtils.showActions(dtde.getDropAction()));
// Get the type of object being transferred and determine
// whether it is appropriate.
checkTransferType(dtde);
// Accept or reject the drag.
acceptOrRejectDrag(dtde);
}
public void dragExit(DropTargetEvent dte) {
DnDUtils.debugPrintln("DropTarget dragExit");
}
public void dragOver(DropTargetDragEvent dtde) {
DnDUtils.debugPrintln("DropTarget dragOver, drop action = "
+ DnDUtils.showActions(dtde.getDropAction()));
// Accept or reject the drag
acceptOrRejectDrag(dtde);
}
public void dropActionChanged(DropTargetDragEvent dtde) {
DnDUtils.debugPrintln("DropTarget dropActionChanged, drop action = "
+ DnDUtils.showActions(dtde.getDropAction()));
// Accept or reject the drag
acceptOrRejectDrag(dtde);
}
public void drop(DropTargetDropEvent dtde) {
DnDUtils.debugPrintln("DropTarget drop, drop action = "
+ DnDUtils.showActions(dtde.getDropAction()));
// Check the drop action
if ((dtde.getDropAction() & DnDConstants.ACTION_COPY_OR_MOVE) != 0) {
// Accept the drop and get the transfer data
dtde.acceptDrop(dtde.getDropAction());
Transferable transferable = dtde.getTransferable();
try {
boolean result = dropComponent(transferable);
dtde.dropComplete(result);
DnDUtils.debugPrintln("Drop completed, success: " + result);
} catch (Exception e) {
DnDUtils.debugPrintln("Exception while handling drop " + e);
dtde.dropComplete(false);
}
} else {
DnDUtils.debugPrintln("Drop target rejected drop");
dtde.rejectDrop();
}
}
// Internal methods start here
protected boolean acceptOrRejectDrag(DropTargetDragEvent dtde) {
int dropAction = dtde.getDropAction();
int sourceActions = dtde.getSourceActions();
boolean acceptedDrag = false;
DnDUtils.debugPrintln("\tSource actions are "
+ DnDUtils.showActions(sourceActions) + ", drop action is "
+ DnDUtils.showActions(dropAction));
// Reject if the object being transferred
// or the operations available are not acceptable.
if (!acceptableType
|| (sourceActions & DnDConstants.ACTION_COPY_OR_MOVE) == 0) {
DnDUtils.debugPrintln("Drop target rejecting drag");
dtde.rejectDrag();
} else if ((dropAction & DnDConstants.ACTION_COPY_OR_MOVE) == 0) {
// Not offering copy or move - suggest a copy
DnDUtils.debugPrintln("Drop target offering COPY");
dtde.acceptDrag(DnDConstants.ACTION_COPY);
acceptedDrag = true;
} else {
// Offering an acceptable operation: accept
DnDUtils.debugPrintln("Drop target accepting drag");
dtde.acceptDrag(dropAction);
acceptedDrag = true;
}
return acceptedDrag;
}
protected void checkTransferType(DropTargetDragEvent dtde) {
// Only accept a flavor that returns a Component
acceptableType = false;
DataFlavor[] fl = dtde.getCurrentDataFlavors();
for (int i = 0; i < fl.length; i++) {
Class dataClass = fl[i].getRepresentationClass();
if (Component.class.isAssignableFrom(dataClass)) {
// This flavor returns a Component - accept it.
targetFlavor = fl[i];
acceptableType = true;
break;
}
}
DnDUtils.debugPrintln("File type acceptable - " + acceptableType);
}
protected boolean dropComponent(Transferable transferable)
throws IOException, UnsupportedFlavorException {
Object o = transferable.getTransferData(targetFlavor);
if (o instanceof Component) {
DnDUtils.debugPrintln("Dragged component class is "
+ o.getClass().getName());
pane.add((Component) o);
pane.validate();
return true;
}
return false;
}
public static void main(String[] args) {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch (Exception evt) {}
final JFrame f = new JFrame("Component drop target example");
JPanel pane = new JPanel();
// Add a drop target to the JPanel
PanelDropTarget target = new PanelDropTarget(pane);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent evt) {
System.exit(0);
}
});
f.getContentPane().add(new JScrollPane(pane), BorderLayout.CENTER);
f.setSize(500, 400);
f.setVisible(true);
}
protected JPanel pane;
protected DropTarget dropTarget;
protected boolean acceptableType; // Indicates whether data is acceptable
protected DataFlavor targetFlavor; // Flavor to use for transfer
}
class DnDUtils {
public static String showActions(int action) {
String actions = "";
if ((action & (DnDConstants.ACTION_LINK | DnDConstants.ACTION_COPY_OR_MOVE)) == 0) {
return "None";
}
if ((action & DnDConstants.ACTION_COPY) != 0) {
actions += "Copy ";
}
if ((action & DnDConstants.ACTION_MOVE) != 0) {
actions += "Move ";
}
if ((action & DnDConstants.ACTION_LINK) != 0) {
actions += "Link";
}
return actions;
}
public static boolean isDebugEnabled() {
return debugEnabled;
}
public static void debugPrintln(String s) {
if (debugEnabled) {
System.out.println(s);
}
}
private static boolean debugEnabled = (System
.getProperty("DnDExamples.debug") != null);
}
Setting text drag in a JTextArea
import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class Main {
public static void main(String[] args) {
JFrame frame = new JFrame();
JTextArea textarea = new JTextArea();
textarea.setDragEnabled(true);
textarea.setText("Drag target");
frame.getContentPane().add(BorderLayout.CENTER, textarea);
JTextField textarea1 = new JTextField();
textarea1.setText("Drop target");
frame.getContentPane().add(BorderLayout.SOUTH, textarea1);
frame.setSize(500, 300);
frame.setVisible(true);
frame.setLocation(100, 100);
}
}
Test of the DragGesture classes and JList to see if we
/*
Java Swing, 2nd Edition
By Marc Loy, Robert Eckstein, Dave Wood, James Elliott, Brian Cole
ISBN: 0-596-00408-7
Publisher: O"Reilly
*/
// GestureTest.java
//A simple (?) test of the DragGesture classes to see if we
//can recognize a simple drag gesture.
//
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 java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.ListSelectionModel;
public class GestureTest extends JFrame implements DragGestureListener {
DragSource ds;
JList jl;
String[] items = { "Java", "C", "C++", "Lisp", "Perl", "Python" };
public GestureTest() {
super("Gesture Test");
setSize(200, 150);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent we) {
System.exit(0);
}
});
jl = new JList(items);
jl.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
getContentPane().add(new JScrollPane(jl), BorderLayout.CENTER);
ds = new DragSource();
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 GestureTest();
}
}
Transferable Color
/*
* This example is from the book "Java Foundation Classes in a Nutshell".
* Written by David Flanagan. Copyright (c) 1999 by O"Reilly & Associates.
* You may distribute this source code for non-commercial purposes only.
* You may study, modify, and use this example for any purpose, as long as
* this notice is retained. Note that this example is provided "as is",
* WITHOUT WARRANTY of any kind either expressed or implied.
*/
import java.awt.Color;
import java.awt.datatransfer.*;
import java.io.*;
/**
* This class is used to transfer a Color object via cut-and-paste or
* drag-and-drop. It allows a color to be transfered as a Color object,
* or as a string. Due to a long-standing bug in Java 1.1 and Java 2,
* transferring a color as a string to native Windows applications will
* not work.
*/
public class TransferableColor implements Transferable {
// This DataFlavor object is used when we transfer Color objects directly
protected static DataFlavor colorFlavor =
new DataFlavor(Color.class, "Java Color Object");
// These are the data flavors we support.
protected static DataFlavor[] supportedFlavors = {
colorFlavor, // Transfer as a Color object
DataFlavor.stringFlavor, // Transfer as a String object
DataFlavor.plainTextFlavor, // Transfer as a stream of unicode text
};
Color color; // The color we encapsulate and transfer
/** Create a new TransferableColor that encapsulates the specified color */
public TransferableColor(Color color) { this.color = color; }
/** Return a list of DataFlavors we can support */
public DataFlavor[] getTransferDataFlavors() { return supportedFlavors; }
/** Check whether a specified DataFlavor is available */
public boolean isDataFlavorSupported(DataFlavor flavor) {
if (flavor.equals(colorFlavor) ||
flavor.equals(DataFlavor.stringFlavor) ||
flavor.equals(DataFlavor.plainTextFlavor)) return true;
return false;
}
/**
* Transfer the data. Given a specified DataFlavor, return an Object
* appropriate for that flavor. Throw UnsupportedFlavorException if we
* don"t support the requested flavor.
*/
public Object getTransferData(DataFlavor flavor)
throws UnsupportedFlavorException, IOException
{
if (flavor.equals(colorFlavor)) return color;
else if (flavor.equals(DataFlavor.stringFlavor)) return color.toString();
else if (flavor.equals(DataFlavor.plainTextFlavor))
return new ByteArrayInputStream(color.toString().getBytes("Unicode"));
else throw new UnsupportedFlavorException(flavor);
}
}
TransferHandler subclass wraps another TransferHandler and delegates most of its operations to the wrapped handler
/*
* 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.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.InputEvent;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.util.List;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.TransferHandler;
/**
* This TransferHandler subclass wraps another TransferHandler and delegates
* most of its operations to the wrapped handler. It adds the ability to to drop
* or paste files using the predefined DataFlavor.javaFileListFlavor. When a
* file list is pasted or dropped, it assumes the files are text, reads them in
* order, concatenates their contents, and then passes the resulting string to
* the wrapped handler for insertion.
*/
public class FileTransferHandler extends TransferHandler {
TransferHandler wrappedHandler; // The handler that we wrap
// We use this array to test the wrapped handler
static DataFlavor[] stringFlavorArray = new DataFlavor[] { DataFlavor.stringFlavor };
/** Pass an existing TransferHandler to this constructor */
public FileTransferHandler(TransferHandler wrappedHandler) {
if (wrappedHandler == null) // Fail immediately on null
throw new NullPointerException();
this.wrappedHandler = wrappedHandler; // Remember wrapped handler
}
/**
* This method returns true if the TransferHandler knows how to work with one
* of the specified flavors. This implementation first checks the superclass,
* then checks for fileListFlavor support
*/
public boolean canImport(JComponent c, DataFlavor[] flavors) {
// If the wrapped handler can import it, we"re done
if (wrappedHandler.canImport(c, flavors))
return true;
// Otherwise, if the wrapped handler can handle string imports, then
// see if we are being offered a list of files that we can convert
// to a string.
if (wrappedHandler.canImport(c, stringFlavorArray)) {
for (int i = 0; i < flavors.length; i++)
if (flavors[i].equals(DataFlavor.javaFileListFlavor))
return true;
}
// Otherwise, we can"t import any of the flavors.
return false;
}
/**
* If the wrapped handler can import strings and the specified Transferable
* can provide its data as a List of File objects, then we read the files, and
* pass their contents as a string to the wrapped handler. Otherwise, we offer
* the Transferable to the wrapped handler to handle on its own.
*/
public boolean importData(JComponent c, Transferable t) {
// See if we"re offered a java.util.List of java.io.File objects.
// We handle this case first because the Transferable is likely to
// also offer the filenames as strings, and we want to import the
// file contents, not their names!
if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor)
&& wrappedHandler.canImport(c, stringFlavorArray)) {
try {
List filelist = (List) t.getTransferData(DataFlavor.javaFileListFlavor);
// Loop through the files to determine total size
int numfiles = filelist.size();
int numbytes = 0;
for (int i = 0; i < numfiles; i++) {
File f = (File) filelist.get(i);
numbytes += (int) f.length();
}
// There will never be more characters than bytes in the files
char[] text = new char[numbytes]; // to hold file contents
int p = 0; // current position in the text[] array
// Loop through the files again, reading their content as text
for (int i = 0; i < numfiles; i++) {
File f = (File) filelist.get(i);
Reader r = new BufferedReader(new FileReader(f));
p += r.read(text, p, (int) f.length());
}
// Convert the character array to a string and wrap it
// in a pre-defined Transferable class for transferring strings
StringSelection selection = new StringSelection(new String(text, 0, p));
// Ask the wrapped handler to import the string
return wrappedHandler.importData(c, selection);
}
// If anything goes wrong, just beep to tell the user
catch (UnsupportedFlavorException e) {
c.getToolkit().beep(); // audible error
return false; // return failure code
} catch (IOException e) {
c.getToolkit().beep(); // audible error
return false; // return failure code
}
}
// Otherwise let the wrapped class handle this transferable itself
return wrappedHandler.importData(c, t);
}
/*
* The following methods just delegate to the wrapped TransferHandler
*/
public void exportAsDrag(JComponent c, InputEvent e, int action) {
wrappedHandler.exportAsDrag(c, e, action);
}
public void exportToClipboard(JComponent c, Clipboard clip, int action) {
wrappedHandler.exportToClipboard(c, clip, action);
}
public int getSourceActions(JComponent c) {
return wrappedHandler.getSourceActions(c);
}
public Icon getVisualRepresentation(Transferable t) {
// This method is not currently (Java 1.4) used by Swing
return wrappedHandler.getVisualRepresentation(t);
}
/**
* This class demonstrates the FileTransferHandler by installing it on a
* JTextArea component and providing a JFileChooser to drag and cut files.
*/
public static void main(String[] args) {
// Here"s the text area. Note how we wrap our TransferHandler
// around the default handler returned by getTransferHandler()
JTextArea textarea = new JTextArea();
TransferHandler defaultHandler = textarea.getTransferHandler();
textarea.setTransferHandler(new FileTransferHandler(defaultHandler));
// Here"s a JFileChooser, with dragging explicitly enabled.
JFileChooser filechooser = new JFileChooser();
filechooser.setDragEnabled(true);
// Display them both in a window
JFrame f = new JFrame("File Transfer Handler Test");
f.getContentPane().add(new JScrollPane(textarea), "Center");
f.getContentPane().add(filechooser, "South");
f.setSize(400, 600);
f.setVisible(true);
}
}
Use drag and drop to reorder a list
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.DragGestureRecognizer;
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.DefaultListModel;
import javax.swing.DropMode;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.TransferHandler;
public class DragDropList extends JList {
DefaultListModel model;
public DragDropList() {
super(new DefaultListModel());
model = (DefaultListModel) getModel();
setDragEnabled(true);
setDropMode(DropMode.INSERT);
setTransferHandler(new MyListDropHandler(this));
new MyDragListener(this);
model.addElement("a");
model.addElement("b");
model.addElement("c");
}
public static void main(String[] a){
JFrame f = new JFrame();
f.add(new JScrollPane(new DragDropList()));
f.setSize(300,300);
f.setVisible(true);
}
}
class MyDragListener implements DragSourceListener, DragGestureListener {
DragDropList list;
DragSource ds = new DragSource();
public MyDragListener(DragDropList list) {
this.list = list;
DragGestureRecognizer dgr = ds.createDefaultDragGestureRecognizer(list,
DnDConstants.ACTION_MOVE, this);
}
public void dragGestureRecognized(DragGestureEvent dge) {
StringSelection transferable = new StringSelection(Integer.toString(list.getSelectedIndex()));
ds.startDrag(dge, DragSource.DefaultCopyDrop, transferable, this);
}
public void dragEnter(DragSourceDragEvent dsde) {
}
public void dragExit(DragSourceEvent dse) {
}
public void dragOver(DragSourceDragEvent dsde) {
}
public void dragDropEnd(DragSourceDropEvent dsde) {
if (dsde.getDropSuccess()) {
System.out.println("Succeeded");
} else {
System.out.println("Failed");
}
}
public void dropActionChanged(DragSourceDragEvent dsde) {
}
}
class MyListDropHandler extends TransferHandler {
DragDropList list;
public MyListDropHandler(DragDropList list) {
this.list = list;
}
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 indexString;
try {
indexString = (String) transferable.getTransferData(DataFlavor.stringFlavor);
} catch (Exception e) {
return false;
}
int index = Integer.parseInt(indexString);
JList.DropLocation dl = (JList.DropLocation) support.getDropLocation();
int dropTargetIndex = dl.getIndex();
System.out.println(dropTargetIndex + " : ");
System.out.println("inserted");
return true;
}
}