1. /*
  2. * @(#)DragSource.java 1.45 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.AWTError;
  9. import java.awt.AWTException;
  10. import java.awt.event.InputEvent;
  11. import java.awt.AWTPermission;
  12. import java.awt.Component;
  13. import java.awt.Cursor;
  14. import java.awt.GraphicsEnvironment;
  15. import java.awt.HeadlessException;
  16. import java.awt.Image;
  17. import java.awt.Point;
  18. import java.awt.Toolkit;
  19. import java.awt.datatransfer.FlavorMap;
  20. import java.awt.datatransfer.SystemFlavorMap;
  21. import java.awt.datatransfer.Transferable;
  22. import java.awt.dnd.peer.DragSourceContextPeer;
  23. import java.io.Serializable;
  24. import java.io.IOException;
  25. import java.io.ObjectInputStream;
  26. import java.io.ObjectOutputStream;
  27. import java.io.Serializable;
  28. import java.security.AccessController;
  29. import java.util.EventListener;
  30. import sun.awt.dnd.SunDragSourceContextPeer;
  31. import sun.security.action.GetIntegerAction;
  32. /**
  33. * The <code>DragSource</code> is the entity responsible
  34. * for the initiation of the Drag
  35. * and Drop operation, and may be used in a number of scenarios:
  36. * <UL>
  37. * <LI>1 default instance per JVM for the lifetime of that JVM.
  38. * <LI>1 instance per class of potential Drag Initiator object (e.g
  39. * TextField). [implementation dependent]
  40. * <LI>1 per instance of a particular
  41. * <code>Component</code>, or application specific
  42. * object associated with a <code>Component</code>
  43. * instance in the GUI. [implementation dependent]
  44. * <LI>Some other arbitrary association. [implementation dependent]
  45. *</UL>
  46. *
  47. * Once the <code>DragSource</code> is
  48. * obtained, a <code>DragGestureRecognizer</code> should
  49. * also be obtained to associate the <code>DragSource</code>
  50. * with a particular
  51. * <code>Component</code>.
  52. * <P>
  53. * The initial interpretation of the user's gesture,
  54. * and the subsequent starting of the drag operation
  55. * are the responsibility of the implementing
  56. * <code>Component</code>, which is usually
  57. * implemented by a <code>DragGestureRecognizer</code>.
  58. *<P>
  59. * When a drag gesture occurs, the
  60. * <code>DragSource</code>'s
  61. * startDrag() method shall be
  62. * invoked in order to cause processing
  63. * of the user's navigational
  64. * gestures and delivery of Drag and Drop
  65. * protocol notifications. A
  66. * <code>DragSource</code> shall only
  67. * permit a single Drag and Drop operation to be
  68. * current at any one time, and shall
  69. * reject any further startDrag() requests
  70. * by throwing an <code>IllegalDnDOperationException</code>
  71. * until such time as the extant operation is complete.
  72. * <P>
  73. * The startDrag() method invokes the
  74. * createDragSourceContext() method to
  75. * instantiate an appropriate
  76. * <code>DragSourceContext</code>
  77. * and associate the <code>DragSourceContextPeer</code>
  78. * with that.
  79. * <P>
  80. * If the Drag and Drop System is
  81. * unable to initiate a drag operation for
  82. * some reason, the startDrag() method throws
  83. * a <code>java.awt.dnd.InvalidDnDOperationException</code>
  84. * to signal such a condition. Typically this
  85. * exception is thrown when the underlying platform
  86. * system is either not in a state to
  87. * initiate a drag, or the parameters specified are invalid.
  88. * <P>
  89. * Note that during the drag, the
  90. * set of operations exposed by the source
  91. * at the start of the drag operation may not change
  92. * until the operation is complete.
  93. * The operation(s) are constant for the
  94. * duration of the operation with respect to the
  95. * <code>DragSource</code>.
  96. *
  97. * @version 1.45, 05/05/04
  98. * @since 1.2
  99. */
  100. public class DragSource implements Serializable {
  101. private static final long serialVersionUID = 6236096958971414066L;
  102. /*
  103. * load a system default cursor
  104. */
  105. private static Cursor load(String name) {
  106. if (GraphicsEnvironment.isHeadless()) {
  107. return null;
  108. }
  109. try {
  110. return (Cursor)Toolkit.getDefaultToolkit().getDesktopProperty(name);
  111. } catch (Exception e) {
  112. e.printStackTrace();
  113. throw new RuntimeException("failed to load system cursor: " + name + " : " + e.getMessage());
  114. }
  115. }
  116. /**
  117. * The default <code>Cursor</code> to use with a copy operation indicating
  118. * that a drop is currently allowed. <code>null</code> if
  119. * <code>GraphicsEnvironment.isHeadless()</code> returns <code>true</code>.
  120. *
  121. * @see java.awt.GraphicsEnvironment#isHeadless
  122. */
  123. public static final Cursor DefaultCopyDrop =
  124. load("DnD.Cursor.CopyDrop");
  125. /**
  126. * The default <code>Cursor</code> to use with a move operation indicating
  127. * that a drop is currently allowed. <code>null</code> if
  128. * <code>GraphicsEnvironment.isHeadless()</code> returns <code>true</code>.
  129. *
  130. * @see java.awt.GraphicsEnvironment#isHeadless
  131. */
  132. public static final Cursor DefaultMoveDrop =
  133. load("DnD.Cursor.MoveDrop");
  134. /**
  135. * The default <code>Cursor</code> to use with a link operation indicating
  136. * that a drop is currently allowed. <code>null</code> if
  137. * <code>GraphicsEnvironment.isHeadless()</code> returns <code>true</code>.
  138. *
  139. * @see java.awt.GraphicsEnvironment#isHeadless
  140. */
  141. public static final Cursor DefaultLinkDrop =
  142. load("DnD.Cursor.LinkDrop");
  143. /**
  144. * The default <code>Cursor</code> to use with a copy operation indicating
  145. * that a drop is currently not allowed. <code>null</code> if
  146. * <code>GraphicsEnvironment.isHeadless()</code> returns <code>true</code>.
  147. *
  148. * @see java.awt.GraphicsEnvironment#isHeadless
  149. */
  150. public static final Cursor DefaultCopyNoDrop =
  151. load("DnD.Cursor.CopyNoDrop");
  152. /**
  153. * The default <code>Cursor</code> to use with a move operation indicating
  154. * that a drop is currently not allowed. <code>null</code> if
  155. * <code>GraphicsEnvironment.isHeadless()</code> returns <code>true</code>.
  156. *
  157. * @see java.awt.GraphicsEnvironment#isHeadless
  158. */
  159. public static final Cursor DefaultMoveNoDrop =
  160. load("DnD.Cursor.MoveNoDrop");
  161. /**
  162. * The default <code>Cursor</code> to use with a link operation indicating
  163. * that a drop is currently not allowed. <code>null</code> if
  164. * <code>GraphicsEnvironment.isHeadless()</code> returns <code>true</code>.
  165. *
  166. * @see java.awt.GraphicsEnvironment#isHeadless
  167. */
  168. public static final Cursor DefaultLinkNoDrop =
  169. load("DnD.Cursor.LinkNoDrop");
  170. private static final DragSource dflt =
  171. (GraphicsEnvironment.isHeadless()) ? null : new DragSource();
  172. /**
  173. * Internal constants for serialization.
  174. */
  175. static final String dragSourceListenerK = "dragSourceL";
  176. static final String dragSourceMotionListenerK = "dragSourceMotionL";
  177. /**
  178. * Gets the <code>DragSource</code> object associated with
  179. * the underlying platform.
  180. *
  181. * @return the platform DragSource
  182. * @exception HeadlessException if GraphicsEnvironment.isHeadless()
  183. * returns true
  184. * @see java.awt.GraphicsEnvironment#isHeadless
  185. */
  186. public static DragSource getDefaultDragSource() {
  187. if (GraphicsEnvironment.isHeadless()) {
  188. throw new HeadlessException();
  189. } else {
  190. return dflt;
  191. }
  192. }
  193. /**
  194. * Reports
  195. * whether or not drag
  196. * <code>Image</code> support
  197. * is available on the underlying platform.
  198. * <P>
  199. * @return if the Drag Image support is available on this platform
  200. */
  201. public static boolean isDragImageSupported() {
  202. Toolkit t = Toolkit.getDefaultToolkit();
  203. Boolean supported;
  204. try {
  205. supported = (Boolean)Toolkit.getDefaultToolkit().getDesktopProperty("DnD.isDragImageSupported");
  206. return supported.booleanValue();
  207. } catch (Exception e) {
  208. return false;
  209. }
  210. }
  211. /**
  212. * Creates a new <code>DragSource</code>.
  213. *
  214. * @exception HeadlessException if GraphicsEnvironment.isHeadless()
  215. * returns true
  216. * @see java.awt.GraphicsEnvironment#isHeadless
  217. */
  218. public DragSource() throws HeadlessException {
  219. if (GraphicsEnvironment.isHeadless()) {
  220. throw new HeadlessException();
  221. }
  222. }
  223. /**
  224. * Start a drag, given the <code>DragGestureEvent</code>
  225. * that initiated the drag, the initial
  226. * <code>Cursor</code> to use,
  227. * the <code>Image</code> to drag,
  228. * the offset of the <code>Image</code> origin
  229. * from the hotspot of the <code>Cursor</code> at
  230. * the instant of the trigger,
  231. * the <code>Transferable</code> subject data
  232. * of the drag, the <code>DragSourceListener</code>,
  233. * and the <code>FlavorMap</code>.
  234. * <P>
  235. * @param trigger the <code>DragGestureEvent</code> that initiated the drag
  236. * @param dragCursor the initial <code>Cursor</code> or <code>null</code> for defaults
  237. * @param dragImage the image to drag or null,
  238. * @param imageOffset the offset of the <code>Image</code> origin from the hotspot
  239. * of the <code>Cursor</code> at the instant of the trigger
  240. * @param transferable the subject data of the drag
  241. * @param dsl the <code>DragSourceListener</code>
  242. * @param flavorMap the <code>FlavorMap</code> to use, or <code>null</code>
  243. * <P>
  244. * @throws <code>java.awt.dnd.InvalidDnDOperationException</code>
  245. * if the Drag and Drop
  246. * system is unable to initiate a drag operation, or if the user
  247. * attempts to start a drag while an existing drag operation
  248. * is still executing
  249. */
  250. public void startDrag(DragGestureEvent trigger,
  251. Cursor dragCursor,
  252. Image dragImage,
  253. Point imageOffset,
  254. Transferable transferable,
  255. DragSourceListener dsl,
  256. FlavorMap flavorMap) throws InvalidDnDOperationException {
  257. SunDragSourceContextPeer.setDragDropInProgress(true);
  258. try {
  259. if (flavorMap != null) this.flavorMap = flavorMap;
  260. DragSourceContextPeer dscp = Toolkit.getDefaultToolkit().createDragSourceContextPeer(trigger);
  261. DragSourceContext dsc = createDragSourceContext(dscp,
  262. trigger,
  263. dragCursor,
  264. dragImage,
  265. imageOffset,
  266. transferable,
  267. dsl
  268. );
  269. if (dsc == null) {
  270. throw new InvalidDnDOperationException();
  271. }
  272. dscp.startDrag(dsc, dsc.getCursor(), dragImage, imageOffset); // may throw
  273. } catch (RuntimeException e) {
  274. SunDragSourceContextPeer.setDragDropInProgress(false);
  275. throw e;
  276. }
  277. }
  278. /**
  279. * Start a drag, given the <code>DragGestureEvent</code>
  280. * that initiated the drag, the initial
  281. * <code>Cursor</code> to use,
  282. * the <code>Transferable</code> subject data
  283. * of the drag, the <code>DragSourceListener</code>,
  284. * and the <code>FlavorMap</code>.
  285. * <P>
  286. * @param trigger the <code>DragGestureEvent</code> that
  287. * initiated the drag
  288. * @param dragCursor the initial <code>Cursor</code> or
  289. * <code>null</code> for defaults
  290. * @param transferable the subject data of the drag
  291. * @param dsl the <code>DragSourceListener</code>
  292. * @param flavorMap the <code>FlavorMap</code> to use or <code>null</code>
  293. * <P>
  294. * @throws <code>java.awt.dnd.InvalidDnDOperationException</code>
  295. * if the Drag and Drop
  296. * system is unable to initiate a drag operation, or if the user
  297. * attempts to start a drag while an existing drag operation
  298. * is still executing
  299. */
  300. public void startDrag(DragGestureEvent trigger,
  301. Cursor dragCursor,
  302. Transferable transferable,
  303. DragSourceListener dsl,
  304. FlavorMap flavorMap) throws InvalidDnDOperationException {
  305. startDrag(trigger, dragCursor, null, null, transferable, dsl, flavorMap);
  306. }
  307. /**
  308. * Start a drag, given the <code>DragGestureEvent</code>
  309. * that initiated the drag, the initial <code>Cursor</code>
  310. * to use,
  311. * the <code>Image</code> to drag,
  312. * the offset of the <code>Image</code> origin
  313. * from the hotspot of the <code>Cursor</code>
  314. * at the instant of the trigger,
  315. * the subject data of the drag, and
  316. * the <code>DragSourceListener</code>.
  317. * <P>
  318. * @param trigger the <code>DragGestureEvent</code> that initiated the drag
  319. * @param dragCursor the initial <code>Cursor</code> or <code>null</code> for defaults
  320. * @param dragImage the <code>Image</code> to drag or <code>null</code>
  321. * @param dragOffset the offset of the <code>Image</code> origin from the hotspot
  322. * of the <code>Cursor</code> at the instant of the trigger
  323. * @param transferable the subject data of the drag
  324. * @param dsl the <code>DragSourceListener</code>
  325. * <P>
  326. * @throws <code>java.awt.dnd.InvalidDnDOperationException</code>
  327. * if the Drag and Drop
  328. * system is unable to initiate a drag operation, or if the user
  329. * attempts to start a drag while an existing drag operation
  330. * is still executing
  331. */
  332. public void startDrag(DragGestureEvent trigger,
  333. Cursor dragCursor,
  334. Image dragImage,
  335. Point dragOffset,
  336. Transferable transferable,
  337. DragSourceListener dsl) throws InvalidDnDOperationException {
  338. startDrag(trigger, dragCursor, dragImage, dragOffset, transferable, dsl, null);
  339. }
  340. /**
  341. * Start a drag, given the <code>DragGestureEvent</code>
  342. * that initiated the drag, the initial
  343. * <code>Cursor</code> to
  344. * use,
  345. * the <code>Transferable</code> subject data
  346. * of the drag, and the <code>DragSourceListener</code>.
  347. * <P>
  348. * @param trigger the <code>DragGestureEvent</code> that initiated the drag
  349. * @param dragCursor the initial <code>Cursor</code> or <code>null</code> for defaults
  350. * @param transferable the subject data of the drag
  351. * @param dsl the <code>DragSourceListener</code>
  352. * <P>
  353. * @throws <code>java.awt.dnd.InvalidDnDOperationException</code>
  354. * if the Drag and Drop
  355. * system is unable to initiate a drag operation, or if the user
  356. * attempts to start a drag while an existing drag operation
  357. * is still executing
  358. */
  359. public void startDrag(DragGestureEvent trigger,
  360. Cursor dragCursor,
  361. Transferable transferable,
  362. DragSourceListener dsl) throws InvalidDnDOperationException {
  363. startDrag(trigger, dragCursor, null, null, transferable, dsl, null);
  364. }
  365. /**
  366. * Creates the <code>DragSourceContext</code> to handle this drag.
  367. * <p>
  368. * To incorporate a new <code>DragSourceContext</code>
  369. * subclass, subclass <code>DragSource</code> and
  370. * override this method.
  371. * <p>
  372. * If <code>dragImage</code> is <code>null</code>, no image is used
  373. * to represent the drag over feedback for this drag operation, but
  374. * <code>NullPointerException</code> is not thrown.
  375. * <p>
  376. * If <code>dsl</code> is <code>null</code>, no drag source listener
  377. * is registered with the created <code>DragSourceContext</code>,
  378. * but <code>NullPointerException</code> is not thrown.
  379. * <p>
  380. * If <code>dragCursor</code> is <code>null</code>, the default drag
  381. * cursors are used for this drag operation.
  382. * <code>NullPointerException</code> is not thrown.
  383. *
  384. * @param dscp The <code>DragSourceContextPeer</code> for this drag
  385. * @param dgl The <code>DragGestureEvent</code> that triggered the
  386. * drag
  387. * @param dragCursor The initial <code>Cursor</code> to display
  388. * @param dragImage The <code>Image</code> to drag or <code>null</code>
  389. * @param imageOffset The offset of the <code>Image</code> origin from the
  390. * hotspot of the cursor at the instant of the trigger
  391. * @param t The subject data of the drag
  392. * @param dsl The <code>DragSourceListener</code>
  393. *
  394. * @return the <code>DragSourceContext</code>
  395. *
  396. * @throws NullPointerException if <code>dscp</code> is <code>null</code>
  397. * @throws NullPointerException if <code>dgl</code> is <code>null</code>
  398. * @throws NullPointerException if <code>dragImage</code> is not
  399. * <code>null</code> and <code>imageOffset</code> is <code>null</code>
  400. * @throws NullPointerException if <code>t</code> is <code>null</code>
  401. * @throws IllegalArgumentException if the <code>Component</code>
  402. * associated with the trigger event is <code>null</code>.
  403. * @throws IllegalArgumentException if the <code>DragSource</code> for the
  404. * trigger event is <code>null</code>.
  405. * @throws IllegalArgumentException if the drag action for the
  406. * trigger event is <code>DnDConstants.ACTION_NONE</code>.
  407. * @throws IllegalArgumentException if the source actions for the
  408. * <code>DragGestureRecognizer</code> associated with the trigger
  409. * event are equal to <code>DnDConstants.ACTION_NONE</code>.
  410. */
  411. protected DragSourceContext createDragSourceContext(DragSourceContextPeer dscp, DragGestureEvent dgl, Cursor dragCursor, Image dragImage, Point imageOffset, Transferable t, DragSourceListener dsl) {
  412. return new DragSourceContext(dscp, dgl, dragCursor, dragImage, imageOffset, t, dsl);
  413. }
  414. /**
  415. * This method returns the
  416. * <code>FlavorMap</code> for this <code>DragSource</code>.
  417. * <P>
  418. * @return the <code>FlavorMap</code> for this <code>DragSource</code>
  419. */
  420. public FlavorMap getFlavorMap() { return flavorMap; }
  421. /**
  422. * Creates a new <code>DragGestureRecognizer</code>
  423. * that implements the specified
  424. * abstract subclass of
  425. * <code>DragGestureRecognizer</code>, and
  426. * sets the specified <code>Component</code>
  427. * and <code>DragGestureListener</code> on
  428. * the newly created object.
  429. * <P>
  430. * @param recognizerAbstractClass the requested abstract type
  431. * @param actions the permitted source drag actions
  432. * @param c the <code>Component</code> target
  433. * @param dgl the <code>DragGestureListener</code> to notify
  434. * <P>
  435. * @return the new <code>DragGestureRecognizer</code> or <code>null</code>
  436. * if the <code>Toolkit.createDragGestureRecognizer</code> method
  437. * has no implementation available for
  438. * the requested <code>DragGestureRecognizer</code>
  439. * subclass and returns <code>null</code>
  440. */
  441. public <T extends DragGestureRecognizer> T
  442. createDragGestureRecognizer(Class<T> recognizerAbstractClass,
  443. Component c, int actions,
  444. DragGestureListener dgl)
  445. {
  446. return Toolkit.getDefaultToolkit().createDragGestureRecognizer(recognizerAbstractClass, this, c, actions, dgl);
  447. }
  448. /**
  449. * Creates a new <code>DragGestureRecognizer</code>
  450. * that implements the default
  451. * abstract subclass of <code>DragGestureRecognizer</code>
  452. * for this <code>DragSource</code>,
  453. * and sets the specified <code>Component</code>
  454. * and <code>DragGestureListener</code> on the
  455. * newly created object.
  456. *
  457. * For this <code>DragSource</code>
  458. * the default is <code>MouseDragGestureRecognizer</code>.
  459. * <P>
  460. * @param c the <code>Component</code> target for the recognizer
  461. * @param actions the permitted source actions
  462. * @param dgl the <code>DragGestureListener</code> to notify
  463. * <P>
  464. * @return the new <code>DragGestureRecognizer</code> or <code>null</code>
  465. * if the <code>Toolkit.createDragGestureRecognizer</code> method
  466. * has no implementation available for
  467. * the requested <code>DragGestureRecognizer</code>
  468. * subclass and returns <code>null</code>
  469. */
  470. public DragGestureRecognizer createDefaultDragGestureRecognizer(Component c, int actions, DragGestureListener dgl) {
  471. return Toolkit.getDefaultToolkit().createDragGestureRecognizer(MouseDragGestureRecognizer.class, this, c, actions, dgl);
  472. }
  473. /**
  474. * Adds the specified <code>DragSourceListener</code> to this
  475. * <code>DragSource</code> to receive drag source events during drag
  476. * operations intiated with this <code>DragSource</code>.
  477. * If a <code>null</code> listener is specified, no action is taken and no
  478. * exception is thrown.
  479. *
  480. * @param dsl the <code>DragSourceListener</code> to add
  481. *
  482. * @see #removeDragSourceListener
  483. * @see #getDragSourceListeners
  484. * @since 1.4
  485. */
  486. public void addDragSourceListener(DragSourceListener dsl) {
  487. if (dsl != null) {
  488. synchronized (this) {
  489. listener = DnDEventMulticaster.add(listener, dsl);
  490. }
  491. }
  492. }
  493. /**
  494. * Removes the specified <code>DragSourceListener</code> from this
  495. * <code>DragSource</code>.
  496. * If a <code>null</code> listener is specified, no action is taken and no
  497. * exception is thrown.
  498. * If the listener specified by the argument was not previously added to
  499. * this <code>DragSource</code>, no action is taken and no exception
  500. * is thrown.
  501. *
  502. * @param dsl the <code>DragSourceListener</code> to remove
  503. *
  504. * @see #addDragSourceListener
  505. * @see #getDragSourceListeners
  506. * @since 1.4
  507. */
  508. public void removeDragSourceListener(DragSourceListener dsl) {
  509. if (dsl != null) {
  510. synchronized (this) {
  511. listener = DnDEventMulticaster.remove(listener, dsl);
  512. }
  513. }
  514. }
  515. /**
  516. * Gets all the <code>DragSourceListener</code>s
  517. * registered with this <code>DragSource</code>.
  518. *
  519. * @return all of this <code>DragSource</code>'s
  520. * <code>DragSourceListener</code>s or an empty array if no
  521. * such listeners are currently registered
  522. *
  523. * @see #addDragSourceListener
  524. * @see #removeDragSourceListener
  525. * @since 1.4
  526. */
  527. public DragSourceListener[] getDragSourceListeners() {
  528. return (DragSourceListener[])getListeners(DragSourceListener.class);
  529. }
  530. /**
  531. * Adds the specified <code>DragSourceMotionListener</code> to this
  532. * <code>DragSource</code> to receive drag motion events during drag
  533. * operations intiated with this <code>DragSource</code>.
  534. * If a <code>null</code> listener is specified, no action is taken and no
  535. * exception is thrown.
  536. *
  537. * @param dsml the <code>DragSourceMotionListener</code> to add
  538. *
  539. * @see #removeDragSourceMotionListener
  540. * @see #getDragSourceMotionListeners
  541. * @since 1.4
  542. */
  543. public void addDragSourceMotionListener(DragSourceMotionListener dsml) {
  544. if (dsml != null) {
  545. synchronized (this) {
  546. motionListener = DnDEventMulticaster.add(motionListener, dsml);
  547. }
  548. }
  549. }
  550. /**
  551. * Removes the specified <code>DragSourceMotionListener</code> from this
  552. * <code>DragSource</code>.
  553. * If a <code>null</code> listener is specified, no action is taken and no
  554. * exception is thrown.
  555. * If the listener specified by the argument was not previously added to
  556. * this <code>DragSource</code>, no action is taken and no exception
  557. * is thrown.
  558. *
  559. * @param dsml the <code>DragSourceMotionListener</code> to remove
  560. *
  561. * @see #addDragSourceMotionListener
  562. * @see #getDragSourceMotionListeners
  563. * @since 1.4
  564. */
  565. public void removeDragSourceMotionListener(DragSourceMotionListener dsml) {
  566. if (dsml != null) {
  567. synchronized (this) {
  568. motionListener = DnDEventMulticaster.remove(motionListener, dsml);
  569. }
  570. }
  571. }
  572. /**
  573. * Gets all of the <code>DragSourceMotionListener</code>s
  574. * registered with this <code>DragSource</code>.
  575. *
  576. * @return all of this <code>DragSource</code>'s
  577. * <code>DragSourceMotionListener</code>s or an empty array if no
  578. * such listeners are currently registered
  579. *
  580. * @see #addDragSourceMotionListener
  581. * @see #removeDragSourceMotionListener
  582. * @since 1.4
  583. */
  584. public DragSourceMotionListener[] getDragSourceMotionListeners() {
  585. return (DragSourceMotionListener[])
  586. getListeners(DragSourceMotionListener.class);
  587. }
  588. /**
  589. * Gets all the objects currently registered as
  590. * <code><em>Foo</em>Listener</code>s upon this <code>DragSource</code>.
  591. * <code><em>Foo</em>Listener</code>s are registered using the
  592. * <code>add<em>Foo</em>Listener</code> method.
  593. *
  594. * @param listenerType the type of listeners requested; this parameter
  595. * should specify an interface that descends from
  596. * <code>java.util.EventListener</code>
  597. * @return an array of all objects registered as
  598. * <code><em>Foo</em>Listener</code>s on this
  599. * <code>DragSource</code>, or an empty array if no such listeners
  600. * have been added
  601. * @exception <code>ClassCastException</code> if <code>listenerType</code>
  602. * doesn't specify a class or interface that implements
  603. * <code>java.util.EventListener</code>
  604. *
  605. * @see #getDragSourceListeners
  606. * @see #getDragSourceMotionListeners
  607. * @since 1.4
  608. */
  609. public <T extends EventListener> T[] getListeners(Class<T> listenerType) {
  610. EventListener l = null;
  611. if (listenerType == DragSourceListener.class) {
  612. l = listener;
  613. } else if (listenerType == DragSourceMotionListener.class) {
  614. l = motionListener;
  615. }
  616. return DnDEventMulticaster.getListeners(l, listenerType);
  617. }
  618. /**
  619. * This method calls <code>dragEnter</code> on the
  620. * <code>DragSourceListener</code>s registered with this
  621. * <code>DragSource</code>, and passes them the specified
  622. * <code>DragSourceDragEvent</code>.
  623. *
  624. * @param dsde the <code>DragSourceDragEvent</code>
  625. */
  626. void processDragEnter(DragSourceDragEvent dsde) {
  627. DragSourceListener dsl = listener;
  628. if (dsl != null) {
  629. dsl.dragEnter(dsde);
  630. }
  631. }
  632. /**
  633. * This method calls <code>dragOver</code> on the
  634. * <code>DragSourceListener</code>s registered with this
  635. * <code>DragSource</code>, and passes them the specified
  636. * <code>DragSourceDragEvent</code>.
  637. *
  638. * @param dsde the <code>DragSourceDragEvent</code>
  639. */
  640. void processDragOver(DragSourceDragEvent dsde) {
  641. DragSourceListener dsl = listener;
  642. if (dsl != null) {
  643. dsl.dragOver(dsde);
  644. }
  645. }
  646. /**
  647. * This method calls <code>dropActionChanged</code> on the
  648. * <code>DragSourceListener</code>s registered with this
  649. * <code>DragSource</code>, and passes them the specified
  650. * <code>DragSourceDragEvent</code>.
  651. *
  652. * @param dsde the <code>DragSourceDragEvent</code>
  653. */
  654. void processDropActionChanged(DragSourceDragEvent dsde) {
  655. DragSourceListener dsl = listener;
  656. if (dsl != null) {
  657. dsl.dropActionChanged(dsde);
  658. }
  659. }
  660. /**
  661. * This method calls <code>dragExit</code> on the
  662. * <code>DragSourceListener</code>s registered with this
  663. * <code>DragSource</code>, and passes them the specified
  664. * <code>DragSourceEvent</code>.
  665. *
  666. * @param dse the <code>DragSourceEvent</code>
  667. */
  668. void processDragExit(DragSourceEvent dse) {
  669. DragSourceListener dsl = listener;
  670. if (dsl != null) {
  671. dsl.dragExit(dse);
  672. }
  673. }
  674. /**
  675. * This method calls <code>dragDropEnd</code> on the
  676. * <code>DragSourceListener</code>s registered with this
  677. * <code>DragSource</code>, and passes them the specified
  678. * <code>DragSourceDropEvent</code>.
  679. *
  680. * @param dsde the <code>DragSourceEvent</code>
  681. */
  682. void processDragDropEnd(DragSourceDropEvent dsde) {
  683. DragSourceListener dsl = listener;
  684. if (dsl != null) {
  685. dsl.dragDropEnd(dsde);
  686. }
  687. }
  688. /**
  689. * This method calls <code>dragMouseMoved</code> on the
  690. * <code>DragSourceMotionListener</code>s registered with this
  691. * <code>DragSource</code>, and passes them the specified
  692. * <code>DragSourceDragEvent</code>.
  693. *
  694. * @param dsde the <code>DragSourceEvent</code>
  695. */
  696. void processDragMouseMoved(DragSourceDragEvent dsde) {
  697. DragSourceMotionListener dsml = motionListener;
  698. if (dsml != null) {
  699. dsml.dragMouseMoved(dsde);
  700. }
  701. }
  702. /**
  703. * Serializes this <code>DragSource</code>. This method first performs
  704. * default serialization. Next, it writes out this object's
  705. * <code>FlavorMap</code> if and only if it can be serialized. If not,
  706. * <code>null</code> is written instead. Next, it writes out
  707. * <code>Serializable</code> listeners registered with this
  708. * object. Listeners are written in a <code>null</code>-terminated sequence
  709. * of 0 or more pairs. The pair consists of a <code>String</code> and an
  710. * <code>Object</code> the <code>String</code> indicates the type of the
  711. * <code>Object</code> and is one of the following:
  712. * <ul>
  713. * <li><code>dragSourceListenerK</code> indicating a
  714. * <code>DragSourceListener</code> object;
  715. * <li><code>dragSourceMotionListenerK</code> indicating a
  716. * <code>DragSourceMotionListener</code> object.
  717. * </ul>
  718. *
  719. * @serialData Either a <code>FlavorMap</code> instance, or
  720. * <code>null</code>, followed by a <code>null</code>-terminated
  721. * sequence of 0 or more pairs; the pair consists of a
  722. * <code>String</code> and an <code>Object</code> the
  723. * <code>String</code> indicates the type of the <code>Object</code>
  724. * and is one of the following:
  725. * <ul>
  726. * <li><code>dragSourceListenerK</code> indicating a
  727. * <code>DragSourceListener</code> object;
  728. * <li><code>dragSourceMotionListenerK</code> indicating a
  729. * <code>DragSourceMotionListener</code> object.
  730. * </ul>.
  731. * @since 1.4
  732. */
  733. private void writeObject(ObjectOutputStream s) throws IOException {
  734. s.defaultWriteObject();
  735. s.writeObject(SerializationTester.test(flavorMap) ? flavorMap : null);
  736. DnDEventMulticaster.save(s, dragSourceListenerK, listener);
  737. DnDEventMulticaster.save(s, dragSourceMotionListenerK, motionListener);
  738. s.writeObject(null);
  739. }
  740. /**
  741. * Deserializes this <code>DragSource</code>. This method first performs
  742. * default deserialization. Next, this object's <code>FlavorMap</code> is
  743. * deserialized by using the next object in the stream.
  744. * If the resulting <code>FlavorMap</code> is <code>null</code>, this
  745. * object's <code>FlavorMap</code> is set to the default FlavorMap for
  746. * this thread's <code>ClassLoader</code>.
  747. * Next, this object's listeners are deserialized by reading a
  748. * <code>null</code>-terminated sequence of 0 or more key/value pairs
  749. * from the stream:
  750. * <ul>
  751. * <li>If a key object is a <code>String</code> equal to
  752. * <code>dragSourceListenerK</code>, a <code>DragSourceListener</code> is
  753. * deserialized using the corresponding value object and added to this
  754. * <code>DragSource</code>.
  755. * <li>If a key object is a <code>String</code> equal to
  756. * <code>dragSourceMotionListenerK</code>, a
  757. * <code>DragSourceMotionListener</code> is deserialized using the
  758. * corresponding value object and added to this <code>DragSource</code>.
  759. * <li>Otherwise, the key/value pair is skipped.
  760. * </ul>
  761. *
  762. * @see java.awt.datatransfer.SystemFlavorMap#getDefaultFlavorMap
  763. * @since 1.4
  764. */
  765. private void readObject(ObjectInputStream s)
  766. throws ClassNotFoundException, IOException {
  767. s.defaultReadObject();
  768. // 'flavorMap' was written explicitly
  769. flavorMap = (FlavorMap)s.readObject();
  770. // Implementation assumes 'flavorMap' is never null.
  771. if (flavorMap == null) {
  772. flavorMap = SystemFlavorMap.getDefaultFlavorMap();
  773. }
  774. Object keyOrNull;
  775. while (null != (keyOrNull = s.readObject())) {
  776. String key = ((String)keyOrNull).intern();
  777. if (dragSourceListenerK == key) {
  778. addDragSourceListener((DragSourceListener)(s.readObject()));
  779. } else if (dragSourceMotionListenerK == key) {
  780. addDragSourceMotionListener(
  781. (DragSourceMotionListener)(s.readObject()));
  782. } else {
  783. // skip value for unrecognized key
  784. s.readObject();
  785. }
  786. }
  787. }
  788. /**
  789. * Returns the drag gesture motion threshold. The drag gesture motion threshold
  790. * defines the recommended behavior for {@link MouseDragGestureRecognizer}s.
  791. * <p>
  792. * If the system property <code>awt.dnd.drag.threshold</code> is set to
  793. * a positive integer, this method returns the value of the system property;
  794. * otherwise if a pertinent desktop property is available and supported by
  795. * the implementation of the Java platform, this method returns the value of
  796. * that property; otherwise this method returns some default value.
  797. * The pertinent desktop property can be queried using
  798. * <code>java.awt.Toolkit.getDesktopProperty("DnD.gestureMotionThreshold")</code>.
  799. *
  800. * @return the drag gesture motion threshold
  801. * @see MouseDragGestureRecognizer
  802. * @since 1.5
  803. */
  804. public static int getDragThreshold() {
  805. int ts = ((Integer)AccessController.doPrivileged(
  806. new GetIntegerAction("awt.dnd.drag.threshold", 0))).intValue();
  807. if (ts > 0) {
  808. return ts;
  809. } else {
  810. Integer td = (Integer)Toolkit.getDefaultToolkit().
  811. getDesktopProperty("DnD.gestureMotionThreshold");
  812. if (td != null) {
  813. return td.intValue();
  814. }
  815. }
  816. return 5;
  817. }
  818. /*
  819. * fields
  820. */
  821. private transient FlavorMap flavorMap = SystemFlavorMap.getDefaultFlavorMap();
  822. private transient DragSourceListener listener;
  823. private transient DragSourceMotionListener motionListener;
  824. }