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