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