Mega Code Archive

 
Categories / Java / Swing JFC
 

JTree drag and drop utilites

/* Copyright (c) 2006, 2009, Carl Burch. License information is located in the  * com.cburch.logisim.Main source code and at www.cburch.com/logisim/. */   import java.awt.AlphaComposite; import java.awt.Graphics2D; 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.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.DropTargetDragEvent; import java.awt.dnd.DropTargetDropEvent; import java.awt.dnd.DropTargetEvent; import java.awt.dnd.DropTargetListener; import java.awt.image.BufferedImage; import java.util.Arrays; import javax.swing.JComponent; import javax.swing.JTree; import javax.swing.tree.TreePath; /* This comes from "Denis" at http://forum.java.sun.com/thread.jspa?forumID=57&threadID=296255 */ /*  * My program use 4 classes. The application displays two trees.  * You can drag (move by default or copy with ctrl pressed) a node from the left tree to the right one, from the right to the left and inside the same tree.  * The rules for moving are :  *   - you can't move the root  *   - you can't move the selected node to its subtree (in the same tree).  *   - you can't move the selected node to itself (in the same tree).  *   - you can't move the selected node to its parent (in the same tree).  *   - you can move a node to anywhere you want according to the 4 previous rules.  *  The rules for copying are :  *   - you can copy a node to anywhere you want.  *  * In the implementation I used DnD version of Java 1.3 because in 1.4 the DnD is too restrictive :  * you can't do what you want (displaying the image of the node while dragging, changing the cursor  * according to where you are dragging, etc...). In 1.4, the DnD is based on the 1.3 version but  * it is too encapsulated.  */ public class JTreeUtil {     private static final Insets DEFAULT_INSETS = new Insets(20, 20, 20, 20);     private static final DataFlavor NODE_FLAVOR = new DataFlavor(             DataFlavor.javaJVMLocalObjectMimeType, "Node");     private static Object draggedNode;     private static BufferedImage image = null; // buff image     private static class TransferableNode implements Transferable {         private Object node;         private DataFlavor[] flavors = { NODE_FLAVOR };         public TransferableNode(Object nd) {             node = nd;         }         public synchronized Object getTransferData(DataFlavor flavor)                 throws UnsupportedFlavorException {             if(flavor == NODE_FLAVOR) {                 return node;             } else {                 throw new UnsupportedFlavorException(flavor);             }         }         public DataFlavor[] getTransferDataFlavors() {             return flavors;         }         public boolean isDataFlavorSupported(DataFlavor flavor) {             return Arrays.asList(flavors).contains(flavor);         }     }     /*      * This class is the most important. It manages all the DnD behavior. It is      * abstract because it contains two abstract methods:      *   public abstract boolean canPerformAction(JTree target,      *     Object draggedNode, int action, Point location);      *   public abstract boolean executeDrop(DNDTree tree,      *     Object draggedNode, Object newParentNode, int action);      * we have to override to give the required behavior of DnD in your tree.      */     private static class TreeTransferHandler implements             DragGestureListener, DragSourceListener, DropTargetListener {         private JTree tree;         private JTreeDragController controller;         private DragSource dragSource; // dragsource         private Rectangle rect2D = new Rectangle();         private boolean drawImage;         protected TreeTransferHandler(JTree tree, JTreeDragController controller,                 int action, boolean drawIcon) {             this.tree = tree;             this.controller = controller;             drawImage = drawIcon;             dragSource = new DragSource();             dragSource.createDefaultDragGestureRecognizer(tree, action, this);         }         /* Methods for DragSourceListener */         public void dragDropEnd(DragSourceDropEvent dsde) {             /*             if(dsde.getDropSuccess()                     && dsde.getDropAction() == DnDConstants.ACTION_MOVE                     && draggedNodeParent != null) {                 ((DefaultTreeModel) tree.getModel())                         .nodeStructureChanged(draggedNodeParent);             }             */         }         public final void dragEnter(DragSourceDragEvent dsde) {             int action = dsde.getDropAction();             if(action == DnDConstants.ACTION_COPY) {                 dsde.getDragSourceContext().setCursor(                         DragSource.DefaultCopyDrop);             } else {                 if(action == DnDConstants.ACTION_MOVE) {                     dsde.getDragSourceContext().setCursor(                             DragSource.DefaultMoveDrop);                 } else {                     dsde.getDragSourceContext().setCursor(                             DragSource.DefaultMoveNoDrop);                 }             }         }         public final void dragOver(DragSourceDragEvent dsde) {             int action = dsde.getDropAction();             if(action == DnDConstants.ACTION_COPY) {                 dsde.getDragSourceContext().setCursor(                         DragSource.DefaultCopyDrop);             } else {                 if(action == DnDConstants.ACTION_MOVE) {                     dsde.getDragSourceContext().setCursor(                             DragSource.DefaultMoveDrop);                 } else {                     dsde.getDragSourceContext().setCursor(                             DragSource.DefaultMoveNoDrop);                 }             }         }         public final void dropActionChanged(DragSourceDragEvent dsde) {             int action = dsde.getDropAction();             if(action == DnDConstants.ACTION_COPY) {                 dsde.getDragSourceContext().setCursor(                         DragSource.DefaultCopyDrop);             } else {                 if(action == DnDConstants.ACTION_MOVE) {                     dsde.getDragSourceContext().setCursor(                             DragSource.DefaultMoveDrop);                 } else {                     dsde.getDragSourceContext().setCursor(                             DragSource.DefaultMoveNoDrop);                 }             }         }         public final void dragExit(DragSourceEvent dse) {             dse.getDragSourceContext().setCursor(DragSource.DefaultMoveNoDrop);         }         /* Methods for DragGestureListener */         public final void dragGestureRecognized(DragGestureEvent dge) {             TreePath path = tree.getSelectionPath();             if(path != null) {                 draggedNode = path.getLastPathComponent();                 if(drawImage) {                     Rectangle pathBounds = tree.getPathBounds(path); // getpathbounds                                                                         // of                                                                         // selectionpath                     JComponent lbl = (JComponent) tree                             .getCellRenderer()                             .getTreeCellRendererComponent(                                     tree,                                     draggedNode,                                     false,                                     tree.isExpanded(path),                                     tree.getModel() .isLeaf(path.getLastPathComponent()),                                     0, false);// returning the label                     lbl.setBounds(pathBounds);// setting bounds to lbl                     image = new BufferedImage(lbl.getWidth(), lbl.getHeight(),                             java.awt.image.BufferedImage.TYPE_INT_ARGB_PRE);// buffered                                                                             // image                                                                             // reference                                                                             // passing                                                                             // the                                                                             // label's                                                                             // ht                                                                             // and                                                                             // width                     Graphics2D graphics = image.createGraphics();// creating                                                                     // the                                                                     // graphics                                                                     // for                                                                     // buffered                                                                     // image                     graphics.setComposite(AlphaComposite.getInstance(                             AlphaComposite.SRC_OVER, 0.5f)); // Sets the                                                                 // Composite for                                                                 // the                                                                 // Graphics2D                                                                 // context                     lbl.setOpaque(false);                     lbl.paint(graphics); // painting the graphics to label                     graphics.dispose();                 }                 dragSource.startDrag(dge, DragSource.DefaultMoveNoDrop, image,                         new Point(0, 0), new TransferableNode(draggedNode),                         this);             }         }         /* Methods for DropTargetListener */         public final void dragEnter(DropTargetDragEvent dtde) {             Point pt = dtde.getLocation();             int action = dtde.getDropAction();             if(drawImage) {                 paintImage(pt);             }             if(controller.canPerformAction(tree, draggedNode, action, pt)) {                 dtde.acceptDrag(action);             } else {                 dtde.rejectDrag();             }         }         public final void dragExit(DropTargetEvent dte) {             if(drawImage) {                 clearImage();             }         }         public final void dragOver(DropTargetDragEvent dtde) {             Point pt = dtde.getLocation();             int action = dtde.getDropAction();             autoscroll(tree, pt);             if(drawImage) {                 paintImage(pt);             }             if(controller.canPerformAction(tree, draggedNode, action, pt)) {                 dtde.acceptDrag(action);             } else {                 dtde.rejectDrag();             }         }         public final void dropActionChanged(DropTargetDragEvent dtde) {             Point pt = dtde.getLocation();             int action = dtde.getDropAction();             if(drawImage) {                 paintImage(pt);             }             if(controller.canPerformAction(tree, draggedNode, action, pt)) {                 dtde.acceptDrag(action);             } else {                 dtde.rejectDrag();             }         }         public final void drop(DropTargetDropEvent dtde) {             try {                 if(drawImage) {                     clearImage();                 }                 int action = dtde.getDropAction();                 Transferable transferable = dtde.getTransferable();                 Point pt = dtde.getLocation();                 if(transferable                         .isDataFlavorSupported(NODE_FLAVOR)                         && controller.canPerformAction(tree, draggedNode, action, pt)) {                     TreePath pathTarget = tree.getPathForLocation(pt.x, pt.y);                     Object node = transferable.getTransferData(NODE_FLAVOR);                     Object newParentNode = pathTarget.getLastPathComponent();                     if(controller.executeDrop(tree, node, newParentNode, action)) {                         dtde.acceptDrop(action);                         dtde.dropComplete(true);                         return;                     }                 }                 dtde.rejectDrop();                 dtde.dropComplete(false);             } catch(Exception e) {                 dtde.rejectDrop();                 dtde.dropComplete(false);             }         }         private final void paintImage(Point pt) {             tree.paintImmediately(rect2D.getBounds());             rect2D.setRect((int) pt.getX(), (int) pt.getY(), image.getWidth(),                     image.getHeight());             tree.getGraphics().drawImage(image, (int) pt.getX(),                     (int) pt.getY(), tree);         }         private final void clearImage() {             tree.paintImmediately(rect2D.getBounds());         }     }          public static void configureDragAndDrop(JTree tree, JTreeDragController controller) {         tree.setAutoscrolls(true);         new TreeTransferHandler(tree, controller, DnDConstants.ACTION_COPY_OR_MOVE, true);     }     private static void autoscroll(JTree tree, Point cursorLocation) {         Insets insets = DEFAULT_INSETS;         Rectangle outer = tree.getVisibleRect();         Rectangle inner = new Rectangle(outer.x + insets.left, outer.y                 + insets.top, outer.width - (insets.left + insets.right),                 outer.height - (insets.top + insets.bottom));         if(!inner.contains(cursorLocation)) {             Rectangle scrollRect = new Rectangle(cursorLocation.x                     - insets.left, cursorLocation.y - insets.top,                     insets.left + insets.right, insets.top + insets.bottom);             tree.scrollRectToVisible(scrollRect);         }     } } /* Copyright (c) 2006, 2009, Carl Burch. License information is located in the  * com.cburch.logisim.Main source code and at www.cburch.com/logisim/. */   /* This comes from "Denis" at http://forum.java.sun.com/thread.jspa?forumID=57&threadID=296255 */ /*  * My program use 4 classes. The application displays two trees.  * You can drag (move by default or copy with ctrl pressed) a node from the left tree to the right one, from the right to the left and inside the same tree.  * The rules for moving are :  *   - you can't move the root  *   - you can't move the selected node to its subtree (in the same tree).  *   - you can't move the selected node to itself (in the same tree).  *   - you can't move the selected node to its parent (in the same tree).  *   - you can move a node to anywhere you want according to the 4 previous rules.  *  The rules for copying are :  *   - you can copy a node to anywhere you want.  *  * In the implementation I used DnD version of Java 1.3 because in 1.4 the DnD is too restrictive :  * you can't do what you want (displaying the image of the node while dragging, changing the cursor  * according to where you are dragging, etc...). In 1.4, the DnD is based on the 1.3 version but  * it is too encapsulated.  */ interface JTreeDragController {     public boolean canPerformAction(JTree target, Object draggedNode,             int action, Point location);     public boolean executeDrop(JTree tree, Object draggedNode,             Object newParentNode, int action); }