TreeTester.java Source code

Java tutorial

Introduction

Here is the source code for TreeTester.java

Source

/*
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;
    }
}