Spec-Zone .ru
спецификации, руководства, описания, API

Swing Data Transfer

For the JavaTM 2 Platform, Standard Edition, v 1.4 release, Swing has added support for data transfer between applications. A drag and drop operation is a data transfer request that has been specified by a gesture with a graphical pointing device. In the case of copy/paste, data transfer is often initiated with the keyboard. The ability to transfer data takes two forms:

When adding data transfer support to Swing, the goal was to make it easy for developers using Swing components to add clipboard transfer as well as drag and drop to an application. Previous AWT support for drag and drop provided a great deal of flexibility, but also a fair amount of complexity, to implement. Also, AWT support for clipboard transfer had not been integrated into Swing in a natural way. For this release, data transfer support has been implemented so that the developer may take advantage of these powerful features with minimal effort.

Because the state of each Swing component is independent of the definition of the data model, it was easy to implement a mechanism for moving the data between components without worrying about the details of the data itself. The data transfer amounts to transferring part of one model to another model. (In the case of cut/copy/paste, the data is transferred between the model and the clipboard.) To support data transfer, we:

Quick Reference: Components That Support DnD

ComponentSupports DragSupports Drop
JColorChooser X X
JEditorPane X X
JFileChooser X
JFormattedTextField X X
JLabel see here see here
JList X
JPasswordField X
JTable X
JTextArea X X
JTextField X X
JTextPane X X
JTree X

This document has the following sections:

Data Transfer Support

The foundation of data transfer is support for handling the transfer of data into and out of a component. With this functionality available on the component, the mechanics of managing a drag and drop can be provided automatically. In addition, support for cut/copy/paste can also be provided automatically. The crux of this implementation is the new class TransferHandler. The JComponent property methods, setTransferHandler and getTransferHandler, provide an entrypoint to the data transfer mechanism for any component which extends JComponent.

The table below details the extent of the cut, copy, paste, and drop support for each of the components when a non-null TransferHandler is installed. Note that this support is enabled by the look and feel code. Support for dragging is initially disabled, but may be enabled by calling setDragEnabled(true) on the component. If the component doesn't have such a method, the drag may be enabled by binding some kind of gesture to it.

Default TransferHandler Support

For the components listed below, Swing installs default implementations of TransferHandler. For those components that have default Swing support, the TransferHandler is installed by the ComponentUI if the value of the transferHandler property is null or marked by the presence of the UIResource interface. The default TransferHandler implementation installed by the ComponentUI is marked by the UIResource interface, enabling developers to override the default TransferHandler. The following table shows the support provided.

Components That Support DnD

Component Exports (Drag, Cut, Copy) Imports (Drop, Paste)
JColorChooser The selected color is offered through the JavaBeansTM property handling of TransferHandler. The flavor offered is application/x-java-jvm-local-objectref; class=java.awt.Color. The value transferred is determined by getColor. Accepts inserts of type Color. The data is imported by using setColor (from the bean property handling). Any flavor having class=java.awt.Color (or a subclass of java.awt.Color) is accepted.
JEditorPane 1.4: If the content-type of the JEditorPane is text/plain, the selected text is offered as as text/plain through the write method of the EditorKit. If the content-type is OTHER, it is exported both as text/plain using the getSelectedText method, and as OTHER using the write method of the EditorKit.

1.4.1: The selected text, as returned by the getSelectedText method, is exported as text/plain. In addition, if the content-type of the JEditorPane is other than text/plain, the selected content is also offered in that other flavor using the EditorKit's write method.

1.4: Accepts inserts of type text/plain and whatever the current type returned by getContentType. If a type is found matching the current type (including text/plain), it is imported using the EditorKit's read method. Otherwise, text/plain is imported through the component's replaceSelection method. Paste: the contents of the selection, if any, are replaced. Drop: the data is inserted at the caret position.

1.4.1: Accepts inserts of type text/plain and whatever the current type returned by getContentType. If a type is found matching the current type (excluding text/plain), it is imported using the EditorKit's read method. Otherwise, text/plain is imported through the component's replaceSelection method. Paste: the contents of the selection, if any, are replaced. Drop: the data is inserted at the caret position.

JFileChooser The selection is offered in the same manner as those from the native file chooser. Imports not accepted. As the mouse is moved over the list, the potential drop point is indicated by highlighting the file/directory under the cursor. See Default Drop Support.
JFormattedTextField The selected text is offered as text/plain. Accepts inserts of type text/plain. Paste: the contents of the selection, if any, are replaced; otherwise the data is inserted at the caret position. Drop: the data is inserted at the caret position. Note that paste and drop employ the same code paths as typing from the keyboard, therefore code validation is preserved.
JList If the selection is a single item, it is offered as text/plain. If multiple items are selected, they are offered as text/html. The format of the text/html is a <UL> tag followed by the selected list items each starting with an <LI> tag. Imports not accepted. As the mouse is moved over the list, the potential drop point is indicated by highlighting the list item under the cursor. See Default Drop Support.
JPasswordField For security reasons, cut, copy, and drag are not supported. Accepts inserts of type text/plain. Paste: the contents of the selection, if any, are replaced; otherwise the data is inserted at the caret position. Drop: the data is inserted at the caret position.
JTable If the selection is a single item, it is offered as text/plain. If multiple items are selected, they are offered as text/html. The format of the text/html is a <TABLE> tag followed by a <TR> tag for each row and a <TD> tag for each cell. Imports not accepted. As the mouse is moved over the table, the potential drop point is indicated by highlighting the cell under the cursor. See Default Drop Support.
JTextArea The selected text is offered as text/plain. Accepts inserts of type text/plain. Paste: the contents of the selection, if any, are replaced; otherwise the data is inserted at the caret position. Drop: the data is inserted at the caret position.
JTextField The selected text is offered as text/plain. Accepts inserts of type text/plain. Paste: the contents of the selection, if any, are replaced; otherwise the data is inserted at the caret position. Drop: the data is inserted at the caret position.
JTextPane Same as JEditorPane. Same as JEditorPane.
JTree If the selection is a single item, it is offered as text/plain. If multiple items are selected, they are offered as text/html. The format of the text/html is nested lists, similar to the format used for JList. Imports not accepted. As the mouse is moved over the table, the potential drop point is indicated by highlighting the tree node under the cursor. See Default Drop Support.

Example of Adding Support to JLabel

The JLabel component does not support DnD by default. The following code fragment creates a JLabel that supports drag and drop on the "text" property (a String):

JLabel componentType = new JLabel();
componentType.setTransferHandler(new TransferHandler("text"));
MouseListener ml = new MouseAdapter() {
    public void mousePressed(MouseEvent e) {
        JComponent c = (JComponent)e.getSource();
        TransferHandler th = c.getTransferHandler();
        th.exportAsDrag(c, e, TransferHandler.COPY);
    }
};
componentType.addMouseListener(ml);

We have included a small example that implements drag and drop using a JTextField and a JLabel. You can type a value into the text field, highlight the text, then hold the mouse button down over the textfield and drag a few pixels. An icon appears under the cursor. Release the icon over the JLabel and see the text replace the "Drop Here" text. Simultaneously with the drop, the text is removed from the source textfield. The default behavior for drag and drop is MOVE. To change the behavior to COPY, hold down the CONTROL key while selecting the text. On Windows, a plus sign appears in the icon. When the text is released on the target, it is left intact in the source. You can likewise drag from the JLabel to the text field. Note that JLabel does not have bindings for copy/paste and is unable to get the focus that is required to support this feature.

See the JLabelDragNDrop.java example here.

Drag Support

Some components, such as text fields, support selections. For those kinds of components, a drag operation is typically initiated by dragging an existing selection with the mouse. A controller for this type of component can recognize this condition and initiate a drag. For those components that don't have selections, Swing can't automatically initiate the drag, but Swing can handle the mechanics of the drag if told that a drag attempt has been initiated as shown in the JLabel example.

With this level of drag support, the Swing developer can focus on implementing a TransferHandler that represents the desired transfer, and setting properties on the Swing component. This greatly simplifies the burden to the Swing developer wanting to support dragging in an application.

Note that we are currently investigating providing different visual appearances of the drag, hence the reference to Icon in the API. Stay tuned for future developments.

Default Drag Support

The simplest level of support is to set a flag that indicates the developer would like the default support enabled. The components that offer default support for dragging are described in the Exports column of the Components That Support DnD table; but to summarize, the classes that directly implement setDragEnabled and getDragEnabled are: JColorChooser, JFileChooser, JList, JTable, JTree, and JTextComponent. The drag gesture is defined as the press of the first mouse button over a selection and dragging a few pixels. Setting the dragEnabled property to true therefore has a subtle effect on mouse behavior.

When dragging is enabled on a component, the Swing controller (in the corresponding ComponentUI subclass) begins looking for a drag gesture, and if the transferHandler property is null, or marked by the presence of the UIResource interface, a default implementation is installed. The implementation provided by Swing is marked with the UIResource interface, so a developer can insert a new TransferHandler by replacing the default TransferHandler property with a custom implementation. When a drag gesture is recognized, the exportAsDrag method is called on the TransferHandler which initiates the drag mechanism. The actual transfer is handled by the java.awt.dnd mechanism, requiring no further effort from the developer.

Adding Drag Support to Subclasses of Swing Classes

The drag support provided by Swing is activated by the TransferHandler.exportAsDrag method. This makes adding drag support as easy as:

  1. Installing a TransferHandler implementation (so there is something to drag) by calling the setTransferHandler method.
  2. Recognizing a drag gesture.
  3. Calling the exportAsDrag method.

Some scenarios for accomplishing this are:

Operation of TransferHandler.exportAsDrag

When the exportAsDrag method is called on TransferHandler, the drag is handled by Swing provided functionality. When this method is called, it is assumed that a valid drag gesture has been recognized. The method performs the following steps:

  1. A Swing implementation of a DragSource and DragListener is used to start the drag using the Transferable implementation returned by createTransferable as data transfer object.
  2. When the drop has completed, the exportDone method is called on the TransferHandler. For some operations, such as MOVE, it may be necessary to remove the data from the source. The default behavior for text-based components, for example, is that a standard drag implements MOVE behavior (following the drop the selected text is removed from the source component). The user may override this behavior by holding down the control key when the text is selected for dragging. On Windows, the drag icon visually reflects this behavior with a small plus-sign.

Drop Support

The primary support for handling a drop is the same as for a paste operation, the importData method on the TransferHandler. The semantics of inserting data into a component are generally more meaningful at the application level than the toolkit level. Users of an application can drop all kinds of Transferable implementations on components that are completely unknown to the Swing toolkit. It is up to the Swing developer to provide a TransferHandler with meaningful import semantics if the default TransferHandler is insufficient.

A drop operation does have some differences from a paste however:

Default Drop Support

To assist Swing developers in adding drop support to an application, Swing provides DropTarget implementations that use the TransferHandler property on the Swing component. For those components that have a non-null TransferHandler property, the drop target is installed by the ComponentUI if the value of the dropTarget property is null or marked by the presence of the UIResource interface. The default DropTarget implementations installed by the ComponentUI is marked by the UIResource interface, enabling developers to override the default DropTarget.

The components that provide a complete drop implementation by default are indicated in the Imports column of the Components That Support DnD table. There are four components that provide only some support for drop. JFileChooser, JList, JTable, and JTree by default have an installed DropTarget that indicates a potential insertion point. However, to fully support imports of data the developer must write and install a custom TransferHandler.

Using the Drop Support in Subclasses of Swing Classes

A well behaved DropTarget implementation uses the transferHandler property on JComponent to perform the drop. The Swing developer automatically gets a simple DropTarget implementation that links the drop to the TransferHandler when the transferHandler property is set and the dropTarget property is null.

Clipboard Transfer Support

Cut, copy, and paste operations perform data transfer in a manner that is more useful to those without a mouse, as they are typically initiated via a keyboard gesture. These operations can use the same TransferHandler services as the drag and drop support. This improves the accessibility of the data transfers, and enables Swing to provide keyboard bindings for these operations even though Swing may not know how to actually transfer the data to/from the clipboard. The keyboard bindings for clipboard transfer are dependent upon the current look and feel that is installed.

Default Clipboard Transfer

As with drag and drop, clipboard transfers are the most useful for those components that support selections. The list of components shown in the Exports column of the Components That Support DnD table have cut, copy, and paste actions in the component action map, along with a LAF dependent set of keyboard bindings in the input map of the component. Having Swing provide these bindings frees the developer from trying to track the current look and feel and change the bindings.

Using the Clipboard Transfer Support in Subclasses of Swing Classes

A well behaved cut, copy, and paste implementation uses the transferHandler property on JComponent to perform the transfer. When the transferHandler property is set on a JComponent, a simple Action implementation that links the transfer of between a Clipboard and TransferHandler is installed in the component's action map under the keys cut, copy, and paste if there is no action currently installed.

Implementation Details

Note: The following information outlines private implementation details and is subject to change. We are providing this information only to satisfy the curiosity of those who have access to the source code and feel compelled to thump the tires and peek under the hood.

If a TransferHandler is installed on a JComponent, the look and feel then enables cut, copy, and paste using the following TransferHandler methods:

If you bind some event to TransferHandler.exportAsDrag you also get drag support. This plumbing is located in package-private nested classes inside of the TransferHandler class.

The following package-private classes were added to the javax.swing.plaf.basic package for creating the default support:

BasicTransferable
The basis of the various Transferable implementations.
BasicDropTargetListener
Adds scrolling support and drop target feedback for those components supporting selection.
BasicDragGestureRecognizer
Supports the "select and move a few pixels" drag gesture recognition.

Each of the ComponentUI classes that support DnD then have some additional nested classes:

BasicTreeUI:

TreeTransferHandler
Default import/export support.
TreeTransferable
The actual tree data.
TreeDragGestureRecognizer
Tree drag gesture recognition, enabled by JTree.setDragEnabled.
TreeDropHandler
Shows drop target location.

BasicListUI, BasicTableUI, BasicTextUI all have a pattern similar to as BasicTreeUI.

BasicFileChooserUI
Uses the list support, but has a FileTransferHandler that produces the FileTransferable that extends the ListTransferable with the flavor used for file transfers.
BasicColorChooserUI
Uses the TransferHandler bean support and binds the "color" property. A mouse listener is added to the preview area to bind a mouse press to the exportAsDrag method on the TransferHandler.

Changes Since Beta

TransferHandler Actions Should be Registered by UI

The bugtraq report that corresponds to this change is: 4460011.

To implement drag and drop, bindings were provided in the Action class to support copying and pasting the data. In order for a look and feel, or other code, to override these Actions, the UI must install them - Actions are no longer automatically installed by the TransferHandler. The package-private methods getCutAction, getCopyAction, and getPasteAction in TransferHandler are now made public.

Ability to Disable DropTarget

The bugtraq report that corresponds to this change is: 4485914.

The drag and drop implementation causes a DropTarget to be added to a JComponent if that component has a TransferHandler installed. This may affect applications that are manually adding DropTargets. Therefore the System property suppressSwingDropSupport has been added. The JComponent methods setTransferHandler(TransferHandler) and getTransferHandler can be used to enable or disable this property.

Known Bugs

Drop Clobbers Selected Text in JTextComponent

The bugtraq report that corresponds to this problem is: 4513715.

Selecting text and then dragging and dropping that text within the selected region of the same text component causes the selected text to be clobbered and nothing to be pasted. This bug is fixed in release 1.4.1.

Occasional Errors in Restoring Caret when Exiting a Component

The bugtraq report that corresponds to this problem is: 4513720.

With the built-in drop support, Swing text components respond to DnD dragovers by setting the Caret to visible and using it to display the potential insert location. When the drag exits the component, the Caret's visibility is restored. Unfortunately, since the Caret uses the same "visible" property to represent the usual meaning of visible as well as when it is in mid-flash, we sometimes restore the Caret's visibility incorrectly.

Cut/Copy/Drag Broken for JEditorPane with RTFEditorKit

The bugtraq report that corresponds to this problem is: 4513638.

When using an RTFEditorKit set explicitly on a JEditorPane using setEditorKit, or by setting the content-type to text/rtf, cut, copy and drag no longer work. Note that this bug, filed against release 1.4, is fixed in release 1.4.1.