FileDocCategorySizeDatePackage
DnDJTree.javaAPI DocExample9669Mon Jan 09 11:01:58 GMT 2006None

DnDJTree.java

import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.dnd.*;
import javax.swing.*;
import javax.swing.tree.*;
import java.io.IOException;
import java.util.*;
import java.awt.image.*;

public class DnDJTree extends JTree
    implements DragSourceListener, DropTargetListener, DragGestureListener {

    static DataFlavor localObjectFlavor;
    static {
        try {
            localObjectFlavor = 
                new DataFlavor (DataFlavor.javaJVMLocalObjectMimeType);
        } catch (ClassNotFoundException cnfe) { cnfe.printStackTrace(); }
    }
    static DataFlavor[] supportedFlavors = { localObjectFlavor };
    DragSource dragSource;
    DropTarget dropTarget;
    TreeNode dropTargetNode = null;
    TreeNode draggedNode = null;

    public DnDJTree () {
        super();
        setCellRenderer (new DnDTreeCellRenderer());
        setModel (new DefaultTreeModel(new DefaultMutableTreeNode("default")));
        dragSource = new DragSource();
        DragGestureRecognizer dgr = 
            dragSource.createDefaultDragGestureRecognizer (this, 
                                                           DnDConstants.ACTION_MOVE,
                                                           this);
        dropTarget = new DropTarget (this, this);
    }

    // DragGestureListener
    public void dragGestureRecognized (DragGestureEvent dge) {
        System.out.println ("dragGestureRecognized");
        // find object at this x,y
        Point clickPoint = dge.getDragOrigin();
        TreePath path = getPathForLocation (clickPoint.x, clickPoint.y);
        if (path == null) {
            System.out.println ("not on a node");
            return;
        }
        draggedNode = (TreeNode) path.getLastPathComponent();
        Transferable trans = new RJLTransferable (draggedNode);
        dragSource.startDrag (dge,Cursor.getDefaultCursor(),
                              trans, this);
    }
    // DragSourceListener events
    public void dragDropEnd (DragSourceDropEvent dsde) {
        System.out.println ("dragDropEnd()");
        dropTargetNode = null;
        draggedNode = null;
        repaint();
    }
    public void dragEnter (DragSourceDragEvent dsde) {}
    public void dragExit (DragSourceEvent dse) {}
    public void dragOver (DragSourceDragEvent dsde) {}
    public void dropActionChanged (DragSourceDragEvent dsde) {}
    // DropTargetListener events
    public void dragEnter (DropTargetDragEvent dtde) {
        System.out.println ("dragEnter");
        dtde.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE);
        System.out.println ("accepted dragEnter");
    }
    public void dragExit (DropTargetEvent dte) {}
    public void dragOver (DropTargetDragEvent dtde) {
        // figure out which cell it's over, no drag to self
        Point dragPoint = dtde.getLocation();
        TreePath path = getPathForLocation (dragPoint.x, dragPoint.y);
        if (path == null)
            dropTargetNode = null;
        else
            dropTargetNode = (TreeNode) path.getLastPathComponent();
        repaint();
    }
    public void drop (DropTargetDropEvent dtde) {
        System.out.println ("drop()!");
        Point dropPoint = dtde.getLocation();
        // int index = locationToIndex (dropPoint);
        TreePath path = getPathForLocation (dropPoint.x, dropPoint.y);
        System.out.println ("drop path is " + path);
        boolean dropped = false;
        try {
            dtde.acceptDrop (DnDConstants.ACTION_MOVE);
            System.out.println ("accepted");
            Object droppedObject =
                dtde.getTransferable().getTransferData(localObjectFlavor);
            /*
            // dropped on self?
            if (droppedObject == draggedNode) {
                System.out.println ("dropped onto self");
                // can't reject, because we've accepted, so no-op
                return;
            }
            */

            MutableTreeNode droppedNode = null;
            if (droppedObject instanceof MutableTreeNode) {
                // remove from old location
                droppedNode = (MutableTreeNode) droppedObject;
                ((DefaultTreeModel)getModel()).removeNodeFromParent(droppedNode);
            } else {
                droppedNode = new DefaultMutableTreeNode (droppedObject);
            }
            // insert into spec'd path.  if dropped into a parent
            // make it last child of that parent
            DefaultMutableTreeNode dropNode =
                (DefaultMutableTreeNode) path.getLastPathComponent();
            if (dropNode.isLeaf()) {
                DefaultMutableTreeNode parent = 
                    (DefaultMutableTreeNode) dropNode.getParent();
                int index = parent.getIndex (dropNode);
                ((DefaultTreeModel)getModel()).insertNodeInto (droppedNode,
                                                               parent, index);
            } else {
                ((DefaultTreeModel)getModel()).insertNodeInto (droppedNode,
                                                               dropNode,
                                                               dropNode.getChildCount());
            }
            dropped = true;
        } catch (Exception e) {
            e.printStackTrace();
        } 
        dtde.dropComplete (dropped);
    }
    public void dropActionChanged (DropTargetDragEvent dtde) {}

    // test 
    public static void main (String[] args) {
        JTree tree = new DnDJTree();
        DefaultMutableTreeNode root = new DefaultMutableTreeNode("People");
        DefaultMutableTreeNode set1 = new DefaultMutableTreeNode("Set 1");
        DefaultMutableTreeNode set2 = new DefaultMutableTreeNode("Set 2");
        DefaultMutableTreeNode set3 = new DefaultMutableTreeNode("Set 3");
        set1.add (new DefaultMutableTreeNode ("Chris"));
        set1.add (new DefaultMutableTreeNode ("Kelly"));
        set1.add (new DefaultMutableTreeNode ("Keagan"));
        set2.add (new DefaultMutableTreeNode ("Joshua"));
        set2.add (new DefaultMutableTreeNode ("Kimi"));
        set3.add (new DefaultMutableTreeNode ("Michael"));
        set3.add (new DefaultMutableTreeNode ("Don"));
        set3.add (new DefaultMutableTreeNode ("Daniel"));
        root.add (set1);
        root.add (set2);
        set2.add (set3);
        DefaultTreeModel mod = new DefaultTreeModel (root);
        tree.setModel (mod);
        // expand all
        for (int i=0; i<tree.getRowCount(); i++)
            tree.expandRow (i);
        // show tree
        JScrollPane scroller =
            new JScrollPane (tree,
                            ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
                            ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        JFrame frame = new JFrame ("DnD JTree");
        frame.getContentPane().add (scroller);
        frame.pack();
        frame.setVisible(true);
    }

    class RJLTransferable implements Transferable {
        Object object;
        public RJLTransferable (Object o) {
            object = o;
        }
        public Object getTransferData(DataFlavor df)
            throws UnsupportedFlavorException, IOException {
            if (isDataFlavorSupported (df))
                return object;
            else
                throw new UnsupportedFlavorException(df);
        }
        public boolean isDataFlavorSupported (DataFlavor df) {
            return (df.equals (localObjectFlavor));
        }
        public DataFlavor[] getTransferDataFlavors () {
            return supportedFlavors;
        }
    }

    // custom renderer
    class DnDTreeCellRenderer
        extends DefaultTreeCellRenderer {
        boolean isTargetNode;
        boolean isTargetNodeLeaf;
        boolean isLastItem;
        Insets normalInsets, lastItemInsets;
        int BOTTOM_PAD = 30;
        public DnDTreeCellRenderer() {
            super();
            normalInsets = super.getInsets();
            lastItemInsets =
                new Insets (normalInsets.top,
                            normalInsets.left,
                            normalInsets.bottom + BOTTOM_PAD,
                            normalInsets.right);
        }
        public Component getTreeCellRendererComponent (JTree tree,
                                                       Object value,
                                                       boolean isSelected,
                                                       boolean isExpanded,
                                                       boolean isLeaf,
                                                       int row,
                                                       boolean hasFocus) {
            isTargetNode = (value == dropTargetNode);
            isTargetNodeLeaf = (isTargetNode &&
                                ((TreeNode)value).isLeaf());
            // isLastItem = (index == list.getModel().getSize()-1);
            boolean showSelected = isSelected &
                                  (dropTargetNode == null);
            return super.getTreeCellRendererComponent (tree, value,
                                                       isSelected, isExpanded,
                                                       isLeaf, row, hasFocus);

        }

        public void paintComponent (Graphics g) {
            super.paintComponent(g);
            if (isTargetNode) {
                g.setColor(Color.black);
                if (isTargetNodeLeaf) {
                    g.drawLine (0, 0, getSize().width, 0);
                } else {
                    g.drawRect (0, 0, getSize().width-1, getSize().height-1);
                }
            }
        }
    }
}