1. /*
  2. * @(#)DropTargetContext.java 1.25 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.Component;
  9. import java.awt.datatransfer.DataFlavor;
  10. import java.awt.datatransfer.Transferable;
  11. import java.awt.datatransfer.UnsupportedFlavorException;
  12. import java.awt.Component;
  13. import java.awt.dnd.DnDConstants;
  14. import java.awt.dnd.DropTarget;
  15. import java.awt.dnd.InvalidDnDOperationException;
  16. import java.awt.dnd.peer.DropTargetContextPeer;
  17. import java.io.ByteArrayInputStream;
  18. import java.io.ByteArrayOutputStream;
  19. import java.io.DataInputStream;
  20. import java.io.InputStream;
  21. import java.io.IOException;
  22. import java.io.ObjectInputStream;
  23. import java.io.ObjectOutputStream;
  24. import java.io.Serializable;
  25. import java.util.Arrays;
  26. import java.util.List;
  27. /**
  28. * A <code>DropTargetContext</code> is created
  29. * whenever the logical cursor associated
  30. * with a Drag and Drop operation coincides with the visible geometry of
  31. * a <code>Component</code> associated with a <code>DropTarget</code>.
  32. * The <code>DropTargetContext</code> provides
  33. * the mechanism for a potential receiver
  34. * of a drop operation to both provide the end user with the appropriate
  35. * drag under feedback, but also to effect the subsequent data transfer
  36. * if appropriate.
  37. *
  38. * @version 1.8
  39. * @since JDK1.2
  40. */
  41. public class DropTargetContext {
  42. /**
  43. * Construct a <code>DropTargetContext</code>
  44. * given a specified <code>DropTarget</code>.
  45. * <P>
  46. * @param dt the DropTarget to associate with
  47. */
  48. DropTargetContext(DropTarget dt) {
  49. super();
  50. dropTarget = dt;
  51. }
  52. /**
  53. * This method returns the <code>DropTarget</code> associated with this
  54. * <code>DropTargetContext</code>.
  55. * <P>
  56. * @return the <code>DropTarget</code> associated with this <code>DropTargetContext</code>
  57. */
  58. public DropTarget getDropTarget() { return dropTarget; }
  59. /**
  60. * This method returns the <code>Component</code> associated with
  61. * this <code>DropTargetContext</code>.
  62. * <P>
  63. * @return the Component associated with this Context
  64. */
  65. public Component getComponent() { return dropTarget.getComponent(); }
  66. /**
  67. * Called when associated with the <code>DropTargetContextPeer</code>.
  68. * <P>
  69. * @param dtcp the <code>DropTargetContextPeer</code>
  70. */
  71. public synchronized void addNotify(DropTargetContextPeer dtcp) {
  72. dropTargetContextPeer = dtcp;
  73. }
  74. /**
  75. * Called when disassociated with the <code>DropTargetContextPeer</code>.
  76. */
  77. public synchronized void removeNotify() {
  78. dropTargetContextPeer = null;
  79. transferable = null;
  80. }
  81. /**
  82. * This method sets the current actions acceptable to
  83. * this <code>DropTarget</code>.
  84. * <P>
  85. * @param actions an <code>int</code> representing the supported action(s)
  86. */
  87. protected void setTargetActions(int actions) {
  88. if (dropTargetContextPeer != null) dropTargetContextPeer.setTargetActions(actions);
  89. }
  90. /**
  91. * This method returns an <code>int</code> representing the
  92. * current actions this <code>DropTarget</code> will accept.
  93. * <P>
  94. * @return the current actions acceptable to this <code>DropTarget</code>
  95. */
  96. protected int getTargetActions() {
  97. return ((dropTargetContextPeer != null)
  98. ? dropTargetContextPeer.getTargetActions()
  99. : dropTarget.getDefaultActions()
  100. );
  101. }
  102. /**
  103. * This method signals that the drop is completed and
  104. * if it was successful or not.
  105. * <P>
  106. * @param success true for success, false if not
  107. * <P>
  108. * @throws InvalidDnDOperationException if a drop is not outstanding/extant
  109. */
  110. public void dropComplete(boolean success) throws InvalidDnDOperationException{
  111. if (dropTargetContextPeer != null)
  112. dropTargetContextPeer.dropComplete(success);
  113. }
  114. /**
  115. * accept the Drag.
  116. * <P>
  117. * @param dragOperation the supported action(s)
  118. */
  119. protected void acceptDrag(int dragOperation) {
  120. if (dropTargetContextPeer != null) dropTargetContextPeer.acceptDrag(dragOperation);
  121. }
  122. /**
  123. * reject the Drag.
  124. */
  125. protected void rejectDrag() {
  126. if (dropTargetContextPeer != null) dropTargetContextPeer.rejectDrag();
  127. }
  128. /**
  129. * called to signal that the drop is acceptable
  130. * using the specified operation.
  131. * must be called during DropTargetListener.drop method invocation.
  132. * <P>
  133. * @param dropOperation the supported action(s)
  134. */
  135. protected void acceptDrop(int dropOperation) {
  136. if (dropTargetContextPeer != null) dropTargetContextPeer.acceptDrop(dropOperation);
  137. }
  138. /**
  139. * called to signal that the drop is unacceptable.
  140. * must be called during DropTargetListener.drop method invocation.
  141. */
  142. protected void rejectDrop() {
  143. if (dropTargetContextPeer != null) dropTargetContextPeer.rejectDrop();
  144. }
  145. /**
  146. * get the available DataFlavors of the
  147. * <code>Transferable</code> operand of this operation.
  148. * <P>
  149. * @return a <code>DataFlavor[]</code> containing the
  150. * supported <code>DataFlavor</code>s of the
  151. * <code>Transferable</code> operand.
  152. */
  153. protected DataFlavor[] getCurrentDataFlavors() {
  154. return dropTargetContextPeer != null ? dropTargetContextPeer.getTransferDataFlavors() : new DataFlavor[0];
  155. }
  156. /**
  157. * This method returns a the currently available DataFlavors
  158. * of the <code>Transferable</code> operand
  159. * as a <code>java.util.List</code>.
  160. * <P>
  161. * @return the currently available
  162. * DataFlavors as a <code>java.util.List</code>
  163. */
  164. protected List getCurrentDataFlavorsAsList() {
  165. return Arrays.asList(getCurrentDataFlavors());
  166. }
  167. /**
  168. * This method returns a <code>boolean</code>
  169. * indicating if the given <code>DataFlavor</code> is
  170. * supported by this <code>DropTargetContext</code>.
  171. * <P>
  172. * @param df the <code>DataFlavor</code>
  173. * <P>
  174. * @return if the <code>DataFlavor</code> specified is supported
  175. */
  176. protected boolean isDataFlavorSupported(DataFlavor df) {
  177. return getCurrentDataFlavorsAsList().contains(df);
  178. }
  179. /**
  180. * get the Transferable (proxy) operand of this operation
  181. * <P>
  182. * @throws InvalidDnDOperationException if a drag is not outstanding/extant
  183. * <P>
  184. * @return the <code>Transferable</code>
  185. */
  186. protected synchronized Transferable getTransferable() throws InvalidDnDOperationException {
  187. if (dropTargetContextPeer == null) {
  188. throw new InvalidDnDOperationException();
  189. } else {
  190. if (transferable == null) {
  191. transferable = createTransferableProxy(dropTargetContextPeer.getTransferable(), dropTargetContextPeer.isTransferableJVMLocal());
  192. }
  193. return transferable;
  194. }
  195. }
  196. /**
  197. * Get the <code>DropTargetContextPeer</code>
  198. * <P>
  199. * @return the platform peer
  200. */
  201. DropTargetContextPeer getDropTargetContextPeer() {
  202. return dropTargetContextPeer;
  203. }
  204. /**
  205. * subclasses may override this to supply their own Proxy Transferable
  206. * <P>
  207. * @param t the <code>Transferable</code>
  208. * @param local <code>boolean</code>
  209. * <P>
  210. * @return the <code>Transferable</code>
  211. */
  212. protected Transferable createTransferableProxy(Transferable t, boolean local) {
  213. return new TransferableProxy(t, local);
  214. }
  215. /****************************************************************************/
  216. /**
  217. * The <code>TransferableProxy</code> is a
  218. * nested helper class that
  219. * supports the <code>DropTargetContext</code>
  220. * in managing the transfer of data.
  221. * In particular it provides automatic
  222. * support for the de-serialization
  223. * of application/x-java-serialized-object
  224. * <code>DatFlavor</code>s.
  225. */
  226. protected class TransferableProxy implements Transferable {
  227. /**
  228. * construct the proxy
  229. * <P>
  230. * @param t the <code>Transferable</code>
  231. * @param local is local?
  232. */
  233. TransferableProxy(Transferable t, boolean local) {
  234. transferable = t;
  235. isLocal = local;
  236. }
  237. /**
  238. * get the flavors
  239. * <P>
  240. * @return the <code>DataFlavor</code> array
  241. */
  242. public synchronized DataFlavor[] getTransferDataFlavors() {
  243. return transferable.getTransferDataFlavors();
  244. }
  245. /**
  246. * check if a particular flavor is supported?
  247. * <P>
  248. * @param flavor the <code>DataFlavor</code>
  249. * <P>
  250. * @return a <code>boolean</code> indicating if
  251. * the specified <code>DataFlavor</code> is supported.
  252. */
  253. public synchronized boolean isDataFlavorSupported(DataFlavor flavor) {
  254. DataFlavor[] flavors = getTransferDataFlavors();
  255. if (flavors != null && flavors.length != 0) {
  256. for (int i = 0; i < flavors.length; i++)
  257. if (flavors[i].equals(flavor)) return true;
  258. }
  259. return false;
  260. }
  261. /**
  262. * get the transfer data
  263. * <P>
  264. * @param df the <code>DataFlavor</code>
  265. * <P>
  266. * @throws UnsupportedFlavorException if the requested <code>DataFlavor</code> is not supported.
  267. * @throws IOException if the data is no longer available in the requested flavor.
  268. * <P>
  269. * @return the Object
  270. */
  271. public synchronized Object getTransferData(DataFlavor df) throws UnsupportedFlavorException, IOException {
  272. if (!isDataFlavorSupported(df))
  273. throw new UnsupportedFlavorException(df);
  274. else {
  275. Object data;
  276. InputStream is = null;
  277. try {
  278. data = transferable.getTransferData(df);
  279. } catch (Exception e) {
  280. throw new IOException(e.getClass() + ":" + e.getMessage() + " caught while getting Data");
  281. }
  282. // if its am application/x-java-serialized-object then
  283. // we should pass it as a serialized copy of the original
  284. if (isLocal && df.isFlavorSerializedObjectType()) {
  285. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  286. (new ObjectOutputStream(baos)).writeObject(data);
  287. ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
  288. try {
  289. data = (new ObjectInputStream(bais)).readObject();
  290. } catch (ClassNotFoundException cnfe) {
  291. throw new IOException(cnfe.getMessage());
  292. }
  293. }
  294. return data;
  295. }
  296. }
  297. /*
  298. * fields
  299. */
  300. /**
  301. * The "actual" <code>Transferable</code>
  302. * that the Proxy is a Proxy for,
  303. * usually supplied from the underlying system.
  304. */
  305. protected Transferable transferable;
  306. /**
  307. * A <code> boolean</code> indicating if
  308. * the <code>DragSource</code> is in the
  309. * same JVM as the <code>DropTarget</code>.
  310. */
  311. protected boolean isLocal;
  312. }
  313. /****************************************************************************/
  314. /*
  315. * fields
  316. */
  317. private DropTarget dropTarget;
  318. private DropTargetContextPeer dropTargetContextPeer;
  319. private Transferable transferable;
  320. }