1 /*
2 * Copyright 1997-2004 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26 package java.awt.dnd;
27
28 import java.awt.Component;
29
30 import java.awt.datatransfer.DataFlavor;
31 import java.awt.datatransfer.Transferable;
32 import java.awt.datatransfer.UnsupportedFlavorException;
33
34 import java.awt.dnd.peer.DropTargetContextPeer;
35
36 import java.io.IOException;
37 import java.io.Serializable;
38
39 import java.util.Arrays;
40 import java.util.List;
41
42
43 /**
44 * A <code>DropTargetContext</code> is created
45 * whenever the logical cursor associated
46 * with a Drag and Drop operation coincides with the visible geometry of
47 * a <code>Component</code> associated with a <code>DropTarget</code>.
48 * The <code>DropTargetContext</code> provides
49 * the mechanism for a potential receiver
50 * of a drop operation to both provide the end user with the appropriate
51 * drag under feedback, but also to effect the subsequent data transfer
52 * if appropriate.
53 *
54 * @since 1.2
55 */
56
57 public class DropTargetContext implements Serializable {
58
59 private static final long serialVersionUID = -634158968993743371L;
60
61 /**
62 * Construct a <code>DropTargetContext</code>
63 * given a specified <code>DropTarget</code>.
64 * <P>
65 * @param dt the DropTarget to associate with
66 */
67
68 DropTargetContext(DropTarget dt) {
69 super();
70
71 dropTarget = dt;
72 }
73
74 /**
75 * This method returns the <code>DropTarget</code> associated with this
76 * <code>DropTargetContext</code>.
77 * <P>
78 * @return the <code>DropTarget</code> associated with this <code>DropTargetContext</code>
79 */
80
81 public DropTarget getDropTarget() { return dropTarget; }
82
83 /**
84 * This method returns the <code>Component</code> associated with
85 * this <code>DropTargetContext</code>.
86 * <P>
87 * @return the Component associated with this Context
88 */
89
90 public Component getComponent() { return dropTarget.getComponent(); }
91
92 /**
93 * Called when associated with the <code>DropTargetContextPeer</code>.
94 * <P>
95 * @param dtcp the <code>DropTargetContextPeer</code>
96 */
97
98 public void addNotify(DropTargetContextPeer dtcp) {
99 dropTargetContextPeer = dtcp;
100 }
101
102 /**
103 * Called when disassociated with the <code>DropTargetContextPeer</code>.
104 */
105
106 public void removeNotify() {
107 dropTargetContextPeer = null;
108 transferable = null;
109 }
110
111 /**
112 * This method sets the current actions acceptable to
113 * this <code>DropTarget</code>.
114 * <P>
115 * @param actions an <code>int</code> representing the supported action(s)
116 */
117
118 protected void setTargetActions(int actions) {
119 DropTargetContextPeer peer = getDropTargetContextPeer();
120 if (peer != null) {
121 synchronized (peer) {
122 peer.setTargetActions(actions);
123 getDropTarget().doSetDefaultActions(actions);
124 }
125 } else {
126 getDropTarget().doSetDefaultActions(actions);
127 }
128 }
129
130 /**
131 * This method returns an <code>int</code> representing the
132 * current actions this <code>DropTarget</code> will accept.
133 * <P>
134 * @return the current actions acceptable to this <code>DropTarget</code>
135 */
136
137 protected int getTargetActions() {
138 DropTargetContextPeer peer = getDropTargetContextPeer();
139 return ((peer != null)
140 ? peer.getTargetActions()
141 : dropTarget.getDefaultActions()
142 );
143 }
144
145 /**
146 * This method signals that the drop is completed and
147 * if it was successful or not.
148 * <P>
149 * @param success true for success, false if not
150 * <P>
151 * @throws InvalidDnDOperationException if a drop is not outstanding/extant
152 */
153
154 public void dropComplete(boolean success) throws InvalidDnDOperationException{
155 DropTargetContextPeer peer = getDropTargetContextPeer();
156 if (peer != null) {
157 peer.dropComplete(success);
158 }
159 }
160
161 /**
162 * accept the Drag.
163 * <P>
164 * @param dragOperation the supported action(s)
165 */
166
167 protected void acceptDrag(int dragOperation) {
168 DropTargetContextPeer peer = getDropTargetContextPeer();
169 if (peer != null) {
170 peer.acceptDrag(dragOperation);
171 }
172 }
173
174 /**
175 * reject the Drag.
176 */
177
178 protected void rejectDrag() {
179 DropTargetContextPeer peer = getDropTargetContextPeer();
180 if (peer != null) {
181 peer.rejectDrag();
182 }
183 }
184
185 /**
186 * called to signal that the drop is acceptable
187 * using the specified operation.
188 * must be called during DropTargetListener.drop method invocation.
189 * <P>
190 * @param dropOperation the supported action(s)
191 */
192
193 protected void acceptDrop(int dropOperation) {
194 DropTargetContextPeer peer = getDropTargetContextPeer();
195 if (peer != null) {
196 peer.acceptDrop(dropOperation);
197 }
198 }
199
200 /**
201 * called to signal that the drop is unacceptable.
202 * must be called during DropTargetListener.drop method invocation.
203 */
204
205 protected void rejectDrop() {
206 DropTargetContextPeer peer = getDropTargetContextPeer();
207 if (peer != null) {
208 peer.rejectDrop();
209 }
210 }
211
212 /**
213 * get the available DataFlavors of the
214 * <code>Transferable</code> operand of this operation.
215 * <P>
216 * @return a <code>DataFlavor[]</code> containing the
217 * supported <code>DataFlavor</code>s of the
218 * <code>Transferable</code> operand.
219 */
220
221 protected DataFlavor[] getCurrentDataFlavors() {
222 DropTargetContextPeer peer = getDropTargetContextPeer();
223 return peer != null ? peer.getTransferDataFlavors() : new DataFlavor[0];
224 }
225
226 /**
227 * This method returns a the currently available DataFlavors
228 * of the <code>Transferable</code> operand
229 * as a <code>java.util.List</code>.
230 * <P>
231 * @return the currently available
232 * DataFlavors as a <code>java.util.List</code>
233 */
234
235 protected List<DataFlavor> getCurrentDataFlavorsAsList() {
236 return Arrays.asList(getCurrentDataFlavors());
237 }
238
239 /**
240 * This method returns a <code>boolean</code>
241 * indicating if the given <code>DataFlavor</code> is
242 * supported by this <code>DropTargetContext</code>.
243 * <P>
244 * @param df the <code>DataFlavor</code>
245 * <P>
246 * @return if the <code>DataFlavor</code> specified is supported
247 */
248
249 protected boolean isDataFlavorSupported(DataFlavor df) {
250 return getCurrentDataFlavorsAsList().contains(df);
251 }
252
253 /**
254 * get the Transferable (proxy) operand of this operation
255 * <P>
256 * @throws InvalidDnDOperationException if a drag is not outstanding/extant
257 * <P>
258 * @return the <code>Transferable</code>
259 */
260
261 protected Transferable getTransferable() throws InvalidDnDOperationException {
262 DropTargetContextPeer peer = getDropTargetContextPeer();
263 if (peer == null) {
264 throw new InvalidDnDOperationException();
265 } else {
266 if (transferable == null) {
267 Transferable t = peer.getTransferable();
268 boolean isLocal = peer.isTransferableJVMLocal();
269 synchronized (this) {
270 if (transferable == null) {
271 transferable = createTransferableProxy(t, isLocal);
272 }
273 }
274 }
275
276 return transferable;
277 }
278 }
279
280 /**
281 * Get the <code>DropTargetContextPeer</code>
282 * <P>
283 * @return the platform peer
284 */
285
286 DropTargetContextPeer getDropTargetContextPeer() {
287 return dropTargetContextPeer;
288 }
289
290 /**
291 * Creates a TransferableProxy to proxy for the specified
292 * Transferable.
293 *
294 * @param t the <tt>Transferable</tt> to be proxied
295 * @param local <tt>true</tt> if <tt>t</tt> represents
296 * the result of a local drag-n-drop operation.
297 * @return the new <tt>TransferableProxy</tt> instance.
298 */
299 protected Transferable createTransferableProxy(Transferable t, boolean local) {
300 return new TransferableProxy(t, local);
301 }
302
303 /****************************************************************************/
304
305
306 /**
307 * <code>TransferableProxy</code> is a helper inner class that implements
308 * <code>Transferable</code> interface and serves as a proxy for another
309 * <code>Transferable</code> object which represents data transfer for
310 * a particular drag-n-drop operation.
311 * <p>
312 * The proxy forwards all requests to the encapsulated transferable
313 * and automatically performs additional conversion on the data
314 * returned by the encapsulated transferable in case of local transfer.
315 */
316
317 protected class TransferableProxy implements Transferable {
318
319 /**
320 * Constructs a <code>TransferableProxy</code> given
321 * a specified <code>Transferable</code> object representing
322 * data transfer for a particular drag-n-drop operation and
323 * a <code>boolean</code> which indicates whether the
324 * drag-n-drop operation is local (within the same JVM).
325 * <p>
326 * @param t the <code>Transferable</code> object
327 * @param local <code>true</code>, if <code>t</code> represents
328 * the result of local drag-n-drop operation
329 */
330 TransferableProxy(Transferable t, boolean local) {
331 proxy = new sun.awt.datatransfer.TransferableProxy(t, local);
332 transferable = t;
333 isLocal = local;
334 }
335
336 /**
337 * Returns an array of DataFlavor objects indicating the flavors
338 * the data can be provided in by the encapsulated transferable.
339 * <p>
340 * @return an array of data flavors in which the data can be
341 * provided by the encapsulated transferable
342 */
343 public DataFlavor[] getTransferDataFlavors() {
344 return proxy.getTransferDataFlavors();
345 }
346
347 /**
348 * Returns whether or not the specified data flavor is supported by
349 * the encapsulated transferable.
350 * @param flavor the requested flavor for the data
351 * @return <code>true</code> if the data flavor is supported,
352 * <code>false</code> otherwise
353 */
354 public boolean isDataFlavorSupported(DataFlavor flavor) {
355 return proxy.isDataFlavorSupported(flavor);
356 }
357
358 /**
359 * Returns an object which represents the data provided by
360 * the encapsulated transferable for the requested data flavor.
361 * <p>
362 * In case of local transfer a serialized copy of the object
363 * returned by the encapsulated transferable is provided when
364 * the data is requested in application/x-java-serialized-object
365 * data flavor.
366 *
367 * @param df the requested flavor for the data
368 * @throws IOException if the data is no longer available
369 * in the requested flavor.
370 * @throws UnsupportedFlavorException if the requested data flavor is
371 * not supported.
372 */
373 public Object getTransferData(DataFlavor df)
374 throws UnsupportedFlavorException, IOException
375 {
376 return proxy.getTransferData(df);
377 }
378
379 /*
380 * fields
381 */
382
383 // We don't need to worry about client code changing the values of
384 // these variables. Since TransferableProxy is a protected class, only
385 // subclasses of DropTargetContext can access it. And DropTargetContext
386 // cannot be subclassed by client code because it does not have a
387 // public constructor.
388
389 /**
390 * The encapsulated <code>Transferable</code> object.
391 */
392 protected Transferable transferable;
393
394 /**
395 * A <code>boolean</code> indicating if the encapsulated
396 * <code>Transferable</code> object represents the result
397 * of local drag-n-drop operation (within the same JVM).
398 */
399 protected boolean isLocal;
400
401 private sun.awt.datatransfer.TransferableProxy proxy;
402 }
403
404 /****************************************************************************/
405
406 /*
407 * fields
408 */
409
410 /**
411 * The DropTarget associated with this DropTargetContext.
412 *
413 * @serial
414 */
415 private DropTarget dropTarget;
416
417 private transient DropTargetContextPeer dropTargetContextPeer;
418
419 private transient Transferable transferable;
420 }