package com.limegroup.gnutella.gui.library;
import java.awt.Color;
import java.awt.Component;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.Icon;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JTree;
import javax.swing.ToolTipManager;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.limegroup.gnutella.FileDesc;
import com.limegroup.gnutella.FileManagerEvent;
import com.limegroup.gnutella.MediaType;
import com.limegroup.gnutella.RouterService;
import com.limegroup.gnutella.gui.GUIMediator;
import com.limegroup.gnutella.gui.actions.ShareFileSpeciallyAction;
import com.limegroup.gnutella.gui.actions.ShareNewFolderAction;
import com.limegroup.gnutella.gui.options.ConfigureOptionsAction;
import com.limegroup.gnutella.gui.playlist.PlaylistMediator;
import com.limegroup.gnutella.gui.search.NamedMediaType;
import com.limegroup.gnutella.gui.tables.DefaultMouseListener;
import com.limegroup.gnutella.gui.tables.DragManager;
import com.limegroup.gnutella.gui.tables.FileTransfer;
import com.limegroup.gnutella.gui.tables.MouseObserver;
import com.limegroup.gnutella.gui.themes.ThemeFileHandler;
import com.limegroup.gnutella.settings.FileSetting;
import com.limegroup.gnutella.settings.QuestionsHandler;
import com.limegroup.gnutella.settings.SharingSettings;
import com.limegroup.gnutella.util.StringUtils;
/**
* This class forms a wrapper around the tree that controls navigation between
* shared folders. It constructs the tree and supplies access to it. It also
* controls tree directory selection, deletion, etc.
*/
// 2345678|012345678|012345678|012345678|012345678|012345678|012345678|012345678|
final class LibraryTree extends JTree implements MouseObserver {
private static final Log LOG = LogFactory.getLog(LibraryTree.class);
///////////////////////////////////////////////////////////////////////////
// Nodes
///////////////////////////////////////////////////////////////////////////
/**
* Constant for the root node of the tree.
*/
private final LibraryTreeNode ROOT_NODE =
new LibraryTreeNode(new RootNodeDirectoryHolder(""));
private RootSharedFilesDirectoryHolder rsfdh = new RootSharedFilesDirectoryHolder();
/** Constant for the tree model. */
private final DefaultTreeModel TREE_MODEL = new DefaultTreeModel(ROOT_NODE);
/** The saved files node. */
private LibraryTreeNode savedFilesNode;
private final SavedFilesDirectoryHolder sfdh = new SavedFilesDirectoryHolder(
SharingSettings.DIRECTORY_FOR_SAVING_FILES,
GUIMediator.getStringResource("LIBRARY_TREE_SAVED_DIRECTORY"));
/** The shared files node. It's an empty meta node. */
private LibraryTreeNode sharedFilesNode;
/** The incomplete node. */
private LibraryTreeNode incompleteFilesNode;
private final IncompleteDirectoryHolder idh = new IncompleteDirectoryHolder();
/** The individually shared files node. */
private LibraryTreeNode speciallySharedFilesNode;
private final SpeciallySharedFilesDirectoryHolder ssfdh = new SpeciallySharedFilesDirectoryHolder();
///////////////////////////////////////////////////////////////////////////
// Singleton Pattern
///////////////////////////////////////////////////////////////////////////
/**
* Singleton instance of this class.
*/
private static final LibraryTree INSTANCE = new LibraryTree();
/**
* @return the <tt>LibraryTree</tt> instance
*/
public static LibraryTree instance() { return INSTANCE; }
/**
* Constructs the tree and its primary listeners,visualization options,
* editors, etc.
*/
private LibraryTree() {
setModel(TREE_MODEL);
setRootVisible(false);
getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
setEditable(false);
setInvokesStopCellEditing(true);
setShowsRootHandles(true);
putClientProperty("JTree.lineStyle", "None");
setCellRenderer(new LibraryTreeCellRenderer());
ToolTipManager.sharedInstance().registerComponent(this);
makePopupMenu();
addMouseListener(new DefaultMouseListener(this));
// 1. add shared node
sharedFilesNode = new LibraryTreeNode(rsfdh);
addNode(ROOT_NODE, sharedFilesNode);
// -> add specially shared sub-node
speciallySharedFilesNode = new LibraryTreeNode(ssfdh);
// 2. add saved node
savedFilesNode = new LibraryTreeNode(sfdh);
addNode(ROOT_NODE, savedFilesNode);
// -> add media types under saved node
addPerMediaTypeDirectories();
// 3. add incomplete node
incompleteFilesNode = new LibraryTreeNode(idh);
addNode(ROOT_NODE, incompleteFilesNode);
updateTheme();
DragManager.install(this);
addTreeSelectionListener(new LibraryTreeSelectionListener());
}
/**
* Adds a child node to the parent making sure the event is propagated
* to the tree.
* @param parent
* @param child
* @param expand whether or not to expand the parent node so that the child
* is visible
*/
private void addNode(LibraryTreeNode parent, LibraryTreeNode child, boolean expand) {
// if parent already has child, expand (if necessary) and return
if (parent.getIndex(child) != -1) {
if (expand)
expandPath(new TreePath(parent.getPath()));
return;
}
// insert shared folders alphabetically (and before the individually shared folder)
int children = parent.getChildCount();
int insert = 0;
// If it wasn't a 'SharedFilesDirectoryHolder', don't even try to sort, 'cause we don't care.
if(!(child.getDirectoryHolder() instanceof SharedFilesDirectoryHolder)) {
insert = children;
} else {
for(; insert < children; insert++) {
File f = ((LibraryTreeNode)parent.getChildAt(insert)).getFile();
if(f == null || StringUtils.compareFullPrimary(f.getName(), child.getFile().getName()) >= 0)
break;
}
}
TREE_MODEL.insertNodeInto(child, parent, insert);
if (expand || (parent == sharedFilesNode && !isExpanded(new TreePath(sharedFilesNode.getPath()))))
expandPath(new TreePath(parent.getPath()));
}
private void addNode(LibraryTreeNode parent, LibraryTreeNode child) {
addNode(parent, child, false);
}
/**
* Removes the child node from the parent node. Does nothing if child not a child of parent.
*/
private void removeNode(LibraryTreeNode parent, LibraryTreeNode child) {
if (parent == null || child == null)
return;
if (parent.getIndex(child) == -1)
return;
TREE_MODEL.removeNodeFromParent(child);
}
private void addPerMediaTypeDirectories() {
for (Iterator i = NamedMediaType.getAllNamedMediaTypes().iterator(); i.hasNext(); ) {
NamedMediaType nm = (NamedMediaType)i.next();
if (nm.getMediaType().getMimeType().equals(MediaType.SCHEMA_ANY_TYPE))
continue;
FileSetting fs = SharingSettings.getFileSettingForMediaType(nm.getMediaType());
DirectoryHolder dh =
new MediaTypeSavedFilesDirectoryHolder(fs, nm.getName(), nm.getMediaType());
LibraryTreeNode node = new LibraryTreeNode(dh);
addNode(savedFilesNode, node, true);
}
}
// inherit doc comment
public void updateTheme() {
Color tableColor = ThemeFileHandler.TABLE_BACKGROUND_COLOR.getValue();
setBackground(tableColor);
setCellRenderer(new LibraryTreeCellRenderer());
}
/**
* Sets the initial selection to the Saved Files folder.
*/
public void setInitialSelection() {
TreePath tp = new TreePath(savedFilesNode.getPath());
setSelectionPath(tp);
}
/**
* Adds the visual representation of this folder to the library.
*
* @param dir
* the <tt>File</tt> instance denoting the abstract pathname of
* the new shared directory to add to the library.
*/
private void addSharedDirectory(File dir) {
SharedFilesDirectoryHolder dh = new SharedFilesDirectoryHolder(dir);
LibraryTreeNode current = new LibraryTreeNode(dh);
// See if this is the parent of any existing nodes. If so,
// redirect that node to be here.
int children = sharedFilesNode.getChildCount();
for(int i = children - 1; i >= 0; i--) {
LibraryTreeNode child = (LibraryTreeNode)sharedFilesNode.getChildAt(i);
File f = child.getFile();
if(f != null && dir.equals(f.getParentFile())) {
TREE_MODEL.removeNodeFromParent(child);
addNode(current, child);
}
}
// Add this into the correct position.
File parent = dir.getParentFile();
LibraryTreeNode parentNode = null;
if (parent != null) {
parentNode = getNodeForFolder(parent, sharedFilesNode);
}
if (parentNode == null)
parentNode = sharedFilesNode;
addNode(parentNode, current);
}
/**
* Handles events created by the FileManager. Adds or removes nodes from the
* tree as necessary.
*/
public void handleFileManagerEvent(final FileManagerEvent evt) {
switch(evt.getKind()) {
case FileManagerEvent.ADD:
// If this was an individually shared file, add that node.
if(ssfdh.accept(evt.getFileDescs()[0].getFile()))
addNode(sharedFilesNode, speciallySharedFilesNode, true);
break;
case FileManagerEvent.REMOVE:
// hide individually shared files node if no individually shared files exist
if (ssfdh.isEmpty()) {
// change selection to saved files
if (ssfdh == getSelectedDirectoryHolder())
setSelectionPath(new TreePath(savedFilesNode.getPath()));
removeNode(sharedFilesNode, speciallySharedFilesNode);
}
break;
case FileManagerEvent.ADD_FOLDER:
File[] files = evt.getFiles();
addSharedDirectory(files[0]);
break;
case FileManagerEvent.REMOVE_FOLDER:
File removed = evt.getFiles()[0];
removeFolder(removed);
break;
}
}
/**
* Removes the given folder from the list of shared folders.
*
* If there are any children of this node when it is removed, they
* are moved up to be children of the 'Shared Folder' node.
*
* This 100% relies on the fact that FileManager.removeFolder sends events
* from the children first.
*/
void removeFolder(File folder) {
LibraryTreeNode node = getNodeForFolder(folder, sharedFilesNode);
if(node == null)
return;
if(getSelectedNode() == node)
setSelectionPath(new TreePath(sharedFilesNode.getPath()));
int childCount = node.getChildCount();
for(int i = childCount - 1; i >= 0; i--) {
// Move any leftover children to be children of sharedFiles.
LibraryTreeNode child = (LibraryTreeNode)node.getChildAt(i);
TREE_MODEL.removeNodeFromParent(child);
addNode(sharedFilesNode, child);
}
// Remove this node.
TREE_MODEL.removeNodeFromParent(node);
}
/**
* Gets the LibraryTreeNode that represents this folder.
*/
LibraryTreeNode getNodeForFolder(File folder, LibraryTreeNode parent) {
int children = parent.getChildCount();
for(int i = children - 1; i >= 0; i--) {
LibraryTreeNode child = (LibraryTreeNode)parent.getChildAt(i);
File childFile = child.getFile();
if(childFile != null) {
if(childFile.equals(folder))
return child;
if(child.isAncestorOf(folder))
return getNodeForFolder(folder, child);
}
}
return null;
}
/**
* Adds files to the playlist recursively.
*/
void addPlayListEntries() {
if (incompleteDirectoryIsSelected() || !GUIMediator.isPlaylistVisible())
return;
final DirectoryHolder dh = getSelectedDirectoryHolder();
if (dh == null)
return;
if (PlaylistMediator.instance() == null)
return;
GUIMediator.instance().schedule(new Runnable() {
public void run() {
PlaylistMediator pm = GUIMediator.getPlayList();
if(pm == null) {
return;
}
ArrayList list = new ArrayList();
File[] files = dh.getFiles();
for (int i = 0; i < files.length; i++) {
if (files[i].getName().endsWith("mp3") ||
files[i].getName().endsWith("ogg")) {
list.add(files[i]);
}
}
if (!list.isEmpty()) {
pm.addFilesToPlaylist((File[])list.toArray(new File[0]));
}
}
});
}
/**
* Returns true if the given node is in the Shared Files subtree.
*/
private boolean canBeUnshared(LibraryTreeNode node) {
if (node == null)
return false;
if (node == speciallySharedFilesNode)
return false;
if (node == incompleteFilesNode)
return false;
if (node == sharedFilesNode)
return false;
if (node.getParent() == null)
return false;
if (node.getParent() == sharedFilesNode)
return true;
return canBeUnshared((LibraryTreeNode)node.getParent());
}
/**
* Returns false in the following cases:
* <ul>
* <li>The node represents the incomplete directory.
* <li>The directory behind the node is null.
* <li>The directory is already shared either explicitly or recursively
* because its parent is shared.
* </ul>
* @param node
* @return
*/
private boolean canBeShared(LibraryTreeNode node) {
if (node == null || node == incompleteFilesNode)
return false;
File dir = node.getDirectoryHolder().getDirectory();
if (dir == null || RouterService.getFileManager().isCompletelySharedDirectory(dir))
return false;
return true;
}
public DirectoryHolder getSelectedDirectoryHolder() {
TreePath path = getSelectionPath();
if (path != null)
return ((LibraryTreeNode)path.getLastPathComponent()).getDirectoryHolder();
return null;
}
/**
* Returns a boolean indicating whether or not the current mouse drop event
* is dropping to the incomplete folder.
*
* @param mousePoint
* the <tt>Point</tt> instance representing the location of the
* mouse release
* @return <tt>true</tt> if the mouse was released on the Incomplete
* folder, <tt>false</tt> otherwise
*/
boolean droppingToIncompleteFolder(Point mousePoint) {
TreePath path = getPathForLocation(mousePoint.x, mousePoint.y);
LibraryTreeNode node = (LibraryTreeNode)path.getLastPathComponent();
return node == incompleteFilesNode;
}
/**
* Returns the File object associated with the currently selected directory.
*
* @return the currently selected directory in the library, or <tt>null</tt>
* if no directory is selected
*/
File getSelectedDirectory() {
LibraryTreeNode node = getSelectedNode();
if (node == null)
return null;
return node.getDirectoryHolder().getDirectory();
}
LibraryTreeNode getSelectedNode() {
return (LibraryTreeNode)getLastSelectedPathComponent();
}
/**
* Returns the top-level directories as an array of <tt>File</tt> objects
* for updating the shared directories in the <tt>SettingsManager</tt>.
*
* @return the array of top-level directories as <tt>File</tt> objects
*/
File[] getSharedDirectories() {
int length = sharedFilesNode.getChildCount();
ArrayList newFiles = new ArrayList(length);
// collect all but the child that holds the specially shared files
for (int i = 0; i < length - 1; i++) {
LibraryTreeNode node = (LibraryTreeNode)sharedFilesNode.getChildAt(i);
if (node != speciallySharedFilesNode)
newFiles.add(node.getDirectoryHolder().getDirectory());
}
return (File[])newFiles.toArray(new File[0]);
}
/**
* Removes all shared directories from the visual display
* and changes the selection if any of them were selected.
*/
void clear() {
boolean selected = false;
int count = sharedFilesNode.getChildCount();
// count down, but do not remove node 0
for (int i = count - 1; i >= 0; i--) {
TreeNode node = sharedFilesNode.getChildAt(i);
if(node == getSelectedNode())
selected = true;
sharedFilesNode.remove(i);
}
TREE_MODEL.reload(sharedFilesNode);
if (selected)
setSelectionPath(new TreePath(sharedFilesNode));
}
/**
* Stops sharing the selected folder in the library if there is a folder
* selected, if the folder is not the save folder, or if the folder is not a
* subdirectory of a "root" shared folder.
*/
void unshareLibraryFolder() {
LibraryTreeNode node = getSelectedNode();
if (node == null)
return;
if (incompleteDirectoryIsSelected()) {
showIncompleteFolderMessage("delete");
} else if (!canBeUnshared(node)) {
GUIMediator.showMessage("MESSAGE_CANNOT_UNSHARE_DIRECTORY");
} else {
String msgKey = "MESSAGE_CONFIRM_UNSHARE_DIRECTORY";
int response = GUIMediator.showYesNoMessage(msgKey, QuestionsHandler.UNSHARE_DIRECTORY);
if (response != GUIMediator.YES_OPTION)
return;
final File file = node.getFile();
GUIMediator.instance().schedule(new Runnable() {
public void run() {
RouterService.getFileManager().removeFolderIfShared(file);
}
});
}
}
/**
* Returns whether or not the incomplete directory is selected in the tree.
*
* @return <tt>true</tt> if the incomplete directory is selected,
* <tt>false</tt> otherwise
*/
boolean incompleteDirectoryIsSelected() {
return incompleteFilesNode == getSelectedNode();
}
/**
* Returns whether or not the saved directory is selected in the tree.
*/
boolean savedDirectoryIsSelected() {
return isSavedDirectory(getSelectedNode());
}
boolean sharedFoldersNodeIsSelected() {
return getSelectedNode() == sharedFilesNode;
}
/**
* Determines whether the LibraryTreeNode parameter is the holder for the
* saved folder.
*
* @param holder
* the <tt>LibraryTreeNode</tt> class to check for whether or
* not it is the saved directory
* @return <tt>true</tt> if it does contain the saved directory,
* <tt>false</tt> otherwise
*/
private boolean isSavedDirectory(LibraryTreeNode node) {
return node == savedFilesNode || (node != null && node.getParent() == savedFilesNode);
}
/**
* Shows a message indicating that a specific action cannot be performed on
* the incomplete directory (such as changing its name).
*
* @param action
* the error that occurred
*/
private void showIncompleteFolderMessage(String action) {
String key1 = "MESSAGE_INCOMPLETE_DIRECTORY_START";
String key2 = "MESSAGE_INCOMPLETE_DIRECTORY_END";
GUIMediator.showError(key1, action, key2);
}
/**
* Selection listener that changes the files displayed in the table if the
* user chooses a new directory in the tree.
*/
private class LibraryTreeSelectionListener implements TreeSelectionListener {
public void valueChanged(TreeSelectionEvent e) {
LibraryTreeNode node = getSelectedNode();
unshareAction.setEnabled(canBeUnshared(node));
shareAction.setEnabled(canBeShared(node));
addDirToPlaylistAction.setEnabled(isEnqueueable());
if (node == null)
return;
if (node == sharedFilesNode)
LibraryMediator.showSharedFiles();
else
LibraryMediator.updateTableFiles(node.getDirectoryHolder());
}
}
/**
* Private class that extends a DefaultMutableTreeNode. Using this class
* ensures that the "UserObjects" associated with the tree nodes will always
* be File objects.
*/
private final class LibraryTreeNode extends DefaultMutableTreeNode
implements FileTransfer {
private DirectoryHolder _holder;
private LibraryTreeNode(DirectoryHolder holder) {
super(holder);
_holder = holder;
}
public DirectoryHolder getDirectoryHolder() {
return _holder;
}
public File getFile() {
return _holder.getDirectory();
}
/**
* Determines if this Node can be an ancestor of given folder.
*/
public boolean isAncestorOf(File folder) {
File f = getFile();
return f != null && folder.getPath().startsWith(f.getPath());
}
/**
* Determines if this is the direct parent of a given folder.
*/
public boolean isParentOf(File folder) {
return folder.getParentFile().equals(getFile());
}
/**
* Returns a description of this node.
*/
public String toString() {
return getClass().getName() + ", file: " + getFile();
}
}
/**
* Root node class the extends AbstractFileHolder
*/
private class RootNodeDirectoryHolder implements DirectoryHolder {
private String name;
public RootNodeDirectoryHolder(String s) { this.name = s; }
public File getDirectory() { return null; }
public String getDescription() { return ""; }
public File[] getFiles() { return new File[0]; }
public FileDesc[] getFileDescs() { return new FileDesc[0]; }
public String getName() { return name; }
public boolean accept(File pathname) { return false; }
public int size() { return 0; }
public Icon getIcon() { return null; }
public boolean isEmpty() { return true; }
}
private class RootSharedFilesDirectoryHolder extends RootNodeDirectoryHolder {
public RootSharedFilesDirectoryHolder() {
super(GUIMediator.getStringResource("LIBRARY_TREE_SHARED_FILES_DIRECTORY"));
}
public boolean accept(File file) {
return RouterService.getFileManager().isFileInCompletelySharedDirectory(file);
}
public Icon getIcon() {
return GUIMediator.getThemeImage("shared_folder");
}
}
private class UnshareAction extends AbstractAction {
public UnshareAction() {
putValue(Action.NAME,
GUIMediator.getStringResource("LIBRARY_TREE_UNSHARE_FOLDER_LABEL"));
}
public void actionPerformed(ActionEvent e) {
unshareLibraryFolder();
}
}
private class AddDirectoryToPlaylistAction extends AbstractAction {
public AddDirectoryToPlaylistAction() {
putValue(Action.NAME,
GUIMediator.getStringResource("LIBRARY_TREE_TO_PLAYLIST_FOLDER_LABEL"));
}
public void actionPerformed(ActionEvent e) {
addPlayListEntries();
}
}
private class LibraryTreeCellRenderer extends DefaultTreeCellRenderer {
public LibraryTreeCellRenderer() {
setOpaque(false);
}
public Component getTreeCellRendererComponent(JTree tree, Object value,
boolean sel, boolean expanded, boolean leaf, int row,
boolean focused) {
super.getTreeCellRendererComponent(tree, value, sel, expanded,
leaf, row, focused);
LibraryTreeNode node = (LibraryTreeNode)value;
DirectoryHolder dh = node.getDirectoryHolder();
setText(dh.getName());
setToolTipText(dh.getDescription());
Icon icon = dh.getIcon();
if (icon != null) {
setIcon(icon);
}
return this;
}
}
private class ShareAction extends AbstractAction {
public ShareAction() {
putValue(Action.NAME, GUIMediator.getStringResource
("LIBRARY_TREE_SHARE_FOLDER_LABEL"));
}
public void actionPerformed(ActionEvent e) {
LibraryMediator.instance().addSharedLibraryFolder(getSelectedDirectory());
}
}
/**
* Enable enqueue action when non-incomplete, non-shared, and has a playable file.
*/
private boolean isEnqueueable() {
LibraryTreeNode node = getSelectedNode();
boolean enqueueable = false;
if (node != null && node != incompleteFilesNode && node != sharedFilesNode) {
File[] files = node.getDirectoryHolder().getFiles();
if (files != null && files.length > 0) {
for (int i = 0; i < files.length; i++) {
if (GUIMediator.isPlaylistVisible() && PlaylistMediator.isPlayableFile(files[i]))
enqueueable = true;
}
}
}
return enqueueable;
}
/**
* Updates the LibraryTree based on whether the player is enabled.
*/
public void setPlayerEnabled(boolean value) {
addDirToPlaylistAction.setEnabled(isEnqueueable());
}
///////////////////////////////////////////////////////////////////////////
// Popups
///////////////////////////////////////////////////////////////////////////
/** Constant for the popup menu. */
private final JPopupMenu DIRECTORY_POPUP = new JPopupMenu();
private Action shareAction = new ShareAction();
private Action unshareAction = new UnshareAction();
private Action addDirToPlaylistAction = new AddDirectoryToPlaylistAction();
/**
* Constructs the popup menu that appears in the tree on a right mouse
* click.
*/
private void makePopupMenu() {
DIRECTORY_POPUP.add(new JMenuItem(shareAction));
DIRECTORY_POPUP.add(new JMenuItem(unshareAction));
DIRECTORY_POPUP.add(new JMenuItem(addDirToPlaylistAction));
DIRECTORY_POPUP.addSeparator();
DIRECTORY_POPUP.add(new JMenuItem(new ShareFileSpeciallyAction()));
DIRECTORY_POPUP.add(new JMenuItem(new ShareNewFolderAction()));
DIRECTORY_POPUP.addSeparator();
DIRECTORY_POPUP.add(new JMenuItem(new ConfigureOptionsAction(
"OPTIONS_SHARED_MAIN_TITLE",
"LIBRARY_SHARED_FILES_CONFIGURE_MENU",
"LIBRARY_SHARED_FILES_CONFIGURE_EXPLAIN")));
}
///////////////////////////////////////////////////////////////////////////
// MouseObserver implementation
///////////////////////////////////////////////////////////////////////////
/**
* Handles when the mouse is double-clicked.
*/
public void handleMouseDoubleClick(MouseEvent e) { }
/**
* Handles a right-mouse click.
*/
public void handleRightMouseClick(MouseEvent e) { }
/**
* Handles a trigger to the popup menu.
*/
public void handlePopupMenu(MouseEvent e) {
int row = getRowForLocation(e.getX(), e.getY());
if(row == -1)
return;
setSelectionRow(row);
DIRECTORY_POPUP.show(this, e.getX(), e.getY());
}
/**
* Sets the tree selection to be the given directory, if it exists.
*
* @return true if the directory exists in the tree and could be selected
*/
public boolean setSelectedDirectory(File dir) {
if (dir == null || !dir.isDirectory())
return false;
LibraryTreeNode ltn = getNodeForFolder(dir, sharedFilesNode);
if (ltn == null)
return false;
setSelectionPath(new TreePath(ltn.getPath()));
return true;
}
}