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
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.