Copying and pasting data to and from the clipboard is a fundamental capability that is expected by users of all windowing systems. The JDK provides the basis for full support of clipboard operations through the Clipboard class and other classes and interfaces of the java.awt.transfer package. This chapter introduces you to the classes of java.awt.transfer. You'll learn how to copy Java objects to the clipboard and paste them into other windows or programs. When you finish this chapter, you'll be able to implement clipboard support in your Java applications.
The java.awt.datatransfer class was created to support platform-independent clipboard operations. It consists of three interfaces (ClipboardOwner, FlavorMap, and Transferable) and four classes (Clipboard, DataFlavor, SystemFlavorMap, and StringSelection). Each of these classes and interfaces is covered in the following sections.
The Clipboard class, as you would expect, is the core class for implementing clipboard operations. It provides access to the system clipboard as well as to Java-internal clipboard objects. The system clipboard can be used to copy and paste data between Java and non-Java programs. The Clipboard object is returned by the getSystemClipboard() method of the Toolkit class. Other Java-internal Clipboard objects can be created using the Clipboard() constructor, which takes a String object (the name of the clipboard) as an argument.
The Clipboard class has two field variables: owner and contents. The owner variable refers to an object that implements the ClipboardOwner interface and identifies the process that owns the clipboard. The contents variable refers to an object that is placed on the clipboard. This object implements the Transferable interface.
The three clipboard access methods, getName(), getContents(), and setContents(), are used to identify a Clipboard object, get the contents of the clipboard, and put new data on the clipboard.
The getContents()method takes a single argument--the object requesting the clipboard's contents. It returns an object that implements the Transferable interface. This object is used to access the clipboard's contents.
The setContents()method takes two arguments: an object that implements the Transferable interface and an object that implements the Clipboard owner interface. The first object contains the data that is to be placed on the clipboard. The second object identifies the object that has placed the data on the clipboard.
Objects that implement the Transferable interface are copied to and from Clipboard objects via the setContents() and getContents() method of the Clipboard class. The Transferable interface has three methods that allow the clipboard data to be read:
The key to reading data from the clipboard is to read the data using the most appropriate data flavor (for example, PostScript, HTML, plain text, and so on). At present, choosing the correct flavor is easy because the java.awt.datatransfer package only provides useful support for simple text transfers. However, the classes and interfaces of java.awt.datatransfer provide a foundation from which more complex data flavors can be created.
The DataFlavor class encapsulates data types used to pass data to and from the clipboard. A DataFlavor object consists of the following information:
The naming scheme of the DataFlavor class bridges the gap between humans, MIME types, and Java. It provides a sound foundation from which complex clipboard operations can be supported.
NOTE: MIME types are covered in Chapter 11, "Using the Utility and Math Packages," and Chapter 33, "Content and Protocol Handlers."
The DataFlavor class provides several constructors that allow a DataFlavor object to be created for a particular Java class or for a specified MIME type. In the first case, a Class object (representing the class of the data to be sent to the keyboard) and a String that provides a human-readable name for the data are provided as arguments to the constructor. The MIME type associated with the DataFlavor object defaults to application/x-java-serialized-object.
In the second case, the MIME type and human-readable name are provided as arguments to the constructor, and the Java class name of the object defaults to either InputStream or null.
Several access methods of DataFlavor are used to get and set the human-readable name, MIME type, and Java class associated with DataFlavor objects:
The DataFlavor class defines two constants, plainTextFlavor and stringFlavor, that are used to identify specific data flavors. The plainTextFlavor constant identifies data that is of the text/plain MIME type and that is associated with an InputStream class or with no class (null). The stringFlavor constant identifies an object of the java.lang.String class that has the application/x-java-serialized-object MIME type.
The FlavorMap interface maps native type strings to their associated MIME types and data flavors. It consists of two methods, getFlavorsForNatives() and getNativesForFlavors(). The SystemFlavorMap class provides an implementation of the FlavorMap interface that also provides support for working with MIME types.
The ReadClipApp program in Listing 15.1 shows how the Clipboard class, Transferable interface, and DataFlavor class are used to obtain information about data that is contained on the clipboard. Figure 15.1 shows the program's opening display. Copy some text to the clipboard using a text editor such as Notepad. When you switch to ReadClipApp and select Clipboard from the Read menu, ReadClipApp displays information about the flavor of the data contained on the clipboard, as shown in Figure 15.2. Try copying nontext objects to the clipboard, such as an image that you create using the Paint program. When you try to read information about these objects, the ReadClipApp program displays the information shown in Figure 15.3. The reason the program does not see the image data is because the DataFlavor class for the image data is not available.
FIGURE 15.1. The opening window of the Readclipapp program.
FIGURE 15.2. Displaying information about the clipboard's contents.
FIGURE 15.3. How unknown data flavors are handled.
import java.awt.*; import java.awt.event.*; import java.awt.datatransfer.*; public class ReadClipApp extends Frame { TextArea textArea = new TextArea(); Toolkit toolkit; int screenWidth = 500; int screenHeight = 500; public static void main(String args[]){ ReadClipApp app = new ReadClipApp(); } public ReadClipApp() { super("ReadClipApp"); setup(); setSize(screenWidth,screenHeight); addWindowListener(new WindowEventHandler()); show(); } void setup() { setupMenuBar(); toolkit=getToolkit(); add("Center",textArea); } void setupMenuBar() { MenuBar menuBar = new MenuBar(); Menu fileMenu = new Menu("File"); Menu readMenu = new Menu("Read"); MenuItem fileExit = new MenuItem("Exit"); MenuItem readClipboard = new MenuItem("Clipboard"); fileExit.addActionListener(new MenuItemHandler()); readClipboard.addActionListener(new MenuItemHandler()); fileMenu.add(fileExit); readMenu.add(readClipboard); menuBar.add(fileMenu); menuBar.add(readMenu); setMenuBar(menuBar); } class MenuItemHandler implements ActionListener { public void actionPerformed(ActionEvent ev){ String s=ev.getActionCommand(); if(s=="Exit"){ System.exit(0); }else if(s=="Clipboard"){ // Use the Toolkit object to obtain access to the system clipboard Clipboard clip=toolkit.getSystemClipboard(); String text="Object Name: "; // Get the name of the clipboard text+=clip.getName(); text+="\n\nData Flavors:"; // Get the clipboard contents Transferable contents=clip.getContents(ReadClipApp.this); if(contents==null) text+="\n\nThe clipboard is empty."; else{ // Get the data flavors associated with the clipboard contents DataFlavor flavors[]=contents.getTransferDataFlavors(); for(int i=0;i<flavors.length;++i){ // Get the name, MIME type, and class associated with each flavor text+="\n\n Name: "+flavors[i].getHumanPresentableName(); text+="\n MIME Type: "+flavors[i].getMimeType(); text+="\n Class: "; Class cl = flavors[i].getRepresentationClass(); if(cl==null) text+="null"; else text+=cl.getName(); } } textArea.setText(text); } } } class WindowEventHandler extends WindowAdapter { public void windowClosing(WindowEvent e){ System.exit(0); } } }
The code that implements clipboard operations is contained in the actionPerfomed() method of the MenuItemHandler class. When the Clipboard menu item is selected, the getSystemClipboard() method of the Toolkit class is invoked to gain access to the system clipboard. This object is assigned to the clip variable. The getName() method of the Clipboard class is used to get the name of the Clipboard object that is returned.
A Transferable object representing the contents of the clipboard is returned by invoking the getContents() method of the Clipboard class. This object is assigned to the contents variable.
If a null value is returned by getContents(), the clipboard is identified as empty. Otherwise, the getTransferDataFlavors() method of the Transferable interface is invoked to obtain an array of data flavors corresponding to the clipboard data. The getHumanPresentableName(), getMimeType(), and getRepresentationClass() methods are used to obtain information about each of the supported DataFlavor objects. This information is then displayed to the user.
The ClipboardOwner interface of java.awt.datatransfer is used to provide a callback method, lostOwnership(), that notifies the current clipboard owner that it has lost ownership of the clipboard. The ClipboardOwner object can then take whatever action is necessary as the result of lost ownership. In most cases, no action is required at all.
The StringSelection class implements both the Transferable and ClipboardOwner interfaces to support the transfer of String objects to and from the clipboard. This is a useful class that simplifies the copying and pasting of text.
The StringSelection class has a single constructor that takes a String object as an argument. This object is the data that is to be transferred via the clipboard. StringSelection implements the getTransferData(), getTransferDataFlavors(), and isDataFlavorSupported() methods of the Transferable interface and the lostOwnership() method of the ClipboardOwner interface. These methods provide all that is needed to copy and paste String objects, as you'll learn in the next section.
The ClipTextApp program of Listing 15.2 shows how text can be copied to or pasted from the clipboard. Figure 15.4 shows the ClipTextApp opening window. Copy some text to the clipboard using a text editor and then switch back to the ClipTextApp program. Select Paste from the Edit menu. The text that you copied to the clipboard is pasted to the ClipTextApp window, as shown in Figure 15.5.
You have seen how ClipTextApp supports pasting from the system clipboard. It is also designed to copy the text Hello from Java! to the system clipboard. Select Copy from the Edit menu to copy text from ClipTextApp to the clipboard. Then select Paste to see which text was copied, as shown in Figure 15.6. ClipTextApp copied the text Hello from Java! to the clipboard. You can verify this by pasting the clipboard's contents using another program, such as Notepad, as shown in Figure 15.7.
FIGURE 15.4. The opening window of the ClipTextApp program.
FIGURE 15.5. Pasting text to the ClipTextApp window.
FIGURE 15.6. The result of copying and pasting.
FIGURE 15.7. The text copied by ClipTextApp can be retrieved by other programs.
import java.awt.*; import java.awt.event.*; import java.awt.*; import java.awt.datatransfer.*; import java.util.*; import java.io.*; public class ClipTextApp extends Frame { Font defaultFont = new Font("default",Font.PLAIN,12); int screenWidth = 400; int screenHeight = 400; Toolkit toolkit; int baseline; int lineSize; FontMetrics fm; Canvas canvas = new MyCanvas(); Vector text = new Vector(); int topLine; public static void main(String args[]){ ClipTextApp app = new ClipTextApp(); } public ClipTextApp() { super("ClipTextApp"); setup(); setSize(screenWidth,screenHeight); addWindowListener(new WindowEventHandler()); show(); } void setup() { setupMenuBar(); setupFontData(); text.addElement(""); add("Center",canvas); } void setupMenuBar() { MenuBar menuBar = new MenuBar(); Menu fileMenu = new Menu("File"); Menu editMenu = new Menu("Edit"); MenuItem fileExit = new MenuItem("Exit"); MenuItem editCopy = new MenuItem("Copy"); MenuItem editPaste = new MenuItem("Paste"); fileExit.addActionListener(new MenuItemHandler()); editCopy.addActionListener(new MenuItemHandler()); editPaste.addActionListener(new MenuItemHandler()); fileMenu.add(fileExit); editMenu.add(editCopy); editMenu.add(editPaste); menuBar.add(fileMenu); menuBar.add(editMenu); setMenuBar(menuBar); } void setupFontData() { setFont(defaultFont); toolkit = getToolkit(); fm = toolkit.getFontMetrics(defaultFont); baseline = fm.getLeading()+fm.getAscent(); lineSize = fm.getHeight(); } public void paint(Graphics g) { canvas.repaint(); } void copyToClipboard() { // Copy the string, "Hello from Java!" to the clipboard String toClipboard="Hello from Java!"; StringSelection ss = new StringSelection(toClipboard); Clipboard clip=toolkit.getSystemClipboard(); clip.setContents(ss,ss); } void pasteFromClipboard() { // Get the system clipboard using the toolkit Clipboard clip=toolkit.getSystemClipboard(); // Get the clipboard contents Transferable contents=clip.getContents(ClipTextApp.this); text.removeAllElements(); if(contents==null) text.addElement("The clipboard is empty."); else{ // If the contents support the string data flavor then retrieve and Âparse the data contained // on the clipboard if(contents.isDataFlavorSupported(DataFlavor.stringFlavor)){ try{ String data = (String) contents.getTransferData( DataFlavor.stringFlavor); if(data==null) text.addElement("null"); else{ StringTokenizer st = new StringTokenizer(data,"\n"); while(st.hasMoreElements()) text.addElement(st.nextToken()); } } catch(IOException ex){ text.addElement("IOException"); } catch(UnsupportedFlavorException ex){ text.addElement("UnsupportedFlavorException"); } }else text.addElement("Wrong flavor."); } repaint(); } class MenuItemHandler implements ActionListener { public void actionPerformed(ActionEvent ev){ String s=ev.getActionCommand(); if(s=="Exit"){ System.exit(0); }else if(s=="Copy") copyToClipboard(); else if(s=="Paste") pasteFromClipboard(); } } class WindowEventHandler extends WindowAdapter { public void windowClosing(WindowEvent e){ System.exit(0); } } class MyCanvas extends Canvas { public void paint(Graphics g) { topLine = 0; int numLines = text.size(); screenHeight = getSize().height; int y = baseline*2; int x = y; for(int i = topLine;(i < numLines) && (y < screenHeight + ÂlineSize);++i) { g.drawString((String) text.elementAt(i),x,y); y += lineSize; } } } }
The copying of text to the clipboard is implemented by the copyToClipboard() method of ClipTextApp. This method creates a StringSelection object with the text Hello from Java!. It invokes the getSystemClipboard() method of the Toolkit class to access the system clipboard and the setContents() method of the Clipboard class to set the StringSelection object as the clipboard's contents.
The pasting of text from the clipboard is performed by the pasteFromClipboard() method. This method invokes getSystemClipboard() to access the system clipboard and getContents() to retrieve the clipboard contents as a Transferable object. If the Transferable object is null, a Clipboard empty. message is displayed to the user. Otherwise, the isDataFlavorSupported() method of the Transferable interface is used to determine whether an object that is compatible with the StringSelection class is contained on the clipboard. If not, a Wrong flavor. message is displayed to the user.
If the data on the clipboard can be accessed as a StringSelection object, the data is retrieved using the getTransferData() method of the Transferable interface and assigned to the data variable. A StringTokenizer object is constructed to parse the data into separate lines and assign them to the Vector object referenced by the text variable. The contents of text are then displayed to the screen via the paint() method of the MyCanvas class.
In this chapter you were introduced to the classes of java.awt.transfer. You learned how to copy data to and from the clipboard using the Clipboard API. In the next chapter, you'll learn how to use the new drag-and-drop capabilities of JDK 1.2.
© Copyright, Macmillan Computer Publishing. All rights reserved.