/*
Java Swing, 2nd Edition
By Marc Loy, Robert Eckstein, Dave Wood, James Elliott, Brian Cole
ISBN: 0-596-00408-7
Publisher: O'Reilly
*/
// TreeDragTest.java
//A simple starting point for testing the DnD JTree code.
//
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
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.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 java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetContext;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.dnd.DropTargetEvent;
import java.awt.dnd.DropTargetListener;
import java.io.IOException;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
public class TreeDragTest extends JFrame {
TreeDragSource ds;
TreeDropTarget dt;
JTree tree;
public TreeDragTest() {
super("Rearrangeable Tree");
setSize(300, 200);
setDefaultCloseOperation(EXIT_ON_CLOSE);
// If you want autoscrolling, use this line:
tree = new AutoScrollingJTree();
// Otherwise, use this line:
//tree = new JTree();
getContentPane().add(new JScrollPane(tree), BorderLayout.CENTER);
// If we only support move operations...
//ds = new TreeDragSource(tree, DnDConstants.ACTION_MOVE);
ds = new TreeDragSource(tree, DnDConstants.ACTION_COPY_OR_MOVE);
dt = new TreeDropTarget(tree);
setVisible(true);
}
public class AutoScrollingJTree extends JTree implements Autoscroll {
private int margin = 12;
public AutoScrollingJTree() {
super();
}
public void autoscroll(Point p) {
int realrow = getRowForLocation(p.x, p.y);
Rectangle outer = getBounds();
realrow = (p.y + outer.y <= margin ? realrow < 1 ? 0 : realrow - 1
: realrow < getRowCount() - 1 ? realrow + 1 : realrow);
scrollRowToVisible(realrow);
}
public Insets getAutoscrollInsets() {
Rectangle outer = getBounds();
Rectangle inner = getParent().getBounds();
return new Insets(inner.y - outer.y + margin, inner.x - outer.x
+ margin, outer.height - inner.height - inner.y + outer.y
+ margin, outer.width - inner.width - inner.x + outer.x
+ margin);
}
// Use this method if you want to see the boundaries of the
// autoscroll active region
public void paintComponent(Graphics g) {
super.paintComponent(g);
Rectangle outer = getBounds();
Rectangle inner = getParent().getBounds();
g.setColor(Color.red);
g.drawRect(-outer.x + 12, -outer.y + 12, inner.width - 24,
inner.height - 24);
}
}
public static void main(String args[]) {
new TreeDragTest();
}
}
//TreeDragSource.java
//A drag source wrapper for a JTree. This class can be used to make
//a rearrangeable DnD tree with the TransferableTreeNode class as the
//transfer data type.
class TreeDragSource implements DragSourceListener, DragGestureListener {
DragSource source;
DragGestureRecognizer recognizer;
TransferableTreeNode transferable;
DefaultMutableTreeNode oldNode;
JTree sourceTree;
public TreeDragSource(JTree tree, int actions) {
sourceTree = tree;
source = new DragSource();
recognizer = source.createDefaultDragGestureRecognizer(sourceTree,
actions, this);
}
/*
* Drag Gesture Handler
*/
public void dragGestureRecognized(DragGestureEvent dge) {
TreePath path = sourceTree.getSelectionPath();
if ((path == null) || (path.getPathCount() <= 1)) {
// We can't move the root node or an empty selection
return;
}
oldNode = (DefaultMutableTreeNode) path.getLastPathComponent();
transferable = new TransferableTreeNode(path);
source.startDrag(dge, DragSource.DefaultMoveNoDrop, transferable, this);
// If you support dropping the node anywhere, you should probably
// start with a valid move cursor:
//source.startDrag(dge, DragSource.DefaultMoveDrop, transferable,
// this);
}
/*
* Drag Event Handlers
*/
public void dragEnter(DragSourceDragEvent dsde) {
}
public void dragExit(DragSourceEvent dse) {
}
public void dragOver(DragSourceDragEvent dsde) {
}
public void dropActionChanged(DragSourceDragEvent dsde) {
System.out.println("Action: " + dsde.getDropAction());
System.out.println("Target Action: " + dsde.getTargetActions());
System.out.println("User Action: " + dsde.getUserAction());
}
public void dragDropEnd(DragSourceDropEvent dsde) {
/*
* to support move or copy, we have to check which occurred:
*/
System.out.println("Drop Action: " + dsde.getDropAction());
if (dsde.getDropSuccess()
&& (dsde.getDropAction() == DnDConstants.ACTION_MOVE)) {
((DefaultTreeModel) sourceTree.getModel())
.removeNodeFromParent(oldNode);
}
/*
* to support move only... if (dsde.getDropSuccess()) {
* ((DefaultTreeModel)sourceTree.getModel()).removeNodeFromParent(oldNode); }
*/
}
}
//TreeDropTarget.java
//A quick DropTarget that's looking for drops from draggable JTrees.
//
class TreeDropTarget implements DropTargetListener {
DropTarget target;
JTree targetTree;
public TreeDropTarget(JTree tree) {
targetTree = tree;
target = new DropTarget(targetTree, this);
}
/*
* Drop Event Handlers
*/
private TreeNode getNodeForEvent(DropTargetDragEvent dtde) {
Point p = dtde.getLocation();
DropTargetContext dtc = dtde.getDropTargetContext();
JTree tree = (JTree) dtc.getComponent();
TreePath path = tree.getClosestPathForLocation(p.x, p.y);
return (TreeNode) path.getLastPathComponent();
}
public void dragEnter(DropTargetDragEvent dtde) {
TreeNode node = getNodeForEvent(dtde);
if (node.isLeaf()) {
dtde.rejectDrag();
} else {
// start by supporting move operations
//dtde.acceptDrag(DnDConstants.ACTION_MOVE);
dtde.acceptDrag(dtde.getDropAction());
}
}
public void dragOver(DropTargetDragEvent dtde) {
TreeNode node = getNodeForEvent(dtde);
if (node.isLeaf()) {
dtde.rejectDrag();
} else {
// start by supporting move operations
//dtde.acceptDrag(DnDConstants.ACTION_MOVE);
dtde.acceptDrag(dtde.getDropAction());
}
}
public void dragExit(DropTargetEvent dte) {
}
public void dropActionChanged(DropTargetDragEvent dtde) {
}
public void drop(DropTargetDropEvent dtde) {
Point pt = dtde.getLocation();
DropTargetContext dtc = dtde.getDropTargetContext();
JTree tree = (JTree) dtc.getComponent();
TreePath parentpath = tree.getClosestPathForLocation(pt.x, pt.y);
DefaultMutableTreeNode parent = (DefaultMutableTreeNode) parentpath
.getLastPathComponent();
if (parent.isLeaf()) {
dtde.rejectDrop();
return;
}
try {
Transferable tr = dtde.getTransferable();
DataFlavor[] flavors = tr.getTransferDataFlavors();
for (int i = 0; i < flavors.length; i++) {
if (tr.isDataFlavorSupported(flavors[i])) {
dtde.acceptDrop(dtde.getDropAction());
TreePath p = (TreePath) tr.getTransferData(flavors[i]);
DefaultMutableTreeNode node = (DefaultMutableTreeNode) p
.getLastPathComponent();
DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
model.insertNodeInto(node, parent, 0);
dtde.dropComplete(true);
return;
}
}
dtde.rejectDrop();
} catch (Exception e) {
e.printStackTrace();
dtde.rejectDrop();
}
}
}
//TransferableTreeNode.java
//A Transferable TreePath to be used with Drag & Drop applications.
//
class TransferableTreeNode implements Transferable {
public static DataFlavor TREE_PATH_FLAVOR = new DataFlavor(TreePath.class,
"Tree Path");
DataFlavor flavors[] = { TREE_PATH_FLAVOR };
TreePath path;
public TransferableTreeNode(TreePath tp) {
path = tp;
}
public synchronized DataFlavor[] getTransferDataFlavors() {
return flavors;
}
public boolean isDataFlavorSupported(DataFlavor flavor) {
return (flavor.getRepresentationClass() == TreePath.class);
}
public synchronized Object getTransferData(DataFlavor flavor)
throws UnsupportedFlavorException, IOException {
if (isDataFlavorSupported(flavor)) {
return (Object) path;
} else {
throw new UnsupportedFlavorException(flavor);
}
}
}
|