/* * @(#)BasicGraphDropTargetListener 1.0 03-JUL-04 * * Copyright (c) 2001-2004 Gaudenz Alder * */ package org.jgraph.plaf.basic; import java.awt.Insets; import java.awt.Point; import java.awt.Rectangle; import java.awt.Toolkit; import java.awt.dnd.DropTargetContext; import java.awt.dnd.DropTargetDragEvent; import java.awt.dnd.DropTargetDropEvent; import java.awt.dnd.DropTargetEvent; import java.awt.dnd.DropTargetListener; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JComponent; import javax.swing.Scrollable; import javax.swing.SwingConstants; import javax.swing.Timer; import javax.swing.plaf.UIResource; @SuppressWarnings ( "all" ) public class BasicGraphDropTargetListener implements DropTargetListener, UIResource, ActionListener { /** * construct a DropTargetAutoScroller */ public BasicGraphDropTargetListener() { } /** * called to save the state of a component in case it needs to * be restored because a drop is not performed. */ protected void saveComponentState(JComponent c) { } /** * called to restore the state of a component in case a drop * is not performed. */ protected void restoreComponentState(JComponent c) { } /** * called to restore the state of a component in case a drop * is performed. */ protected void restoreComponentStateForDrop(JComponent c) { } /** * called to set the insertion location to match the current * mouse pointer coordinates. */ protected void updateInsertionLocation(JComponent c, Point p) { } /** * 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. * <p> * This is implemented to use the visible area of the component * as the outer rectangle and the insets are based upon the * Scrollable information (if any). If the Scrollable is * scrollable along an axis, the step increment is used as * the autoscroll inset. If the component is not scrollable, * the insets will be zero (i.e. autoscroll will not happen). */ void updateAutoscrollRegion(JComponent c) { // compute the outer Rectangle visible = c.getVisibleRect(); outer.setBounds(visible.x, visible.y, visible.width, visible.height); // compute the insets // TBD - the thing with the scrollable Insets i = new Insets(0, 0, 0, 0); if (c instanceof Scrollable) { Scrollable s = (Scrollable) c; i.left = s.getScrollableUnitIncrement( visible, SwingConstants.HORIZONTAL, 1); i.top = s.getScrollableUnitIncrement( visible, SwingConstants.VERTICAL, 1); i.right = s.getScrollableUnitIncrement( visible, SwingConstants.HORIZONTAL, -1); i.bottom = s.getScrollableUnitIncrement( visible, SwingConstants.VERTICAL, -1); } // set the inner from the insets inner.setBounds( visible.x + i.left, visible.y + i.top, visible.width - (i.left + i.right), visible.height - (i.top + i.bottom)); } /** * 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. */ void autoscroll(JComponent c, Point pos) { if (c instanceof org.jgraph.JGraph) BasicGraphUI.autoscroll((org.jgraph.JGraph) c, pos); } /** * Initializes the internal properties if they haven't been already * inited. This is done lazily to avoid loading of desktop properties. */ private void initPropertiesIfNecessary() { 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 } } } static JComponent getComponent(DropTargetEvent e) { DropTargetContext context = e.getDropTargetContext(); return (JComponent) context.getComponent(); } // --- ActionListener methods -------------------------------------- /** * The timer fired, perform autoscroll if the pointer is within the * autoscroll region. * <P> * @param e the <code>ActionEvent</code> */ public synchronized void actionPerformed(ActionEvent e) { updateAutoscrollRegion(component); if (outer.contains(lastPosition) && !inner.contains(lastPosition)) { autoscroll(component, lastPosition); } } // --- DropTargetListener methods ----------------------------------- public void dragEnter(DropTargetDragEvent e) { component = getComponent(e); // DO NOT REMOVE OR MODIFY THIS LINE! javax.swing.TransferHandler // JAVA13: org.jgraph.plaf.basic.TransferHandler th = ( // DO NOT REMOVE OR MODIFY THIS LINE! (JComponent) // JAVA13: (org.jgraph.plaf.basic.TransferHandler.JDNDAdapter) component).getTransferHandler(); canImport = th.canImport(component, e.getCurrentDataFlavors()); if (canImport) { saveComponentState(component); lastPosition = e.getLocation(); updateAutoscrollRegion(component); initPropertiesIfNecessary(); } } public void dragOver(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 dragExit(DropTargetEvent e) { if (canImport) { restoreComponentState(component); } cleanup(); } public void drop(DropTargetDropEvent e) { if (canImport) { restoreComponentStateForDrop(component); } cleanup(); } public void dropActionChanged(DropTargetDragEvent e) { } /** * Cleans up internal state after the drop has finished (either succeeded * or failed). */ private void cleanup() { if (timer != null) { timer.stop(); } component = null; lastPosition = null; } // --- fields -------------------------------------------------- private Timer timer; private Point lastPosition; private Rectangle outer = new Rectangle(); private Rectangle inner = new Rectangle(); private int hysteresis = 10; private boolean canImport; /** * The 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. */ private JComponent component; }