FileTransferHandler.java Source code

Java tutorial

Introduction

Here is the source code for FileTransferHandler.java

Source

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

}