1. /*
  2. * @(#)DragSource.java 1.27 01/11/29
  3. *
  4. * Copyright 2002 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.Image;
  15. import java.awt.Point;
  16. import java.awt.Toolkit;
  17. import java.awt.datatransfer.Transferable;
  18. import java.awt.dnd.DnDConstants;
  19. import java.awt.dnd.DragSourceContext;
  20. import java.awt.dnd.DragSourceListener;
  21. import java.awt.datatransfer.FlavorMap;
  22. import java.awt.datatransfer.SystemFlavorMap;
  23. import java.awt.dnd.InvalidDnDOperationException;
  24. import java.awt.dnd.peer.DragSourceContextPeer;
  25. import java.security.AccessController;
  26. /**
  27. * The <code>DragSource</code> is the entity responsible
  28. * for the initiation of the Drag
  29. * and Drop operation, and may be used in a number of scenarios:
  30. * <UL>
  31. * <LI>1 default instance per JVM for the lifetime of that JVM.
  32. * <LI>1 instance per class of potential Drag Initiator object (e.g
  33. * TextField). [implementation dependent]
  34. * <LI>1 per instance of a particular
  35. * <code>Component</code>, or application specific
  36. * object associated with a <code>Component</code>
  37. * instance in the GUI. [implementation dependent]
  38. * <LI>Some other arbitrary association. [implementation dependent]
  39. *</UL>
  40. *
  41. * Once the <code>DragSource</code> is
  42. * obtained, a <code>DragGestureRecognizer</code> should
  43. * also be obtained to associate the <code>DragSource</code>
  44. * with a particular
  45. * <code>Component</code>.
  46. * <P>
  47. * The initial interpretation of the user's gesture,
  48. * and the subsequent starting of the drag operation
  49. * are the responsibility of the implementing
  50. * <code>Component</code>, which is usually
  51. * implemented by a <code>DragGestureRecognizer</code>.
  52. *<P>
  53. * When a drag gesture occurs, the
  54. * <code>DragSource</code>'s
  55. * startDrag() method shall be
  56. * invoked in order to cause processing
  57. * of the user's navigational
  58. * gestures and delivery of Drag and Drop
  59. * protocol notifications. A
  60. * <code>DragSource</code> shall only
  61. * permit a single Drag and Drop operation to be
  62. * current at any one time, and shall
  63. * reject any further startDrag() requests
  64. * by throwing an <code>IllegalDnDOperationException</code>
  65. * until such time as the extant operation is complete.
  66. * <P>
  67. * The startDrag() method invokes the
  68. * createDragSourceContext() method to
  69. * instantiate an appropriate
  70. * <code>DragSourceContext</code>
  71. * and associate the <code>DragSourceContextPeer</code>
  72. * with that.
  73. * <P>
  74. * If the Drag and Drop System is
  75. * unable to initiate a drag operation for
  76. * some reason, the startDrag() method throws
  77. * a <code>java.awt.dnd.InvalidDnDOperationException</code>
  78. * to signal such a condition. Typically this
  79. * exception is thrown when the underlying platform
  80. * system is either not in a state to
  81. * initiate a drag, or the parameters specified are invalid.
  82. * <P>
  83. * Note that during the drag, the
  84. * set of operations exposed by the source
  85. * at the start of the drag operation may not change
  86. * until the operation is complete.
  87. * The operation(s) are constant for the
  88. * duration of the operation with respect to the
  89. * <code>DragSource</code>.
  90. *
  91. * @version 1.27
  92. * @since JDK1.2
  93. */
  94. public class DragSource {
  95. /*
  96. * load a system default cursor
  97. */
  98. private static Cursor load(String name) {
  99. try {
  100. return (Cursor)Toolkit.getDefaultToolkit().getDesktopProperty(name);
  101. } catch (Exception e) {
  102. e.printStackTrace();
  103. throw new RuntimeException("failed to load system cursor: " + name + " : " + e.getMessage());
  104. }
  105. }
  106. /**
  107. * The default <code>Cursor</code> to use with a copy operation
  108. * indicating that a drop is currently allowed.
  109. */
  110. public static final Cursor DefaultCopyDrop = load("DnD.Cursor.CopyDrop");
  111. /**
  112. * The default <code>Cursor</code> to use
  113. * with a move operation indicating that
  114. * a drop is currently allowed.
  115. */
  116. public static final Cursor DefaultMoveDrop = load("DnD.Cursor.MoveDrop");
  117. /**
  118. * The default <code>Cursor</code> to use with a
  119. * link operation indicating that a
  120. * drop is currently allowed.
  121. */
  122. public static final Cursor DefaultLinkDrop = load("DnD.Cursor.LinkDrop");
  123. /**
  124. * The default <code>Cursor</code> to use with
  125. * a copy operation indicating that a drop is currently not allowed.
  126. */
  127. public static final Cursor DefaultCopyNoDrop = load("DnD.Cursor.CopyNoDrop");
  128. /**
  129. * The default <code>Cursor</code> to use with a move
  130. * operation indicating that a drop is currently not allowed.
  131. */
  132. public static final Cursor DefaultMoveNoDrop = load("DnD.Cursor.MoveNoDrop");
  133. /**
  134. * The default <code>Cursor</code> to use
  135. * with a link operation indicating
  136. * that a drop is currently not allowed.
  137. */
  138. public static final Cursor DefaultLinkNoDrop = load("DnD.Cursor.LinkNoDrop");
  139. /*
  140. * The System FlavorMap
  141. */
  142. private static final FlavorMap defaultFlavorMap = SystemFlavorMap.getDefaultFlavorMap();
  143. private static DragSource dflt;
  144. /**
  145. * This method returns the <code>DragSource</code>
  146. * object associated with the underlying platform.
  147. * <P>
  148. * @return the platform DragSource
  149. */
  150. public static DragSource getDefaultDragSource() {
  151. if (dflt == null) dflt = new DragSource();
  152. return dflt;
  153. }
  154. /**
  155. * This method returns a <code>boolean</code>
  156. * indicating whether or not drag
  157. * <code>Image</code> support
  158. * is available on the underlying platform.
  159. * <P>
  160. * @return if the Drag Image support is available on this platform
  161. */
  162. public static boolean isDragImageSupported() {
  163. Toolkit t = Toolkit.getDefaultToolkit();
  164. Boolean supported;
  165. try {
  166. supported = (Boolean)Toolkit.getDefaultToolkit().getDesktopProperty("DnD.isDragImageSupported");
  167. return supported.booleanValue();
  168. } catch (Exception e) {
  169. return false;
  170. }
  171. }
  172. /**
  173. * Construct a new <code>DragSource</code>.
  174. */
  175. public DragSource() { super(); }
  176. /**
  177. * Start a drag, given the <code>DragGestureEvent</code>
  178. * that initiated the drag, the initial
  179. * <code>Cursor</code> to use,
  180. * the <code>Image</code> to drag,
  181. * the offset of the <code>Image</code> origin
  182. * from the hotspot of the <code>Cursor</code> at
  183. * the instant of the trigger,
  184. * the <code>Transferable</code> subject data
  185. * of the drag, the <code>DragSourceListener</code>,
  186. * and the <code>FlavorMap</code>.
  187. * <P>
  188. * @param trigger The <code>DragGestureEvent</code> that initiated the drag
  189. * @param dragCursor The initial <code>Cursor</code> or <code>null</code> for defaults
  190. * @param dragImage The image to drag or null,
  191. * @param imageOffset The offset of the <code>Image</code> origin from the hotspot
  192. * of the <code>Cursor</code> at the instant of the trigger
  193. * @param transferable The subject data of the drag
  194. * @param dsl The <code>DragSourceListener</code>
  195. * @param flavorMap The <code>FlavorMap</code> to use, or <code>null</code>
  196. * <P>
  197. * @throws <code>java.awt.dnd.InvalidDnDOperationException</code>
  198. * if the Drag and Drop
  199. * system is unable to initiate a drag operation, or if the user
  200. * attempts to start a drag while an existing drag operation
  201. * is still executing.
  202. */
  203. public void startDrag(DragGestureEvent trigger,
  204. Cursor dragCursor,
  205. Image dragImage,
  206. Point imageOffset,
  207. Transferable transferable,
  208. DragSourceListener dsl,
  209. FlavorMap flavorMap) throws InvalidDnDOperationException {
  210. if (flavorMap != null) this.flavorMap = flavorMap;
  211. DragSourceContextPeer dscp = Toolkit.getDefaultToolkit().createDragSourceContextPeer(trigger);
  212. DragSourceContext dsc = createDragSourceContext(dscp,
  213. trigger,
  214. dragCursor,
  215. dragImage,
  216. imageOffset,
  217. transferable,
  218. dsl
  219. );
  220. if (dsc == null) {
  221. throw new InvalidDnDOperationException();
  222. }
  223. dscp.startDrag(dsc, dsc.getCursor(), dragImage, imageOffset); // may throw
  224. }
  225. /**
  226. * Start a drag, given the <code>DragGestureEvent</code>
  227. * that initiated the drag, the initial
  228. * <code>Cursor</code> to use,
  229. * the <code>Transferable</code> subject data
  230. * of the drag, the <code>DragSourceListener</code>,
  231. * and the <code>FlavorMap</code>.
  232. * <P>
  233. * @param trigger The <code>DragGestureEvent</code> that
  234. * initiated the drag
  235. * @param dragCursor The initial <code>Cursor</code> or
  236. * <code>null</code> for defaults
  237. * @param transferable The subject data of the drag
  238. * @param dsl The <code>DragSourceListener</code>
  239. * @param flavorMap The <code>FlavorMap to use or <code>null</code>
  240. * <P>
  241. * @throws <code>java.awt.dnd.InvalidDnDOperationException</code>
  242. * if the Drag and Drop
  243. * system is unable to initiate a drag operation, or if the user
  244. * attempts to start a drag while an existing drag operation
  245. * is still executing.
  246. */
  247. public void startDrag(DragGestureEvent trigger,
  248. Cursor dragCursor,
  249. Transferable transferable,
  250. DragSourceListener dsl,
  251. FlavorMap flavorMap) throws InvalidDnDOperationException {
  252. startDrag(trigger, dragCursor, null, null, transferable, dsl, flavorMap);
  253. }
  254. /**
  255. * Start a drag, given the <code>DragGestureEvent</code>
  256. * that initiated the drag, the initial <code>Cursor</code>
  257. * to use,
  258. * the <code>Image</code> to drag,
  259. * the offset of the <code>Image</code> origin
  260. * from the hotspot of the <code>Cursor</code>
  261. * at the instant of the trigger,
  262. * the subject data of the drag, and
  263. * the <code>DragSourceListener</code>.
  264. * <P>
  265. * @param trigger The <code>DragGestureEvent</code> that initiated the drag
  266. * @param dragCursor The initial <code>Cursor</code> or <code>null</code> for defaults
  267. * @param dragImage The <code>Image</code> to drag or <code>null</code>
  268. * @param imageOffset The offset of the <code>Image</code> origin from the hotspot
  269. * of the <code>Cursor</code> at the instant of the trigger
  270. * @param transferable The subject data of the drag
  271. * @param dsl The <code>DragSourceListener</code>
  272. * <P>
  273. * @throws <code>java.awt.dnd.InvalidDnDOperationException</code>
  274. * if the Drag and Drop
  275. * system is unable to initiate a drag operation, or if the user
  276. * attempts to start a drag while an existing drag operation
  277. * is still executing.
  278. */
  279. public void startDrag(DragGestureEvent trigger,
  280. Cursor dragCursor,
  281. Image dragImage,
  282. Point dragOffset,
  283. Transferable transferable,
  284. DragSourceListener dsl) throws InvalidDnDOperationException {
  285. startDrag(trigger, dragCursor, dragImage, dragOffset, transferable, dsl, null);
  286. }
  287. /**
  288. * Start a drag, given the <code>DragGestureEvent</code>
  289. * that initiated the drag, the initial
  290. * <code>Cursor</code> to
  291. * use,
  292. * the <code>Transferable</code> subject data
  293. * of the drag, and the <code>DragSourceListener</code>.
  294. * <P>
  295. * @param trigger The <code>DragGestureEvent</code> that initiated the drag
  296. * @param dragCursor The initial <code>Cursor</code> or <code>null</code> for defaults
  297. * @param transferable The subject data of the drag
  298. * @param dsl The <code>DragSourceListener</code>
  299. * <P>
  300. * @throws <code>java.awt.dnd.InvalidDnDOperationException</code>
  301. * if the Drag and Drop
  302. * system is unable to initiate a drag operation, or if the user
  303. * attempts to start a drag while an existing drag operation
  304. * is still executing.
  305. */
  306. public void startDrag(DragGestureEvent trigger,
  307. Cursor dragCursor,
  308. Transferable transferable,
  309. DragSourceListener dsl) throws InvalidDnDOperationException {
  310. startDrag(trigger, dragCursor, null, null, transferable, dsl, null);
  311. }
  312. /**
  313. * Create the <code>DragSourceContext</code> to handle this drag.
  314. *
  315. * To incorporate a new <code>DragSourceContext</code>
  316. * subclass, subclass <code>DragSource</code> and
  317. * override this method.
  318. * <P>
  319. * @param dscp The <code>DragSourceContextPeer</code> for this drag
  320. * @param trigger The <code>DragGestureEvent</code> that triggered the drag
  321. * @param dragCursor The initial <code>Cursor</code> to display
  322. * @param dragImage The <code>Image</code> to drag or <code>null</code>
  323. * @param imageOffset The offset of the <code>Image</code> origin from the hotspot
  324. * of the cursor at the instant of the trigger
  325. * @param transferable The subject data of the drag
  326. * @param dsl The <code>DragSourceListener</code>
  327. * <P>
  328. * @return the <code>DragSourceContext</code>
  329. */
  330. protected DragSourceContext createDragSourceContext(DragSourceContextPeer dscp, DragGestureEvent dgl, Cursor dragCursor, Image dragImage, Point imageOffset, Transferable t, DragSourceListener dsl) {
  331. return new DragSourceContext(dscp, dgl, dragCursor, dragImage, imageOffset, t, dsl);
  332. }
  333. /**
  334. * This method returns the
  335. * <code>FlavorMap</code> for this <code>DragSource</code>.
  336. * <P>
  337. * @return the <code>FlavorMap</code> for this <code>DragSource</code>
  338. */
  339. public FlavorMap getFlavorMap() { return flavorMap; }
  340. /**
  341. * Creates a new <code>DragGestureRecognizer</code>
  342. * that implements the specified
  343. * abstract subclass of
  344. * <code>DragGestureRecognizer</code>, and
  345. * sets the specified <code>Component</code>
  346. * and <code>DragGestureListener</code> on
  347. * the newly created object.
  348. * <P>
  349. * @param recognizerAbstractClass The requested abstract type
  350. * @param actions The permitted source drag actions
  351. * @param c The <code>Component</code> target
  352. * @param dgl The <code>DragGestureListener</code> to notify
  353. * <P>
  354. * @return the new <code>DragGestureRecognizer</code> or <code>null</code>
  355. * if the Toolkit.createDragGestureRecognizer() method
  356. * has no implementation available for
  357. * the requested <code>DragGestureRecognizer</code>
  358. * subclass and returns <code>null</code>.
  359. */
  360. public DragGestureRecognizer createDragGestureRecognizer(Class recognizerAbstractClass, Component c, int actions, DragGestureListener dgl) {
  361. return Toolkit.getDefaultToolkit().createDragGestureRecognizer(recognizerAbstractClass, this, c, actions, dgl);
  362. }
  363. /**
  364. * Creates a new <code>DragSourceRecognizer</code>
  365. * that implements the default
  366. * abstract subclass of <code>DragGestureRecognizer</code>
  367. * for this <code>DragSource</code>,
  368. * and sets the specified <code>Component</code>
  369. * and <code>DragGestureListener</code> on the
  370. * newly created object.
  371. *
  372. * For this <code>DragSource</code>
  373. * the default is <code>MouseDragGestureRecognizer</code>.
  374. * <P>
  375. * @param c The <code>Component</code> target for the recognizer
  376. * @param actions The permitted source actions
  377. * @param dgl The <code>DragGestureListener</code> to notify
  378. * <P>
  379. * @return the new <code>DragGestureRecognizer</code> or <code>null</code>
  380. * if the Toolkit.createDragGestureRecognizer() method
  381. * has no implementation available for
  382. * the requested <code>DragGestureRecognizer</code>
  383. * subclass and returns <code>null</code>.
  384. */
  385. public DragGestureRecognizer createDefaultDragGestureRecognizer(Component c, int actions, DragGestureListener dgl) {
  386. return Toolkit.getDefaultToolkit().createDragGestureRecognizer(MouseDragGestureRecognizer.class, this, c, actions, dgl);
  387. }
  388. /*
  389. * fields
  390. */
  391. private transient FlavorMap flavorMap = defaultFlavorMap;
  392. }