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