package gui.tree;
import javax.swing.*;
import javax.swing.tree.TreePath;
import java.awt.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.*;
import java.net.MalformedURLException;
import java.util.*;
import java.util.List;
public class FileTreeDropTarget implements DropTargetListener,
PropertyChangeListener {
public FileTreeDropTarget(FileTree tree) {
this.tree = tree;
tree.addPropertyChangeListener(this);
dropTarget = new DropTarget(tree,
DnDConstants.ACTION_COPY_OR_MOVE,
this,
tree.isEnabled(), null);
}
public void dragEnter(DropTargetDragEvent dtde) {
DnDUtils.debugPrintln("dragEnter, drop action = "
+ DnDUtils.showActions(dtde.getDropAction()));
saveTreeSelection();
checkTransferType(dtde);
boolean acceptedDrag = acceptOrRejectDrag(dtde);
dragUnderFeedback(dtde, acceptedDrag);
}
public void dragExit(DropTargetEvent dte) {
DnDUtils.debugPrintln("DropTarget dragExit");
dragUnderFeedback(null, false);
restoreTreeSelection();
}
public void dragOver(DropTargetDragEvent dtde) {
DnDUtils.debugPrintln("DropTarget dragOver, drop action = "
+ DnDUtils.showActions(dtde.getDropAction()));
boolean acceptedDrag = acceptOrRejectDrag(dtde);
dragUnderFeedback(dtde, acceptedDrag);
}
public void dropActionChanged(DropTargetDragEvent dtde) {
DnDUtils.debugPrintln("DropTarget dropActionChanged, drop action = "
+ DnDUtils.showActions(dtde.getDropAction()));
boolean acceptedDrag = acceptOrRejectDrag(dtde);
dragUnderFeedback(dtde, acceptedDrag);
}
public void drop(DropTargetDropEvent dtde) {
DnDUtils.debugPrintln("DropTarget drop, drop action = "
+ DnDUtils.showActions(dtde.getDropAction()));
if ((dtde.getDropAction() & DnDConstants.ACTION_COPY_OR_MOVE) != 0) {
dtde.acceptDrop(dtde.getDropAction());
Transferable transferable = dtde.getTransferable();
boolean dropSucceeded = false;
try {
tree.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
saveTreeSelection();
dropSucceeded = dropFile(dtde.getDropAction(),
transferable, dtde.getLocation());
DnDUtils.debugPrintln("Drop completed, success: "
+ dropSucceeded);
} catch (Exception e) {
DnDUtils.debugPrintln("Exception while handling drop " + e);
} finally {
tree.setCursor(Cursor.getDefaultCursor());
restoreTreeSelection();
dtde.dropComplete(dropSucceeded);
}
} else {
DnDUtils.debugPrintln("Drop target rejected drop");
dtde.dropComplete(false);
}
}
public void propertyChange(PropertyChangeEvent evt) {
String propertyName = evt.getPropertyName();
if (propertyName.equals("enabled")) {
dropTarget.setActive(tree.isEnabled());
}
}
protected boolean acceptOrRejectDrag(DropTargetDragEvent dtde) {
int dropAction = dtde.getDropAction();
int sourceActions = dtde.getSourceActions();
boolean acceptedDrag = false;
DnDUtils.debugPrintln("\tSource actions are " +
DnDUtils.showActions(sourceActions) +
", drop action is " +
DnDUtils.showActions(dropAction));
Point location = dtde.getLocation();
boolean acceptableDropLocation = isAcceptableDropLocation(location);
if (!acceptableType ||
(sourceActions & DnDConstants.ACTION_COPY_OR_MOVE) == 0) {
DnDUtils.debugPrintln("Drop target rejecting drag");
dtde.rejectDrag();
} else if (!tree.isEditable()) {
DnDUtils.debugPrintln("Drop target rejecting drag");
dtde.rejectDrag();
} else if (!acceptableDropLocation) {
DnDUtils.debugPrintln("Drop target rejecting drag");
dtde.rejectDrag();
} else if ((dropAction & DnDConstants.ACTION_COPY_OR_MOVE) == 0) {
DnDUtils.debugPrintln("Drop target offering COPY");
dtde.acceptDrag(DnDConstants.ACTION_COPY);
acceptedDrag = true;
} else {
DnDUtils.debugPrintln("Drop target accepting drag");
dtde.acceptDrag(dropAction);
acceptedDrag = true;
}
return acceptedDrag;
}
protected void dragUnderFeedback(DropTargetDragEvent dtde,
boolean acceptedDrag) {
if (dtde != null && acceptedDrag) {
Point location = dtde.getLocation();
if (isAcceptableDropLocation(location)) {
tree.setSelectionRow(
tree.getRowForLocation(location.x, location.y));
} else {
tree.clearSelection();
}
} else {
tree.clearSelection();
}
}
protected void checkTransferType(DropTargetDragEvent dtde) {
acceptableType = false;
if (dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
acceptableType = true;
}
DnDUtils.debugPrintln("Data type acceptable - " + acceptableType);
}
protected boolean dropFile(int action,
Transferable transferable, Point location)
throws IOException, UnsupportedFlavorException,
MalformedURLException {
List files = (List) transferable.getTransferData(
DataFlavor.javaFileListFlavor);
TreePath treePath = tree.getPathForLocation(
location.x, location.y);
File targetDirectory = findTargetDirectory(location);
if (treePath == null || targetDirectory == null) {
return false;
}
FileTree.DefaultMutableFileTreeNode node =
(FileTree.DefaultMutableFileTreeNode) treePath.getLastPathComponent();
tree.setSelectionPath(treePath);
File[] fileList = getFileList(files);
copyOverExistingFiles = false;
for (int i = 0; i < fileList.length; i++) {
File f = fileList[i];
if (f.isDirectory()) {
transferDirectory(action, f, targetDirectory, node);
} else {
try {
transferFile(action, fileList[i],
targetDirectory, node);
} catch (IllegalStateException e) {
return false;
}
}
}
return true;
}
protected File findTargetDirectory(Point location) {
TreePath treePath = tree.getPathForLocation(location.x, location.y);
if (treePath != null) {
FileTree.DefaultMutableFileTreeNode node =
(FileTree.DefaultMutableFileTreeNode) treePath.getLastPathComponent();
if (node.isDir()) {
try {
File f = new File(node.getFullName());
if (f.canWrite()) {
return f;
}
} catch (Exception e) {
}
}
}
return null;
}
protected boolean isAcceptableDropLocation(Point location) {
return findTargetDirectory(location) != null;
}
protected void saveTreeSelection() {
selections = tree.getSelectionPaths();
leadSelection = tree.getLeadSelectionPath();
tree.clearSelection();
}
protected void restoreTreeSelection() {
tree.setSelectionPaths(selections);
if (leadSelection != null) {
tree.removeSelectionPath(leadSelection);
tree.addSelectionPath(leadSelection);
}
}
protected File[] getFileList(List files) {
int size = files.size();
File[] f = new File[size];
Iterator iter = files.iterator();
int count = 0;
while (iter.hasNext()) {
f[count++] = (File) iter.next();
}
Arrays.sort(f, new Comparator() {
public boolean equals(Object o1) {
return false;
}
public int compare(Object o1, Object o2) {
return ((File) o1).getAbsolutePath().compareTo(
((File) o2).getAbsolutePath());
}
});
Vector v = new Vector();
char separator = System.getProperty("file.separator").charAt(0);
outer:
for (int i = f.length - 1; i >= 0; i--) {
String secondPath = f[i].getAbsolutePath();
int secondLength = secondPath.length();
for (int j = i - 1; j >= 0; j--) {
String firstPath = f[j].getAbsolutePath();
int firstLength = firstPath.length();
if (secondPath.startsWith(firstPath)
&& firstLength != secondLength
&& secondPath.charAt(firstLength) == separator) {
continue outer;
}
}
v.add(f[i]);
}
f = new File[v.size()];
v.copyInto(f);
return f;
}
protected void transferFile(int action, File srcFile,
File targetDirectory,
FileTree.DefaultMutableFileTreeNode targetNode) {
DnDUtils.debugPrintln(
(action == DnDConstants.ACTION_COPY ? "Copy" : "Move") +
" file " + srcFile.getAbsolutePath() +
" to " + targetDirectory.getAbsolutePath());
String name = srcFile.getName();
File newFile = new File(targetDirectory, name);
if (newFile.exists()) {
if (newFile.equals(srcFile)) {
return;
}
if (copyOverExistingFiles == false) {
int res = JOptionPane.showOptionDialog(tree,
"A file called\n " + name +
"\nalready exists in the directory\n " +
targetDirectory.getAbsolutePath() +
"\nOverwrite it?",
"File Exists",
JOptionPane.DEFAULT_OPTION,
JOptionPane.QUESTION_MESSAGE,
null, new String[]{
"Yes", "Yes to All", "No", "Cancel"
},
"No");
switch (res) {
case 1: copyOverExistingFiles = true;
case 0: break;
case 2: return;
default: throw new IllegalStateException("Cancelled");
}
}
} else {
try {
newFile.createNewFile();
} catch (IOException e) {
JOptionPane.showMessageDialog(tree,
"Failed to create new file\n " +
newFile.getAbsolutePath(),
"File Creation Failed",
JOptionPane.ERROR_MESSAGE);
return;
}
}
BufferedInputStream is = null;
BufferedOutputStream os = null;
try {
is = new BufferedInputStream(
new FileInputStream(srcFile));
os = new BufferedOutputStream(
new FileOutputStream(newFile));
int size = 4096;
byte[] buffer = new byte[size];
int len;
while ((len = is.read(buffer, 0, size)) > 0) {
os.write(buffer, 0, len);
}
} catch (IOException e) {
JOptionPane.showMessageDialog(tree,
"Failed to copy file\n " +
name + "\nto directory\n " +
targetDirectory.getAbsolutePath(),
"File Copy Failed",
JOptionPane.ERROR_MESSAGE);
return;
} finally {
try {
if (is != null) {
is.close();
}
if (os != null) {
os.close();
}
} catch (IOException e) {
}
}
if (action == DnDConstants.ACTION_MOVE &&
System.getProperty("DnDExamples.allowRemove") != null) {
srcFile.delete();
}
if (targetNode != null) {
tree.addNode(targetNode, name);
}
}
protected void transferDirectory(int action, File srcDir,
File targetDirectory,
FileTree.DefaultMutableFileTreeNode targetNode) {
DnDUtils.debugPrintln(
(action == DnDConstants.ACTION_COPY ? "Copy" : "Move") +
" directory " + srcDir.getAbsolutePath() +
" to " + targetDirectory.getAbsolutePath());
File parentDir = targetDirectory;
while (parentDir != null) {
if (parentDir.equals(srcDir)) {
DnDUtils.debugPrintln("-- SUPPRESSED");
return;
}
parentDir = parentDir.getParentFile();
}
String name = srcDir.getName();
File newDir = new File(targetDirectory, name);
if (newDir.exists()) {
if (newDir.equals(srcDir)) {
return;
}
} else {
if (newDir.mkdir() == false) {
JOptionPane.showMessageDialog(tree,
"Failed to create target directory\n " +
newDir.getAbsolutePath(),
"Directory creation Failed",
JOptionPane.ERROR_MESSAGE);
return;
}
}
if (targetNode != null) {
targetNode = tree.addNode(targetNode, name);
}
File[] files = srcDir.listFiles();
for (int i = 0; i < files.length; i++) {
File f = files[i];
if (f.isFile()) {
transferFile(action, f, newDir, targetNode);
} else if (f.isDirectory()) {
transferDirectory(action, f, newDir, targetNode);
}
}
if (action == DnDConstants.ACTION_MOVE &&
System.getProperty("DnDExamples.allowRemove") != null) {
srcDir.delete();
}
}
public static void main(String[] args) {
final JFrame f = new JFrame("FileTree Drop Target Example");
try {
final FileTree tree = new FileTree(args[0]);
FileTreeDropTarget target = new FileTreeDropTarget(tree);
tree.setEditable(true);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent evt) {
System.exit(0);
}
});
JPanel panel = new JPanel();
final JCheckBox editable = new JCheckBox("Editable");
editable.setSelected(true);
panel.add(editable);
editable.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
tree.setEditable(editable.isSelected());
}
});
final JCheckBox enabled = new JCheckBox("Enabled");
enabled.setSelected(true);
panel.add(enabled);
enabled.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
tree.setEnabled(enabled.isSelected());
}
});
f.getContentPane().add(new JScrollPane(tree), BorderLayout.CENTER);
f.getContentPane().add(panel, BorderLayout.SOUTH);
f.setSize(500, 400);
f.setVisible(true);
} catch (Exception e) {
System.out.println("Failed to build GUI: " + e);
}
}
protected FileTree tree;
protected DropTarget dropTarget;
protected boolean acceptableType; TreePath[] selections; TreePath leadSelection; boolean copyOverExistingFiles;
}