/*
* @(#)FileTextFieldTransferHandler.java 1.2 2010-10-02
*
* Copyright (c) 2007-2010 Werner Randelshofer
* Staldenmattweg 2, CH-6405 Immensee, Switzerland
* All rights reserved.
*
* This software is the confidential and proprietary information of
* Werner Randelshofer. ("Confidential Information"). You shall not
* disclose such Confidential Information and shall use it only in
* accordance with the terms of the license agreement you entered into
* with Werner Randelshofer.
*/
package ch.randelshofer.gui.datatransfer;
import java.awt.datatransfer.*;
import java.awt.im.InputContext;
import java.io.*;
import java.util.*;
import javax.swing.*;
import javax.swing.text.*;
/**
* The FileTextFieldTransferHandler can be used to add drag and drop
* support for JTextFields, which contain the path to a file.
*
* @author Werner Randelshofer
* @version 1.2 2010-10-03 Adds support for file filter.
*
1.1 2008-12-03 Added file selection mode.
*
1.0 September 8, 2007 Created.
*/
public class FileTextFieldTransferHandler extends TransferHandler {
private boolean shouldRemove;
private JTextComponent exportComp;
private int p0;
private int p1;
private int fileSelectionMode;
private FileFilter fileFilter;
/** Creates a new instance. */
public FileTextFieldTransferHandler() {
this(JFileChooser.FILES_ONLY);
}
/** Creates a new instance.
* @param fileSelectionMode JFileChooser file selection mode.
*/
public FileTextFieldTransferHandler(int fileSelectionMode) {
this(fileSelectionMode, null);
}
/** Creates a new instance.
* @param fileSelectionMode JFileChooser file selection mode.
*/
public FileTextFieldTransferHandler(int fileSelectionMode, FileFilter filter) {
this.fileFilter = filter;
if (fileSelectionMode != JFileChooser.FILES_AND_DIRECTORIES
&& fileSelectionMode != JFileChooser.FILES_ONLY
&& fileSelectionMode != JFileChooser.DIRECTORIES_ONLY) {
throw new IllegalArgumentException("illegal file selection mode:" + fileSelectionMode);
}
this.fileSelectionMode = fileSelectionMode;
}
@Override
public boolean importData(JComponent comp, Transferable t) {
JTextComponent c = (JTextComponent) comp;
// if we are importing to the same component that we exported from
// then don't actually do anything if the drop location is inside
// the drag location and set shouldRemove to false so that exportDone
// knows not to remove any data
if (c == exportComp && c.getCaretPosition() >= p0 && c.getCaretPosition() <= p1) {
shouldRemove = false;
return true;
}
boolean imported = false;
if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
InputContext ic = c.getInputContext();
if (ic != null) {
ic.endComposition();
}
try {
List> list = (List>)
t.getTransferData(DataFlavor.javaFileListFlavor);
if (list.size() > 0) {
File file = (File) list.get(0);
switch (fileSelectionMode) {
case JFileChooser.FILES_AND_DIRECTORIES:
break;
case JFileChooser.FILES_ONLY:
if (file.isDirectory()) {
return false;
}
break;
case JFileChooser.DIRECTORIES_ONLY:
if (!file.isDirectory()) {
return false;
}
break;
}
if (fileFilter != null && !fileFilter.accept(file)) {
return false;
}
c.setText(file.getPath());
}
imported = true;
} catch (UnsupportedFlavorException ex) {
// ex.printStackTrace();
} catch (IOException ex) {
// ex.printStackTrace();
}
}
if (!imported) {
DataFlavor importFlavor = getImportFlavor(t.getTransferDataFlavors(), c);
if (importFlavor != null) {
InputContext ic = c.getInputContext();
if (ic != null) {
ic.endComposition();
}
try {
// String text = (String) t.getTransferData(DataFlavor.stringFlavor);
Reader r = importFlavor.getReaderForText(t);
boolean useRead = false;
handleReaderImport(r, c, useRead);
imported = true;
} catch (UnsupportedFlavorException ex) {
// ex.printStackTrace();
} catch (BadLocationException ex) {
// ex.printStackTrace();
} catch (IOException ex) {
// ex.printStackTrace();
}
}
}
return imported;
}
@Override
protected Transferable createTransferable(JComponent comp) {
CompositeTransferable t;
JTextComponent c = (JTextComponent) comp;
shouldRemove = true;
p0 = c.getSelectionStart();
p1 = c.getSelectionEnd();
if (p0 != p1) {
t = new CompositeTransferable();
String text = c.getSelectedText();
//LinkedList fileList = new LinkedList();
//fileList.add(new File(text));
//t.add(new JVMLocalObjectTransferable(DataFlavor.javaFileListFlavor, fileList));
t.add(new StringTransferable(text));
t.add(new PlainTextTransferable(text));
} else {
t = null;
}
return t;
}
@Override
public boolean canImport(JComponent comp, DataFlavor[] transferFlavors) {
JTextComponent c = (JTextComponent) comp;
if (!(c.isEditable() && c.isEnabled())) {
return false;
}
for (DataFlavor flavor : transferFlavors) {
if (flavor.isFlavorJavaFileListType()
|| flavor.isFlavorTextType()) {
return true;
}
}
return false;
}
/**
* Try to find a flavor that can be used to import a Transferable.
* The set of usable flavors are tried in the following order:
*
NONE
.
* @param action The actual action that was performed.
*/
@Override
protected void exportDone(JComponent comp, Transferable data, int action) {
JTextComponent c = (JTextComponent) comp;
// only remove the text if shouldRemove has not been set to
// false by importData and only if the action is a move
if (shouldRemove && action == MOVE) {
try {
Document doc = c.getDocument();
doc.remove(p0, p1 - p0);
} catch (BadLocationException e) {
}
}
exportComp = null;
}
/**
* @return the fileFilter
*/
public FileFilter getFileFilter() {
return fileFilter;
}
/**
* @param fileFilter the fileFilter to set
*/
public void setFileFilter(FileFilter fileFilter) {
this.fileFilter = fileFilter;
}
}