FileDocCategorySizeDatePackage
FileTransferHandler.javaAPI DocExample6430Sat Jan 24 10:44:38 GMT 2004je3.datatransfer

FileTransferHandler.java

/*
 * 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.
 */
package je3.datatransfer;
import javax.swing.*;
import java.awt.datatransfer.*;
import java.io.*;
import java.awt.event.InputEvent;
import java.util.List;

/**
 * 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 class Test {
	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);
	}
    }
}