Source Code Cross Referenced for TransferHandler.java in  » 6.0-JDK-Core » swing » javax » swing » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Home
Java Source Code / Java Documentation
1.6.0 JDK Core
2.6.0 JDK Modules
3.6.0 JDK Modules com.sun
4.6.0 JDK Modules com.sun.java
5.6.0 JDK Modules sun
6.6.0 JDK Platform
7.Ajax
8.Apache Harmony Java SE
9.Aspect oriented
10.Authentication Authorization
11.Blogger System
12.Build
13.Byte Code
14.Cache
15.Chart
16.Chat
17.Code Analyzer
18.Collaboration
19.Content Management System
20.Database Client
21.Database DBMS
22.Database JDBC Connection Pool
23.Database ORM
24.Development
25.EJB Server
26.ERP CRM Financial
27.ESB
28.Forum
29.Game
30.GIS
31.Graphic 3D
32.Graphic Library
33.Groupware
34.HTML Parser
35.IDE
36.IDE Eclipse
37.IDE Netbeans
38.Installer
39.Internationalization Localization
40.Inversion of Control
41.Issue Tracking
42.J2EE
43.J2ME
44.JBoss
45.JMS
46.JMX
47.Library
48.Mail Clients
49.Music
50.Net
51.Parser
52.PDF
53.Portal
54.Profiler
55.Project Management
56.Report
57.RSS RDF
58.Rule Engine
59.Science
60.Scripting
61.Search Engine
62.Security
63.Sevlet Container
64.Source Control
65.Swing Library
66.Template Engine
67.Test Coverage
68.Testing
69.UML
70.Web Crawler
71.Web Framework
72.Web Mail
73.Web Server
74.Web Services
75.Web Services apache cxf 2.2.6
76.Web Services AXIS2
77.Wiki Engine
78.Workflow Engines
79.XML
80.XML UI
Java Source Code / Java Documentation » 6.0 JDK Core » swing » javax.swing 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001        /*
0002         * Copyright 2000-2006 Sun Microsystems, Inc.  All Rights Reserved.
0003         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004         *
0005         * This code is free software; you can redistribute it and/or modify it
0006         * under the terms of the GNU General Public License version 2 only, as
0007         * published by the Free Software Foundation.  Sun designates this
0008         * particular file as subject to the "Classpath" exception as provided
0009         * by Sun in the LICENSE file that accompanied this code.
0010         *
0011         * This code is distributed in the hope that it will be useful, but WITHOUT
0012         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013         * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
0014         * version 2 for more details (a copy is included in the LICENSE file that
0015         * accompanied this code).
0016         *
0017         * You should have received a copy of the GNU General Public License version
0018         * 2 along with this work; if not, write to the Free Software Foundation,
0019         * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020         *
0021         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022         * CA 95054 USA or visit www.sun.com if you need additional information or
0023         * have any questions.
0024         */
0025        package javax.swing;
0026
0027        import java.awt.*;
0028        import java.awt.event.*;
0029        import java.awt.datatransfer.*;
0030        import java.awt.dnd.*;
0031        import java.beans.*;
0032        import java.lang.reflect.*;
0033        import java.io.*;
0034        import java.util.TooManyListenersException;
0035        import javax.swing.plaf.UIResource;
0036        import javax.swing.event.*;
0037        import javax.swing.text.JTextComponent;
0038
0039        import sun.reflect.misc.MethodUtil;
0040        import sun.swing.SwingUtilities2;
0041        import sun.awt.AppContext;
0042        import sun.swing.*;
0043
0044        /**
0045         * This class is used to handle the transfer of a <code>Transferable</code>
0046         * to and from Swing components.  The <code>Transferable</code> is used to
0047         * represent data that is exchanged via a cut, copy, or paste 
0048         * to/from a clipboard.  It is also used in drag-and-drop operations
0049         * to represent a drag from a component, and a drop to a component.
0050         * Swing provides functionality that automatically supports cut, copy,
0051         * and paste keyboard bindings that use the functionality provided by
0052         * an implementation of this class.  Swing also provides functionality
0053         * that automatically supports drag and drop that uses the functionality
0054         * provided by an implementation of this class.  The Swing developer can 
0055         * concentrate on specifying the semantics of a transfer primarily by setting
0056         * the <code>transferHandler</code> property on a Swing component.
0057         * <p>
0058         * This class is implemented to provide a default behavior of transferring
0059         * a component property simply by specifying the name of the property in 
0060         * the constructor.  For example, to transfer the foreground color from
0061         * one component to another either via the clipboard or a drag and drop operation
0062         * a <code>TransferHandler</code> can be constructed with the string "foreground".  The
0063         * built in support will use the color returned by <code>getForeground</code> as the source
0064         * of the transfer, and <code>setForeground</code> for the target of a transfer.  
0065         * <p>
0066         * Please see
0067         * <a href="http://java.sun.com/docs/books/tutorial/uiswing/misc/dnd.html">
0068         * How to Use Drag and Drop and Data Transfer</a>,
0069         * a section in <em>The Java Tutorial</em>, for more information.
0070         * 
0071         *
0072         * @author Timothy Prinzing
0073         * @author Shannon Hickey
0074         * @version 1.53 05/05/07
0075         * @since 1.4
0076         */
0077        @SuppressWarnings("serial")
0078        public class TransferHandler implements  Serializable {
0079
0080            /**
0081             * An <code>int</code> representing no transfer action. 
0082             */
0083            public static final int NONE = DnDConstants.ACTION_NONE;
0084
0085            /**
0086             * An <code>int</code> representing a &quot;copy&quot; transfer action.
0087             * This value is used when data is copied to a clipboard
0088             * or copied elsewhere in a drag and drop operation.
0089             */
0090            public static final int COPY = DnDConstants.ACTION_COPY;
0091
0092            /**
0093             * An <code>int</code> representing a &quot;move&quot; transfer action.
0094             * This value is used when data is moved to a clipboard (i.e. a cut)
0095             * or moved elsewhere in a drag and drop operation.
0096             */
0097            public static final int MOVE = DnDConstants.ACTION_MOVE;
0098
0099            /**
0100             * An <code>int</code> representing a source action capability of either
0101             * &quot;copy&quot; or &quot;move&quot;.
0102             */
0103            public static final int COPY_OR_MOVE = DnDConstants.ACTION_COPY_OR_MOVE;
0104
0105            /**
0106             * An <code>int</code> representing a &quot;link&quot; transfer action.
0107             * This value is used to specify that data should be linked in a drag
0108             * and drop operation.
0109             *
0110             * @see java.awt.dnd.DnDConstants#ACTION_LINK
0111             * @since 1.6
0112             */
0113            public static final int LINK = DnDConstants.ACTION_LINK;
0114
0115            /**
0116             * An interface to tag things with a {@code getTransferHandler} method.
0117             */
0118            interface HasGetTransferHandler {
0119
0120                /** Returns the {@code TransferHandler}.
0121                 *
0122                 * @return The {@code TransferHandler} or {@code null}
0123                 */
0124                public TransferHandler getTransferHandler();
0125            }
0126
0127            /**
0128             * Represents a location where dropped data should be inserted.
0129             * This is a base class that only encapsulates a point.
0130             * Components supporting drop may provide subclasses of this
0131             * containing more information.
0132             * <p>
0133             * Developers typically shouldn't create instances of, or extend, this
0134             * class. Instead, these are something provided by the DnD
0135             * implementation by <code>TransferSupport</code> instances and by
0136             * components with a <code>getDropLocation()</code> method.
0137             *
0138             * @see javax.swing.TransferHandler.TransferSupport#getDropLocation
0139             * @since 1.6
0140             */
0141            public static class DropLocation {
0142                private final Point dropPoint;
0143
0144                /**
0145                 * Constructs a drop location for the given point.
0146                 *
0147                 * @param dropPoint the drop point, representing the mouse's
0148                 *        current location within the component.
0149                 * @throws IllegalArgumentException if the point
0150                 *         is <code>null</code>
0151                 */
0152                protected DropLocation(Point dropPoint) {
0153                    if (dropPoint == null) {
0154                        throw new IllegalArgumentException(
0155                                "Point cannot be null");
0156                    }
0157
0158                    this .dropPoint = new Point(dropPoint);
0159                }
0160
0161                /**
0162                 * Returns the drop point, representing the mouse's
0163                 * current location within the component.
0164                 *
0165                 * @return the drop point.
0166                 */
0167                public final Point getDropPoint() {
0168                    return new Point(dropPoint);
0169                }
0170
0171                /**
0172                 * Returns a string representation of this drop location.
0173                 * This method is intended to be used for debugging purposes,
0174                 * and the content and format of the returned string may vary
0175                 * between implementations.
0176                 *
0177                 * @return a string representation of this drop location
0178                 */
0179                public String toString() {
0180                    return getClass().getName() + "[dropPoint=" + dropPoint
0181                            + "]";
0182                }
0183            };
0184
0185            /**
0186             * This class encapsulates all relevant details of a clipboard
0187             * or drag and drop transfer, and also allows for customizing
0188             * aspects of the drag and drop experience.
0189             * <p>
0190             * The main purpose of this class is to provide the information
0191             * needed by a developer to determine the suitability of a
0192             * transfer or to import the data contained within. But it also
0193             * doubles as a controller for customizing properties during drag
0194             * and drop, such as whether or not to show the drop location,
0195             * and which drop action to use.
0196             * <p>
0197             * Developers typically need not create instances of this
0198             * class. Instead, they are something provided by the DnD
0199             * implementation to certain methods in <code>TransferHandler</code>.
0200             *
0201             * @see #canImport(TransferHandler.TransferSupport)
0202             * @see #importData(TransferHandler.TransferSupport)
0203             * @since 1.6
0204             */
0205            public final static class TransferSupport {
0206                private boolean isDrop;
0207                private Component component;
0208
0209                private boolean showDropLocationIsSet;
0210                private boolean showDropLocation;
0211
0212                private int dropAction = -1;
0213
0214                /**
0215                 * The source is a {@code DropTargetDragEvent} or
0216                 * {@code DropTargetDropEvent} for drops,
0217                 * and a {@code Transferable} otherwise
0218                 */
0219                private Object source;
0220
0221                private DropLocation dropLocation;
0222
0223                /**
0224                 * Create a <code>TransferSupport</code> with <code>isDrop()</code>
0225                 * <code>true</code> for the given component, event, and index.
0226                 *
0227                 * @param component the target component
0228                 * @param event a <code>DropTargetEvent</code>
0229                 */
0230                private TransferSupport(Component component,
0231                        DropTargetEvent event) {
0232
0233                    isDrop = true;
0234                    setDNDVariables(component, event);
0235                }
0236
0237                /**
0238                 * Create a <code>TransferSupport</code> with <code>isDrop()</code>
0239                 * <code>false</code> for the given component and
0240                 * <code>Transferable</code>.
0241                 *
0242                 * @param component the target component
0243                 * @param transferable the transferable
0244                 * @throws NullPointerException if either parameter
0245                 *         is <code>null</code>
0246                 */
0247                public TransferSupport(Component component,
0248                        Transferable transferable) {
0249                    if (component == null) {
0250                        throw new NullPointerException("component is null");
0251                    }
0252
0253                    if (transferable == null) {
0254                        throw new NullPointerException("transferable is null");
0255                    }
0256
0257                    isDrop = false;
0258                    this .component = component;
0259                    this .source = transferable;
0260                }
0261
0262                /**
0263                 * Allows for a single instance to be reused during DnD.
0264                 *
0265                 * @param component the target component
0266                 * @param event a <code>DropTargetEvent</code>
0267                 */
0268                private void setDNDVariables(Component component,
0269                        DropTargetEvent event) {
0270
0271                    assert isDrop;
0272
0273                    this .component = component;
0274                    this .source = event;
0275                    dropLocation = null;
0276                    dropAction = -1;
0277                    showDropLocationIsSet = false;
0278
0279                    if (source == null) {
0280                        return;
0281                    }
0282
0283                    assert source instanceof  DropTargetDragEvent
0284                            || source instanceof  DropTargetDropEvent;
0285
0286                    Point p = source instanceof  DropTargetDragEvent ? ((DropTargetDragEvent) source)
0287                            .getLocation()
0288                            : ((DropTargetDropEvent) source).getLocation();
0289
0290                    if (component instanceof  JTextComponent) {
0291                        try {
0292                            AccessibleMethod method = new AccessibleMethod(
0293                                    JTextComponent.class,
0294                                    "dropLocationForPoint", Point.class);
0295
0296                            dropLocation = (DropLocation) method
0297                                    .invokeNoChecked(component, p);
0298                        } catch (NoSuchMethodException e) {
0299                            throw new AssertionError(
0300                                    "Couldn't locate method JTextComponent.dropLocationForPoint");
0301                        }
0302                    } else if (component instanceof  JComponent) {
0303                        dropLocation = ((JComponent) component)
0304                                .dropLocationForPoint(p);
0305                    }
0306
0307                    /*
0308                     * The drop location may be null at this point if the component
0309                     * doesn't return custom drop locations. In this case, a point-only
0310                     * drop location will be created lazily when requested.
0311                     */
0312                }
0313
0314                /**
0315                 * Returns whether or not this <code>TransferSupport</code>
0316                 * represents a drop operation.
0317                 *
0318                 * @return <code>true</code> if this is a drop operation,
0319                 *         <code>false</code> otherwise.
0320                 */
0321                public boolean isDrop() {
0322                    return isDrop;
0323                }
0324
0325                /**
0326                 * Returns the target component of this transfer.
0327                 *
0328                 * @return the target component
0329                 */
0330                public Component getComponent() {
0331                    return component;
0332                }
0333
0334                /**
0335                 * Checks that this is a drop and throws an
0336                 * {@code IllegalStateException} if it isn't.
0337                 *
0338                 * @throws IllegalStateException if {@code isDrop} is false.
0339                 */
0340                private void assureIsDrop() {
0341                    if (!isDrop) {
0342                        throw new IllegalStateException("Not a drop");
0343                    }
0344                }
0345
0346                /**
0347                 * Returns the current (non-{@code null}) drop location for the component,
0348                 * when this {@code TransferSupport} represents a drop.
0349                 * <p>
0350                 * Note: For components with built-in drop support, this location
0351                 * will be a subclass of {@code DropLocation} of the same type
0352                 * returned by that component's {@code getDropLocation} method.
0353                 * <p>
0354                 * This method is only for use with drag and drop transfers.
0355                 * Calling it when {@code isDrop()} is {@code false} results
0356                 * in an {@code IllegalStateException}.
0357                 *
0358                 * @return the drop location
0359                 * @throws IllegalStateException if this is not a drop
0360                 * @see #isDrop
0361                 */
0362                public DropLocation getDropLocation() {
0363                    assureIsDrop();
0364
0365                    if (dropLocation == null) {
0366                        /*
0367                         * component didn't give us a custom drop location,
0368                         * so lazily create a point-only location
0369                         */
0370                        Point p = source instanceof  DropTargetDragEvent ? ((DropTargetDragEvent) source)
0371                                .getLocation()
0372                                : ((DropTargetDropEvent) source).getLocation();
0373
0374                        dropLocation = new DropLocation(p);
0375                    }
0376
0377                    return dropLocation;
0378                }
0379
0380                /**
0381                 * Sets whether or not the drop location should be visually indicated
0382                 * for the transfer - which must represent a drop. This is applicable to
0383                 * those components that automatically
0384                 * show the drop location when appropriate during a drag and drop
0385                 * operation). By default, the drop location is shown only when the
0386                 * {@code TransferHandler} has said it can accept the import represented
0387                 * by this {@code TransferSupport}. With this method you can force the
0388                 * drop location to always be shown, or always not be shown.
0389                 * <p>
0390                 * This method is only for use with drag and drop transfers.
0391                 * Calling it when {@code isDrop()} is {@code false} results
0392                 * in an {@code IllegalStateException}.
0393                 *
0394                 * @param showDropLocation whether or not to indicate the drop location
0395                 * @throws IllegalStateException if this is not a drop
0396                 * @see #isDrop
0397                 */
0398                public void setShowDropLocation(boolean showDropLocation) {
0399                    assureIsDrop();
0400
0401                    this .showDropLocation = showDropLocation;
0402                    this .showDropLocationIsSet = true;
0403                }
0404
0405                /**
0406                 * Sets the drop action for the transfer - which must represent a drop
0407                 * - to the given action,
0408                 * instead of the default user drop action. The action must be
0409                 * supported by the source's drop actions, and must be one
0410                 * of {@code COPY}, {@code MOVE} or {@code LINK}.
0411                 * <p>
0412                 * This method is only for use with drag and drop transfers.
0413                 * Calling it when {@code isDrop()} is {@code false} results
0414                 * in an {@code IllegalStateException}.
0415                 *
0416                 * @param dropAction the drop action
0417                 * @throws IllegalStateException if this is not a drop
0418                 * @throws IllegalArgumentException if an invalid action is specified
0419                 * @see #getDropAction
0420                 * @see #getUserDropAction
0421                 * @see #getSourceDropActions
0422                 * @see #isDrop
0423                 */
0424                public void setDropAction(int dropAction) {
0425                    assureIsDrop();
0426
0427                    int action = dropAction & getSourceDropActions();
0428
0429                    if (!(action == COPY || action == MOVE || action == LINK)) {
0430                        throw new IllegalArgumentException(
0431                                "unsupported drop action: " + dropAction);
0432                    }
0433
0434                    this .dropAction = dropAction;
0435                }
0436
0437                /**
0438                 * Returns the action chosen for the drop, when this
0439                 * {@code TransferSupport} represents a drop.
0440                 * <p>
0441                 * Unless explicitly chosen by way of {@code setDropAction},
0442                 * this returns the user drop action provided by
0443                 * {@code getUserDropAction}.
0444                 * <p>
0445                 * You may wish to query this in {@code TransferHandler}'s
0446                 * {@code importData} method to customize processing based
0447                 * on the action.
0448                 * <p>
0449                 * This method is only for use with drag and drop transfers.
0450                 * Calling it when {@code isDrop()} is {@code false} results
0451                 * in an {@code IllegalStateException}.
0452                 *
0453                 * @return the action chosen for the drop
0454                 * @throws IllegalStateException if this is not a drop
0455                 * @see #setDropAction
0456                 * @see #getUserDropAction
0457                 * @see #isDrop
0458                 */
0459                public int getDropAction() {
0460                    return dropAction == -1 ? getUserDropAction() : dropAction;
0461                }
0462
0463                /**
0464                 * Returns the user drop action for the drop, when this
0465                 * {@code TransferSupport} represents a drop.
0466                 * <p>
0467                 * The user drop action is chosen for a drop as described in the
0468                 * documentation for {@link java.awt.dnd.DropTargetDragEvent} and
0469                 * {@link java.awt.dnd.DropTargetDropEvent}. A different action
0470                 * may be chosen as the drop action by way of the {@code setDropAction}
0471                 * method.
0472                 * <p>
0473                 * You may wish to query this in {@code TransferHandler}'s
0474                 * {@code canImport} method when determining the suitability of a
0475                 * drop or when deciding on a drop action to explicitly choose.
0476                 * <p>
0477                 * This method is only for use with drag and drop transfers.
0478                 * Calling it when {@code isDrop()} is {@code false} results
0479                 * in an {@code IllegalStateException}.
0480                 *
0481                 * @return the user drop action
0482                 * @throws IllegalStateException if this is not a drop
0483                 * @see #setDropAction
0484                 * @see #getDropAction
0485                 * @see #isDrop
0486                 */
0487                public int getUserDropAction() {
0488                    assureIsDrop();
0489
0490                    return (source instanceof  DropTargetDragEvent) ? ((DropTargetDragEvent) source)
0491                            .getDropAction()
0492                            : ((DropTargetDropEvent) source).getDropAction();
0493                }
0494
0495                /**
0496                 * Returns the drag source's supported drop actions, when this
0497                 * {@code TransferSupport} represents a drop.
0498                 * <p>
0499                 * The source actions represent the set of actions supported by the
0500                 * source of this transfer, and are represented as some bitwise-OR
0501                 * combination of {@code COPY}, {@code MOVE} and {@code LINK}.
0502                 * You may wish to query this in {@code TransferHandler}'s
0503                 * {@code canImport} method when determining the suitability of a drop
0504                 * or when deciding on a drop action to explicitly choose. To determine
0505                 * if a particular action is supported by the source, bitwise-AND
0506                 * the action with the source drop actions, and then compare the result
0507                 * against the original action. For example:
0508                 * <pre>
0509                 * boolean copySupported = (COPY & getSourceDropActions()) == COPY;
0510                 * </pre>
0511                 * <p>
0512                 * This method is only for use with drag and drop transfers.
0513                 * Calling it when {@code isDrop()} is {@code false} results
0514                 * in an {@code IllegalStateException}.
0515                 *
0516                 * @return the drag source's supported drop actions
0517                 * @throws IllegalStateException if this is not a drop
0518                 * @see #isDrop
0519                 */
0520                public int getSourceDropActions() {
0521                    assureIsDrop();
0522
0523                    return (source instanceof  DropTargetDragEvent) ? ((DropTargetDragEvent) source)
0524                            .getSourceActions()
0525                            : ((DropTargetDropEvent) source).getSourceActions();
0526                }
0527
0528                /**
0529                 * Returns the data flavors for this transfer.
0530                 *
0531                 * @return the data flavors for this transfer
0532                 */
0533                public DataFlavor[] getDataFlavors() {
0534                    if (isDrop) {
0535                        if (source instanceof  DropTargetDragEvent) {
0536                            return ((DropTargetDragEvent) source)
0537                                    .getCurrentDataFlavors();
0538                        } else {
0539                            return ((DropTargetDropEvent) source)
0540                                    .getCurrentDataFlavors();
0541                        }
0542                    }
0543
0544                    return ((Transferable) source).getTransferDataFlavors();
0545                }
0546
0547                /**
0548                 * Returns whether or not the given data flavor is supported.
0549                 *
0550                 * @param df the <code>DataFlavor</code> to test
0551                 * @return whether or not the given flavor is supported.
0552                 */
0553                public boolean isDataFlavorSupported(DataFlavor df) {
0554                    if (isDrop) {
0555                        if (source instanceof  DropTargetDragEvent) {
0556                            return ((DropTargetDragEvent) source)
0557                                    .isDataFlavorSupported(df);
0558                        } else {
0559                            return ((DropTargetDropEvent) source)
0560                                    .isDataFlavorSupported(df);
0561                        }
0562                    }
0563
0564                    return ((Transferable) source).isDataFlavorSupported(df);
0565                }
0566
0567                /**
0568                 * Returns the <code>Transferable</code> associated with this transfer.
0569                 * <p>
0570                 * Note: Unless it is necessary to fetch the <code>Transferable</code>
0571                 * directly, use one of the other methods on this class to inquire about
0572                 * the transfer. This may perform better than fetching the
0573                 * <code>Transferable</code> and asking it directly.
0574                 *
0575                 * @return the <code>Transferable</code> associated with this transfer
0576                 */
0577                public Transferable getTransferable() {
0578                    if (isDrop) {
0579                        if (source instanceof  DropTargetDragEvent) {
0580                            return ((DropTargetDragEvent) source)
0581                                    .getTransferable();
0582                        } else {
0583                            return ((DropTargetDropEvent) source)
0584                                    .getTransferable();
0585                        }
0586                    }
0587
0588                    return (Transferable) source;
0589                }
0590            }
0591
0592            /**
0593             * Returns an {@code Action} that performs cut operations to the
0594             * clipboard. When performed, this action operates on the {@code JComponent}
0595             * source of the {@code ActionEvent} by invoking {@code exportToClipboard},
0596             * with a {@code MOVE} action, on the component's {@code TransferHandler}.
0597             *
0598             * @return an {@code Action} for performing cuts to the clipboard
0599             */
0600            public static Action getCutAction() {
0601                return cutAction;
0602            }
0603
0604            /**
0605             * Returns an {@code Action} that performs copy operations to the
0606             * clipboard. When performed, this action operates on the {@code JComponent}
0607             * source of the {@code ActionEvent} by invoking {@code exportToClipboard},
0608             * with a {@code COPY} action, on the component's {@code TransferHandler}.
0609             *
0610             * @return an {@code Action} for performing copies to the clipboard
0611             */
0612            public static Action getCopyAction() {
0613                return copyAction;
0614            }
0615
0616            /**
0617             * Returns an {@code Action} that performs paste operations from the
0618             * clipboard. When performed, this action operates on the {@code JComponent}
0619             * source of the {@code ActionEvent} by invoking {@code importData},
0620             * with the clipboard contents, on the component's {@code TransferHandler}.
0621             *
0622             * @return an {@code Action} for performing pastes from the clipboard
0623             */
0624            public static Action getPasteAction() {
0625                return pasteAction;
0626            }
0627
0628            /**
0629             * Constructs a transfer handler that can transfer a Java Bean property
0630             * from one component to another via the clipboard or a drag and drop
0631             * operation.
0632             *
0633             * @param property  the name of the property to transfer; this can
0634             *  be <code>null</code> if there is no property associated with the transfer
0635             *  handler (a subclass that performs some other kind of transfer, for example)
0636             */
0637            public TransferHandler(String property) {
0638                propertyName = property;
0639            }
0640
0641            /**
0642             * Convenience constructor for subclasses.
0643             */
0644            protected TransferHandler() {
0645                this (null);
0646            }
0647
0648            /**
0649             * Causes the Swing drag support to be initiated.  This is called by 
0650             * the various UI implementations in the <code>javax.swing.plaf.basic</code>
0651             * package if the dragEnabled property is set on the component. 
0652             * This can be called by custom UI 
0653             * implementations to use the Swing drag support.  This method can also be called 
0654             * by a Swing extension written as a subclass of <code>JComponent</code>
0655             * to take advantage of the Swing drag support.
0656             * <p>
0657             * The transfer <em>will not necessarily</em> have been completed at the
0658             * return of this call (i.e. the call does not block waiting for the drop).
0659             * The transfer will take place through the Swing implementation of the
0660             * <code>java.awt.dnd</code> mechanism, requiring no further effort
0661             * from the developer. The <code>exportDone</code> method will be called
0662             * when the transfer has completed.
0663             *
0664             * @param comp  the component holding the data to be transferred;
0665             *              provided to enable sharing of <code>TransferHandler</code>s
0666             * @param e     the event that triggered the transfer
0667             * @param action the transfer action initially requested;
0668             *               either {@code COPY}, {@code MOVE} or {@code LINK};
0669             *               the DnD system may change the action used during the
0670             *               course of the drag operation
0671             */
0672            public void exportAsDrag(JComponent comp, InputEvent e, int action) {
0673                int srcActions = getSourceActions(comp);
0674
0675                // only mouse events supported for drag operations
0676                if (!(e instanceof  MouseEvent)
0677                // only support known actions
0678                        || !(action == COPY || action == MOVE || action == LINK)
0679                        // only support valid source actions
0680                        || (srcActions & action) == 0) {
0681
0682                    action = NONE;
0683                }
0684
0685                if (action != NONE && !GraphicsEnvironment.isHeadless()) {
0686                    if (recognizer == null) {
0687                        recognizer = new SwingDragGestureRecognizer(
0688                                new DragHandler());
0689                    }
0690                    recognizer.gestured(comp, (MouseEvent) e, srcActions,
0691                            action);
0692                } else {
0693                    exportDone(comp, null, NONE);
0694                }
0695            }
0696
0697            /**
0698             * Causes a transfer from the given component to the
0699             * given clipboard.  This method is called by the default cut and
0700             * copy actions registered in a component's action map.  
0701             * <p>
0702             * The transfer will take place using the <code>java.awt.datatransfer</code>
0703             * mechanism, requiring no further effort from the developer. Any data
0704             * transfer <em>will</em> be complete and the <code>exportDone</code>
0705             * method will be called with the action that occurred, before this method
0706             * returns. Should the clipboard be unavailable when attempting to place
0707             * data on it, the <code>IllegalStateException</code> thrown by
0708             * {@link Clipboard#setContents(Transferable, ClipboardOwner)} will
0709             * be propogated through this method. However, 
0710             * <code>exportDone</code> will first be called with an action
0711             * of <code>NONE</code> for consistency.
0712             *
0713             * @param comp  the component holding the data to be transferred;
0714             *              provided to enable sharing of <code>TransferHandler</code>s
0715             * @param clip  the clipboard to transfer the data into  
0716             * @param action the transfer action requested; this should
0717             *  be a value of either <code>COPY</code> or <code>MOVE</code>;
0718             *  the operation performed is the intersection  of the transfer
0719             *  capabilities given by getSourceActions and the requested action;
0720             *  the intersection may result in an action of <code>NONE</code>
0721             *  if the requested action isn't supported
0722             * @throws IllegalStateException if the clipboard is currently unavailable
0723             * @see Clipboard#setContents(Transferable, ClipboardOwner)
0724             */
0725            public void exportToClipboard(JComponent comp, Clipboard clip,
0726                    int action) throws IllegalStateException {
0727
0728                if ((action == COPY || action == MOVE)
0729                        && (getSourceActions(comp) & action) != 0) {
0730
0731                    Transferable t = createTransferable(comp);
0732                    if (t != null) {
0733                        try {
0734                            clip.setContents(t, null);
0735                            exportDone(comp, t, action);
0736                            return;
0737                        } catch (IllegalStateException ise) {
0738                            exportDone(comp, t, NONE);
0739                            throw ise;
0740                        }
0741                    }
0742                }
0743
0744                exportDone(comp, null, NONE);
0745            }
0746
0747            /**
0748             * Causes a transfer to occur from a clipboard or a drag and
0749             * drop operation. The <code>Transferable</code> to be
0750             * imported and the component to transfer to are contained
0751             * within the <code>TransferSupport</code>.
0752             * <p>
0753             * While the drag and drop implementation calls {@code canImport}
0754             * to determine the suitability of a transfer before calling this
0755             * method, the implementation of paste does not. As such, it cannot
0756             * be assumed that the transfer is acceptable upon a call to
0757             * this method for paste. It is recommended that {@code canImport} be
0758             * explicitly called to cover this case.
0759             * <p>
0760             * Note: The <code>TransferSupport</code> object passed to this method
0761             * is only valid for the duration of the method call. It is undefined
0762             * what values it may contain after this method returns.
0763             *
0764             * @param support the object containing the details of
0765             *        the transfer, not <code>null</code>.
0766             * @return true if the data was inserted into the component,
0767             *         false otherwise
0768             * @throws NullPointerException if <code>support</code> is {@code null}
0769             * @see #canImport(TransferHandler.TransferSupport)
0770             * @since 1.6
0771             */
0772            public boolean importData(TransferSupport support) {
0773                return support.getComponent() instanceof  JComponent ? importData(
0774                        (JComponent) support.getComponent(), support
0775                                .getTransferable())
0776                        : false;
0777            }
0778
0779            /**
0780             * Causes a transfer to a component from a clipboard or a 
0781             * DND drop operation.  The <code>Transferable</code> represents
0782             * the data to be imported into the component.
0783             * <p>
0784             * Note: Swing now calls the newer version of <code>importData</code>
0785             * that takes a <code>TransferSupport</code>, which in turn calls this
0786             * method (if the component in the {@code TransferSupport} is a
0787             * {@code JComponent}). Developers are encouraged to call and override the
0788             * newer version as it provides more information (and is the only
0789             * version that supports use with a {@code TransferHandler} set directly
0790             * on a {@code JFrame} or other non-{@code JComponent}).
0791             *
0792             * @param comp  the component to receive the transfer;
0793             *              provided to enable sharing of <code>TransferHandler</code>s
0794             * @param t     the data to import
0795             * @return  true if the data was inserted into the component, false otherwise
0796             * @see #importData(TransferHandler.TransferSupport)
0797             */
0798            public boolean importData(JComponent comp, Transferable t) {
0799                PropertyDescriptor prop = getPropertyDescriptor(comp);
0800                if (prop != null) {
0801                    Method writer = prop.getWriteMethod();
0802                    if (writer == null) {
0803                        // read-only property. ignore
0804                        return false;
0805                    }
0806                    Class<?>[] params = writer.getParameterTypes();
0807                    if (params.length != 1) {
0808                        // zero or more than one argument, ignore
0809                        return false;
0810                    }
0811                    DataFlavor flavor = getPropertyDataFlavor(params[0], t
0812                            .getTransferDataFlavors());
0813                    if (flavor != null) {
0814                        try {
0815                            Object value = t.getTransferData(flavor);
0816                            Object[] args = { value };
0817                            MethodUtil.invoke(writer, comp, args);
0818                            return true;
0819                        } catch (Exception ex) {
0820                            System.err.println("Invocation failed");
0821                            // invocation code
0822                        }
0823                    }
0824                }
0825                return false;
0826            }
0827
0828            /**
0829             * This method is called repeatedly during a drag and drop operation
0830             * to allow the developer to configure properties of, and to return
0831             * the acceptability of transfers; with a return value of {@code true}
0832             * indicating that the transfer represented by the given
0833             * {@code TransferSupport} (which contains all of the details of the
0834             * transfer) is acceptable at the current time, and a value of {@code false}
0835             * rejecting the transfer.
0836             * <p>
0837             * For those components that automatically display a drop location during
0838             * drag and drop, accepting the transfer, by default, tells them to show
0839             * the drop location. This can be changed by calling
0840             * {@code setShowDropLocation} on the {@code TransferSupport}.
0841             * <p>
0842             * By default, when the transfer is accepted, the chosen drop action is that
0843             * picked by the user via their drag gesture. The developer can override
0844             * this and choose a different action, from the supported source
0845             * actions, by calling {@code setDropAction} on the {@code TransferSupport}.
0846             * <p>
0847             * On every call to {@code canImport}, the {@code TransferSupport} contains
0848             * fresh state. As such, any properties set on it must be set on every
0849             * call. Upon a drop, {@code canImport} is called one final time before
0850             * calling into {@code importData}. Any state set on the
0851             * {@code TransferSupport} during that last call will be available in
0852             * {@code importData}.
0853             * <p>
0854             * This method is not called internally in response to paste operations.
0855             * As such, it is recommended that implementations of {@code importData}
0856             * explicitly call this method for such cases and that this method
0857             * be prepared to return the suitability of paste operations as well.
0858             * <p>
0859             * Note: The <code>TransferSupport</code> object passed to this method
0860             * is only valid for the duration of the method call. It is undefined
0861             * what values it may contain after this method returns.
0862             *
0863             * @param support the object containing the details of
0864             *        the transfer, not <code>null</code>.
0865             * @return <code>true</code> if the import can happen,
0866             *         <code>false</code> otherwise
0867             * @throws NullPointerException if <code>support</code> is {@code null}
0868             * @see #importData(TransferHandler.TransferSupport)
0869             * @see javax.swing.TransferHandler.TransferSupport#setShowDropLocation
0870             * @see javax.swing.TransferHandler.TransferSupport#setDropAction
0871             * @since 1.6
0872             */
0873            public boolean canImport(TransferSupport support) {
0874                return support.getComponent() instanceof  JComponent ? canImport(
0875                        (JComponent) support.getComponent(), support
0876                                .getDataFlavors())
0877                        : false;
0878            }
0879
0880            /**
0881             * Indicates whether a component will accept an import of the given
0882             * set of data flavors prior to actually attempting to import it. 
0883             * <p>
0884             * Note: Swing now calls the newer version of <code>canImport</code>
0885             * that takes a <code>TransferSupport</code>, which in turn calls this
0886             * method (only if the component in the {@code TransferSupport} is a
0887             * {@code JComponent}). Developers are encouraged to call and override the
0888             * newer version as it provides more information (and is the only
0889             * version that supports use with a {@code TransferHandler} set directly
0890             * on a {@code JFrame} or other non-{@code JComponent}).
0891             *
0892             * @param comp  the component to receive the transfer;
0893             *              provided to enable sharing of <code>TransferHandler</code>s
0894             * @param transferFlavors  the data formats available
0895             * @return  true if the data can be inserted into the component, false otherwise
0896             * @see #canImport(TransferHandler.TransferSupport)
0897             */
0898            public boolean canImport(JComponent comp,
0899                    DataFlavor[] transferFlavors) {
0900                PropertyDescriptor prop = getPropertyDescriptor(comp);
0901                if (prop != null) {
0902                    Method writer = prop.getWriteMethod();
0903                    if (writer == null) {
0904                        // read-only property. ignore
0905                        return false;
0906                    }
0907                    Class<?>[] params = writer.getParameterTypes();
0908                    if (params.length != 1) {
0909                        // zero or more than one argument, ignore
0910                        return false;
0911                    }
0912                    DataFlavor flavor = getPropertyDataFlavor(params[0],
0913                            transferFlavors);
0914                    if (flavor != null) {
0915                        return true;
0916                    }
0917                }
0918                return false;
0919            }
0920
0921            /**
0922             * Returns the type of transfer actions supported by the source;
0923             * any bitwise-OR combination of {@code COPY}, {@code MOVE}
0924             * and {@code LINK}.
0925             * <p>
0926             * Some models are not mutable, so a transfer operation of {@code MOVE}
0927             * should not be advertised in that case. Returning {@code NONE}
0928             * disables transfers from the component.
0929             * 
0930             * @param c  the component holding the data to be transferred;
0931             *           provided to enable sharing of <code>TransferHandler</code>s
0932             * @return {@code COPY} if the transfer property can be found,
0933             *          otherwise returns <code>NONE</code>
0934             */
0935            public int getSourceActions(JComponent c) {
0936                PropertyDescriptor prop = getPropertyDescriptor(c);
0937                if (prop != null) {
0938                    return COPY;
0939                }
0940                return NONE;
0941            }
0942
0943            /**
0944             * Returns an object that establishes the look of a transfer.  This is
0945             * useful for both providing feedback while performing a drag operation and for 
0946             * representing the transfer in a clipboard implementation that has a visual 
0947             * appearance.  The implementation of the <code>Icon</code> interface should
0948             * not alter the graphics clip or alpha level. 
0949             * The icon implementation need not be rectangular or paint all of the
0950             * bounding rectangle and logic that calls the icons paint method should
0951             * not assume the all bits are painted. <code>null</code> is a valid return value 
0952             * for this method and indicates there is no visual representation provided.
0953             * In that case, the calling logic is free to represent the
0954             * transferable however it wants.  
0955             * <p>
0956             * The default Swing logic will not do an alpha blended drag animation if
0957             * the return is <code>null</code>.
0958             *
0959             * @param t  the data to be transferred; this value is expected to have been 
0960             *  created by the <code>createTransferable</code> method
0961             * @return  <code>null</code>, indicating
0962             *    there is no default visual representation
0963             */
0964            public Icon getVisualRepresentation(Transferable t) {
0965                return null;
0966            }
0967
0968            /**
0969             * Creates a <code>Transferable</code> to use as the source for
0970             * a data transfer. Returns the representation of the data to
0971             * be transferred, or <code>null</code> if the component's
0972             * property is <code>null</code>
0973             *
0974             * @param c  the component holding the data to be transferred;
0975             *              provided to enable sharing of <code>TransferHandler</code>s
0976             * @return  the representation of the data to be transferred, or
0977             *  <code>null</code> if the property associated with <code>c</code>
0978             *  is <code>null</code> 
0979             *  
0980             */
0981            protected Transferable createTransferable(JComponent c) {
0982                PropertyDescriptor property = getPropertyDescriptor(c);
0983                if (property != null) {
0984                    return new PropertyTransferable(property, c);
0985                }
0986                return null;
0987            }
0988
0989            /**
0990             * Invoked after data has been exported.  This method should remove 
0991             * the data that was transferred if the action was <code>MOVE</code>.
0992             * <p>
0993             * This method is implemented to do nothing since <code>MOVE</code>
0994             * is not a supported action of this implementation
0995             * (<code>getSourceActions</code> does not include <code>MOVE</code>).
0996             *
0997             * @param source the component that was the source of the data
0998             * @param data   The data that was transferred or possibly null
0999             *               if the action is <code>NONE</code>.
1000             * @param action the actual action that was performed  
1001             */
1002            protected void exportDone(JComponent source, Transferable data,
1003                    int action) {
1004            }
1005
1006            /**
1007             * Fetches the property descriptor for the property assigned to this transfer
1008             * handler on the given component (transfer handler may be shared).  This 
1009             * returns <code>null</code> if the property descriptor can't be found
1010             * or there is an error attempting to fetch the property descriptor.
1011             */
1012            private PropertyDescriptor getPropertyDescriptor(JComponent comp) {
1013                if (propertyName == null) {
1014                    return null;
1015                }
1016                Class<?> k = comp.getClass();
1017                BeanInfo bi;
1018                try {
1019                    bi = Introspector.getBeanInfo(k);
1020                } catch (IntrospectionException ex) {
1021                    return null;
1022                }
1023                PropertyDescriptor props[] = bi.getPropertyDescriptors();
1024                for (int i = 0; i < props.length; i++) {
1025                    if (propertyName.equals(props[i].getName())) {
1026                        Method reader = props[i].getReadMethod();
1027
1028                        if (reader != null) {
1029                            Class<?>[] params = reader.getParameterTypes();
1030
1031                            if (params == null || params.length == 0) {
1032                                // found the desired descriptor
1033                                return props[i];
1034                            }
1035                        }
1036                    }
1037                }
1038                return null;
1039            }
1040
1041            /**
1042             * Fetches the data flavor from the array of possible flavors that
1043             * has data of the type represented by property type.  Null is
1044             * returned if there is no match.
1045             */
1046            private DataFlavor getPropertyDataFlavor(Class<?> k,
1047                    DataFlavor[] flavors) {
1048                for (int i = 0; i < flavors.length; i++) {
1049                    DataFlavor flavor = flavors[i];
1050                    if ("application".equals(flavor.getPrimaryType())
1051                            && "x-java-jvm-local-objectref".equals(flavor
1052                                    .getSubType())
1053                            && k.isAssignableFrom(flavor
1054                                    .getRepresentationClass())) {
1055
1056                        return flavor;
1057                    }
1058                }
1059                return null;
1060            }
1061
1062            private String propertyName;
1063            private static SwingDragGestureRecognizer recognizer = null;
1064
1065            private static DropTargetListener getDropTargetListener() {
1066                synchronized (DropHandler.class) {
1067                    DropHandler handler = (DropHandler) AppContext
1068                            .getAppContext().get(DropHandler.class);
1069
1070                    if (handler == null) {
1071                        handler = new DropHandler();
1072                        AppContext.getAppContext().put(DropHandler.class,
1073                                handler);
1074                    }
1075
1076                    return handler;
1077                }
1078            }
1079
1080            static class PropertyTransferable implements  Transferable {
1081
1082                PropertyTransferable(PropertyDescriptor p, JComponent c) {
1083                    property = p;
1084                    component = c;
1085                }
1086
1087                // --- Transferable methods ----------------------------------------------
1088
1089                /**
1090                 * Returns an array of <code>DataFlavor</code> objects indicating the flavors the data 
1091                 * can be provided in.  The array should be ordered according to preference
1092                 * for providing the data (from most richly descriptive to least descriptive).
1093                 * @return an array of data flavors in which this data can be transferred
1094                 */
1095                public DataFlavor[] getTransferDataFlavors() {
1096                    DataFlavor[] flavors = new DataFlavor[1];
1097                    Class<?> propertyType = property.getPropertyType();
1098                    String mimeType = DataFlavor.javaJVMLocalObjectMimeType
1099                            + ";class=" + propertyType.getName();
1100                    try {
1101                        flavors[0] = new DataFlavor(mimeType);
1102                    } catch (ClassNotFoundException cnfe) {
1103                        flavors = new DataFlavor[0];
1104                    }
1105                    return flavors;
1106                }
1107
1108                /**
1109                 * Returns whether the specified data flavor is supported for
1110                 * this object.
1111                 * @param flavor the requested flavor for the data
1112                 * @return true if this <code>DataFlavor</code> is supported,
1113                 *   otherwise false
1114                 */
1115                public boolean isDataFlavorSupported(DataFlavor flavor) {
1116                    Class<?> propertyType = property.getPropertyType();
1117                    if ("application".equals(flavor.getPrimaryType())
1118                            && "x-java-jvm-local-objectref".equals(flavor
1119                                    .getSubType())
1120                            && flavor.getRepresentationClass()
1121                                    .isAssignableFrom(propertyType)) {
1122
1123                        return true;
1124                    }
1125                    return false;
1126                }
1127
1128                /**
1129                 * Returns an object which represents the data to be transferred.  The class 
1130                 * of the object returned is defined by the representation class of the flavor.
1131                 *
1132                 * @param flavor the requested flavor for the data
1133                 * @see DataFlavor#getRepresentationClass
1134                 * @exception IOException                if the data is no longer available
1135                 *              in the requested flavor.
1136                 * @exception UnsupportedFlavorException if the requested data flavor is
1137                 *              not supported.
1138                 */
1139                public Object getTransferData(DataFlavor flavor)
1140                        throws UnsupportedFlavorException, IOException {
1141                    if (!isDataFlavorSupported(flavor)) {
1142                        throw new UnsupportedFlavorException(flavor);
1143                    }
1144                    Method reader = property.getReadMethod();
1145                    Object value = null;
1146                    try {
1147                        value = MethodUtil.invoke(reader, component,
1148                                (Object[]) null);
1149                    } catch (Exception ex) {
1150                        throw new IOException("Property read failed: "
1151                                + property.getName());
1152                    }
1153                    return value;
1154                }
1155
1156                JComponent component;
1157                PropertyDescriptor property;
1158            }
1159
1160            /**
1161             * This is the default drop target for drag and drop operations if
1162             * one isn't provided by the developer.  <code>DropTarget</code>
1163             * only supports one <code>DropTargetListener</code> and doesn't
1164             * function properly if it isn't set.
1165             * This class sets the one listener as the linkage of drop handling
1166             * to the <code>TransferHandler</code>, and adds support for
1167             * additional listeners which some of the <code>ComponentUI</code>
1168             * implementations install to manipulate a drop insertion location.
1169             */
1170            static class SwingDropTarget extends DropTarget implements 
1171                    UIResource {
1172
1173                SwingDropTarget(Component c) {
1174                    super (c, COPY_OR_MOVE | LINK, null);
1175                    try {
1176                        // addDropTargetListener is overridden
1177                        // we specifically need to add to the superclass
1178                        super .addDropTargetListener(getDropTargetListener());
1179                    } catch (TooManyListenersException tmle) {
1180                    }
1181                }
1182
1183                public void addDropTargetListener(DropTargetListener dtl)
1184                        throws TooManyListenersException {
1185                    // Since the super class only supports one DropTargetListener,
1186                    // and we add one from the constructor, we always add to the
1187                    // extended list.
1188                    if (listenerList == null) {
1189                        listenerList = new EventListenerList();
1190                    }
1191                    listenerList.add(DropTargetListener.class, dtl);
1192                }
1193
1194                public void removeDropTargetListener(DropTargetListener dtl) {
1195                    if (listenerList != null) {
1196                        listenerList.remove(DropTargetListener.class, dtl);
1197                    }
1198                }
1199
1200                // --- DropTargetListener methods (multicast) --------------------------
1201
1202                public void dragEnter(DropTargetDragEvent e) {
1203                    super .dragEnter(e);
1204                    if (listenerList != null) {
1205                        Object[] listeners = listenerList.getListenerList();
1206                        for (int i = listeners.length - 2; i >= 0; i -= 2) {
1207                            if (listeners[i] == DropTargetListener.class) {
1208                                ((DropTargetListener) listeners[i + 1])
1209                                        .dragEnter(e);
1210                            }
1211                        }
1212                    }
1213                }
1214
1215                public void dragOver(DropTargetDragEvent e) {
1216                    super .dragOver(e);
1217                    if (listenerList != null) {
1218                        Object[] listeners = listenerList.getListenerList();
1219                        for (int i = listeners.length - 2; i >= 0; i -= 2) {
1220                            if (listeners[i] == DropTargetListener.class) {
1221                                ((DropTargetListener) listeners[i + 1])
1222                                        .dragOver(e);
1223                            }
1224                        }
1225                    }
1226                }
1227
1228                public void dragExit(DropTargetEvent e) {
1229                    super .dragExit(e);
1230                    if (listenerList != null) {
1231                        Object[] listeners = listenerList.getListenerList();
1232                        for (int i = listeners.length - 2; i >= 0; i -= 2) {
1233                            if (listeners[i] == DropTargetListener.class) {
1234                                ((DropTargetListener) listeners[i + 1])
1235                                        .dragExit(e);
1236                            }
1237                        }
1238                    }
1239                }
1240
1241                public void drop(DropTargetDropEvent e) {
1242                    super .drop(e);
1243                    if (listenerList != null) {
1244                        Object[] listeners = listenerList.getListenerList();
1245                        for (int i = listeners.length - 2; i >= 0; i -= 2) {
1246                            if (listeners[i] == DropTargetListener.class) {
1247                                ((DropTargetListener) listeners[i + 1]).drop(e);
1248                            }
1249                        }
1250                    }
1251                }
1252
1253                public void dropActionChanged(DropTargetDragEvent e) {
1254                    super .dropActionChanged(e);
1255                    if (listenerList != null) {
1256                        Object[] listeners = listenerList.getListenerList();
1257                        for (int i = listeners.length - 2; i >= 0; i -= 2) {
1258                            if (listeners[i] == DropTargetListener.class) {
1259                                ((DropTargetListener) listeners[i + 1])
1260                                        .dropActionChanged(e);
1261                            }
1262                        }
1263                    }
1264                }
1265
1266                private EventListenerList listenerList;
1267            }
1268
1269            private static class DropHandler implements  DropTargetListener,
1270                    Serializable, ActionListener {
1271
1272                private Timer timer;
1273                private Point lastPosition;
1274                private Rectangle outer = new Rectangle();
1275                private Rectangle inner = new Rectangle();
1276                private int hysteresis = 10;
1277
1278                private Component component;
1279                private Object state;
1280                private TransferSupport support = new TransferSupport(null,
1281                        (DropTargetEvent) null);
1282
1283                private static final int AUTOSCROLL_INSET = 10;
1284
1285                /**
1286                 * Update the geometry of the autoscroll region.  The geometry is
1287                 * maintained as a pair of rectangles.  The region can cause
1288                 * a scroll if the pointer sits inside it for the duration of the
1289                 * timer.  The region that causes the timer countdown is the area
1290                 * between the two rectangles.
1291                 * <p>
1292                 * This is implemented to use the visible area of the component 
1293                 * as the outer rectangle, and the insets are fixed at 10. Should
1294                 * the component be smaller than a total of 20 in any direction,
1295                 * autoscroll will not occur in that direction.
1296                 */
1297                private void updateAutoscrollRegion(JComponent c) {
1298                    // compute the outer
1299                    Rectangle visible = c.getVisibleRect();
1300                    outer.setBounds(visible.x, visible.y, visible.width,
1301                            visible.height);
1302
1303                    // compute the insets
1304                    Insets i = new Insets(0, 0, 0, 0);
1305                    if (c instanceof  Scrollable) {
1306                        int minSize = 2 * AUTOSCROLL_INSET;
1307
1308                        if (visible.width >= minSize) {
1309                            i.left = i.right = AUTOSCROLL_INSET;
1310                        }
1311
1312                        if (visible.height >= minSize) {
1313                            i.top = i.bottom = AUTOSCROLL_INSET;
1314                        }
1315                    }
1316
1317                    // set the inner from the insets
1318                    inner.setBounds(visible.x + i.left, visible.y + i.top,
1319                            visible.width - (i.left + i.right), visible.height
1320                                    - (i.top + i.bottom));
1321                }
1322
1323                /**
1324                 * Perform an autoscroll operation.  This is implemented to scroll by the
1325                 * unit increment of the Scrollable using scrollRectToVisible.  If the 
1326                 * cursor is in a corner of the autoscroll region, more than one axis will
1327                 * scroll.
1328                 */
1329                private void autoscroll(JComponent c, Point pos) {
1330                    if (c instanceof  Scrollable) {
1331                        Scrollable s = (Scrollable) c;
1332                        if (pos.y < inner.y) {
1333                            // scroll upward
1334                            int dy = s.getScrollableUnitIncrement(outer,
1335                                    SwingConstants.VERTICAL, -1);
1336                            Rectangle r = new Rectangle(inner.x, outer.y - dy,
1337                                    inner.width, dy);
1338                            c.scrollRectToVisible(r);
1339                        } else if (pos.y > (inner.y + inner.height)) {
1340                            // scroll downard
1341                            int dy = s.getScrollableUnitIncrement(outer,
1342                                    SwingConstants.VERTICAL, 1);
1343                            Rectangle r = new Rectangle(inner.x, outer.y
1344                                    + outer.height, inner.width, dy);
1345                            c.scrollRectToVisible(r);
1346                        }
1347
1348                        if (pos.x < inner.x) {
1349                            // scroll left
1350                            int dx = s.getScrollableUnitIncrement(outer,
1351                                    SwingConstants.HORIZONTAL, -1);
1352                            Rectangle r = new Rectangle(outer.x - dx, inner.y,
1353                                    dx, inner.height);
1354                            c.scrollRectToVisible(r);
1355                        } else if (pos.x > (inner.x + inner.width)) {
1356                            // scroll right
1357                            int dx = s.getScrollableUnitIncrement(outer,
1358                                    SwingConstants.HORIZONTAL, 1);
1359                            Rectangle r = new Rectangle(outer.x + outer.width,
1360                                    inner.y, dx, inner.height);
1361                            c.scrollRectToVisible(r);
1362                        }
1363                    }
1364                }
1365
1366                /**
1367                 * Initializes the internal properties if they haven't been already
1368                 * inited. This is done lazily to avoid loading of desktop properties.
1369                 */
1370                private void initPropertiesIfNecessary() {
1371                    if (timer == null) {
1372                        Toolkit t = Toolkit.getDefaultToolkit();
1373                        Integer prop;
1374
1375                        prop = (Integer) t
1376                                .getDesktopProperty("DnD.Autoscroll.interval");
1377
1378                        timer = new Timer(prop == null ? 100 : prop.intValue(),
1379                                this );
1380
1381                        prop = (Integer) t
1382                                .getDesktopProperty("DnD.Autoscroll.initialDelay");
1383
1384                        timer.setInitialDelay(prop == null ? 100 : prop
1385                                .intValue());
1386
1387                        prop = (Integer) t
1388                                .getDesktopProperty("DnD.Autoscroll.cursorHysteresis");
1389
1390                        if (prop != null) {
1391                            hysteresis = prop.intValue();
1392                        }
1393                    }
1394                }
1395
1396                /**
1397                 * The timer fired, perform autoscroll if the pointer is within the
1398                 * autoscroll region.
1399                 * <P>
1400                 * @param e the <code>ActionEvent</code>
1401                 */
1402                public void actionPerformed(ActionEvent e) {
1403                    updateAutoscrollRegion((JComponent) component);
1404                    if (outer.contains(lastPosition)
1405                            && !inner.contains(lastPosition)) {
1406                        autoscroll((JComponent) component, lastPosition);
1407                    }
1408                }
1409
1410                // --- DropTargetListener methods -----------------------------------
1411
1412                private void setComponentDropLocation(TransferSupport support,
1413                        boolean forDrop) {
1414
1415                    DropLocation dropLocation = (support == null) ? null
1416                            : support.getDropLocation();
1417
1418                    if (component instanceof  JTextComponent) {
1419                        try {
1420                            AccessibleMethod method = new AccessibleMethod(
1421                                    JTextComponent.class, "setDropLocation",
1422                                    DropLocation.class, Object.class,
1423                                    Boolean.TYPE);
1424
1425                            state = method.invokeNoChecked(component,
1426                                    dropLocation, state, forDrop);
1427                        } catch (NoSuchMethodException e) {
1428                            throw new AssertionError(
1429                                    "Couldn't locate method JTextComponet.setDropLocation");
1430                        }
1431                    } else if (component instanceof  JComponent) {
1432                        state = ((JComponent) component).setDropLocation(
1433                                dropLocation, state, forDrop);
1434                    }
1435                }
1436
1437                private void handleDrag(DropTargetDragEvent e) {
1438                    TransferHandler importer = ((HasGetTransferHandler) component)
1439                            .getTransferHandler();
1440
1441                    if (importer == null) {
1442                        e.rejectDrag();
1443                        setComponentDropLocation(null, false);
1444                        return;
1445                    }
1446
1447                    support.setDNDVariables(component, e);
1448                    boolean canImport = importer.canImport(support);
1449
1450                    if (canImport) {
1451                        e.acceptDrag(support.getDropAction());
1452                    } else {
1453                        e.rejectDrag();
1454                    }
1455
1456                    boolean showLocation = support.showDropLocationIsSet ? support.showDropLocation
1457                            : canImport;
1458
1459                    setComponentDropLocation(showLocation ? support : null,
1460                            false);
1461                }
1462
1463                public void dragEnter(DropTargetDragEvent e) {
1464                    state = null;
1465                    component = e.getDropTargetContext().getComponent();
1466
1467                    handleDrag(e);
1468
1469                    if (component instanceof  JComponent) {
1470                        lastPosition = e.getLocation();
1471                        updateAutoscrollRegion((JComponent) component);
1472                        initPropertiesIfNecessary();
1473                    }
1474                }
1475
1476                public void dragOver(DropTargetDragEvent e) {
1477                    handleDrag(e);
1478
1479                    if (!(component instanceof  JComponent)) {
1480                        return;
1481                    }
1482
1483                    Point p = e.getLocation();
1484
1485                    if (Math.abs(p.x - lastPosition.x) > hysteresis
1486                            || Math.abs(p.y - lastPosition.y) > hysteresis) {
1487                        // no autoscroll 
1488                        if (timer.isRunning())
1489                            timer.stop();
1490                    } else {
1491                        if (!timer.isRunning())
1492                            timer.start();
1493                    }
1494
1495                    lastPosition = p;
1496                }
1497
1498                public void dragExit(DropTargetEvent e) {
1499                    cleanup(false);
1500                }
1501
1502                public void drop(DropTargetDropEvent e) {
1503                    TransferHandler importer = ((HasGetTransferHandler) component)
1504                            .getTransferHandler();
1505
1506                    if (importer == null) {
1507                        e.rejectDrop();
1508                        cleanup(false);
1509                        return;
1510                    }
1511
1512                    support.setDNDVariables(component, e);
1513                    boolean canImport = importer.canImport(support);
1514
1515                    if (canImport) {
1516                        e.acceptDrop(support.getDropAction());
1517
1518                        boolean showLocation = support.showDropLocationIsSet ? support.showDropLocation
1519                                : canImport;
1520
1521                        setComponentDropLocation(showLocation ? support : null,
1522                                false);
1523
1524                        boolean success;
1525
1526                        try {
1527                            success = importer.importData(support);
1528                        } catch (RuntimeException re) {
1529                            success = false;
1530                        }
1531
1532                        e.dropComplete(success);
1533                        cleanup(success);
1534                    } else {
1535                        e.rejectDrop();
1536                        cleanup(false);
1537                    }
1538                }
1539
1540                public void dropActionChanged(DropTargetDragEvent e) {
1541                    /*
1542                     * Work-around for Linux bug where dropActionChanged
1543                     * is called before dragEnter.
1544                     */
1545                    if (component == null) {
1546                        return;
1547                    }
1548
1549                    handleDrag(e);
1550                }
1551
1552                private void cleanup(boolean forDrop) {
1553                    setComponentDropLocation(null, forDrop);
1554                    if (component instanceof  JComponent) {
1555                        ((JComponent) component).dndDone();
1556                    }
1557
1558                    if (timer != null) {
1559                        timer.stop();
1560                    }
1561
1562                    state = null;
1563                    component = null;
1564                    lastPosition = null;
1565                }
1566            }
1567
1568            /**
1569             * This is the default drag handler for drag and drop operations that 
1570             * use the <code>TransferHandler</code>.
1571             */
1572            private static class DragHandler implements  DragGestureListener,
1573                    DragSourceListener {
1574
1575                private boolean scrolls;
1576
1577                // --- DragGestureListener methods -----------------------------------
1578
1579                /**
1580                 * a Drag gesture has been recognized
1581                 */
1582                public void dragGestureRecognized(DragGestureEvent dge) {
1583                    JComponent c = (JComponent) dge.getComponent();
1584                    TransferHandler th = c.getTransferHandler();
1585                    Transferable t = th.createTransferable(c);
1586                    if (t != null) {
1587                        scrolls = c.getAutoscrolls();
1588                        c.setAutoscrolls(false);
1589                        try {
1590                            dge.startDrag(null, t, this );
1591                            return;
1592                        } catch (RuntimeException re) {
1593                            c.setAutoscrolls(scrolls);
1594                        }
1595                    }
1596
1597                    th.exportDone(c, t, NONE);
1598                }
1599
1600                // --- DragSourceListener methods -----------------------------------
1601
1602                /**
1603                 * as the hotspot enters a platform dependent drop site
1604                 */
1605                public void dragEnter(DragSourceDragEvent dsde) {
1606                }
1607
1608                /**
1609                 * as the hotspot moves over a platform dependent drop site
1610                 */
1611                public void dragOver(DragSourceDragEvent dsde) {
1612                }
1613
1614                /**
1615                 * as the hotspot exits a platform dependent drop site
1616                 */
1617                public void dragExit(DragSourceEvent dsde) {
1618                }
1619
1620                /**
1621                 * as the operation completes
1622                 */
1623                public void dragDropEnd(DragSourceDropEvent dsde) {
1624                    DragSourceContext dsc = dsde.getDragSourceContext();
1625                    JComponent c = (JComponent) dsc.getComponent();
1626                    if (dsde.getDropSuccess()) {
1627                        c.getTransferHandler().exportDone(c,
1628                                dsc.getTransferable(), dsde.getDropAction());
1629                    } else {
1630                        c.getTransferHandler().exportDone(c,
1631                                dsc.getTransferable(), NONE);
1632                    }
1633                    c.setAutoscrolls(scrolls);
1634                }
1635
1636                public void dropActionChanged(DragSourceDragEvent dsde) {
1637                }
1638            }
1639
1640            private static class SwingDragGestureRecognizer extends
1641                    DragGestureRecognizer {
1642
1643                SwingDragGestureRecognizer(DragGestureListener dgl) {
1644                    super (DragSource.getDefaultDragSource(), null, NONE, dgl);
1645                }
1646
1647                void gestured(JComponent c, MouseEvent e, int srcActions,
1648                        int action) {
1649                    setComponent(c);
1650                    setSourceActions(srcActions);
1651                    appendEvent(e);
1652                    fireDragGestureRecognized(action, e.getPoint());
1653                }
1654
1655                /**
1656                 * register this DragGestureRecognizer's Listeners with the Component
1657                 */
1658                protected void registerListeners() {
1659                }
1660
1661                /**
1662                 * unregister this DragGestureRecognizer's Listeners with the Component
1663                 *
1664                 * subclasses must override this method
1665                 */
1666                protected void unregisterListeners() {
1667                }
1668
1669            }
1670
1671            static final Action cutAction = new TransferAction("cut");
1672            static final Action copyAction = new TransferAction("copy");
1673            static final Action pasteAction = new TransferAction("paste");
1674
1675            static class TransferAction extends UIAction implements  UIResource {
1676
1677                TransferAction(String name) {
1678                    super (name);
1679                }
1680
1681                public boolean isEnabled(Object sender) {
1682                    if (sender instanceof  JComponent
1683                            && ((JComponent) sender).getTransferHandler() == null) {
1684                        return false;
1685                    }
1686
1687                    return true;
1688                }
1689
1690                public void actionPerformed(ActionEvent e) {
1691                    Object src = e.getSource();
1692                    if (src instanceof  JComponent) {
1693                        JComponent c = (JComponent) src;
1694                        TransferHandler th = c.getTransferHandler();
1695                        Clipboard clipboard = getClipboard(c);
1696                        String name = (String) getValue(Action.NAME);
1697
1698                        Transferable trans = null;
1699
1700                        // any of these calls may throw IllegalStateException
1701                        try {
1702                            if ((clipboard != null) && (th != null)
1703                                    && (name != null)) {
1704                                if ("cut".equals(name)) {
1705                                    th.exportToClipboard(c, clipboard, MOVE);
1706                                } else if ("copy".equals(name)) {
1707                                    th.exportToClipboard(c, clipboard, COPY);
1708                                } else if ("paste".equals(name)) {
1709                                    trans = clipboard.getContents(null);
1710                                }
1711                            }
1712                        } catch (IllegalStateException ise) {
1713                            // clipboard was unavailable
1714                            UIManager.getLookAndFeel().provideErrorFeedback(c);
1715                            return;
1716                        }
1717
1718                        // this is a paste action, import data into the component
1719                        if (trans != null) {
1720                            th.importData(new TransferSupport(c, trans));
1721                        }
1722                    }
1723                }
1724
1725                /**
1726                 * Returns the clipboard to use for cut/copy/paste.
1727                 */
1728                private Clipboard getClipboard(JComponent c) {
1729                    if (SwingUtilities2.canAccessSystemClipboard()) {
1730                        return c.getToolkit().getSystemClipboard();
1731                    }
1732                    Clipboard clipboard = (Clipboard) sun.awt.AppContext
1733                            .getAppContext().get(SandboxClipboardKey);
1734                    if (clipboard == null) {
1735                        clipboard = new Clipboard(
1736                                "Sandboxed Component Clipboard");
1737                        sun.awt.AppContext.getAppContext().put(
1738                                SandboxClipboardKey, clipboard);
1739                    }
1740                    return clipboard;
1741                }
1742
1743                /**
1744                 * Key used in app context to lookup Clipboard to use if access to
1745                 * System clipboard is denied.
1746                 */
1747                private static Object SandboxClipboardKey = new Object();
1748
1749            }
1750
1751        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.