1788 lines · 68.7 KB · Java
RawDownload
/* * Copyright (c) 2000, 2011, 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 javax.swing; import java.awt.*;import java.awt.event.*;import java.awt.datatransfer.*;import java.awt.dnd.*;import java.beans.*;import java.lang.reflect.*;import java.io.*;import java.util.TooManyListenersException;import javax.swing.plaf.UIResource;import javax.swing.event.*;import javax.swing.text.JTextComponent; import sun.reflect.misc.MethodUtil;import sun.swing.SwingUtilities2;import sun.awt.AppContext;import sun.swing.*;import sun.awt.SunToolkit; import java.security.AccessController;import java.security.PrivilegedAction; import java.security.AccessControlContext;import java.security.ProtectionDomain;import sun.misc.SharedSecrets;import sun.misc.JavaSecurityAccess; import sun.awt.AWTAccessor; /** * This class is used to handle the transfer of a <code>Transferable</code> * to and from Swing components.  The <code>Transferable</code> is used to * represent data that is exchanged via a cut, copy, or paste * to/from a clipboard.  It is also used in drag-and-drop operations * to represent a drag from a component, and a drop to a component. * Swing provides functionality that automatically supports cut, copy, * and paste keyboard bindings that use the functionality provided by * an implementation of this class.  Swing also provides functionality * that automatically supports drag and drop that uses the functionality * provided by an implementation of this class.  The Swing developer can * concentrate on specifying the semantics of a transfer primarily by setting * the <code>transferHandler</code> property on a Swing component. * <p> * This class is implemented to provide a default behavior of transferring * a component property simply by specifying the name of the property in * the constructor.  For example, to transfer the foreground color from * one component to another either via the clipboard or a drag and drop operation * a <code>TransferHandler</code> can be constructed with the string "foreground".  The * built in support will use the color returned by <code>getForeground</code> as the source * of the transfer, and <code>setForeground</code> for the target of a transfer. * <p> * Please see * <a href="http://java.sun.com/docs/books/tutorial/uiswing/misc/dnd.html"> * How to Use Drag and Drop and Data Transfer</a>, * a section in <em>The Java Tutorial</em>, for more information. * * * @author Timothy Prinzing * @author Shannon Hickey * @since 1.4 */@SuppressWarnings("serial")public class TransferHandler implements Serializable {     /**     * An <code>int</code> representing no transfer action.     */    public static final int NONE = DnDConstants.ACTION_NONE;     /**     * An <code>int</code> representing a &quot;copy&quot; transfer action.     * This value is used when data is copied to a clipboard     * or copied elsewhere in a drag and drop operation.     */    public static final int COPY = DnDConstants.ACTION_COPY;     /**     * An <code>int</code> representing a &quot;move&quot; transfer action.     * This value is used when data is moved to a clipboard (i.e. a cut)     * or moved elsewhere in a drag and drop operation.     */    public static final int MOVE = DnDConstants.ACTION_MOVE;     /**     * An <code>int</code> representing a source action capability of either     * &quot;copy&quot; or &quot;move&quot;.     */    public static final int COPY_OR_MOVE = DnDConstants.ACTION_COPY_OR_MOVE;     /**     * An <code>int</code> representing a &quot;link&quot; transfer action.     * This value is used to specify that data should be linked in a drag     * and drop operation.     *     * @see java.awt.dnd.DnDConstants#ACTION_LINK     * @since 1.6     */    public static final int LINK = DnDConstants.ACTION_LINK;     /**     * An interface to tag things with a {@code getTransferHandler} method.     */    interface HasGetTransferHandler {         /** Returns the {@code TransferHandler}.         *         * @return The {@code TransferHandler} or {@code null}         */        public TransferHandler getTransferHandler();    }     /**     * Represents a location where dropped data should be inserted.     * This is a base class that only encapsulates a point.     * Components supporting drop may provide subclasses of this     * containing more information.     * <p>     * Developers typically shouldn't create instances of, or extend, this     * class. Instead, these are something provided by the DnD     * implementation by <code>TransferSupport</code> instances and by     * components with a <code>getDropLocation()</code> method.     *     * @see javax.swing.TransferHandler.TransferSupport#getDropLocation     * @since 1.6     */    public static class DropLocation {        private final Point dropPoint;         /**         * Constructs a drop location for the given point.         *         * @param dropPoint the drop point, representing the mouse's         *        current location within the component.         * @throws IllegalArgumentException if the point         *         is <code>null</code>         */        protected DropLocation(Point dropPoint) {            if (dropPoint == null) {                throw new IllegalArgumentException("Point cannot be null");            }             this.dropPoint = new Point(dropPoint);        }         /**         * Returns the drop point, representing the mouse's         * current location within the component.         *         * @return the drop point.         */        public final Point getDropPoint() {            return new Point(dropPoint);        }         /**         * Returns a string representation of this drop location.         * This method is intended to be used for debugging purposes,         * and the content and format of the returned string may vary         * between implementations.         *         * @return a string representation of this drop location         */        public String toString() {            return getClass().getName() + "[dropPoint=" + dropPoint + "]";        }    };     /**     * This class encapsulates all relevant details of a clipboard     * or drag and drop transfer, and also allows for customizing     * aspects of the drag and drop experience.     * <p>     * The main purpose of this class is to provide the information     * needed by a developer to determine the suitability of a     * transfer or to import the data contained within. But it also     * doubles as a controller for customizing properties during drag     * and drop, such as whether or not to show the drop location,     * and which drop action to use.     * <p>     * Developers typically need not create instances of this     * class. Instead, they are something provided by the DnD     * implementation to certain methods in <code>TransferHandler</code>.     *     * @see #canImport(TransferHandler.TransferSupport)     * @see #importData(TransferHandler.TransferSupport)     * @since 1.6     */    public final static class TransferSupport {        private boolean isDrop;        private Component component;         private boolean showDropLocationIsSet;        private boolean showDropLocation;         private int dropAction = -1;         /**         * The source is a {@code DropTargetDragEvent} or         * {@code DropTargetDropEvent} for drops,         * and a {@code Transferable} otherwise         */        private Object source;         private DropLocation dropLocation;         /**         * Create a <code>TransferSupport</code> with <code>isDrop()</code>         * <code>true</code> for the given component, event, and index.         *         * @param component the target component         * @param event a <code>DropTargetEvent</code>         */        private TransferSupport(Component component,                             DropTargetEvent event) {             isDrop = true;            setDNDVariables(component, event);        }         /**         * Create a <code>TransferSupport</code> with <code>isDrop()</code>         * <code>false</code> for the given component and         * <code>Transferable</code>.         *         * @param component the target component         * @param transferable the transferable         * @throws NullPointerException if either parameter         *         is <code>null</code>         */        public TransferSupport(Component component, Transferable transferable) {            if (component == null) {                throw new NullPointerException("component is null");            }             if (transferable == null) {                throw new NullPointerException("transferable is null");            }             isDrop = false;            this.component = component;            this.source = transferable;        }         /**         * Allows for a single instance to be reused during DnD.         *         * @param component the target component         * @param event a <code>DropTargetEvent</code>         */        private void setDNDVariables(Component component,                                     DropTargetEvent event) {             assert isDrop;             this.component = component;            this.source = event;            dropLocation = null;            dropAction = -1;            showDropLocationIsSet = false;             if (source == null) {                return;            }             assert source instanceof DropTargetDragEvent ||                   source instanceof DropTargetDropEvent;             Point p = source instanceof DropTargetDragEvent                          ? ((DropTargetDragEvent)source).getLocation()                          : ((DropTargetDropEvent)source).getLocation();             if (SunToolkit.isInstanceOf(component, "javax.swing.text.JTextComponent")) {                dropLocation = SwingAccessor.getJTextComponentAccessor().                                   dropLocationForPoint((JTextComponent)component, p);            } else if (component instanceof JComponent) {                dropLocation = ((JComponent)component).dropLocationForPoint(p);            }             /*             * The drop location may be null at this point if the component             * doesn't return custom drop locations. In this case, a point-only             * drop location will be created lazily when requested.             */        }         /**         * Returns whether or not this <code>TransferSupport</code>         * represents a drop operation.         *         * @return <code>true</code> if this is a drop operation,         *         <code>false</code> otherwise.         */        public boolean isDrop() {            return isDrop;        }         /**         * Returns the target component of this transfer.         *         * @return the target component         */        public Component getComponent() {            return component;        }         /**         * Checks that this is a drop and throws an         * {@code IllegalStateException} if it isn't.         *         * @throws IllegalStateException if {@code isDrop} is false.         */        private void assureIsDrop() {            if (!isDrop) {                throw new IllegalStateException("Not a drop");            }        }         /**         * Returns the current (non-{@code null}) drop location for the component,         * when this {@code TransferSupport} represents a drop.         * <p>         * Note: For components with built-in drop support, this location         * will be a subclass of {@code DropLocation} of the same type         * returned by that component's {@code getDropLocation} method.         * <p>         * This method is only for use with drag and drop transfers.         * Calling it when {@code isDrop()} is {@code false} results         * in an {@code IllegalStateException}.         *         * @return the drop location         * @throws IllegalStateException if this is not a drop         * @see #isDrop()         */        public DropLocation getDropLocation() {            assureIsDrop();             if (dropLocation == null) {                /*                 * component didn't give us a custom drop location,                 * so lazily create a point-only location                 */                Point p = source instanceof DropTargetDragEvent                              ? ((DropTargetDragEvent)source).getLocation()                              : ((DropTargetDropEvent)source).getLocation();                 dropLocation = new DropLocation(p);            }             return dropLocation;        }         /**         * Sets whether or not the drop location should be visually indicated         * for the transfer - which must represent a drop. This is applicable to         * those components that automatically         * show the drop location when appropriate during a drag and drop         * operation). By default, the drop location is shown only when the         * {@code TransferHandler} has said it can accept the import represented         * by this {@code TransferSupport}. With this method you can force the         * drop location to always be shown, or always not be shown.         * <p>         * This method is only for use with drag and drop transfers.         * Calling it when {@code isDrop()} is {@code false} results         * in an {@code IllegalStateException}.         *         * @param showDropLocation whether or not to indicate the drop location         * @throws IllegalStateException if this is not a drop         * @see #isDrop()         */        public void setShowDropLocation(boolean showDropLocation) {            assureIsDrop();             this.showDropLocation = showDropLocation;            this.showDropLocationIsSet = true;        }         /**         * Sets the drop action for the transfer - which must represent a drop         * - to the given action,         * instead of the default user drop action. The action must be         * supported by the source's drop actions, and must be one         * of {@code COPY}, {@code MOVE} or {@code LINK}.         * <p>         * This method is only for use with drag and drop transfers.         * Calling it when {@code isDrop()} is {@code false} results         * in an {@code IllegalStateException}.         *         * @param dropAction the drop action         * @throws IllegalStateException if this is not a drop         * @throws IllegalArgumentException if an invalid action is specified         * @see #getDropAction         * @see #getUserDropAction         * @see #getSourceDropActions         * @see #isDrop()         */        public void setDropAction(int dropAction) {            assureIsDrop();             int action = dropAction & getSourceDropActions();             if (!(action == COPY || action == MOVE || action == LINK)) {                throw new IllegalArgumentException("unsupported drop action: " + dropAction);            }             this.dropAction = dropAction;        }         /**         * Returns the action chosen for the drop, when this         * {@code TransferSupport} represents a drop.         * <p>         * Unless explicitly chosen by way of {@code setDropAction},         * this returns the user drop action provided by         * {@code getUserDropAction}.         * <p>         * You may wish to query this in {@code TransferHandler}'s         * {@code importData} method to customize processing based         * on the action.         * <p>         * This method is only for use with drag and drop transfers.         * Calling it when {@code isDrop()} is {@code false} results         * in an {@code IllegalStateException}.         *         * @return the action chosen for the drop         * @throws IllegalStateException if this is not a drop         * @see #setDropAction         * @see #getUserDropAction         * @see #isDrop()         */        public int getDropAction() {            return dropAction == -1 ? getUserDropAction() : dropAction;        }         /**         * Returns the user drop action for the drop, when this         * {@code TransferSupport} represents a drop.         * <p>         * The user drop action is chosen for a drop as described in the         * documentation for {@link java.awt.dnd.DropTargetDragEvent} and         * {@link java.awt.dnd.DropTargetDropEvent}. A different action         * may be chosen as the drop action by way of the {@code setDropAction}         * method.         * <p>         * You may wish to query this in {@code TransferHandler}'s         * {@code canImport} method when determining the suitability of a         * drop or when deciding on a drop action to explicitly choose.         * <p>         * This method is only for use with drag and drop transfers.         * Calling it when {@code isDrop()} is {@code false} results         * in an {@code IllegalStateException}.         *         * @return the user drop action         * @throws IllegalStateException if this is not a drop         * @see #setDropAction         * @see #getDropAction         * @see #isDrop()         */        public int getUserDropAction() {            assureIsDrop();             return (source instanceof DropTargetDragEvent)                ? ((DropTargetDragEvent)source).getDropAction()                : ((DropTargetDropEvent)source).getDropAction();        }         /**         * Returns the drag source's supported drop actions, when this         * {@code TransferSupport} represents a drop.         * <p>         * The source actions represent the set of actions supported by the         * source of this transfer, and are represented as some bitwise-OR         * combination of {@code COPY}, {@code MOVE} and {@code LINK}.         * You may wish to query this in {@code TransferHandler}'s         * {@code canImport} method when determining the suitability of a drop         * or when deciding on a drop action to explicitly choose. To determine

Lines 1–500 of 1788.