/**
* author: Marcel Genzmehr
* 27.07.2011
*/
package org.freeplane.plugin.workspace.dnd;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.Transferable;
import java.awt.dnd.DnDConstants;
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 javax.swing.JComponent;
import javax.swing.JTree;
import javax.swing.TransferHandler;
import javax.swing.tree.TreePath;
import org.freeplane.plugin.workspace.WorkspaceController;
import org.freeplane.plugin.workspace.components.WorkspaceNodeRenderer;
import org.freeplane.plugin.workspace.model.AWorkspaceTreeNode;
import org.freeplane.plugin.workspace.nodes.WorkspaceRoot;
/**
*
*/
public class WorkspaceTransferHandler extends TransferHandler implements DropTargetListener {
/**
*
*/
private static final long serialVersionUID = 1L;
private static final Insets DEFAULT_INSETS = new Insets(20, 20, 20, 20);
private JTree tree;
private final IDropTargetDispatcher dispatcher;
/***********************************************************************************
* CONSTRUCTORS
**********************************************************************************/
public WorkspaceTransferHandler(JTree tree) {
this.dispatcher = new DefaultWorkspaceDropTargetDispatcher();
this.tree = tree;
this.tree.setTransferHandler(this);
this.tree.setDragEnabled(true);
this.tree.setAutoscrolls(true);
new DropTarget(tree, COPY_OR_MOVE, this);
}
/***********************************************************************************
* METHODS
**********************************************************************************/
public static WorkspaceTransferHandler configureDragAndDrop(JTree tree) {
return new WorkspaceTransferHandler(tree);
}
private 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);
}
}
public Transferable createTransferable(JComponent comp) {
if (comp instanceof JTree) {
JTree t = (JTree) comp;
for (TreePath p : t.getSelectionPaths()) {
AWorkspaceTreeNode node = (AWorkspaceTreeNode) p.getLastPathComponent();
if (node instanceof IWorkspaceTransferableCreator) {
//FIXME: prepare for multiple node selection
return ((IWorkspaceTransferableCreator)node).getTransferable();
}
}
}
return null;
}
public boolean importData(JComponent comp, Transferable transf) {
if (comp instanceof JTree) {
JTree t = (JTree) comp;
for (TreePath p : t.getSelectionPaths()) {
AWorkspaceTreeNode targetNode = (AWorkspaceTreeNode) p.getLastPathComponent();
if (targetNode instanceof IDropAcceptor) {
if(transf == null) {
return false;
}
return ((IDropAcceptor) targetNode).processDrop(transf, DnDConstants.ACTION_COPY);
}
}
}
return false;
}
public int getSourceActions(JComponent comp) {
if(comp == WorkspaceController.getController().getWorkspaceViewTree()) {
TreePath selectionPath = WorkspaceController.getController().getWorkspaceViewTree().getSelectionPath();
if(selectionPath != null) {
if(selectionPath.getLastPathComponent() instanceof WorkspaceRoot) {
return NONE;
}
//SYSTEM NODES are vulnerable for DnD move events (e.g. Copy a system file link and delete the copy hard afterwards, maybe the original will also be deleted.)
if(selectionPath.getLastPathComponent() instanceof AWorkspaceTreeNode
&& ( ((AWorkspaceTreeNode) selectionPath.getLastPathComponent()).isSystem() || !((AWorkspaceTreeNode) selectionPath.getLastPathComponent()).isTransferable() ) ) {
//DOCEAR: REJECT DnD on system nodes for now
return NONE;
}
}
}
return comp.getDropTarget().getDefaultActions();
}
public void exportToClipboard(JComponent comp, Clipboard clip, int action) throws IllegalStateException {
super.exportToClipboard(comp, clip, action);
}
// Causes the Swing drag support to be initiated.
public void exportAsDrag(JComponent comp, java.awt.event.InputEvent e, int action) {
super.exportAsDrag(comp, e, action);
}
// Invoked after data has been exported.
public void exportDone(JComponent source, Transferable data, int action) {
super.exportDone(source, data, action);
}
/***********************************************************************************
* REQUIRED METHODS FOR INTERFACES
**********************************************************************************/
/* DropTarget Methods */
public final void drop(DropTargetDropEvent event) {
if(WorkspaceController.getController().getWorkspaceViewTree().getPathForLocation(event.getLocation().x, event.getLocation().y) == null) {
return;
}
// new method to handle drop events
if(this.dispatcher.dispatchDropEvent(event)) {
return;
}
event.rejectDrop();
}
public final void dragEnter(DropTargetDragEvent dtde) {
}
public final void dragExit(DropTargetEvent dte) {
}
private TreePath lastPathLocation = null;
public final void dragOver(DropTargetDragEvent dtde) {
autoscroll(this.tree, dtde.getLocation());
TreePath path = tree.getPathForLocation(dtde.getLocation().x, dtde.getLocation().y);
if(path == lastPathLocation) {
return;
}
WorkspaceNodeRenderer renderer = (WorkspaceNodeRenderer) tree.getCellRenderer();
if(path != null && path != lastPathLocation) {
lastPathLocation = path;
renderer.highlightRow(tree.getRowForLocation(dtde.getLocation().x, dtde.getLocation().y));
tree.repaint();
}
else if(lastPathLocation != null) {
lastPathLocation = null;
renderer.highlightRow(-1);
tree.repaint();
}
}
public final void dropActionChanged(DropTargetDragEvent dtde) {
}
/***********************************************************************************
* INTERNAL CLASSES
**********************************************************************************/
}