1 /* 2 * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package javax.swing.plaf.basic; 26 27 import java.awt.Toolkit; 28 import java.awt.event.*; 29 import java.awt.dnd.DragSource; 30 import javax.swing.*; 31 import sun.awt.dnd.SunDragSourceContextPeer; 32 import sun.awt.AppContext; 33 34 /** 35 * Drag gesture recognition support for classes that have a 36 * <code>TransferHandler</code>. The gesture for a drag in this class is a mouse 37 * press followed by movement by <code>DragSource.getDragThreshold()</code> 38 * pixels. An instance of this class is maintained per AppContext, and the 39 * public static methods call into the appropriate instance. 40 * 41 * @author Shannon Hickey 42 */ 43 class DragRecognitionSupport { 44 private int motionThreshold; 45 private MouseEvent dndArmedEvent; 46 private JComponent component; 47 48 /** 49 * This interface allows us to pass in a handler to mouseDragged, 50 * so that we can be notified immediately before a drag begins. 51 */ 52 public static interface BeforeDrag { 53 public void dragStarting(MouseEvent me); 54 } 55 56 /** 57 * Returns the DragRecognitionSupport for the caller's AppContext. 58 */ 59 private static DragRecognitionSupport getDragRecognitionSupport() { 60 DragRecognitionSupport support = 61 (DragRecognitionSupport)AppContext.getAppContext(). 62 get(DragRecognitionSupport.class); 63 64 if (support == null) { 65 support = new DragRecognitionSupport(); 66 AppContext.getAppContext().put(DragRecognitionSupport.class, support); 67 } 68 69 return support; 70 } 71 72 /** 73 * Returns whether or not the event is potentially part of a drag sequence. 74 */ 75 public static boolean mousePressed(MouseEvent me) { 76 return getDragRecognitionSupport().mousePressedImpl(me); 77 } 78 79 /** 80 * If a dnd recognition has been going on, return the MouseEvent 81 * that started the recognition. Otherwise, return null. 82 */ 83 public static MouseEvent mouseReleased(MouseEvent me) { 84 return getDragRecognitionSupport().mouseReleasedImpl(me); 85 } 86 87 /** 88 * Returns whether or not a drag gesture recognition is ongoing. 89 */ 90 public static boolean mouseDragged(MouseEvent me, BeforeDrag bd) { 91 return getDragRecognitionSupport().mouseDraggedImpl(me, bd); 92 } 93 94 private void clearState() { 95 dndArmedEvent = null; 96 component = null; 97 } 98 99 private int mapDragOperationFromModifiers(MouseEvent me, 100 TransferHandler th) { 101 102 if (th == null || !SwingUtilities.isLeftMouseButton(me)) { 103 return TransferHandler.NONE; 104 } 105 106 return SunDragSourceContextPeer. 107 convertModifiersToDropAction(me.getModifiersEx(), 108 th.getSourceActions(component)); 109 } 110 111 /** 112 * Returns whether or not the event is potentially part of a drag sequence. 113 */ 114 private boolean mousePressedImpl(MouseEvent me) { 115 component = (JComponent)me.getSource(); 116 117 if (mapDragOperationFromModifiers(me, component.getTransferHandler()) 118 != TransferHandler.NONE) { 119 120 motionThreshold = DragSource.getDragThreshold(); 121 dndArmedEvent = me; 122 return true; 123 } 124 125 clearState(); 126 return false; 127 } 128 129 /** 130 * If a dnd recognition has been going on, return the MouseEvent 131 * that started the recognition. Otherwise, return null. 132 */ 133 private MouseEvent mouseReleasedImpl(MouseEvent me) { 134 /* no recognition has been going on */ 135 if (dndArmedEvent == null) { 136 return null; 137 } 138 139 MouseEvent retEvent = null; 140 141 if (me.getSource() == component) { 142 retEvent = dndArmedEvent; 143 } // else component has changed unexpectedly, so return null 144 145 clearState(); 146 return retEvent; 147 } 148 149 /** 150 * Returns whether or not a drag gesture recognition is ongoing. 151 */ 152 private boolean mouseDraggedImpl(MouseEvent me, BeforeDrag bd) { 153 /* no recognition is in progress */ 154 if (dndArmedEvent == null) { 155 return false; 156 } 157 158 /* component has changed unexpectedly, so bail */ 159 if (me.getSource() != component) { 160 clearState(); 161 return false; 162 } 163 164 int dx = Math.abs(me.getX() - dndArmedEvent.getX()); 165 int dy = Math.abs(me.getY() - dndArmedEvent.getY()); 166 if ((dx > motionThreshold) || (dy > motionThreshold)) { 167 TransferHandler th = component.getTransferHandler(); 168 int action = mapDragOperationFromModifiers(me, th); 169 if (action != TransferHandler.NONE) { 170 /* notify the BeforeDrag instance */ 171 if (bd != null) { 172 bd.dragStarting(dndArmedEvent); 173 } 174 th.exportAsDrag(component, dndArmedEvent, action); 175 clearState(); 176 } 177 } 178 179 return true; 180 } 181 }