/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is NetBeans. The Initial Developer of the Original
* Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun
* Microsystems, Inc. All Rights Reserved.
*/
package org.openide.explorer.view;
import java.awt.dnd.*;
import java.awt.datatransfer.*;
import javax.swing.JList;
import javax.swing.SwingUtilities;
import org.openide.nodes.Node;
import org.openide.util.datatransfer.PasteType;
import org.openide.util.RequestProcessor;
/**
*
* @author Dafe Simonek
*/
final class ListViewDropSupport
implements DropTargetListener, Runnable
{
// Attributes
/** true if support is active, false otherwise */
boolean active = false;
boolean dropTargetPopupAllowed;
/** Drop target asociated with the tree */
DropTarget dropTarget;
/** The index of last item the cursor hotspot was above */
int lastIndex = -1;
// Associations
/** View manager. */
protected ListView view;
/** The component we are supporting with drop support */
protected JList list;
/** For managing visual appearance of JList cells. */
protected NodeRenderer.List cellRenderer;
// Operations
public ListViewDropSupport (ListView view, JList list) {
this( view, list, true );
}
/** Creates new TreeViewDropSupport */
public ListViewDropSupport (ListView view, JList list, boolean dropTargetPopupAllowed)
{
this.view = view;
this.list = list;
//cellRenderer = (NodeListCellRenderer)list.getCellRenderer();
this.dropTargetPopupAllowed = dropTargetPopupAllowed;
}
public void setDropTargetPopupAllowed(boolean value) {
dropTargetPopupAllowed=value;
}
public boolean isDropTargetPopupAllowed() {
return dropTargetPopupAllowed;
}
/** User is starting to drag over us */
public void dragEnter (DropTargetDragEvent dtde) {
lastIndex = indexWithCheck(dtde);
if (lastIndex < 0)
dtde.rejectDrag();
else {
dtde.acceptDrag(dtde.getDropAction());
NodeRenderer.dragEnter(
list.getModel().getElementAt(lastIndex));
list.repaint(list.getCellBounds(lastIndex, lastIndex));
}
}
/** User drags over us */
public void dragOver (DropTargetDragEvent dtde) {
int index = indexWithCheck(dtde);
if (index < 0) {
dtde.rejectDrag();
if (lastIndex >= 0) {
NodeRenderer.dragExit();
list.repaint(list.getCellBounds(lastIndex, lastIndex));
lastIndex = -1;
}
} else {
dtde.acceptDrag(dtde.getDropAction());
if (lastIndex != index) {
if (lastIndex < 0)
lastIndex = index;
NodeRenderer.dragExit();
NodeRenderer.dragEnter(list.getModel().getElementAt(index));
list.repaint(list.getCellBounds(lastIndex, index));
lastIndex = index;
}
}
}
public void dropActionChanged (DropTargetDragEvent dtde) {
// System.out.println("Changing drop action..."); // NOI18N
// PENDING...?
}
/** User exits the dragging */
public void dragExit (DropTargetEvent dte) {
if (lastIndex >= 0) {
NodeRenderer.dragExit();
list.repaint(list.getCellBounds(lastIndex, lastIndex));
}
}
/** Performs the drop action, if we are dropping on
* right node and target node agrees.
*/
public void drop (DropTargetDropEvent dtde) {
// System.out.println("Dropping!!!"); // NOI18N
// obtain the node we have cursor on
int index = list.locationToIndex(dtde.getLocation());
Object obj = list.getModel().getElementAt(index);
Node dropNode = null;
if( obj instanceof VisualizerNode )
dropNode = ((VisualizerNode) obj).node;
int dropAction = dtde.getDropAction();
// return if conditions are not satisfied
if (index < 0 || !canDrop (dropNode, dropAction)) {
dtde.rejectDrop();
return;
}
// get paste types for given transferred transferable
PasteType[] pt =
DragDropUtilities.getPasteTypes((Node)obj,
ExplorerDnDManager.getDefault ().getDraggedTransferable (DnDConstants.ACTION_MOVE==dropAction));
if ((pt == null) || (pt.length <= 0)) {
dtde.dropComplete(false);
// something is wrong, notify user
// ugly hack, but if we don't wait, deadlock will come
// (sun's issue....)
RequestProcessor.getDefault().post(this, 500);
return;
}
// finally perform the drop
dtde.acceptDrop(dropAction);
if (dropAction == DnDConstants.ACTION_LINK) {
// show popup menu to the user
// PENDING
} else {
DragDropUtilities.performDrop(pt[0]);
}
}
/** Can node recieve given drop action? */
// XXX canditate for more general support
private boolean canDrop (Node n, int dropAction) {
if (n == null) {
return false;
}
if (ExplorerDnDManager.getDefault ().getAllowedDragActions()==DnDConstants.ACTION_NONE) {
return false;
}
// test if a parent of the dragged nodes isn't the node over
// only for MOVE action
if (DnDConstants.ACTION_MOVE==dropAction) {
Node[] nodes = ExplorerDnDManager.getDefault ().getDraggedNodes();
for (int i=0; i<nodes.length; i++) {
if (n.equals(nodes[i].getParentNode ()))
return false;
}
}
Transferable trans = ExplorerDnDManager.getDefault ().getDraggedTransferable (DnDConstants.ACTION_MOVE==dropAction);
if (trans==null) {
return false;
}
// get paste types for given transferred transferable
PasteType[] pt = DragDropUtilities.getPasteTypes(n, trans);
return ((pt!=null) && (pt.length!=0));
}
/** Activates or deactivates Drag support on asociated JTree
* component
* @param active true if the support should be active, false
* otherwise
*/
public void activate (boolean active) {
if (this.active == active)
return;
this.active = active;
getDropTarget().setActive(active);
}
/** Implementation of the runnable interface.
* Notifies user in AWT thread. */
public void run () {
if (!SwingUtilities.isEventDispatchThread()) {
SwingUtilities.invokeLater (this);
return;
}
DragDropUtilities.dropNotSuccesfull();
}
/** @return The tree path to the node the cursor is above now or
* null if no such node currently exists or if conditions were not
* satisfied to continue with DnD operation.
*/
int indexWithCheck (DropTargetDragEvent dtde) {
int dropAction = dtde.getDropAction();
// check actions
if ((dropAction & view.getAllowedDropActions()) == 0)
return -1;
// check location
int index = list.locationToIndex(dtde.getLocation());
Object obj = list.getModel().getElementAt(index);
if( obj instanceof VisualizerNode )
obj = ((VisualizerNode) obj).node;
if ( index < 0 )
return -1;
if( ! ( obj instanceof Node) )
return -1;
/* JST: Is necessary? Cannot be replaced by the use of special
* transferable?
// accept only node data flavors or multi flavor
if (!dtde.isDataFlavorSupported(NodeTransfer.nodeCutFlavor) &&
!dtde.isDataFlavorSupported(NodeTransfer.nodeCopyFlavor) &&
!dtde.isDataFlavorSupported(ExTransferable.multiFlavor))
return -1;
*/
// succeeded
return index;
}
/** Safe accessor to the drop target which is asociated
* with the tree */
DropTarget getDropTarget () {
if (dropTarget == null) {
dropTarget =
new DropTarget(list, view.getAllowedDropActions(),
this, false);
}
return dropTarget;
}
/** Safe getter for the cell renderer of asociated list */
NodeRenderer.List getCellRenderer () {
if (cellRenderer == null)
cellRenderer = (NodeRenderer.List)list.getCellRenderer();
return cellRenderer;
}
}