BasicDropTargetListenerpublic class BasicDropTargetListener extends Object implements DropTargetListener, ActionListener, UIResourceThe Swing DropTarget implementation supports multicast notification
to listeners, so this implementation is used as an additional
listener that extends the primary drop target functionality
(i.e. linkage to the TransferHandler) to include autoscroll and
establish an insertion point for the drop. This is used by the ComponentUI
of components supporting a selection mechanism, which have a
way of indicating a location within their model.
The autoscroll functionality is based upon the Swing scrolling mechanism
of the Scrollable interface. The unit scroll increment is used to as
the scroll amount, and the scrolling is based upon JComponent.getVisibleRect
and JComponent.scrollRectToVisible. The band of area around the visible
rectangle used to invoke autoscroll is based upon the unit scroll increment
as that is assumed to represent the last possible item in the visible region.
The subclasses are expected to implement the following methods to manage the
insertion location via the components selection mechanism.
- saveComponentState
- restoreComponentState
- restoreComponentStateForDrop
- updateInsertionLocation
|
Fields Summary |
---|
private static final int | AUTOSCROLL_INSET | private Timer | timer | private Point | lastPosition | private Rectangle | outer | private Rectangle | inner | private int | hysteresis | private boolean | canImport | private JComponent | componentThe current component. The value is cached from the drop events and used
by the timer. When a drag exits or a drop occurs, this value is cleared. |
Constructors Summary |
---|
protected BasicDropTargetListener()construct a DropTargetAutoScroller
|
Methods Summary |
---|
public synchronized void | actionPerformed(java.awt.event.ActionEvent e)The timer fired, perform autoscroll if the pointer is within the
autoscroll region.
updateAutoscrollRegion(component);
if (outer.contains(lastPosition) && !inner.contains(lastPosition)) {
autoscroll(component, lastPosition);
}
| void | autoscroll(javax.swing.JComponent c, java.awt.Point pos)Perform an autoscroll operation. This is implemented to scroll by the
unit increment of the Scrollable using scrollRectToVisible. If the
cursor is in a corner of the autoscroll region, more than one axis will
scroll.
if (c instanceof Scrollable) {
Scrollable s = (Scrollable) c;
if (pos.y < inner.y) {
// scroll upward
int dy = s.getScrollableUnitIncrement(outer, SwingConstants.VERTICAL, -1);
Rectangle r = new Rectangle(inner.x, outer.y - dy, inner.width, dy);
c.scrollRectToVisible(r);
} else if (pos.y > (inner.y + inner.height)) {
// scroll downard
int dy = s.getScrollableUnitIncrement(outer, SwingConstants.VERTICAL, 1);
Rectangle r = new Rectangle(inner.x, outer.y + outer.height, inner.width, dy);
c.scrollRectToVisible(r);
}
if (pos.x < inner.x) {
// scroll left
int dx = s.getScrollableUnitIncrement(outer, SwingConstants.HORIZONTAL, -1);
Rectangle r = new Rectangle(outer.x - dx, inner.y, dx, inner.height);
c.scrollRectToVisible(r);
} else if (pos.x > (inner.x + inner.width)) {
// scroll right
int dx = s.getScrollableUnitIncrement(outer, SwingConstants.HORIZONTAL, 1);
Rectangle r = new Rectangle(outer.x + outer.width, inner.y, dx, inner.height);
c.scrollRectToVisible(r);
}
}
| private void | cleanup()Cleans up internal state after the drop has finished (either succeeded
or failed).
if (timer != null) {
timer.stop();
}
component = null;
lastPosition = null;
| public void | dragEnter(java.awt.dnd.DropTargetDragEvent e)
component = getComponent(e);
TransferHandler th = component.getTransferHandler();
canImport = th.canImport(component, e.getCurrentDataFlavors());
if (canImport) {
saveComponentState(component);
lastPosition = e.getLocation();
updateAutoscrollRegion(component);
initPropertiesIfNecessary();
}
| public void | dragExit(java.awt.dnd.DropTargetEvent e)
if (canImport) {
restoreComponentState(component);
}
cleanup();
| public void | dragOver(java.awt.dnd.DropTargetDragEvent e)
if (canImport) {
Point p = e.getLocation();
updateInsertionLocation(component, p);
// check autoscroll
synchronized(this) {
if (Math.abs(p.x - lastPosition.x) > hysteresis ||
Math.abs(p.y - lastPosition.y) > hysteresis) {
// no autoscroll
if (timer.isRunning()) timer.stop();
} else {
if (!timer.isRunning()) timer.start();
}
lastPosition = p;
}
}
| public void | drop(java.awt.dnd.DropTargetDropEvent e)
if (canImport) {
restoreComponentStateForDrop(component);
}
cleanup();
| public void | dropActionChanged(java.awt.dnd.DropTargetDragEvent e)
| static javax.swing.JComponent | getComponent(java.awt.dnd.DropTargetEvent e)
DropTargetContext context = e.getDropTargetContext();
return (JComponent) context.getComponent();
| private void | initPropertiesIfNecessary()Initializes the internal properties if they haven't been already
inited. This is done lazily to avoid loading of desktop properties.
if (timer == null) {
Toolkit t = Toolkit.getDefaultToolkit();
Integer initial = new Integer(100);
Integer interval = new Integer(100);
try {
initial = (Integer)t.getDesktopProperty(
"DnD.Autoscroll.initialDelay");
} catch (Exception e) {
// ignore
}
try {
interval = (Integer)t.getDesktopProperty(
"DnD.Autoscroll.interval");
} catch (Exception e) {
// ignore
}
timer = new Timer(interval.intValue(), this);
timer.setCoalesce(true);
timer.setInitialDelay(initial.intValue());
try {
hysteresis = ((Integer)t.getDesktopProperty(
"DnD.Autoscroll.cursorHysteresis")).intValue();
} catch (Exception e) {
// ignore
}
}
| protected void | restoreComponentState(javax.swing.JComponent c)called to restore the state of a component in case a drop
is not performed.
| protected void | restoreComponentStateForDrop(javax.swing.JComponent c)called to restore the state of a component in case a drop
is performed.
| protected void | saveComponentState(javax.swing.JComponent c)called to save the state of a component in case it needs to
be restored because a drop is not performed.
| void | updateAutoscrollRegion(javax.swing.JComponent c)Update the geometry of the autoscroll region. The geometry is
maintained as a pair of rectangles. The region can cause
a scroll if the pointer sits inside it for the duration of the
timer. The region that causes the timer countdown is the area
between the two rectangles.
This is implemented to use the visible area of the component
as the outer rectangle, and the insets are fixed at 10. Should
the component be smaller than a total of 20 in any direction,
autoscroll will not occur in that direction.
// compute the outer
Rectangle visible = c.getVisibleRect();
outer.reshape(visible.x, visible.y, visible.width, visible.height);
// compute the insets
Insets i = new Insets(0, 0, 0, 0);
if (c instanceof Scrollable) {
int minSize = 2 * AUTOSCROLL_INSET;
if (visible.width >= minSize) {
i.left = i.right = AUTOSCROLL_INSET;
}
if (visible.height >= minSize) {
i.top = i.bottom = AUTOSCROLL_INSET;
}
}
// set the inner from the insets
inner.reshape(visible.x + i.left,
visible.y + i.top,
visible.width - (i.left + i.right),
visible.height - (i.top + i.bottom));
| protected void | updateInsertionLocation(javax.swing.JComponent c, java.awt.Point p)called to set the insertion location to match the current
mouse pointer coordinates.
|
|