Drag Drop Tree Example
/*
Core SWING Advanced Programming
By Kim Topley
ISBN: 0 13 083292 8
Publisher: Prentice Hall
*/
import java.awt.BorderLayout;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.Autoscroll;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DragGestureEvent;
import java.awt.dnd.DragGestureListener;
import java.awt.dnd.DragSource;
import java.awt.dnd.DragSourceDragEvent;
import java.awt.dnd.DragSourceDropEvent;
import java.awt.dnd.DragSourceEvent;
import java.awt.dnd.DragSourceListener;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.dnd.DropTargetEvent;
import java.awt.dnd.DropTargetListener;
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.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeExpansionListener;
import javax.swing.plaf.basic.BasicTreeUI.TreeExpansionHandler;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
public class DragDropTreeExample {
public static void main(String[] args) {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch (Exception evt) {}
final JFrame f = new JFrame("FileTree Drop and Drop Example");
try {
final FileTree tree = new FileTree("D:\\");
// Add a drop target to the FileTree
FileTreeDropTarget target = new FileTreeDropTarget(tree);
// Add a drag source to the FileTree
FileTreeDragSource source = new FileTreeDragSource(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);
}
}
}
class FileTree extends JTree implements Autoscroll {
public static final Insets defaultScrollInsets = new Insets(8, 8, 8, 8);
protected Insets scrollInsets = defaultScrollInsets;
public FileTree(String path) throws FileNotFoundException,
SecurityException {
super((TreeModel) null); // Create the JTree itself
// Use horizontal and vertical lines
putClientProperty("JTree.lineStyle", "Angled");
// Create the first node
FileTreeNode rootNode = new FileTreeNode(null, path);
// Populate the root node with its subdirectories
boolean addedNodes = rootNode.populateDirectories(true);
setModel(new DefaultTreeModel(rootNode));
// Listen for Tree Selection Events
addTreeExpansionListener(new TreeExpansionHandler());
}
// Returns the full pathname for a path, or null if not a known path
public String getPathName(TreePath path) {
Object o = path.getLastPathComponent();
if (o instanceof FileTreeNode) {
return ((FileTreeNode) o).fullName;
}
return null;
}
// Adds a new node to the tree after construction.
// Returns the inserted node, or null if the parent
// directory has not been expanded.
public FileTreeNode addNode(FileTreeNode parent, String name) {
int index = parent.addNode(name);
if (index != -1) {
((DefaultTreeModel) getModel()).nodesWereInserted(parent,
new int[] { index });
return (FileTreeNode) parent.getChildAt(index);
}
// No node was created
return null;
}
// Autoscrolling support
public void setScrollInsets(Insets insets) {
this.scrollInsets = insets;
}
public Insets getScrollInsets() {
return scrollInsets;
}
// Implementation of Autoscroll interface
public Insets getAutoscrollInsets() {
Rectangle r = getVisibleRect();
Dimension size = getSize();
Insets i = new Insets(r.y + scrollInsets.top, r.x + scrollInsets.left,
size.height - r.y - r.height + scrollInsets.bottom, size.width
- r.x - r.width + scrollInsets.right);
return i;
}
public void autoscroll(Point location) {
JScrollPane scroller = (JScrollPane) SwingUtilities.getAncestorOfClass(
JScrollPane.class, this);
if (scroller != null) {
JScrollBar hBar = scroller.getHorizontalScrollBar();
JScrollBar vBar = scroller.getVerticalScrollBar();
Rectangle r = getVisibleRect();
if (location.x <= r.x + scrollInsets.left) {
// Need to scroll left
hBar.setValue(hBar.getValue() - hBar.getUnitIncrement(-1));
}
if (location.y <= r.y + scrollInsets.top) {
// Need to scroll up
vBar.setValue(vBar.getValue() - vBar.getUnitIncrement(-1));
}
if (location.x >= r.x + r.width - scrollInsets.right) {
// Need to scroll right
hBar.setValue(hBar.getValue() + hBar.getUnitIncrement(1));
}
if (location.y >= r.y + r.height - scrollInsets.bottom) {
// Need to scroll down
vBar.setValue(vBar.getValue() + vBar.getUnitIncrement(1));
}
}
}
// Inner class that represents a node in this file system tree
public static class FileTreeNode extends DefaultMutableTreeNode {
public FileTreeNode(String parent, String name)
throws SecurityException, FileNotFoundException {
this.name = name;
// See if this node exists and whether it is a directory
fullName = parent == null ? name : parent + File.separator + name;
File f = new File(fullName);
if (f.exists() == false) {
throw new FileNotFoundException("File " + fullName
+ " does not exist");
}
isDir = f.isDirectory();
// Hack for Windows which doesn't consider a drive to be a
// directory!
if (isDir == false && f.isFile() == false) {
isDir = true;
}
}
// Override isLeaf to check whether this is a directory
public boolean isLeaf() {
return !isDir;
}
// Override getAllowsChildren to check whether this is a directory
public boolean getAllowsChildren() {
return isDir;
}
// Return whether this is a directory
public boolean isDir() {
return isDir;
}
// Get full path
public String getFullName() {
return fullName;
}
// For display purposes, we return our own name
public String toString() {
return name;
}
// If we are a directory, scan our contents and populate
// with children. In addition, populate those children
// if the "descend" flag is true. We only descend once,
// to avoid recursing the whole subtree.
// Returns true if some nodes were added
boolean populateDirectories(boolean descend) {
boolean addedNodes = false;
// Do this only once
if (populated == false) {
File f;
try {
f = new File(fullName);
} catch (SecurityException e) {
populated = true;
return false;
}
if (interim == true) {
// We have had a quick look here before:
// remove the dummy node that we added last time
removeAllChildren();
interim = false;
}
String[] names = f.list(); // Get list of contents
// Process the contents
ArrayList list = new ArrayList();
for (int i = 0; i < names.length; i++) {
String name = names[i];
File d = new File(fullName, name);
try {
FileTreeNode node = new FileTreeNode(fullName, name);
list.add(node);
if (descend && d.isDirectory()) {
node.populateDirectories(false);
}
addedNodes = true;
if (descend == false) {
// Only add one node if not descending
break;
}
} catch (Throwable t) {
// Ignore phantoms or access problems
}
}
if (addedNodes == true) {
// Now sort the list of contained files and directories
Object[] nodes = list.toArray();
Arrays.sort(nodes, new Comparator() {
public boolean equals(Object o) {
return false;
}
public int compare(Object o1, Object o2) {
FileTreeNode node1 = (FileTreeNode) o1;
FileTreeNode node2 = (FileTreeNode) o2;
// Directories come first
if (node1.isDir != node2.isDir) {
return node1.isDir ? -1 : +1;
}
// Both directories or both files -
// compare based on pathname
return node1.fullName.compareTo(node2.fullName);
}
});
// Add sorted items as children of this node
for (int j = 0; j < nodes.length; j++) {
this.add((FileTreeNode) nodes[j]);
}
}
// If we were scanning to get all subdirectories,
// or if we found no content, there is no
// reason to look at this directory again, so
// set populated to true. Otherwise, we set interim
// so that we look again in the future if we need to
if (descend == true || addedNodes == false) {
populated = true;
} else {
// Just set interim state
interim = true;
}
}
return addedNodes;
}
// Adding a new file or directory after
// constructing the FileTree. Returns
// the index of the inserted node.
public int addNode(String name) {
// If not populated yet, do nothing
if (populated == true) {
// Do not add a new node if
// the required node is already there
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
FileTreeNode node = (FileTreeNode) getChildAt(i);
if (node.name.equals(name)) {
// Already exists - ensure
// we repopulate
if (node.isDir()) {
node.interim = true;
node.populated = false;
}
return -1;
}
}
// Add a new node
try {
FileTreeNode node = new FileTreeNode(fullName, name);
add(node);
return childCount;
} catch (Exception e) {
}
}
return -1;
}
protected String name; // Name of this component
protected String fullName; // Full pathname
protected boolean populated;// true if we have been populated
protected boolean interim; // true if we are in interim state
protected boolean isDir; // true if this is a directory
}
// Inner class that handles Tree Expansion Events
protected class TreeExpansionHandler implements TreeExpansionListener {
public void treeExpanded(TreeExpansionEvent evt) {
TreePath path = evt.getPath(); // The expanded path
JTree tree = (JTree) evt.getSource(); // The tree
// Get the last component of the path and
// arrange to have it fully populated.
FileTreeNode node = (FileTreeNode) path.getLastPathComponent();
if (node.populateDirectories(true)) {
((DefaultTreeModel) tree.getModel()).nodeStructureChanged(node);
}
}
public void treeCollapsed(TreeExpansionEvent evt) {
// Nothing to do
}
}
}
class FileTreeDropTarget implements DropTargetListener, PropertyChangeListener {
public FileTreeDropTarget(FileTree tree) {
this.tree = tree;
// Listen for changes in the enabled property
tree.addPropertyChangeListener(this);
// Create the DropTarget and register
// it with the FileTree.
dropTarget = new DropTarget(tree, DnDConstants.ACTION_COPY_OR_MOVE,
this, tree.isEnabled(), null);
}
// Implementation of the DropTargetListener interface
public void dragEnter(DropTargetDragEvent dtde) {
DnDUtils.debugPrintln("dragEnter, drop action = "
+ DnDUtils.showActions(dtde.getDropAction()));
// Save the list of selected items
saveTreeSelection();
// Get the type of object being transferred and determine
// whether it is appropriate.
checkTransferType(dtde);
// Accept or reject the drag.
boolean acceptedDrag = acceptOrRejectDrag(dtde);
// Do drag-under feedback
dragUnderFeedback(dtde, acceptedDrag);
}
public void dragExit(DropTargetEvent dte) {
DnDUtils.debugPrintln("DropTarget dragExit");
// Do drag-under feedback
dragUnderFeedback(null, false);
// Restore the original selections
restoreTreeSelection();
}
public void dragOver(DropTargetDragEvent dtde) {
DnDUtils.debugPrintln("DropTarget dragOver, drop action = "
+ DnDUtils.showActions(dtde.getDropAction()));
// Accept or reject the drag
boolean acceptedDrag = acceptOrRejectDrag(dtde);
// Do drag-under feedback
dragUnderFeedback(dtde, acceptedDrag);
}
public void dropActionChanged(DropTargetDragEvent dtde) {
DnDUtils.debugPrintln("DropTarget dropActionChanged, drop action = "
+ DnDUtils.showActions(dtde.getDropAction()));
// Accept or reject the drag
boolean acceptedDrag = acceptOrRejectDrag(dtde);
// Do drag-under feedback
dragUnderFeedback(dtde, acceptedDrag);
}
public void drop(DropTargetDropEvent dtde) {
DnDUtils.debugPrintln("DropTarget drop, drop action = "
+ DnDUtils.showActions(dtde.getDropAction()));
// Check the drop action
if ((dtde.getDropAction() & DnDConstants.ACTION_COPY_OR_MOVE) != 0) {
// Accept the drop and get the transfer data
dtde.acceptDrop(dtde.getDropAction());
Transferable transferable = dtde.getTransferable();
boolean dropSucceeded = false;
try {
tree.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
// Save the user's selections
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());
// Restore the user's selections
restoreTreeSelection();
dtde.dropComplete(dropSucceeded);
}
} else {
DnDUtils.debugPrintln("Drop target rejected drop");
dtde.dropComplete(false);
}
}
// PropertyChangeListener interface
public void propertyChange(PropertyChangeEvent evt) {
String propertyName = evt.getPropertyName();
if (propertyName.equals("enabled")) {
// Enable the drop target if the FileTree is enabled
// and vice versa.
dropTarget.setActive(tree.isEnabled());
}
}
// Internal methods start here
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);
// Reject if the object being transferred
// or the operations available are not acceptable.
if (!acceptableType
|| (sourceActions & DnDConstants.ACTION_COPY_OR_MOVE) == 0) {
DnDUtils.debugPrintln("Drop target rejecting drag");
dtde.rejectDrag();
} else if (!tree.isEditable()) {
// Can't drag to a read-only FileTree
DnDUtils.debugPrintln("Drop target rejecting drag");
dtde.rejectDrag();
} else if (!acceptableDropLocation) {
// Can only drag to writable directory
DnDUtils.debugPrintln("Drop target rejecting drag");
dtde.rejectDrag();
} else if ((dropAction & DnDConstants.ACTION_COPY_OR_MOVE) == 0) {
// Not offering copy or move - suggest a copy
DnDUtils.debugPrintln("Drop target offering COPY");
dtde.acceptDrag(DnDConstants.ACTION_COPY);
acceptedDrag = true;
} else {
// Offering an acceptable operation: accept
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) {
// Accept a list of files
acceptableType = false;
if (dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
acceptableType = true;
}
DnDUtils.debugPrintln("Data type acceptable - " + acceptableType);
}
// This method handles a drop for a list of files
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.FileTreeNode node = (FileTree.FileTreeNode) treePath
.getLastPathComponent();
// Highlight the drop location while we perform the drop
tree.setSelectionPath(treePath);
// Get File objects for all files being
// transferred, eliminating duplicates.
File[] fileList = getFileList(files);
// Don't overwrite files by default
copyOverExistingFiles = false;
// Copy or move each source object to the target
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) {
// Cancelled by user
return false;
}
}
}
return true;
}
protected File findTargetDirectory(Point location) {
TreePath treePath = tree.getPathForLocation(location.x, location.y);
if (treePath != null) {
FileTree.FileTreeNode node = (FileTree.FileTreeNode) treePath
.getLastPathComponent();
// Only allow a drop on a writable directory
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);
// Restore the lead selection
if (leadSelection != null) {
tree.removeSelectionPath(leadSelection);
tree.addSelectionPath(leadSelection);
}
}
// Get the list of files being transferred and
// remove any duplicates. For example, if the
// list contains /a/b/c and /a/b/c/d, the
// second entry is removed.
protected File[] getFileList(List files) {
int size = files.size();
// Get the files into an array for sorting
File[] f = new File[size];
Iterator iter = files.iterator();
int count = 0;
while (iter.hasNext()) {
f[count++] = (File) iter.next();
}
// Sort the files into alphabetical order
// based on pathnames.
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());
}
});
// Remove duplicates, retaining the results in a Vector
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]);
}
// Copy the retained files into an array
f = new File[v.size()];
v.copyInto(f);
return f;
}
// Copy or move a file
protected void transferFile(int action, File srcFile, File targetDirectory,
FileTree.FileTreeNode targetNode) {
DnDUtils.debugPrintln((action == DnDConstants.ACTION_COPY ? "Copy"
: "Move")
+ " file "
+ srcFile.getAbsolutePath()
+ " to "
+ targetDirectory.getAbsolutePath());
// Create a File entry for the target
String name = srcFile.getName();
File newFile = new File(targetDirectory, name);
if (newFile.exists()) {
// Already exists - is it the same file?
if (newFile.equals(srcFile)) {
// Exactly the same file - ignore
return;
}
// File of this name exists in this directory
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: // Yes to all
copyOverExistingFiles = true;
case 0: // Yes
break;
case 2: // No
return;
default: // Cancel
throw new IllegalStateException("Cancelled");
}
}
} else {
// New file - create it
try {
newFile.createNewFile();
} catch (IOException e) {
JOptionPane.showMessageDialog(tree,
"Failed to create new file\n "
+ newFile.getAbsolutePath(),
"File Creation Failed", JOptionPane.ERROR_MESSAGE);
return;
}
}
// Copy the data and close file.
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) {
}
}
// Remove the source if this is a move operation.
if (action == DnDConstants.ACTION_MOVE
&& System.getProperty("DnDExamples.allowRemove") != null) {
srcFile.delete();
}
// Update the tree display
if (targetNode != null) {
tree.addNode(targetNode, name);
}
}
protected void transferDirectory(int action, File srcDir,
File targetDirectory, FileTree.FileTreeNode targetNode) {
DnDUtils.debugPrintln((action == DnDConstants.ACTION_COPY ? "Copy"
: "Move")
+ " directory "
+ srcDir.getAbsolutePath()
+ " to "
+ targetDirectory.getAbsolutePath());
// Do not copy a directory into itself or
// a subdirectory of itself.
File parentDir = targetDirectory;
while (parentDir != null) {
if (parentDir.equals(srcDir)) {
DnDUtils.debugPrintln("-- SUPPRESSED");
return;
}
parentDir = parentDir.getParentFile();
}
// Copy the directory itself, then its contents
// Create a File entry for the target
String name = srcDir.getName();
File newDir = new File(targetDirectory, name);
if (newDir.exists()) {
// Already exists - is it the same directory?
if (newDir.equals(srcDir)) {
// Exactly the same file - ignore
return;
}
} else {
// Directory does not exist - create it
if (newDir.mkdir() == false) {
// Failed to create - abandon this directory
JOptionPane.showMessageDialog(tree,
"Failed to create target directory\n "
+ newDir.getAbsolutePath(),
"Directory creation Failed", JOptionPane.ERROR_MESSAGE);
return;
}
}
// Add a node for the new directory
if (targetNode != null) {
targetNode = tree.addNode(targetNode, name);
}
// Now copy the directory content.
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);
}
}
// Remove the source directory after moving
if (action == DnDConstants.ACTION_MOVE
&& System.getProperty("DnDExamples.allowRemove") != null) {
srcDir.delete();
}
}
public static void main(String[] args) {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch (Exception evt) {}
final JFrame f = new JFrame("FileTree Drop Target Example");
try {
final FileTree tree = new FileTree("D:\\");
// Add a drop target to the FileTree
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; // Indicates whether data is acceptable
TreePath[] selections; // Initially selected rows
TreePath leadSelection; // Initial lead selection
boolean copyOverExistingFiles;
}
class DnDUtils {
public static String showActions(int action) {
String actions = "";
if ((action & (DnDConstants.ACTION_LINK | DnDConstants.ACTION_COPY_OR_MOVE)) == 0) {
return "None";
}
if ((action & DnDConstants.ACTION_COPY) != 0) {
actions += "Copy ";
}
if ((action & DnDConstants.ACTION_MOVE) != 0) {
actions += "Move ";
}
if ((action & DnDConstants.ACTION_LINK) != 0) {
actions += "Link";
}
return actions;
}
public static boolean isDebugEnabled() {
return debugEnabled;
}
public static void debugPrintln(String s) {
if (debugEnabled) {
System.out.println(s);
}
}
private static boolean debugEnabled = (System
.getProperty("DnDExamples.debug") != null);
}
class FileTreeDragSource implements DragGestureListener, DragSourceListener {
public FileTreeDragSource(FileTree tree) {
this.tree = tree;
// Use the default DragSource
DragSource dragSource = DragSource.getDefaultDragSource();
// Create a DragGestureRecognizer and
// register as the listener
dragSource.createDefaultDragGestureRecognizer(tree,
DnDConstants.ACTION_COPY_OR_MOVE, this);
}
// Implementation of DragGestureListener interface.
public void dragGestureRecognized(DragGestureEvent dge) {
// Get the mouse location and convert it to
// a location within the tree.
Point location = dge.getDragOrigin();
TreePath dragPath = tree.getPathForLocation(location.x, location.y);
if (dragPath != null && tree.isPathSelected(dragPath)) {
// Get the list of selected files and create a Transferable
// The list of files and the is saved for use when
// the drop completes.
paths = tree.getSelectionPaths();
if (paths != null && paths.length > 0) {
dragFiles = new File[paths.length];
for (int i = 0; i < paths.length; i++) {
String pathName = tree.getPathName(paths[i]);
dragFiles[i] = new File(pathName);
}
Transferable transferable = new FileListTransferable(dragFiles);
dge.startDrag(null, transferable, this);
}
}
}
// Implementation of DragSourceListener interface
public void dragEnter(DragSourceDragEvent dsde) {
DnDUtils.debugPrintln("Drag Source: dragEnter, drop action = "
+ DnDUtils.showActions(dsde.getDropAction()));
}
public void dragOver(DragSourceDragEvent dsde) {
DnDUtils.debugPrintln("Drag Source: dragOver, drop action = "
+ DnDUtils.showActions(dsde.getDropAction()));
}
public void dragExit(DragSourceEvent dse) {
DnDUtils.debugPrintln("Drag Source: dragExit");
}
public void dropActionChanged(DragSourceDragEvent dsde) {
DnDUtils.debugPrintln("Drag Source: dropActionChanged, drop action = "
+ DnDUtils.showActions(dsde.getDropAction()));
}
public void dragDropEnd(DragSourceDropEvent dsde) {
DnDUtils.debugPrintln("Drag Source: drop completed, drop action = "
+ DnDUtils.showActions(dsde.getDropAction()) + ", success: "
+ dsde.getDropSuccess());
// If the drop action was ACTION_MOVE,
// the tree might need to be updated.
if (dsde.getDropAction() == DnDConstants.ACTION_MOVE) {
final File[] draggedFiles = dragFiles;
final TreePath[] draggedPaths = paths;
Timer tm = new Timer(200, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
// Check whether each of the dragged files exists.
// If it does not, we need to remove the node
// that represents it from the tree.
for (int i = 0; i < draggedFiles.length; i++) {
if (draggedFiles[i].exists() == false) {
// Remove this node
DefaultMutableTreeNode node = (DefaultMutableTreeNode) draggedPaths[i]
.getLastPathComponent();
((DefaultTreeModel) tree.getModel())
.removeNodeFromParent(node);
}
}
}
});
tm.setRepeats(false);
tm.start();
}
}
public static void main(String[] args) {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch (Exception evt) {}
JFrame f = new JFrame("Draggable File Tree");
try {
FileTree tree = new FileTree("D:\\");
f.getContentPane().add(new JScrollPane(tree));
// Attach the drag source
FileTreeDragSource dragSource = new FileTreeDragSource(tree);
} catch (Exception e) {
}
f.pack();
f.setVisible(true);
}
protected FileTree tree; // The associated tree
protected File[] dragFiles; // Dragged files
protected TreePath[] paths; // Dragged paths
}
class FileListTransferable implements Transferable {
public FileListTransferable(File[] files) {
fileList = new ArrayList();
for (int i = 0; i < files.length; i++) {
fileList.add(files[i]);
}
}
// Implementation of the Transferable interface
public DataFlavor[] getTransferDataFlavors() {
return new DataFlavor[] { DataFlavor.javaFileListFlavor };
}
public boolean isDataFlavorSupported(DataFlavor fl) {
return fl.equals(DataFlavor.javaFileListFlavor);
}
public Object getTransferData(DataFlavor fl) {
if (!isDataFlavorSupported(fl)) {
return null;
}
return fileList;
}
List fileList; // The list of files
}
Related examples in the same category