| /* |
| * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package java.awt.dnd; |
| |
| import java.awt.Component; |
| |
| import java.awt.datatransfer.DataFlavor; |
| import java.awt.datatransfer.Transferable; |
| import java.awt.datatransfer.UnsupportedFlavorException; |
| |
| import java.awt.dnd.peer.DropTargetContextPeer; |
| |
| import java.io.IOException; |
| import java.io.Serializable; |
| |
| import java.util.Arrays; |
| import java.util.List; |
| |
| import sun.awt.AWTAccessor; |
| import sun.awt.AWTAccessor.DropTargetContextAccessor; |
| |
| /** |
| * A {@code DropTargetContext} is created |
| * whenever the logical cursor associated |
| * with a Drag and Drop operation coincides with the visible geometry of |
| * a {@code Component} associated with a {@code DropTarget}. |
| * The {@code DropTargetContext} provides |
| * the mechanism for a potential receiver |
| * of a drop operation to both provide the end user with the appropriate |
| * drag under feedback, but also to effect the subsequent data transfer |
| * if appropriate. |
| * |
| * @since 1.2 |
| */ |
| |
| public class DropTargetContext implements Serializable { |
| |
| private static final long serialVersionUID = -634158968993743371L; |
| |
| static { |
| AWTAccessor.setDropTargetContextAccessor(new DropTargetContextAccessor() { |
| @Override |
| public void reset(DropTargetContext dtc) { |
| dtc.reset(); |
| } |
| @Override |
| public void setDropTargetContextPeer(DropTargetContext dtc, |
| DropTargetContextPeer dtcp) { |
| dtc.setDropTargetContextPeer(dtcp); |
| } |
| }); |
| } |
| /** |
| * Construct a {@code DropTargetContext} |
| * given a specified {@code DropTarget}. |
| * |
| * @param dt the DropTarget to associate with |
| */ |
| |
| DropTargetContext(DropTarget dt) { |
| super(); |
| |
| dropTarget = dt; |
| } |
| |
| /** |
| * This method returns the {@code DropTarget} associated with this |
| * {@code DropTargetContext}. |
| * |
| * @return the {@code DropTarget} associated with this {@code DropTargetContext} |
| */ |
| |
| public DropTarget getDropTarget() { return dropTarget; } |
| |
| /** |
| * This method returns the {@code Component} associated with |
| * this {@code DropTargetContext}. |
| * |
| * @return the Component associated with this Context |
| */ |
| |
| public Component getComponent() { return dropTarget.getComponent(); } |
| |
| /** |
| * Called when disassociated with the {@code DropTargetContextPeer}. |
| */ |
| void reset() { |
| dropTargetContextPeer = null; |
| transferable = null; |
| } |
| |
| /** |
| * This method sets the current actions acceptable to |
| * this {@code DropTarget}. |
| * |
| * @param actions an {@code int} representing the supported action(s) |
| */ |
| |
| protected void setTargetActions(int actions) { |
| DropTargetContextPeer peer = getDropTargetContextPeer(); |
| if (peer != null) { |
| synchronized (peer) { |
| peer.setTargetActions(actions); |
| getDropTarget().doSetDefaultActions(actions); |
| } |
| } else { |
| getDropTarget().doSetDefaultActions(actions); |
| } |
| } |
| |
| /** |
| * This method returns an {@code int} representing the |
| * current actions this {@code DropTarget} will accept. |
| * |
| * @return the current actions acceptable to this {@code DropTarget} |
| */ |
| |
| protected int getTargetActions() { |
| DropTargetContextPeer peer = getDropTargetContextPeer(); |
| return ((peer != null) |
| ? peer.getTargetActions() |
| : dropTarget.getDefaultActions() |
| ); |
| } |
| |
| /** |
| * This method signals that the drop is completed and |
| * if it was successful or not. |
| * |
| * @param success true for success, false if not |
| * |
| * @throws InvalidDnDOperationException if a drop is not outstanding/extant |
| */ |
| |
| public void dropComplete(boolean success) throws InvalidDnDOperationException{ |
| DropTargetContextPeer peer = getDropTargetContextPeer(); |
| if (peer != null) { |
| peer.dropComplete(success); |
| } |
| } |
| |
| /** |
| * accept the Drag. |
| * |
| * @param dragOperation the supported action(s) |
| */ |
| |
| protected void acceptDrag(int dragOperation) { |
| DropTargetContextPeer peer = getDropTargetContextPeer(); |
| if (peer != null) { |
| peer.acceptDrag(dragOperation); |
| } |
| } |
| |
| /** |
| * reject the Drag. |
| */ |
| |
| protected void rejectDrag() { |
| DropTargetContextPeer peer = getDropTargetContextPeer(); |
| if (peer != null) { |
| peer.rejectDrag(); |
| } |
| } |
| |
| /** |
| * called to signal that the drop is acceptable |
| * using the specified operation. |
| * must be called during DropTargetListener.drop method invocation. |
| * |
| * @param dropOperation the supported action(s) |
| */ |
| |
| protected void acceptDrop(int dropOperation) { |
| DropTargetContextPeer peer = getDropTargetContextPeer(); |
| if (peer != null) { |
| peer.acceptDrop(dropOperation); |
| } |
| } |
| |
| /** |
| * called to signal that the drop is unacceptable. |
| * must be called during DropTargetListener.drop method invocation. |
| */ |
| |
| protected void rejectDrop() { |
| DropTargetContextPeer peer = getDropTargetContextPeer(); |
| if (peer != null) { |
| peer.rejectDrop(); |
| } |
| } |
| |
| /** |
| * get the available DataFlavors of the |
| * {@code Transferable} operand of this operation. |
| * |
| * @return a {@code DataFlavor[]} containing the |
| * supported {@code DataFlavor}s of the |
| * {@code Transferable} operand. |
| */ |
| |
| protected DataFlavor[] getCurrentDataFlavors() { |
| DropTargetContextPeer peer = getDropTargetContextPeer(); |
| return peer != null ? peer.getTransferDataFlavors() : new DataFlavor[0]; |
| } |
| |
| /** |
| * This method returns a the currently available DataFlavors |
| * of the {@code Transferable} operand |
| * as a {@code java.util.List}. |
| * |
| * @return the currently available |
| * DataFlavors as a {@code java.util.List} |
| */ |
| |
| protected List<DataFlavor> getCurrentDataFlavorsAsList() { |
| return Arrays.asList(getCurrentDataFlavors()); |
| } |
| |
| /** |
| * This method returns a {@code boolean} |
| * indicating if the given {@code DataFlavor} is |
| * supported by this {@code DropTargetContext}. |
| * |
| * @param df the {@code DataFlavor} |
| * |
| * @return if the {@code DataFlavor} specified is supported |
| */ |
| |
| protected boolean isDataFlavorSupported(DataFlavor df) { |
| return getCurrentDataFlavorsAsList().contains(df); |
| } |
| |
| /** |
| * get the Transferable (proxy) operand of this operation |
| * |
| * @throws InvalidDnDOperationException if a drag is not outstanding/extant |
| * |
| * @return the {@code Transferable} |
| */ |
| |
| protected Transferable getTransferable() throws InvalidDnDOperationException { |
| DropTargetContextPeer peer = getDropTargetContextPeer(); |
| if (peer == null) { |
| throw new InvalidDnDOperationException(); |
| } else { |
| if (transferable == null) { |
| Transferable t = peer.getTransferable(); |
| boolean isLocal = peer.isTransferableJVMLocal(); |
| synchronized (this) { |
| if (transferable == null) { |
| transferable = createTransferableProxy(t, isLocal); |
| } |
| } |
| } |
| |
| return transferable; |
| } |
| } |
| |
| /** |
| * Get the {@code DropTargetContextPeer} |
| * |
| * @return the platform peer |
| */ |
| DropTargetContextPeer getDropTargetContextPeer() { |
| return dropTargetContextPeer; |
| } |
| |
| /** |
| * Sets the {@code DropTargetContextPeer} |
| */ |
| void setDropTargetContextPeer(final DropTargetContextPeer dtcp) { |
| dropTargetContextPeer = dtcp; |
| } |
| |
| /** |
| * Creates a TransferableProxy to proxy for the specified |
| * Transferable. |
| * |
| * @param t the {@code Transferable} to be proxied |
| * @param local {@code true} if {@code t} represents |
| * the result of a local drag-n-drop operation. |
| * @return the new {@code TransferableProxy} instance. |
| */ |
| protected Transferable createTransferableProxy(Transferable t, boolean local) { |
| return new TransferableProxy(t, local); |
| } |
| |
| /****************************************************************************/ |
| |
| |
| /** |
| * {@code TransferableProxy} is a helper inner class that implements |
| * {@code Transferable} interface and serves as a proxy for another |
| * {@code Transferable} object which represents data transfer for |
| * a particular drag-n-drop operation. |
| * <p> |
| * The proxy forwards all requests to the encapsulated transferable |
| * and automatically performs additional conversion on the data |
| * returned by the encapsulated transferable in case of local transfer. |
| */ |
| |
| protected class TransferableProxy implements Transferable { |
| |
| /** |
| * Constructs a {@code TransferableProxy} given |
| * a specified {@code Transferable} object representing |
| * data transfer for a particular drag-n-drop operation and |
| * a {@code boolean} which indicates whether the |
| * drag-n-drop operation is local (within the same JVM). |
| * |
| * @param t the {@code Transferable} object |
| * @param local {@code true}, if {@code t} represents |
| * the result of local drag-n-drop operation |
| */ |
| TransferableProxy(Transferable t, boolean local) { |
| proxy = new sun.awt.datatransfer.TransferableProxy(t, local); |
| transferable = t; |
| isLocal = local; |
| } |
| |
| /** |
| * Returns an array of DataFlavor objects indicating the flavors |
| * the data can be provided in by the encapsulated transferable. |
| * |
| * @return an array of data flavors in which the data can be |
| * provided by the encapsulated transferable |
| */ |
| public DataFlavor[] getTransferDataFlavors() { |
| return proxy.getTransferDataFlavors(); |
| } |
| |
| /** |
| * Returns whether or not the specified data flavor is supported by |
| * the encapsulated transferable. |
| * @param flavor the requested flavor for the data |
| * @return {@code true} if the data flavor is supported, |
| * {@code false} otherwise |
| */ |
| public boolean isDataFlavorSupported(DataFlavor flavor) { |
| return proxy.isDataFlavorSupported(flavor); |
| } |
| |
| /** |
| * Returns an object which represents the data provided by |
| * the encapsulated transferable for the requested data flavor. |
| * <p> |
| * In case of local transfer a serialized copy of the object |
| * returned by the encapsulated transferable is provided when |
| * the data is requested in application/x-java-serialized-object |
| * data flavor. |
| * |
| * @param df the requested flavor for the data |
| * @throws IOException if the data is no longer available |
| * in the requested flavor. |
| * @throws UnsupportedFlavorException if the requested data flavor is |
| * not supported. |
| */ |
| public Object getTransferData(DataFlavor df) |
| throws UnsupportedFlavorException, IOException |
| { |
| return proxy.getTransferData(df); |
| } |
| |
| /* |
| * fields |
| */ |
| |
| // We don't need to worry about client code changing the values of |
| // these variables. Since TransferableProxy is a protected class, only |
| // subclasses of DropTargetContext can access it. And DropTargetContext |
| // cannot be subclassed by client code because it does not have a |
| // public constructor. |
| |
| /** |
| * The encapsulated {@code Transferable} object. |
| */ |
| protected Transferable transferable; |
| |
| /** |
| * A {@code boolean} indicating if the encapsulated |
| * {@code Transferable} object represents the result |
| * of local drag-n-drop operation (within the same JVM). |
| */ |
| protected boolean isLocal; |
| |
| private sun.awt.datatransfer.TransferableProxy proxy; |
| } |
| |
| /****************************************************************************/ |
| |
| /* |
| * fields |
| */ |
| |
| /** |
| * The DropTarget associated with this DropTargetContext. |
| * |
| * @serial |
| */ |
| private final DropTarget dropTarget; |
| |
| private transient DropTargetContextPeer dropTargetContextPeer; |
| |
| private transient Transferable transferable; |
| } |