First Comes Data Transfer

   

The Data Transfer API is used to develop JFC programs that cut objects to and paste objects from either the system clipboard or a private clipboard. Although almost any kind of object can be cut and pasted (in theory), this API is typically used to cut and paste text strings. As a result, special support for cutting and pasting strings is provided.

The Data Transfer API is located in the java.awt.datatransfer package, which contains three interfaces and six classes ”described in Table 19.1.

Table 19.1. Data Transfer Classes and Interfaces
Interface/Class Description
Clipboard This class implements a mechanism for transferring data by way of copy/cut/paste operations.
ClipboardOwner This interface is used by classes whose objects provide data to a clipboard.
DataFlavor Each instance of this class represents a data format for data appearing on a clipboard, during drag and drop, or in a file system.
FlavorMap This interface is used by classes (such as SystemFlavorMap ) to provide mappings between platform native type names and MIME types (and their associated data flavors).
MimeTypeParseException This class is used to create objects that represent MIME type parsing exceptions. (This class is used internally by DataFlavor. )
StringSelection This convenience class is used for transferring String objects to a clipboard.
SystemFlavorMap This class is used (by Drag and Drop) to create objects that represent externally configurable flavor maps.
Transferable This interface is used by classes whose objects provide data for a transfer operation.
UnsupportedFlavorException This class is used to create objects that represent unsupported flavor exceptions.

Table 19.1 introduces several concepts that are important to data transfer. These concepts include data flavors, transferables, clipboard owners , and clipboards.

Data Flavors

Data flavors are objects that represent formats in which data can be transferred. These formats tell recipients what kind of data has been sent. Without this knowledge, a recipient would not know how to handle newly received data. For example, is the data formatted as text, image, audio, video, or something else? If text is sent, is this text plain, rich, or Unicode? Furthermore, if an image is sent, is this image GIF, JPEG, PNG, or some other kind? As this example shows, formats are divided into primary types (such as text) and subtypes (such as rich).

Each format corresponds to a MIME (Multipurpose Internet Mail Extensions) type. Although originally developed as a means to identify the various formats of data included in an email message, MIME's usefulness extends into the Data Transfer API.

Each MIME type consists of a primary type and a subtype, with a forward slash character serving as a separator. For example, text/plain represents a MIME type. The primary type is text and the subtype is plain. Furthermore, optional parameters might be present with some MIME types. For example, the text/plain MIME type might be followed by a charset=Unicode parameter. As a result, the fully qualified MIME type would read text/plain; charset=Unicode. (The charset parameter is used to differentiate between different kinds of plain text. The Unicode value represents text formatted as 16-bit Unicode characters .)

Objects created from the DataFlavor class represent data flavors. This class has quite a few methods , which include

  • Constructors

  • getHumanPresentableName

  • getMimeType

  • getParameter

  • getPrimaryType

  • getRepresentationClass

  • getSubType

  • isMimeTypeEqual

DataFlavor has several constructors. However, only two of these constructors will be examined. The first constructor has the following signature:

 DataFlavor (String mimeType, String humanPresentableName) 

A data flavor corresponding to a MIME type, as specified by the mimeType argument, is constructed . A more user -friendly name is provided by the humanPresentableName argument. This name can be displayed in a menu to provide a user with a selection of data flavors from which to choose. Furthermore, the resulting data flavor is associated with the default java.io.InputStream representation class. (The concept of a representation class will be explained when the next constructor is discussed.) The following code fragment constructs a data flavor using this constructor:

 DataFlavor df1 = new DataFlavor ("text/plain; charset=ASCII",                                  "Plain ASCII text"); 

The MIME type is text/plain; charset=ASCII, and its human presentable name is Plain ASCII text. The representation class is java.io.InputStream.

The second constructor has the following signature:

 DataFlavor (Class representationClass, String humanPresentableName) 

A data flavor corresponding to a representation class, as specified by the representationClass argument, is constructed. This class is used by a recipient to retrieve data by creating an object from this class and calling its methods. As with the previous constructor, a more user-friendly name is provided by the humanPresentableName argument. This name can be displayed in a menu to provide a user with a selection of data flavors from which to choose. The following code fragment constructs a data flavor using this constructor:

 DataFlavor df = new DataFlavor (java.awt.Button.class, "AWT Button"); 

The representation class is java.awt.Button, and the human presentable name is AWT Button. Assuming that a Button object has been transferred to a clipboard, its getText method can be called to retrieve the button's text after this object is fetched from the clipboard. The MIME type is application/x-java-serialized-object.

Note

The concepts of files and serialization (saving objects in files so they can be reconstructed at a later point in time) are used by the Data Transfer API. Because these concepts are discussed at great length in subsequent chapters, they are only briefly referred to in this chapter.


The getHumanPresentableName method returns the human presentable name. It has the following signature:

 String getHumanPresentableName () 

The MIME type is returned by the getMimeType method. It has the following signature:

 String getMimeType () 

A MIME type's parameter is returned by the getParameter method. This method has the following signature:

 String getParameter (String name) 

If the parameter, identified by name, is part of a MIME type, its value is returned.

The getPrimaryType method returns a MIME type's primary type. It has the following signature:

 String getPrimaryType () 

The getRepresentationClass method returns the data flavor's representation class. This method has the following signature:

 Class getRepresentationClass () 

A MIME type's subtype is returned by the getSubType method, which has the following signature:

 String getSubType () 

Finally, the current DataFlavor object can be compared to another DataFlavor object, to see if they are identical. Comparison is based on MIME types and performed by the isMimeTypeEqual method. It has the following signature:

 boolean isMimeTypeEqual (DataFlavor df) 

If the current data flavor's MIME type matches the MIME type of the df argument, a Boolean true value is returned. Otherwise, false is returned.

To make sense out of these methods, Listing 19.1 presents source code to a DataFlavorDemo1 application.

Listing 19.1 The DataFlavorDemo1 Application Source Code
 // DataFlavorDemo1.java import java.awt.datatransfer.*; class DataFlavorDemo1 {    public static void main (String [] args)    {       DataFlavor df1 = new DataFlavor ("text/plain; charset=ASCII",                                        "Plain ASCII text");       System.out.println ("Mime type: " + df1.getMimeType ());       System.out.println ("Primary type: " + df1.getPrimaryType ());       System.out.println ("Subtype: " + df1.getSubType ());       System.out.println ("Parameter: " + df1.getParameter ("charset"));       System.out.println ("Name: " + df1.getHumanPresentableName ());       String s = df1.getRepresentationClass ().toString ();       System.out.println ("Representation class: " + s + "\ n");       DataFlavor df2 = new DataFlavor (java.awt.Button.class,                                        "AWT Button");       System.out.println ("Mime type: " + df2.getMimeType ());       System.out.println ("Primary type: " + df2.getPrimaryType ());       System.out.println ("Subtype: " + df2.getSubType ());       System.out.println ("Name: " + df2.getHumanPresentableName ());       s = df2.getRepresentationClass ().toString ();       System.out.println ("Representation class: " + s + "\ n");       System.out.println ("df1 equals df2: " +                           df1.isMimeTypeEqual (df2));    } } 

DataFlavorDemo1 constructs two data flavors. The first data flavor uses the text/plain; charset=ASCII MIME type and is automatically assigned java.io.InputStream as its representation class. The second data flavor uses the application/x-java-serialized-object MIME type and is assigned java.awt.Button as its representation class.

DataFlavor includes three predefined data flavor variables that represent common data flavors. These variables include stringFlavor, plainTextFlavor, and javaFileListFlavor.

The stringFlavor variable is the data flavor for textual data represented by Java's String objects. Its MIME type is application/x-java-serialized-object, and its representation class is java.lang.String. The plainTextFlavor variable is the data flavor for textual data represented by Unicode characters. Its MIME type is text/plain; charset=unicode, and its representation class is java.io.InputStream. Finally, the javaFileListFlavor variable is the data flavor for files represented by Java's File objects. Its MIME type is application/x-java-file-list, and its representation class is java.util.List.

Caution

plainTextFlavor has been deprecated because its InputStream representation class uses 8-bit bytes to retrieve 16-bit Unicode characters. Instead of using plainTextFlavor, DataFlavor 's getReaderForText method is recommended.


Listing 19.2 presents source code to a DataFlavorDemo2 application that extracts information from the stringFlavor, plainTextFlavor, and javaFileListFlavor data flavor objects.

Listing 19.2 The DataFlavorDemo2 Application Source Code
 // DataFlavorDemo2.java import java.awt.datatransfer.*; class DataFlavorDemo2 {    public static void main (String [] args)    {       DataFlavor df = DataFlavor.stringFlavor;       System.out.println ("Mime type: " + df.getMimeType ());       System.out.println ("Primary type: " + df.getPrimaryType ());       System.out.println ("Subtype: " + df.getSubType ());       System.out.println ("Name: " + df.getHumanPresentableName ());       String s = df.getRepresentationClass ().toString ();       System.out.println ("Representation class: " + s + "\ n");       df = DataFlavor.plainTextFlavor;         System.out.println ("Mime type: " + df.getMimeType ());       System.out.println ("Primary type: " + df.getPrimaryType ());       System.out.println ("Subtype: " + df.getSubType ());       System.out.println ("Parameter: " + df.getParameter ("charset"));       System.out.println ("Name: " + df.getHumanPresentableName ());       s = df.getRepresentationClass ().toString ();       System.out.println ("Representation class: " + s + "\ n");       df = DataFlavor.javaFileListFlavor;       System.out.println ("Mime type: " + df.getMimeType ());       System.out.println ("Primary type: " + df.getPrimaryType ());       System.out.println ("Subtype: " + df.getSubType ());       System.out.println ("Name: " + df.getHumanPresentableName ());       s = df.getRepresentationClass ().toString ();       System.out.println ("Representation class: " + s);    } } 

Note

To establish a sense of completeness, DataFlavorDemo2 extracts information using plainTextFlavor. However, plainTextFlavor is only presented as an illustration. Because this flavor has been deprecated, you should avoid using plainTextFlavor in your programs.


Version 1.3 of the Java 2 Platform Standard Edition adds two new methods to DataFlavor : getReaderForText and selectBestTextFlavor.

The getReaderForText method takes a single Transferable argument and returns a reader (a mechanism for reading Unicode character streams by interpreting a stream's contents as a sequence of 16-bit Unicode characters) corresponding to the input stream, based on the MIME charset parameter value. (This works if the representation class is java.io.InputStream or a subclass. If the representation class is a reader, the representation class is returned.)

The selectBestTextFlavor method takes an array of DataFlavor objects (corresponding to text data flavors) as its single argument and attempts to locate the data flavor of highest fidelity. If found, this data flavor is returned. Otherwise, null is returned.

Transferables

Transferables are objects placed on or retrieved from a clipboard. Their classes implement the Transferable interface. Transferable 's methods allow transferables to describe their presentations to clipboard readers, and include

  • getTransferData

  • getTransferDataFlavors

  • isDataFlavorSupported

The getTransferData method returns an object representing the data retrieved from a clipboard. It has the following signature:

 Object getTransferData (DataFlavor df) 

The df argument identifies the desired data flavor in which to obtain the data. If the data is no longer available in this data flavor, an IOException object is thrown. Furthermore, if the df data flavor is not supported, an UnsupportedFlavorException object is thrown.

Assuming that the data is available and that the data flavor is supported, this method returns an object created from the data flavor's representation class. Methods can then be called on this object to retrieve the data. However, if the data flavor is DataFlavor.stringFlavor, you don't have to call any methods, because this flavor returns an instance of the String class. All you need to do is cast from Object to String. (The ClipboardDemo1 application ” introduced later in this chapter ”provides an illustration.)

The getTransferDataFlavors method returns an array of DataFlavor objects that correspond to all supported data flavors. It has the following signature:

 DataFlavor [] getTransferDataFlavors () 

This array is usually ordered from the most descriptive data flavor (such as a rich text data flavor) to the least descriptive data flavor (such as a plain text data flavor).

The isDataFlavorSupported method returns a Boolean that indicates whether a specific data flavor is supported. It has the following signature:

 boolean isDataFlavorSupported (DataFlavor df) 

A Boolean true value is returned if the transferable supports the data flavor specified by df. Otherwise, false is returned.

Clipboard Owners

Clipboard owners are objects created from classes that implement the ClipboardOwner interface. These objects are responsible for placing transferables on the clipboard. (You'll learn about clipboards very shortly.) When a clipboard owner places a transferable on the clipboard, it becomes the owner of that clipboard. However, if some other clipboard owner places an object on the clipboard, it becomes the new owner and the previous owner loses ownership.

ClipboardOwner provides a single method, which has the following signature:

 void lostOwnership (Clipboard clipboard, Transferable contents) 

This method is called when a clipboard owner loses ownership of a clipboard (and can be used to prompt a user to keep or remove any data on the clipboard prior to exiting a program). The clipboard argument identifies the previously owned clipboard, and contents identifies the transferable previously on the clipboard. (In other words, contents represents the notified clipboard owner's transferable.)

Clipboards

One of the more intuitive aspects of a windowing system is the concept of a clipboard. Most users are familiar with this concept, along with the standard copy/cut/paste metaphor that is used to copy or cut text from one document and paste it into another document. Between copy/cut and paste operations, a clipboard serves as a repository for this text.

In a much broader sense, a clipboard serves as a repository for transferables. These transferables are not limited to text, but can include any other kind of data (such as audio or image data). Only a single transferable can be stored on a clipboard at any given point in time.

Clipboards fall into two categories: system and private. The system clipboard is used by the underlying windowing system. JFC applications and native programs have access to the system clipboard. You can obtain the system clipboard by calling Toolkit 's getSystemClipboard method. For example, the following code fragment acquires the system clipboard:

 Clipboard c = java.awt.Toolkit.getDefaultToolkit ().getSystemClipboard (); 

Private clipboards are used by the currently running program and have no security restrictions placed on them. (This means that an applet can create and use a private clipboard.) You can obtain a private clipboard by constructing objects from the Clipboard class. Clipboard 's methods include

  • Constructor

  • getContents

  • getName

  • setContents

Clipboard 's single constructor has the following signature:

 Clipboard (String name) 

The name argument identifies the newly constructed clipboard. The following code fragment constructs a private clipboard:

 Clipboard c = new Clipboard ("My private clipboard"); 

The getContents method retrieves the current transferable placed on the clipboard, or null if the clipboard is empty. It has the following signature:

 Transferable getContents (Object requester) 

The requester argument identifies the object requesting the transferable. However, the concept of a requester is currently not implemented. Therefore, the requester argument is ignored. (It's a good idea to pass this as the requester argument's value. This way, your code will work properly when the requester concept is implemented.)

The getName method returns the name of the clipboard. It has the following signature:

 String getName () 

The name passed to a private clipboard's constructor is returned. However, System is returned if this method is called for the system clipboard.

The setContents method changes the clipboard's contents and owner. It has the following signature:

 void setContents (Transferable contents, ClipboardOwner owner) 

The new contents are specified by contents, and the new owner is specified by owner. The previous clipboard owner is notified by a call to its lostOwnership method.

Listing 19.3 presents source code to a ClipboardDemo1 application that demonstrates clipboards, transferables, and data flavors.

Listing 19.3 The ClipBoardDemo1 Application Source Code
 // ClipboardDemo1.java import java.awt.*; import java.awt.datatransfer.*; import java.awt.event.*; import java.io.*; class ClipboardDemo1 extends Frame                      implements ActionListener, ItemListener {    TextArea ta;    Checkbox cbFlavor;    boolean useFlavor = true;    ClipboardDemo1 (String title)    {       super (title);       addWindowListener (new WindowAdapter ()                         {                              public void windowClosing (WindowEvent e)                              {                                 System.exit (0);                              }                         } );       MenuBar mb = new MenuBar ();       Menu file = new Menu ("File");       file.add ("Exit");       // An action listener is being assigned to       // the entire menu instead of just a single       // menu item because there is only one menu       // item. Swing does not support this capability.       file.addActionListener (this);       mb.add (file);       Menu edit = new Menu ("Edit");       edit.add ("Paste");       // An action listener is being assigned to       // the entire menu instead of just a single       // menu item because there is only one menu       // item. Swing does not support this capability.       edit.addActionListener (this);       mb.add (edit);       setMenuBar (mb);       Panel p = new Panel ();       CheckboxGroup cbg = new CheckboxGroup ();       cbFlavor = new Checkbox ("Flavor", true, cbg);       cbFlavor.addItemListener (this);       p.add (cbFlavor);       Checkbox cb = new Checkbox ("Text", false, cbg);       cb.addItemListener (this);       p.add (cb);       add (p, BorderLayout.SOUTH);       p = new Panel ();       ta = new TextArea (10, 60);       ta.setEditable (false);       p.add (ta);       add (p, BorderLayout.NORTH);       pack ();       setVisible (true);    }   public void actionPerformed (ActionEvent e)    {       if (e.getActionCommand ().equals ("Exit"))           System.exit (0);       // Paste is assumed.       ta.setText ("");       Toolkit tk = Toolkit.getDefaultToolkit ();       Clipboard c = tk.getSystemClipboard ();       Transferable t = c.getContents (this);       if (t == null)           return;       String s = "";       if (useFlavor)       {           DataFlavor [] df = t.getTransferDataFlavors ();           for (int i = 0; i < df.length; i++)                s = s + df [i].getHumanPresentableName () + " ("                      + df [i].getMimeType () + ")\ n";       }       else           try           {               s = (String) t.getTransferData (DataFlavor.stringFlavor);           }           catch (IOException e2) { }           catch (UnsupportedFlavorException e2) { }       ta.setText (s);    }   public void itemStateChanged (ItemEvent e)    {       if (e.getItemSelectable () == cbFlavor)           useFlavor = true;       else           useFlavor = false;    }    public static void main (String [] args)    {       new ClipboardDemo1 ("Clipboard Demo1");    } } 

ClipboardDemo1 is an AWT application that creates a GUI consisting of a menu bar with two menus , a text area, and a pair of radio buttons that are used to select whether data flavor information or text will be pasted. (The default is data flavor information.) You can select Exit from the File menu to terminate this program, or you can select Paste from the Edit menu to paste either the transferable's data flavor information (if there is a transferable) or the transferable's data (provided that its data flavor corresponds to the string data flavor) from the system clipboard to the text area.

When you select Paste, the actionPerformed method is called. The contents of the text area are erased, and then the system clipboard is obtained (via getDefaultToolkit and getSystemClipboard ) along with its transferable (via the getContents method). If no transferable is present, getContents returns null, and this method exits. If getContents returns a reference to a Transferable object, either all data flavors are captured by calling getTransferDataFlavors or the transferable's data is obtained by calling getTransferData.

In the situation where data flavors are retrieved, each data flavor's human presentable name and MIME type are extracted and appended to a String object. Figure 19.1 shows ClipboardDemo1 's GUI displaying data flavors.

Figure 19.1. The ClipboardDemo1 application displays the transferable's data flavors.

graphics/19fig01.gif

The first displayed data flavor has Unicode String as its human presentable string, whereas the second data flavor is identified as Plain Text.

When data is retrieved, this data is stored in a String object. Figure 19.2 shows ClipboardDemo1 's GUI displaying the data (using the string data flavor).

Figure 19.2. The ClipboardDemo1 application displays the transferable's data.

graphics/19fig02.gif

So far, you've seen how data is pasted from the system clipboard. It's time to broaden this knowledge by learning how to copy data to either the system or a private clipboard, as well as learning how to paste this data from a private clipboard. Therefore, Listing 19.4 presents source code to a ClipboardDemo2 application that demonstrates these tasks .

Listing 19.4 The ClipBoardDemo2 Application Source Code
 // ClipboardDemo2.java import java.awt.*; import java.awt.datatransfer.*; import java.awt.event.*; import java.io.*; class ClipboardDemo2 extends Frame                      implements ActionListener, ItemListener {    TextArea ta;    TextField tf;    Checkbox cbSystem;    boolean useSystem = true;    Clipboard pc = new Clipboard ("Personal");    Clipboard sc = Toolkit.getDefaultToolkit ().getSystemClipboard ();    ClipboardDemo2 (String title)    {       super (title);       addWindowListener (new WindowAdapter ()                          {                              public void windowClosing (WindowEvent e)                              {                                 System.exit (0);                              }                          } );       MenuBar mb = new MenuBar ();       Menu file = new Menu ("File");       MenuItem fileItem = new MenuItem ("Exit");       fileItem.addActionListener (this);       file.add (fileItem);       mb.add (file);       Menu edit = new Menu ("Edit");       MenuItem editItem = new MenuItem ("Copy");       editItem.addActionListener (this);       edit.add (editItem);       editItem = new MenuItem ("Paste");       editItem.addActionListener (this);       edit.add (editItem);       mb.add (edit);       setMenuBar (mb);       Panel p = new Panel ();       CheckboxGroup cbg = new CheckboxGroup ();       cbSystem = new Checkbox ("System", true, cbg);       cbSystem.addItemListener (this);       p.add (cbSystem);       Checkbox cb = new Checkbox ("Private", false, cbg);       cb.addItemListener (this);       p.add (cb);       add (p, BorderLayout.SOUTH);       p = new Panel ();       tf = new TextField (60);       p.add (tf);       add (p, BorderLayout.CENTER);       p = new Panel ();       ta = new TextArea (10, 60);       ta.setEditable (false);       p.add (ta);       add (p, BorderLayout.NORTH);       pack ();       setVisible (true);    }   public void actionPerformed (ActionEvent e)    {       if (e.getActionCommand ().equals ("Exit"))           System.exit (0);       Clipboard c = (useSystem) ? sc : pc;       if (e.getActionCommand ().equals ("Copy"))       {           myTransferable mt = new myTransferable (tf.getText ());           c.setContents (mt, mt);           return;       }       // Paste is the default.       try       {          Transferable t = c.getContents (this);          if (t != null)          {              String s;              s = (String) t.getTransferData (DataFlavor.stringFlavor);              ta.setText (s);          }       }       catch (IOException e2) { }       catch (UnsupportedFlavorException e2) { }       return;    }    public void itemStateChanged (ItemEvent e)    {       ta.setText ("");       if (e.getItemSelectable () == cbSystem)           useSystem = true;       else           useSystem = false;    }   public static void main (String [] args)    {       new ClipboardDemo2 ("Clipboard Demo2");    } } class myTransferable implements Transferable, ClipboardOwner {    private DataFlavor [] dataFlavors =    {       DataFlavor.stringFlavor    } ;   private String data;   myTransferable (String data)    {       this.data = data;    }   public DataFlavor [] getTransferDataFlavors ()    {       // Do not allow caller to modify the flavors.       return (DataFlavor []) dataFlavors.clone ();    }   public boolean isDataFlavorSupported (DataFlavor flavor)    {       return (flavor == DataFlavor.stringFlavor) ? true : false;    }   public Object getTransferData (DataFlavor flavor)           throws UnsupportedFlavorException, IOException    {       if (flavor == DataFlavor.stringFlavor)           return (Object) data;       else           throw new UnsupportedFlavorException (flavor);    }   public void lostOwnership (Clipboard c, Transferable contents)    {       System.out.println ("losing ownership");    } } 

ClipboardDemo2 is an AWT application that creates a GUI consisting of a menu bar with two menus, a text area, a text field, and a pair of radio buttons that are used to select whether the system or the private clipboard is used. (The default is the system clipboard.) You can select Exit from the File menu to terminate this program, Copy from the Edit menu to copy the contents of the text field to the appropriate clipboard, or Paste from the Edit menu to paste the transferable's data (provided that there is a transferable and that its data flavor corresponds to the string flavor) from the clipboard to the text area.

To take care of copying, ClipboardDemo2 needs to create an object from a class that implements the Transferable and ClipboardOwner interfaces. This class is given the name myTransferable. When Copy is selected, an object from this class is created and its constructor is given the contents of the text field. These contents are saved in a private String variable. Then, the current clipboard's setContents method is called to transfer this data to either the system or private clipboard. (You can get away with passing the myTransferable variable as both arguments to setContents because myTransferable is both a transferable and a clipboard owner, by virtue of implementing both interfaces.)

To take care of pasting, the clipboard's getContents method is called to return the transferable. If an accessible transferable exists on the clipboard, getTransferData is called to return the data in accordance with the string data flavor.

Figure shows ClipboardDemo2 's GUI displaying text field data copied to the system clipboard and then pasted to the text area.

Figure 19.3. The ClipboardDemo2 application displays text field data pasted from the system clipboard to the text area.

graphics/19fig03.gif

The myTransferable class isn't necessary because the Data Transfer API includes a convenience class called StringSelection. This class behaves identically to myTransferable. To demonstrate StringSelection (and also to provide a Swing alternative), Listing 19.5 presents source code to an application called ClipboardDemo3.

Listing 19.5 The ClipBoardDemo3 Application Source Code
 // ClipboardDemo3.java import javax.swing.*; import java.awt.*; import java.awt.datatransfer.*; import java.awt.event.*; import java.io.*; class ClipboardDemo3 extends JFrame implements ActionListener {    JTextArea ta;    JTextField tf;    JRadioButton rbSystem, rbPrivate;    boolean useSystem = true;    Clipboard pc = new Clipboard ("Personal");    Clipboard sc = Toolkit.getDefaultToolkit ().getSystemClipboard ();    ClipboardDemo3 (String title)    {       super (title);       addWindowListener (new WindowAdapter ()                          {                              public void windowClosing (WindowEvent e)                              {                                 System.exit (0);                              }                          } );       JMenuBar mb = new JMenuBar ();       JMenu file = new JMenu ("File");       JMenuItem fileItem = new JMenuItem ("Exit");       fileItem.addActionListener (this);       file.add (fileItem);       mb.add (file);       JMenu edit = new JMenu ("Edit");       JMenuItem editItem = new JMenuItem ("Copy");       editItem.addActionListener (this);       edit.add (editItem);       editItem = new JMenuItem ("Paste");       editItem.addActionListener (this);       edit.add (editItem);       mb.add (edit);       setJMenuBar (mb);       JPanel p = new JPanel ();       rbSystem = new JRadioButton ("System", true);       rbSystem.addActionListener (this);       p.add (rbSystem);       rbPrivate = new JRadioButton ("Private", false);       rbPrivate.addActionListener (this);       p.add (rbPrivate);       ButtonGroup bg = new ButtonGroup ();       bg.add (rbSystem);       bg.add (rbPrivate);       getContentPane ().add (p, BorderLayout.SOUTH);       p = new JPanel ();       tf = new JTextField (40);       p.add (tf);       getContentPane ().add (p, BorderLayout.CENTER);       p = new JPanel ();       ta = new JTextArea (10, 40);       ta.setEditable (false);       p.add (ta);       getContentPane ().add (p, BorderLayout.NORTH);       pack ();       setVisible (true);    }   public void actionPerformed (ActionEvent e)    {       ta.setText ("");       if (e.getSource () == rbSystem)       {           useSystem = true;           return;       }       if (e.getSource () == rbPrivate)       {           useSystem = false;           return;       }       if (e.getActionCommand ().equals ("Exit"))           System.exit (0);       Clipboard c = (useSystem) ? sc : pc;       if (e.getActionCommand ().equals ("Copy"))       {           StringSelection ss = new StringSelection (tf.getText ());           c.setContents (ss, ss);           return;       }       // Paste is the default.       try       {          Transferable t = c.getContents (this);          if (t != null)          {              String s;              s = (String) t.getTransferData (DataFlavor.stringFlavor);              ta.setText (s);          }       }       catch (IOException e2) { }       catch (UnsupportedFlavorException e2) { }       return;    }   public static void main (String [] args)    {       new ClipboardDemo3 ("Clipboard Demo3");    } } 

ClipboardDemo3 is a Swing application that presents an equivalent GUI to ClipboardDemo2. The only real difference (in terms of clipboard functionality) is the use of StringSelection instead of myTransferable to transfer data using a string data flavor. Figure 19.4 shows ClipboardDemo3 's GUI displaying text field data copied to a private clipboard and then pasted to the text area.

Figure 19.4. The ClipboardDemo3 application displays text field data pasted from the private clipboard to the text area.

graphics/19fig04.gif

Troubleshooting Tip

Text field and text area components provide automatic copy, cut, and paste operations. However, there might be situations in which you need to perform these operations in a programmatic fashion. If you're having trouble figuring out how to accomplish this task, see "Programmatically Copying, Cutting, and Pasting" in the "Troubleshooting" section at the end of this chapter.


So far, the discussion has revolved around transferring textual data to the clipboard. However, as you know, other kinds of data (such as images) exist. To give you an idea of what is required in transferring an image to a clipboard, Listing 19.6 presents source code to the ClipboardDemo4 application.

Listing 19.6 The ClipboardDemo4 Application Source Code
 // ClipboardDemo4.java import java.awt.*; import java.awt.datatransfer.*; import java.awt.event.*; import java.awt.image.*; class ClipboardDemo4 {    static Clipboard c = new Clipboard ("My clipboard");    public static void main (String [] args)    {       int width = 100;       int height = 100;       int [] pixels = new int [width * height];       int index = 0;       for (int y = 0; y < height; y++)       {            int numerator = y * 255;            int b = numerator / height;            int r = 255 - numerator / height;           for (int x = 0; x < width; x++)            {                 int g = x * 255 / width;                 pixels [index++] = (255 << 24)  (r << 16)  (g << 8)                                     b;            }       }       Toolkit tk = Toolkit.getDefaultToolkit ();       Image im = tk.createImage (new MemoryImageSource (width,                                                         height,                                                         pixels,                                                         0,                                                         width));       ImageSelection is = new ImageSelection (im);       c.setContents (is, is);       Frame f = new Frame ("Clipboard Demo4");       f.addWindowListener (new WindowAdapter ()                            {                              public void windowClosing (WindowEvent e)                              {                                 System.exit (0);                              }                            } );       picture p = new picture (f);       f.add (p);       Transferable t = c.getContents (new ClipboardDemo4 ());       if (t == null)           return;       try       {           p.draw ((Image)                   t.getTransferData (ImageSelection.imageFlavor));       }       catch (java.io.IOException e) { }       catch (UnsupportedFlavorException e) { }       f.pack ();       f.setVisible (true);    } } class ImageSelection implements Transferable, ClipboardOwner {     public static final DataFlavor imageFlavor =                                  new DataFlavor (java.awt.Image.class,                                                  "AWT Image");     private DataFlavor [] flavors =     {        imageFlavor     } ;     private Image picture;     public ImageSelection (Image picture)     {        this.picture = picture;     }     public DataFlavor [] getTransferDataFlavors ()     {        return flavors;     }        public boolean isDataFlavorSupported (DataFlavor df)     {        return imageFlavor.equals (df);     }     public Object getTransferData (DataFlavor df)                   throws UnsupportedFlavorException     {        if (df.equals (imageFlavor))            return picture;        else            throw new UnsupportedFlavorException (df);     }     public void lostOwnership (Clipboard c, Transferable contents)     {        System.out.println ("lost ownership");     } }  class picture extends Canvas {     private Frame observer;  // The frame window that monitors an image.     private Image image;     // The current image.   picture (Frame observer)    {       this.observer = observer; // Save the current observer.       setBackground (Color.lightGray);     }   public void draw (Image image)    {       this.image = image;           // Save the current image.       repaint ();                   // Draw the image.    }   public Dimension getPreferredSize ()    {       // When the layout manager calls picture's getPreferredSize ()       // method, this method will return a Dimension object that       // tells the layout manager how much room to reserve for the       // picture component. Because images are already present in       // memory (by virtue of being on the clipboard), it's okay to       // call the Image's getWidth and getHeight methods. However,       // an 80-pixel border is also provided.       return new Dimension (image.getWidth (observer) + 80,                             image.getHeight (observer) + 80);    }   public void paint (Graphics g)    {       // Determine the upper-left image corner (x, y) coordinates so       // that the image will be centered.       int x = (getSize ().width - image.getWidth (observer)) / 2;       int y = (getSize ().height - image.getHeight (observer)) / 2;       // Draw the image.       g.drawImage (image, x, y, observer);    }   public void update (Graphics g)    {       // The inherited update method clears the background prior       // to calling paint. This results in flicker. The flicker       // is eliminated by overriding update.       paint (g);    } } 

ClipboardDemo4 constructs an image in memory and converts this image into an Image object by way of a MemoryImageSource producer. This Image object is copied to a clipboard and later retrieved.

Because you've seen most of this code in previous chapters, the only new concept is the ImageSelection class. This class is modeled after StringSelection and introduces a flavor called imageFlavor. The idea is to return an Image object from the clipboard when getTransferData is called.

You cannot use this program (at least not under Windows or Unix) to transfer an image to the system clipboard because that clipboard does not understand the MIME type corresponding to the image flavor. (This is why a private clipboard is created.)

From one perspective, this program is "much ado about nothing." After all, you aren't really accomplishing anything useful by transferring the image to and from the private clipboard. However, imagine creating a drawing program. You could use ClipboardDemo4 's ImageSelection class, and its metaphor for transferring images to and from a private clipboard, to support clipboard functionality in this drawing program.

Troubleshooting Tip

ClipboardDemo4 shows that textual data isn't the only kind of data that can be copied to and pasted from a private clipboard. An image object can also be copied and pasted. However, you'll be disappointed if you try to copy this image object to the system clipboard. If you're having trouble trying to transfer an image or some other kind of nontextual data to/from the system clipboard, see "Transferring Nontextual Data to/from the System Clipboard" in the "Troubleshooting" section at the end of this chapter.


   


Special Edition Using Java 2 Standard Edition
Special Edition Using Java 2, Standard Edition (Special Edition Using...)
ISBN: 0789724685
EAN: 2147483647
Year: 1999
Pages: 353

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net