1 /*
2 * Copyright 1998-2006 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 */
25
26 package java.awt.dnd;
27
28 import java.awt.event.InputEvent;
29 import java.awt.Component;
30 import java.awt.Point;
31
32 import java.util.TooManyListenersException;
33 import java.util.ArrayList;
34
35 import java.io.IOException;
36 import java.io.ObjectInputStream;
37 import java.io.ObjectOutputStream;
38 import java.io.Serializable;
39
40 /**
41 * The <code>DragGestureRecognizer</code> is an
42 * abstract base class for the specification
43 * of a platform-dependent listener that can be associated with a particular
44 * <code>Component</code> in order to
45 * identify platform-dependent drag initiating gestures.
46 * <p>
47 * The appropriate <code>DragGestureRecognizer</code>
48 * subclass instance is obtained from the
49 * {@link DragSource} asssociated with
50 * a particular <code>Component</code>, or from the <code>Toolkit</code> object via its
51 * {@link java.awt.Toolkit#createDragGestureRecognizer createDragGestureRecognizer()}
52 * method.
53 * <p>
54 * Once the <code>DragGestureRecognizer</code>
55 * is associated with a particular <code>Component</code>
56 * it will register the appropriate listener interfaces on that
57 * <code>Component</code>
58 * in order to track the input events delivered to the <code>Component</code>.
59 * <p>
60 * Once the <code>DragGestureRecognizer</code> identifies a sequence of events
61 * on the <code>Component</code> as a drag initiating gesture, it will notify
62 * its unicast <code>DragGestureListener</code> by
63 * invoking its
64 * {@link java.awt.dnd.DragGestureListener#dragGestureRecognized gestureRecognized()}
65 * method.
66 * <P>
67 * When a concrete <code>DragGestureRecognizer</code>
68 * instance detects a drag initiating
69 * gesture on the <code>Component</code> it is associated with,
70 * it fires a {@link DragGestureEvent} to
71 * the <code>DragGestureListener</code> registered on
72 * its unicast event source for <code>DragGestureListener</code>
73 * events. This <code>DragGestureListener</code> is responsible
74 * for causing the associated
75 * <code>DragSource</code> to start the Drag and Drop operation (if
76 * appropriate).
77 * <P>
78 * @author Laurence P. G. Cable
79 * @see java.awt.dnd.DragGestureListener
80 * @see java.awt.dnd.DragGestureEvent
81 * @see java.awt.dnd.DragSource
82 */
83
84 public abstract class DragGestureRecognizer implements Serializable {
85
86 private static final long serialVersionUID = 8996673345831063337L;
87
88 /**
89 * Construct a new <code>DragGestureRecognizer</code>
90 * given the <code>DragSource</code> to be used
91 * in this Drag and Drop operation, the <code>Component</code>
92 * this <code>DragGestureRecognizer</code> should "observe"
93 * for drag initiating gestures, the action(s) supported
94 * for this Drag and Drop operation, and the
95 * <code>DragGestureListener</code> to notify
96 * once a drag initiating gesture has been detected.
97 * <P>
98 * @param ds the <code>DragSource</code> this
99 * <code>DragGestureRecognizer</code>
100 * will use to process the Drag and Drop operation
101 *
102 * @param c the <code>Component</code>
103 * this <code>DragGestureRecognizer</code>
104 * should "observe" the event stream to,
105 * in order to detect a drag initiating gesture.
106 * If this value is <code>null</code>, the
107 * <code>DragGestureRecognizer</code>
108 * is not associated with any <code>Component</code>.
109 *
110 * @param sa the set (logical OR) of the
111 * <code>DnDConstants</code>
112 * that this Drag and Drop operation will support
113 *
114 * @param dgl the <code>DragGestureRecognizer</code>
115 * to notify when a drag gesture is detected
116 * <P>
117 * @throws <code>IllegalArgumentException</code>
118 * if ds is <code>null</code>.
119 */
120
121 protected DragGestureRecognizer(DragSource ds, Component c, int sa, DragGestureListener dgl) {
122 super();
123
124 if (ds == null) throw new IllegalArgumentException("null DragSource");
125
126 dragSource = ds;
127 component = c;
128 sourceActions = sa & (DnDConstants.ACTION_COPY_OR_MOVE | DnDConstants.ACTION_LINK);
129
130 try {
131 if (dgl != null) addDragGestureListener(dgl);
132 } catch (TooManyListenersException tmle) {
133 // cant happen ...
134 }
135 }
136
137 /**
138 * Construct a new <code>DragGestureRecognizer</code>
139 * given the <code>DragSource</code> to be used in this
140 * Drag and Drop
141 * operation, the <code>Component</code> this
142 * <code>DragGestureRecognizer</code> should "observe"
143 * for drag initiating gestures, and the action(s)
144 * supported for this Drag and Drop operation.
145 * <P>
146 * @param ds the <code>DragSource</code> this
147 * <code>DragGestureRecognizer</code> will use to
148 * process the Drag and Drop operation
149 *
150 * @param c the <code>Component</code> this
151 * <code>DragGestureRecognizer</code> should "observe" the event
152 * stream to, in order to detect a drag initiating gesture.
153 * If this value is <code>null</code>, the
154 * <code>DragGestureRecognizer</code>
155 * is not associated with any <code>Component</code>.
156 *
157 * @param sa the set (logical OR) of the <code>DnDConstants</code>
158 * that this Drag and Drop operation will support
159 * <P>
160 * @throws <code>IllegalArgumentException</code>
161 * if ds is <code>null</code>.
162 */
163
164 protected DragGestureRecognizer(DragSource ds, Component c, int sa) {
165 this(ds, c, sa, null);
166 }
167
168 /**
169 * Construct a new <code>DragGestureRecognizer</code>
170 * given the <code>DragSource</code> to be used
171 * in this Drag and Drop operation, and
172 * the <code>Component</code> this
173 * <code>DragGestureRecognizer</code>
174 * should "observe" for drag initiating gestures.
175 * <P>
176 * @param ds the <code>DragSource</code> this
177 * <code>DragGestureRecognizer</code>
178 * will use to process the Drag and Drop operation
179 *
180 * @param c the <code>Component</code>
181 * this <code>DragGestureRecognizer</code>
182 * should "observe" the event stream to,
183 * in order to detect a drag initiating gesture.
184 * If this value is <code>null</code>,
185 * the <code>DragGestureRecognizer</code>
186 * is not associated with any <code>Component</code>.
187 * <P>
188 * @throws <code>IllegalArgumentException</code>
189 * if ds is <code>null</code>.
190 */
191
192 protected DragGestureRecognizer(DragSource ds, Component c) {
193 this(ds, c, DnDConstants.ACTION_NONE);
194 }
195
196 /**
197 * Construct a new <code>DragGestureRecognizer</code>
198 * given the <code>DragSource</code> to be used in this
199 * Drag and Drop operation.
200 * <P>
201 * @param ds the <code>DragSource</code> this
202 * <code>DragGestureRecognizer</code> will
203 * use to process the Drag and Drop operation
204 * <P>
205 * @throws <code>IllegalArgumentException</code>
206 * if ds is <code>null</code>.
207 */
208
209 protected DragGestureRecognizer(DragSource ds) {
210 this(ds, null);
211 }
212
213 /**
214 * register this DragGestureRecognizer's Listeners with the Component
215 *
216 * subclasses must override this method
217 */
218
219 protected abstract void registerListeners();
220
221 /**
222 * unregister this DragGestureRecognizer's Listeners with the Component
223 *
224 * subclasses must override this method
225 */
226
227 protected abstract void unregisterListeners();
228
229 /**
230 * This method returns the <code>DragSource</code>
231 * this <code>DragGestureRecognizer</code>
232 * will use in order to process the Drag and Drop
233 * operation.
234 * <P>
235 * @return the DragSource
236 */
237
238 public DragSource getDragSource() { return dragSource; }
239
240 /**
241 * This method returns the <code>Component</code>
242 * that is to be "observed" by the
243 * <code>DragGestureRecognizer</code>
244 * for drag initiating gestures.
245 * <P>
246 * @return The Component this DragGestureRecognizer
247 * is associated with
248 */
249
250 public synchronized Component getComponent() { return component; }
251
252 /**
253 * set the Component that the DragGestureRecognizer is associated with
254 *
255 * registerListeners() and unregisterListeners() are called as a side
256 * effect as appropriate.
257 * <P>
258 * @param c The <code>Component</code> or <code>null</code>
259 */
260
261 public synchronized void setComponent(Component c) {
262 if (component != null && dragGestureListener != null)
263 unregisterListeners();
264
265 component = c;
266
267 if (component != null && dragGestureListener != null)
268 registerListeners();
269 }
270
271 /**
272 * This method returns an int representing the
273 * type of action(s) this Drag and Drop
274 * operation will support.
275 * <P>
276 * @return the currently permitted source action(s)
277 */
278
279 public synchronized int getSourceActions() { return sourceActions; }
280
281 /**
282 * This method sets the permitted source drag action(s)
283 * for this Drag and Drop operation.
284 * <P>
285 * @param actions the permitted source drag action(s)
286 */
287
288 public synchronized void setSourceActions(int actions) {
289 sourceActions = actions & (DnDConstants.ACTION_COPY_OR_MOVE | DnDConstants.ACTION_LINK);
290 }
291
292 /**
293 * This method returns the first event in the
294 * series of events that initiated
295 * the Drag and Drop operation.
296 * <P>
297 * @return the initial event that triggered the drag gesture
298 */
299
300 public InputEvent getTriggerEvent() { return events.isEmpty() ? null : (InputEvent)events.get(0); }
301
302 /**
303 * Reset the Recognizer, if its currently recognizing a gesture, ignore
304 * it.
305 */
306
307 public void resetRecognizer() { events.clear(); }
308
309 /**
310 * Register a new <code>DragGestureListener</code>.
311 * <P>
312 * @param dgl the <code>DragGestureListener</code> to register
313 * with this <code>DragGestureRecognizer</code>.
314 * <P>
315 * @throws java.util.TooManyListenersException if a
316 * <code>DragGestureListener</code> has already been added.
317 */
318
319 public synchronized void addDragGestureListener(DragGestureListener dgl) throws TooManyListenersException {
320 if (dragGestureListener != null)
321 throw new TooManyListenersException();
322 else {
323 dragGestureListener = dgl;
324
325 if (component != null) registerListeners();
326 }
327 }
328
329 /**
330 * unregister the current DragGestureListener
331 * <P>
332 * @param dgl the <code>DragGestureListener</code> to unregister
333 * from this <code>DragGestureRecognizer</code>
334 * <P>
335 * @throws <code>IllegalArgumentException</code> if
336 * dgl is not (equal to) the currently registered <code>DragGestureListener</code>.
337 */
338
339 public synchronized void removeDragGestureListener(DragGestureListener dgl) {
340 if (dragGestureListener == null || !dragGestureListener.equals(dgl))
341 throw new IllegalArgumentException();
342 else {
343 dragGestureListener = null;
344
345 if (component != null) unregisterListeners();
346 }
347 }
348
349 /**
350 * Notify the DragGestureListener that a Drag and Drop initiating
351 * gesture has occurred. Then reset the state of the Recognizer.
352 * <P>
353 * @param dragAction The action initially selected by the users gesture
354 * @param p The point (in Component coords) where the gesture originated
355 */
356 protected synchronized void fireDragGestureRecognized(int dragAction, Point p) {
357 try {
358 if (dragGestureListener != null) {
359 dragGestureListener.dragGestureRecognized(new DragGestureEvent(this, dragAction, p, events));
360 }
361 } finally {
362 events.clear();
363 }
364 }
365
366 /**
367 * Listeners registered on the Component by this Recognizer shall record
368 * all Events that are recognized as part of the series of Events that go
369 * to comprise a Drag and Drop initiating gesture via this API.
370 *<P>
371 * This method is used by a <code>DragGestureRecognizer</code>
372 * implementation to add an <code>InputEvent</code>
373 * subclass (that it believes is one in a series
374 * of events that comprise a Drag and Drop operation)
375 * to the array of events that this
376 * <code>DragGestureRecognizer</code> maintains internally.
377 * <P>
378 * @param awtie the <code>InputEvent</code>
379 * to add to this <code>DragGestureRecognizer</code>'s
380 * internal array of events. Note that <code>null</code>
381 * is not a valid value, and will be ignored.
382 */
383
384 protected synchronized void appendEvent(InputEvent awtie) {
385 events.add(awtie);
386 }
387
388 /**
389 * Serializes this <code>DragGestureRecognizer</code>. This method first
390 * performs default serialization. Then, this object's
391 * <code>DragGestureListener</code> is written out if and only if it can be
392 * serialized. If not, <code>null</code> is written instead.
393 *
394 * @serialData The default serializable fields, in alphabetical order,
395 * followed by either a <code>DragGestureListener</code>, or
396 * <code>null</code>.
397 * @since 1.4
398 */
399 private void writeObject(ObjectOutputStream s) throws IOException {
400 s.defaultWriteObject();
401
402 s.writeObject(SerializationTester.test(dragGestureListener)
403 ? dragGestureListener : null);
404 }
405
406 /**
407 * Deserializes this <code>DragGestureRecognizer</code>. This method first
408 * performs default deserialization for all non-<code>transient</code>
409 * fields. This object's <code>DragGestureListener</code> is then
410 * deserialized as well by using the next object in the stream.
411 *
412 * @since 1.4
413 */
414 private void readObject(ObjectInputStream s)
415 throws ClassNotFoundException, IOException
416 {
417 s.defaultReadObject();
418
419 dragGestureListener = (DragGestureListener)s.readObject();
420 }
421
422 /*
423 * fields
424 */
425
426 /**
427 * The <code>DragSource</code>
428 * associated with this
429 * <code>DragGestureRecognizer</code>.
430 *
431 * @serial
432 */
433 protected DragSource dragSource;
434
435 /**
436 * The <code>Component</code>
437 * associated with this <code>DragGestureRecognizer</code>.
438 *
439 * @serial
440 */
441 protected Component component;
442
443 /**
444 * The <code>DragGestureListener</code>
445 * associated with this <code>DragGestureRecognizer</code>.
446 */
447 protected transient DragGestureListener dragGestureListener;
448
449 /**
450 * An <code>int</code> representing
451 * the type(s) of action(s) used
452 * in this Drag and Drop operation.
453 *
454 * @serial
455 */
456 protected int sourceActions;
457
458 /**
459 * The list of events (in order) that
460 * the <code>DragGestureRecognizer</code>
461 * "recognized" as a "gesture" that triggers a drag.
462 *
463 * @serial
464 */
465 protected ArrayList<InputEvent> events = new ArrayList<InputEvent>(1);
466 }