/* |
|
* Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved. |
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
* |
|
* This code is free software; you can redistribute it and/or modify it |
|
* under the terms of the GNU General Public License version 2 only, as |
|
* published by the Free Software Foundation. Oracle designates this |
|
* particular file as subject to the "Classpath" exception as provided |
|
* by Oracle in the LICENSE file that accompanied this code. |
|
* |
|
* This code is distributed in the hope that it will be useful, but WITHOUT |
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
* version 2 for more details (a copy is included in the LICENSE file that |
|
* accompanied this code). |
|
* |
|
* You should have received a copy of the GNU General Public License version |
|
* 2 along with this work; if not, write to the Free Software Foundation, |
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
* |
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
* or visit www.oracle.com if you need additional information or have any |
|
* questions. |
|
*/ |
|
package javax.swing.plaf.basic; |
|
import java.awt.Toolkit; |
|
import java.awt.event.*; |
|
import java.awt.dnd.DragSource; |
|
import javax.swing.*; |
|
import sun.awt.dnd.SunDragSourceContextPeer; |
|
import sun.awt.AppContext; |
|
/** |
|
* Drag gesture recognition support for classes that have a |
|
* <code>TransferHandler</code>. The gesture for a drag in this class is a mouse |
|
* press followed by movement by <code>DragSource.getDragThreshold()</code> |
|
* pixels. An instance of this class is maintained per AppContext, and the |
|
* public static methods call into the appropriate instance. |
|
* |
|
* @author Shannon Hickey |
|
*/ |
|
class DragRecognitionSupport { |
|
private int motionThreshold; |
|
private MouseEvent dndArmedEvent; |
|
private JComponent component; |
|
/** |
|
* This interface allows us to pass in a handler to mouseDragged, |
|
* so that we can be notified immediately before a drag begins. |
|
*/ |
|
public static interface BeforeDrag { |
|
public void dragStarting(MouseEvent me); |
|
} |
|
/** |
|
* Returns the DragRecognitionSupport for the caller's AppContext. |
|
*/ |
|
private static DragRecognitionSupport getDragRecognitionSupport() { |
|
DragRecognitionSupport support = |
|
(DragRecognitionSupport)AppContext.getAppContext(). |
|
get(DragRecognitionSupport.class); |
|
if (support == null) { |
|
support = new DragRecognitionSupport(); |
|
AppContext.getAppContext().put(DragRecognitionSupport.class, support); |
|
} |
|
return support; |
|
} |
|
/** |
|
* Returns whether or not the event is potentially part of a drag sequence. |
|
*/ |
|
public static boolean mousePressed(MouseEvent me) { |
|
return getDragRecognitionSupport().mousePressedImpl(me); |
|
} |
|
/** |
|
* If a dnd recognition has been going on, return the MouseEvent |
|
* that started the recognition. Otherwise, return null. |
|
*/ |
|
public static MouseEvent mouseReleased(MouseEvent me) { |
|
return getDragRecognitionSupport().mouseReleasedImpl(me); |
|
} |
|
/** |
|
* Returns whether or not a drag gesture recognition is ongoing. |
|
*/ |
|
public static boolean mouseDragged(MouseEvent me, BeforeDrag bd) { |
|
return getDragRecognitionSupport().mouseDraggedImpl(me, bd); |
|
} |
|
private void clearState() { |
|
dndArmedEvent = null; |
|
component = null; |
|
} |
|
private int mapDragOperationFromModifiers(MouseEvent me, |
|
TransferHandler th) { |
|
if (th == null || !SwingUtilities.isLeftMouseButton(me)) { |
|
return TransferHandler.NONE; |
|
} |
|
return SunDragSourceContextPeer. |
|
convertModifiersToDropAction(me.getModifiersEx(), |
|
th.getSourceActions(component)); |
|
} |
|
/** |
|
* Returns whether or not the event is potentially part of a drag sequence. |
|
*/ |
|
private boolean mousePressedImpl(MouseEvent me) { |
|
component = (JComponent)me.getSource(); |
|
if (mapDragOperationFromModifiers(me, component.getTransferHandler()) |
|
!= TransferHandler.NONE) { |
|
motionThreshold = DragSource.getDragThreshold(); |
|
dndArmedEvent = me; |
|
return true; |
|
} |
|
clearState(); |
|
return false; |
|
} |
|
/** |
|
* If a dnd recognition has been going on, return the MouseEvent |
|
* that started the recognition. Otherwise, return null. |
|
*/ |
|
private MouseEvent mouseReleasedImpl(MouseEvent me) { |
|
/* no recognition has been going on */ |
|
if (dndArmedEvent == null) { |
|
return null; |
|
} |
|
MouseEvent retEvent = null; |
|
if (me.getSource() == component) { |
|
retEvent = dndArmedEvent; |
|
} // else component has changed unexpectedly, so return null |
|
clearState(); |
|
return retEvent; |
|
} |
|
/** |
|
* Returns whether or not a drag gesture recognition is ongoing. |
|
*/ |
|
private boolean mouseDraggedImpl(MouseEvent me, BeforeDrag bd) { |
|
/* no recognition is in progress */ |
|
if (dndArmedEvent == null) { |
|
return false; |
|
} |
|
/* component has changed unexpectedly, so bail */ |
|
if (me.getSource() != component) { |
|
clearState(); |
|
return false; |
|
} |
|
int dx = Math.abs(me.getX() - dndArmedEvent.getX()); |
|
int dy = Math.abs(me.getY() - dndArmedEvent.getY()); |
|
if ((dx > motionThreshold) || (dy > motionThreshold)) { |
|
TransferHandler th = component.getTransferHandler(); |
|
int action = mapDragOperationFromModifiers(me, th); |
|
if (action != TransferHandler.NONE) { |
|
/* notify the BeforeDrag instance */ |
|
if (bd != null) { |
|
bd.dragStarting(dndArmedEvent); |
|
} |
|
th.exportAsDrag(component, dndArmedEvent, action); |
|
clearState(); |
|
} |
|
} |
|
return true; |
|
} |
|
} |