/*
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.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.UIManager;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeExpansionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
public 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 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 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);
}
|