A simple DnD system that does not allow DnD operations with other programs,
but does things very nicely within a single app. git-svn-id: https://samskivert.googlecode.com/svn/trunk@814 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
@@ -0,0 +1,229 @@
|
||||
//
|
||||
// $Id: DnDManager.java,v 1.1 2002/08/20 02:49:19 ray Exp $
|
||||
|
||||
package com.samskivert.swing.dnd;
|
||||
|
||||
import java.awt.AWTEvent;
|
||||
import java.awt.Component;
|
||||
import java.awt.Cursor;
|
||||
import java.awt.Image;
|
||||
import java.awt.Point;
|
||||
import java.awt.Toolkit;
|
||||
|
||||
import java.awt.event.AWTEventListener;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseMotionListener;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Stack;
|
||||
|
||||
import javax.swing.JComponent;
|
||||
|
||||
import javax.swing.event.AncestorEvent;
|
||||
|
||||
import com.samskivert.swing.event.AncestorAdapter;
|
||||
|
||||
/**
|
||||
* A custom Drag and Drop manager for use within a single JVM. Does what we
|
||||
* need it to do and no more.
|
||||
*/
|
||||
public class DnDManager
|
||||
implements MouseMotionListener, AWTEventListener
|
||||
{
|
||||
/**
|
||||
* Add the specified component as a source of drags, with the DragSource
|
||||
* controller.
|
||||
*/
|
||||
public static void addDragSource (DragSource source, JComponent comp)
|
||||
{
|
||||
singleton.addSource(source, comp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the specified component as a drop target.
|
||||
*/
|
||||
public static void addDropTarget (DropTarget target, JComponent comp)
|
||||
{
|
||||
singleton.addTarget(target, comp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a custom cursor out of the specified image.
|
||||
*/
|
||||
public static Cursor createImageCursor (Image img)
|
||||
{
|
||||
// TODO: check colors/size
|
||||
Toolkit tk = Toolkit.getDefaultToolkit();
|
||||
return tk.createCustomCursor(img,
|
||||
new Point(img.getWidth(null) / 2, img.getHeight(null) / 2),
|
||||
"samskivertDnDCursor");
|
||||
}
|
||||
|
||||
/**
|
||||
* Restrict construction.
|
||||
*/
|
||||
private DnDManager ()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a dragsource.
|
||||
*/
|
||||
protected void addSource (DragSource source, JComponent comp)
|
||||
{
|
||||
_draggers.put(comp, source);
|
||||
comp.addAncestorListener(_remover);
|
||||
comp.addMouseMotionListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a droptarget.
|
||||
*/
|
||||
protected void addTarget (DropTarget target, JComponent comp)
|
||||
{
|
||||
_droppers.put(comp, target);
|
||||
comp.addAncestorListener(_remover);
|
||||
}
|
||||
|
||||
// documentation inherited from interface MouseMotionListener
|
||||
public void mouseMoved (MouseEvent me)
|
||||
{
|
||||
// who cares.
|
||||
}
|
||||
|
||||
// documentation inherited from interface MouseMotionListener
|
||||
public void mouseDragged (MouseEvent me)
|
||||
{
|
||||
// make sure a drag hasn't already started.
|
||||
if (_sourceComp != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
_sourceComp = me.getComponent();
|
||||
_source = (DragSource) _draggers.get(_sourceComp);
|
||||
|
||||
// make sure the source wants to start a drag.
|
||||
if (!_source.startDrag(_cursors, _data)) {
|
||||
// if not, reset our start conditions and bail
|
||||
reset();
|
||||
return;
|
||||
}
|
||||
|
||||
// use standard cursors if custom ones not specified
|
||||
if (_cursors[0] == null) {
|
||||
_cursors[0] = java.awt.dnd.DragSource.DefaultMoveDrop;
|
||||
}
|
||||
if (_cursors[1] == null) {
|
||||
_cursors[1] = java.awt.dnd.DragSource.DefaultMoveNoDrop;
|
||||
}
|
||||
|
||||
// install a listener so we know everywhere that the mouse enters
|
||||
Toolkit.getDefaultToolkit().addAWTEventListener(this,
|
||||
AWTEvent.MOUSE_EVENT_MASK);
|
||||
|
||||
// and start out with the no-drop cursor
|
||||
_lastComp = _sourceComp;
|
||||
_lastComp.setCursor(_cursors[1]);
|
||||
}
|
||||
|
||||
// documentation inherited from interface AWTEventListener
|
||||
public void eventDispatched (AWTEvent event)
|
||||
{
|
||||
int id = event.getID();
|
||||
if (id == MouseEvent.MOUSE_ENTERED) {
|
||||
Component oldcomp = _lastComp;
|
||||
_lastComp = ((MouseEvent) event).getComponent();
|
||||
_lastTarget = findAppropriateTarget(_lastComp);
|
||||
_lastComp.setCursor(_cursors[(_lastTarget == null) ? 1 : 0]);
|
||||
if (_lastComp != oldcomp) {
|
||||
oldcomp.setCursor(null);
|
||||
}
|
||||
|
||||
} else if (id == MouseEvent.MOUSE_RELEASED) {
|
||||
// since the release comes with a component of the source,
|
||||
// we use the last enter...
|
||||
if (_lastTarget != null) {
|
||||
_lastTarget.dropCompleted(_data[0]);
|
||||
_source.dragCompleted(_lastTarget);
|
||||
}
|
||||
|
||||
if (_lastComp != null) {
|
||||
_lastComp.setCursor(null);
|
||||
}
|
||||
Toolkit.getDefaultToolkit().removeAWTEventListener(this);
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the lowest accepting parental target to this component.
|
||||
*/
|
||||
protected DropTarget findAppropriateTarget (Component comp)
|
||||
{
|
||||
Component parent;
|
||||
DropTarget target;
|
||||
while (true) {
|
||||
// here we sneakily prevent dropping on the source
|
||||
target = (comp == _sourceComp) ? null
|
||||
: (DropTarget) _droppers.get(comp);
|
||||
if ((target != null) && target.checkDrop(_source, _data[0])) {
|
||||
return target;
|
||||
}
|
||||
parent = comp.getParent();
|
||||
if (parent == null) {
|
||||
return null;
|
||||
}
|
||||
comp = parent;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset dnd to a starting state.
|
||||
*/
|
||||
protected void reset ()
|
||||
{
|
||||
_source = null;
|
||||
_sourceComp = null;
|
||||
_lastComp = null;
|
||||
_lastTarget = null;
|
||||
_data[0] = null;
|
||||
_cursors[0] = null;
|
||||
_cursors[1] = null;
|
||||
}
|
||||
|
||||
/** A handy helper that removes components when they're no longer in
|
||||
* the hierarchy. */
|
||||
protected AncestorAdapter _remover = new AncestorAdapter() {
|
||||
public void ancestorRemoved (AncestorEvent ae)
|
||||
{
|
||||
JComponent comp = ae.getComponent();
|
||||
_draggers.remove(comp);
|
||||
_droppers.remove(comp);
|
||||
}
|
||||
};
|
||||
|
||||
/** Our DropTargets, indexed by associated Component. */
|
||||
protected HashMap _droppers = new HashMap();
|
||||
|
||||
/** Our DragSources, indexed by associated component. */
|
||||
protected HashMap _draggers = new HashMap();
|
||||
|
||||
/** The original and last component that the mouse was in during a drag. */
|
||||
protected Component _sourceComp, _lastComp;
|
||||
|
||||
/** The source of a drag. */
|
||||
protected DragSource _source;
|
||||
|
||||
/** The last target, or null if no last target. */
|
||||
protected DropTarget _lastTarget;
|
||||
|
||||
/** The accept/reject cursors. */
|
||||
protected Cursor[] _cursors = new Cursor[2];
|
||||
|
||||
/** The data to be passed in the drop. */
|
||||
protected Object[] _data = new Object[1];
|
||||
|
||||
/** A single manager for the entire JVM. */
|
||||
protected static final DnDManager singleton = new DnDManager();
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// $Id: DragSource.java,v 1.1 2002/08/20 02:49:19 ray Exp $
|
||||
|
||||
package com.samskivert.swing.dnd;
|
||||
|
||||
import java.awt.Cursor;
|
||||
|
||||
/**
|
||||
* A drag source is associated with a component and represents a valid
|
||||
* place to start a drag and drop operation.
|
||||
*/
|
||||
public interface DragSource
|
||||
{
|
||||
/**
|
||||
* Called by the DnDManager to verify that a drag may begin at this source.
|
||||
*
|
||||
* @param cursors a two-element array- the first element should contain
|
||||
* the cursor to use for valid drops, the second for invalid drops. Either
|
||||
* or both may be left blank to use the default DnD cursors.
|
||||
* @param data a single-element array that should be filled in with
|
||||
* the data that will be sent to a DropTarget if there is a successful
|
||||
* drop.
|
||||
* @return true if the drag may begin.
|
||||
*/
|
||||
public boolean startDrag (Cursor[] cursors, Object[] data);
|
||||
|
||||
/**
|
||||
* A callback to let the source know that the drop completed successfully.
|
||||
*/
|
||||
public void dragCompleted (DropTarget target);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// $Id: DropTarget.java,v 1.1 2002/08/20 02:49:19 ray Exp $
|
||||
|
||||
package com.samskivert.swing.dnd;
|
||||
|
||||
/**
|
||||
* A drop target is associated with a component and represents a valid
|
||||
* place to end a drag and drop.
|
||||
*/
|
||||
public interface DropTarget
|
||||
{
|
||||
/**
|
||||
* Return true if the specified drop should be allowed on this target.
|
||||
*/
|
||||
public boolean checkDrop (DragSource source, Object peekdata);
|
||||
|
||||
/**
|
||||
* Called when the drop is actually executed.
|
||||
*/
|
||||
public void dropCompleted (Object data);
|
||||
}
|
||||
Reference in New Issue
Block a user