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