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:
Drag and drop (DnD) support
Clipboard transfer via cut/copy/paste
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:
Added a small amount of API to enable data transfer with a few
method calls.
Made it possible to disable the Swing DnD implementation so
that the user can use the support provided by AWT to customize any
special behavior.
Implemented the necessary changes in the look and feel
implementations we provide.
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-nullTransferHandler 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.
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.
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 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 (includingtext/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 (excludingtext/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.
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.
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.
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:
Installing a TransferHandler implementation (so
there is something to drag) by calling the
setTransferHandler method.
Recognizing a drag gesture.
Calling the exportAsDrag method.
Some scenarios for accomplishing this are:
Add a MouseListener that watches for the desired
gesture, then call getTransferHandler on the component
and call the exportAsDrag method when the desired
gesture is found. See the JLabel
example.
Reimplement the processMouseEvent method in a
subclass and call the exportAsDrag method on the
ComponentUI variable when a drag gesture is seen, otherwise execute
the superclass behavior.
In a component with a custom UI implementation, have the
controller call exportAsDrag when a drag gesture has
been seen.
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:
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.
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.
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:
Typically a potential drop site provides feedback of where the
data would be accepted.
For components with selection capabilities, the insertion point
is moved to indicate where the data would be placed.
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-nullTransferHandler 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.
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.
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.
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.
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.
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.
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.