Tree: Drag and Drop
/*
Definitive Guide to Swing for Java 2, Second Edition
By John Zukowski
ISBN: 1-893115-78-X
Publisher: APress
*/
import java.awt.BorderLayout;
import java.awt.Insets;
import java.awt.Point;
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.DragSourceContext;
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.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.Iterator;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
public class TreeTester {
public static void main(String args[]) {
JFrame f = new JFrame("Tree Dragging Tester");
DndTree tree1 = new DndTree();
JScrollPane leftPane = new JScrollPane(tree1);
DndTree tree2 = new DndTree();
JScrollPane rightPane = new JScrollPane(tree2);
JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
leftPane, rightPane);
f.getContentPane().add(splitPane, BorderLayout.CENTER);
f.setSize(300, 200);
f.setVisible(true);
}
}
class DndTree extends JTree implements Autoscroll {
private Insets insets;
private int top = 0, bottom = 0, topRow = 0, bottomRow = 0;
public DndTree() {
DragSource dragSource = DragSource.getDefaultDragSource();
dragSource
.createDefaultDragGestureRecognizer(this,
DnDConstants.ACTION_COPY_OR_MOVE,
new TreeDragGestureListener());
DropTarget dropTarget = new DropTarget(this,
new TreeDropTargetListener());
}
public DndTree(TreeModel model) {
super(model);
DragSource dragSource = DragSource.getDefaultDragSource();
dragSource
.createDefaultDragGestureRecognizer(this,
DnDConstants.ACTION_COPY_OR_MOVE,
new TreeDragGestureListener());
DropTarget dropTarget = new DropTarget(this,
new TreeDropTargetListener());
}
public Insets getAutoscrollInsets() {
return insets;
}
public void autoscroll(Point p) {
// Only support up/down scrolling
top = Math.abs(getLocation().y) + 10;
bottom = top + getParent().getHeight() - 20;
int next;
if (p.y < top) {
next = topRow--;
bottomRow++;
scrollRowToVisible(next);
} else if (p.y > bottom) {
next = bottomRow++;
topRow--;
scrollRowToVisible(next);
}
}
private static class TreeDragGestureListener implements DragGestureListener {
public void dragGestureRecognized(DragGestureEvent dragGestureEvent) {
// Can only drag leafs
JTree tree = (JTree) dragGestureEvent.getComponent();
TreePath path = tree.getSelectionPath();
if (path == null) {
// Nothing selected, nothing to drag
System.out.println("Nothing selected - beep");
tree.getToolkit().beep();
} else {
DefaultMutableTreeNode selection = (DefaultMutableTreeNode) path
.getLastPathComponent();
if (selection.isLeaf()) {
TransferableTreeNode node = new TransferableTreeNode(
selection);
dragGestureEvent.startDrag(DragSource.DefaultCopyDrop,
node, new MyDragSourceListener());
} else {
System.out.println("Not a leaf - beep");
tree.getToolkit().beep();
}
}
}
}
private class TreeDropTargetListener implements DropTargetListener {
public void dragEnter(DropTargetDragEvent dropTargetDragEvent) {
// Setup positioning info for auto-scrolling
top = Math.abs(getLocation().y);
bottom = top + getParent().getHeight();
topRow = getClosestRowForLocation(0, top);
bottomRow = getClosestRowForLocation(0, bottom);
insets = new Insets(top + 10, 0, bottom - 10, getWidth());
}
public void dragExit(DropTargetEvent dropTargetEvent) {
}
public void dragOver(DropTargetDragEvent dropTargetDragEvent) {
}
public void dropActionChanged(DropTargetDragEvent dropTargetDragEvent) {
}
public synchronized void drop(DropTargetDropEvent dropTargetDropEvent) {
// Only support dropping over nodes that aren't leafs
Point location = dropTargetDropEvent.getLocation();
TreePath path = getPathForLocation(location.x, location.y);
Object node = path.getLastPathComponent();
if ((node != null) && (node instanceof TreeNode)
&& (!((TreeNode) node).isLeaf())) {
try {
Transferable tr = dropTargetDropEvent.getTransferable();
if (tr
.isDataFlavorSupported(TransferableTreeNode.DEFAULT_MUTABLE_TREENODE_FLAVOR)) {
dropTargetDropEvent
.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
Object userObject = tr
.getTransferData(TransferableTreeNode.DEFAULT_MUTABLE_TREENODE_FLAVOR);
addElement(path, userObject);
dropTargetDropEvent.dropComplete(true);
} else if (tr
.isDataFlavorSupported(DataFlavor.stringFlavor)) {
dropTargetDropEvent
.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
String string = (String) tr
.getTransferData(DataFlavor.stringFlavor);
addElement(path, string);
dropTargetDropEvent.dropComplete(true);
} else if (tr
.isDataFlavorSupported(DataFlavor.plainTextFlavor)) {
dropTargetDropEvent
.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
Object stream = tr
.getTransferData(DataFlavor.plainTextFlavor);
if (stream instanceof InputStream) {
InputStreamReader isr = new InputStreamReader(
(InputStream) stream);
BufferedReader reader = new BufferedReader(isr);
String line;
while ((line = reader.readLine()) != null) {
addElement(path, line);
}
dropTargetDropEvent.dropComplete(true);
} else if (stream instanceof Reader) {
BufferedReader reader = new BufferedReader(
(Reader) stream);
String line;
while ((line = reader.readLine()) != null) {
addElement(path, line);
}
dropTargetDropEvent.dropComplete(true);
} else {
System.err.println("Unknown type: "
+ stream.getClass());
dropTargetDropEvent.rejectDrop();
}
} else if (tr
.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
dropTargetDropEvent
.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
List fileList = (List) tr
.getTransferData(DataFlavor.javaFileListFlavor);
Iterator iterator = fileList.iterator();
while (iterator.hasNext()) {
File file = (File) iterator.next();
addElement(path, file.toURL());
}
dropTargetDropEvent.dropComplete(true);
} else {
System.err.println("Rejected");
dropTargetDropEvent.rejectDrop();
}
} catch (IOException io) {
io.printStackTrace();
dropTargetDropEvent.rejectDrop();
} catch (UnsupportedFlavorException ufe) {
ufe.printStackTrace();
dropTargetDropEvent.rejectDrop();
}
} else {
System.out.println("Can't drop on a leaf");
dropTargetDropEvent.rejectDrop();
}
}
private void addElement(TreePath path, Object element) {
DefaultMutableTreeNode parent = (DefaultMutableTreeNode) path
.getLastPathComponent();
DefaultMutableTreeNode node = new DefaultMutableTreeNode(element);
System.out.println("Added: " + node + " to " + parent);
DefaultTreeModel model = (DefaultTreeModel) (DndTree.this
.getModel());
model.insertNodeInto(node, parent, parent.getChildCount());
}
}
private static class MyDragSourceListener implements DragSourceListener {
public void dragDropEnd(DragSourceDropEvent dragSourceDropEvent) {
if (dragSourceDropEvent.getDropSuccess()) {
int dropAction = dragSourceDropEvent.getDropAction();
if (dropAction == DnDConstants.ACTION_MOVE) {
System.out.println("MOVE: remove node");
}
}
}
public void dragEnter(DragSourceDragEvent dragSourceDragEvent) {
DragSourceContext context = dragSourceDragEvent
.getDragSourceContext();
int dropAction = dragSourceDragEvent.getDropAction();
if ((dropAction & DnDConstants.ACTION_COPY) != 0) {
context.setCursor(DragSource.DefaultCopyDrop);
} else if ((dropAction & DnDConstants.ACTION_MOVE) != 0) {
context.setCursor(DragSource.DefaultMoveDrop);
} else {
context.setCursor(DragSource.DefaultCopyNoDrop);
}
}
public void dragExit(DragSourceEvent dragSourceEvent) {
}
public void dragOver(DragSourceDragEvent dragSourceDragEvent) {
}
public void dropActionChanged(DragSourceDragEvent dragSourceDragEvent) {
}
}
}
class TransferableTreeNode extends DefaultMutableTreeNode implements
Transferable {
final static int TREE = 0;
final static int STRING = 1;
final static int PLAIN_TEXT = 1;
final public static DataFlavor DEFAULT_MUTABLE_TREENODE_FLAVOR = new DataFlavor(
DefaultMutableTreeNode.class, "Default Mutable Tree Node");
static DataFlavor flavors[] = { DEFAULT_MUTABLE_TREENODE_FLAVOR,
DataFlavor.stringFlavor, DataFlavor.plainTextFlavor };
private DefaultMutableTreeNode data;
public TransferableTreeNode(DefaultMutableTreeNode data) {
this.data = data;
}
public DataFlavor[] getTransferDataFlavors() {
return flavors;
}
public Object getTransferData(DataFlavor flavor)
throws UnsupportedFlavorException, IOException {
Object returnObject;
if (flavor.equals(flavors[TREE])) {
Object userObject = data.getUserObject();
if (userObject == null) {
returnObject = data;
} else {
returnObject = userObject;
}
} else if (flavor.equals(flavors[STRING])) {
Object userObject = data.getUserObject();
if (userObject == null) {
returnObject = data.toString();
} else {
returnObject = userObject.toString();
}
} else if (flavor.equals(flavors[PLAIN_TEXT])) {
Object userObject = data.getUserObject();
String string;
if (userObject == null) {
string = data.toString();
} else {
string = userObject.toString();
}
returnObject = new ByteArrayInputStream(string.getBytes("Unicode"));
} else {
throw new UnsupportedFlavorException(flavor);
}
return returnObject;
}
public boolean isDataFlavorSupported(DataFlavor flavor) {
boolean returnValue = false;
for (int i = 0, n = flavors.length; i < n; i++) {
if (flavor.equals(flavors[i])) {
returnValue = true;
break;
}
}
return returnValue;
}
}
Related examples in the same category