blob: 060019810e4f3ca8cb7e8fe3317a6ad241188e9b [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2005 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25package javax.swing.plaf.basic;
26
27import java.awt.Toolkit;
28import java.awt.event.*;
29import java.awt.dnd.DragSource;
30import javax.swing.*;
31import sun.awt.dnd.SunDragSourceContextPeer;
32import 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 */
43class 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 ((DragRecognitionSupport)getDragRecognitionSupport()).
77 mousePressedImpl(me);
78 }
79
80 /**
81 * If a dnd recognition has been going on, return the MouseEvent
82 * that started the recognition. Otherwise, return null.
83 */
84 public static MouseEvent mouseReleased(MouseEvent me) {
85 return ((DragRecognitionSupport)getDragRecognitionSupport()).
86 mouseReleasedImpl(me);
87 }
88
89 /**
90 * Returns whether or not a drag gesture recognition is ongoing.
91 */
92 public static boolean mouseDragged(MouseEvent me, BeforeDrag bd) {
93 return ((DragRecognitionSupport)getDragRecognitionSupport()).
94 mouseDraggedImpl(me, bd);
95 }
96
97 private void clearState() {
98 dndArmedEvent = null;
99 component = null;
100 }
101
102 private int mapDragOperationFromModifiers(MouseEvent me,
103 TransferHandler th) {
104
105 if (th == null || !SwingUtilities.isLeftMouseButton(me)) {
106 return TransferHandler.NONE;
107 }
108
109 return SunDragSourceContextPeer.
110 convertModifiersToDropAction(me.getModifiersEx(),
111 th.getSourceActions(component));
112 }
113
114 /**
115 * Returns whether or not the event is potentially part of a drag sequence.
116 */
117 private boolean mousePressedImpl(MouseEvent me) {
118 component = (JComponent)me.getSource();
119
120 if (mapDragOperationFromModifiers(me, component.getTransferHandler())
121 != TransferHandler.NONE) {
122
123 motionThreshold = DragSource.getDragThreshold();
124 dndArmedEvent = me;
125 return true;
126 }
127
128 clearState();
129 return false;
130 }
131
132 /**
133 * If a dnd recognition has been going on, return the MouseEvent
134 * that started the recognition. Otherwise, return null.
135 */
136 private MouseEvent mouseReleasedImpl(MouseEvent me) {
137 /* no recognition has been going on */
138 if (dndArmedEvent == null) {
139 return null;
140 }
141
142 MouseEvent retEvent = null;
143
144 if (me.getSource() == component) {
145 retEvent = dndArmedEvent;
146 } // else component has changed unexpectedly, so return null
147
148 clearState();
149 return retEvent;
150 }
151
152 /**
153 * Returns whether or not a drag gesture recognition is ongoing.
154 */
155 private boolean mouseDraggedImpl(MouseEvent me, BeforeDrag bd) {
156 /* no recognition is in progress */
157 if (dndArmedEvent == null) {
158 return false;
159 }
160
161 /* component has changed unexpectedly, so bail */
162 if (me.getSource() != component) {
163 clearState();
164 return false;
165 }
166
167 int dx = Math.abs(me.getX() - dndArmedEvent.getX());
168 int dy = Math.abs(me.getY() - dndArmedEvent.getY());
169 if ((dx > motionThreshold) || (dy > motionThreshold)) {
170 TransferHandler th = component.getTransferHandler();
171 int action = mapDragOperationFromModifiers(me, th);
172 if (action != TransferHandler.NONE) {
173 /* notify the BeforeDrag instance */
174 if (bd != null) {
175 bd.dragStarting(dndArmedEvent);
176 }
177 th.exportAsDrag(component, dndArmedEvent, action);
178 clearState();
179 }
180 }
181
182 return true;
183 }
184}