/*
* Copyright (c) 2004 David Flanagan. All rights reserved.
* This code is from the book Java Examples in a Nutshell, 3nd Edition.
* It is provided AS-IS, WITHOUT ANY WARRANTY either expressed or implied.
* You may study, use, and modify it for any non-commercial purpose,
* including teaching and use in open-source projects.
* You may distribute it non-commercially as long as you retain this notice.
* For a commercial use license, or to purchase the book,
* please visit http://www.davidflanagan.com/javaexamples3.
*/
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.InputEvent;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.util.List;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.TransferHandler;
/**
* This TransferHandler subclass wraps another TransferHandler and delegates
* most of its operations to the wrapped handler. It adds the ability to to drop
* or paste files using the predefined DataFlavor.javaFileListFlavor. When a
* file list is pasted or dropped, it assumes the files are text, reads them in
* order, concatenates their contents, and then passes the resulting string to
* the wrapped handler for insertion.
*/
public class FileTransferHandler extends TransferHandler {
TransferHandler wrappedHandler; // The handler that we wrap
// We use this array to test the wrapped handler
static DataFlavor[] stringFlavorArray = new DataFlavor[] { DataFlavor.stringFlavor };
/** Pass an existing TransferHandler to this constructor */
public FileTransferHandler(TransferHandler wrappedHandler) {
if (wrappedHandler == null) // Fail immediately on null
throw new NullPointerException();
this.wrappedHandler = wrappedHandler; // Remember wrapped handler
}
/**
* This method returns true if the TransferHandler knows how to work with one
* of the specified flavors. This implementation first checks the superclass,
* then checks for fileListFlavor support
*/
public boolean canImport(JComponent c, DataFlavor[] flavors) {
// If the wrapped handler can import it, we're done
if (wrappedHandler.canImport(c, flavors))
return true;
// Otherwise, if the wrapped handler can handle string imports, then
// see if we are being offered a list of files that we can convert
// to a string.
if (wrappedHandler.canImport(c, stringFlavorArray)) {
for (int i = 0; i < flavors.length; i++)
if (flavors[i].equals(DataFlavor.javaFileListFlavor))
return true;
}
// Otherwise, we can't import any of the flavors.
return false;
}
/**
* If the wrapped handler can import strings and the specified Transferable
* can provide its data as a List of File objects, then we read the files, and
* pass their contents as a string to the wrapped handler. Otherwise, we offer
* the Transferable to the wrapped handler to handle on its own.
*/
public boolean importData(JComponent c, Transferable t) {
// See if we're offered a java.util.List of java.io.File objects.
// We handle this case first because the Transferable is likely to
// also offer the filenames as strings, and we want to import the
// file contents, not their names!
if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor)
&& wrappedHandler.canImport(c, stringFlavorArray)) {
try {
List filelist = (List) t.getTransferData(DataFlavor.javaFileListFlavor);
// Loop through the files to determine total size
int numfiles = filelist.size();
int numbytes = 0;
for (int i = 0; i < numfiles; i++) {
File f = (File) filelist.get(i);
numbytes += (int) f.length();
}
// There will never be more characters than bytes in the files
char[] text = new char[numbytes]; // to hold file contents
int p = 0; // current position in the text[] array
// Loop through the files again, reading their content as text
for (int i = 0; i < numfiles; i++) {
File f = (File) filelist.get(i);
Reader r = new BufferedReader(new FileReader(f));
p += r.read(text, p, (int) f.length());
}
// Convert the character array to a string and wrap it
// in a pre-defined Transferable class for transferring strings
StringSelection selection = new StringSelection(new String(text, 0, p));
// Ask the wrapped handler to import the string
return wrappedHandler.importData(c, selection);
}
// If anything goes wrong, just beep to tell the user
catch (UnsupportedFlavorException e) {
c.getToolkit().beep(); // audible error
return false; // return failure code
} catch (IOException e) {
c.getToolkit().beep(); // audible error
return false; // return failure code
}
}
// Otherwise let the wrapped class handle this transferable itself
return wrappedHandler.importData(c, t);
}
/*
* The following methods just delegate to the wrapped TransferHandler
*/
public void exportAsDrag(JComponent c, InputEvent e, int action) {
wrappedHandler.exportAsDrag(c, e, action);
}
public void exportToClipboard(JComponent c, Clipboard clip, int action) {
wrappedHandler.exportToClipboard(c, clip, action);
}
public int getSourceActions(JComponent c) {
return wrappedHandler.getSourceActions(c);
}
public Icon getVisualRepresentation(Transferable t) {
// This method is not currently (Java 1.4) used by Swing
return wrappedHandler.getVisualRepresentation(t);
}
/**
* This class demonstrates the FileTransferHandler by installing it on a
* JTextArea component and providing a JFileChooser to drag and cut files.
*/
public static void main(String[] args) {
// Here's the text area. Note how we wrap our TransferHandler
// around the default handler returned by getTransferHandler()
JTextArea textarea = new JTextArea();
TransferHandler defaultHandler = textarea.getTransferHandler();
textarea.setTransferHandler(new FileTransferHandler(defaultHandler));
// Here's a JFileChooser, with dragging explicitly enabled.
JFileChooser filechooser = new JFileChooser();
filechooser.setDragEnabled(true);
// Display them both in a window
JFrame f = new JFrame("File Transfer Handler Test");
f.getContentPane().add(new JScrollPane(textarea), "Center");
f.getContentPane().add(filechooser, "South");
f.setSize(400, 600);
f.setVisible(true);
}
}
|