package cn.org.tpeach.nosql.view;

import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import java.awt.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.*;
import java.io.IOException;
 
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);
		}
	}
}