package com.limegroup.gnutella.gui.library; import java.awt.Frame; import java.awt.event.ActionEvent; import java.io.File; import java.io.IOException; import java.net.URLEncoder; import java.util.ArrayList; import java.util.Arrays; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.JComponent; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; import javax.swing.JTable; import javax.swing.ListSelectionModel; import javax.swing.event.MouseInputListener; import javax.swing.table.TableCellEditor; import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import com.limegroup.gnutella.FileDesc; import com.limegroup.gnutella.FileDetails; import com.limegroup.gnutella.FileManager; import com.limegroup.gnutella.FileManagerEvent; import com.limegroup.gnutella.IncompleteFileDesc; import com.limegroup.gnutella.MediaType; import com.limegroup.gnutella.RouterService; import com.limegroup.gnutella.SaveLocationException; import com.limegroup.gnutella.URN; import com.limegroup.gnutella.downloader.CantResumeException; import com.limegroup.gnutella.gui.ButtonRow; import com.limegroup.gnutella.gui.FileDetailsProvider; import com.limegroup.gnutella.gui.GUIMediator; import com.limegroup.gnutella.gui.LicenseWindow; import com.limegroup.gnutella.gui.MessageService; import com.limegroup.gnutella.gui.actions.ActionUtils; import com.limegroup.gnutella.gui.actions.BitziLookupAction; import com.limegroup.gnutella.gui.actions.CopyMagnetLinkToClipboardAction; import com.limegroup.gnutella.gui.actions.SearchAction; import com.limegroup.gnutella.gui.actions.LimeAction; import com.limegroup.gnutella.gui.playlist.PlaylistMediator; import com.limegroup.gnutella.gui.tables.AbstractTableMediator; import com.limegroup.gnutella.gui.tables.DataLine; import com.limegroup.gnutella.gui.tables.DragManager; import com.limegroup.gnutella.gui.tables.LimeJTable; import com.limegroup.gnutella.gui.themes.ThemeMediator; import com.limegroup.gnutella.gui.util.CoreExceptionHandler; import com.limegroup.gnutella.gui.xml.MetaEditorFrame; import com.limegroup.gnutella.gui.xml.editor.MetaEditor; import com.limegroup.gnutella.licenses.License; import com.limegroup.gnutella.licenses.VerificationListener; import com.limegroup.gnutella.settings.QuestionsHandler; import com.limegroup.gnutella.util.FileUtils; import com.limegroup.gnutella.util.Launcher; import com.limegroup.gnutella.util.NetworkUtils; import com.limegroup.gnutella.util.StringUtils; import com.limegroup.gnutella.xml.LimeXMLDocument; import com.limegroup.gnutella.xml.LimeXMLUtils; /** * This class wraps the JTable that displays files in the library, * controlling access to the table and the various table properties. * It is the Mediator to the Table part of the Library display. */ //2345678|012345678|012345678|012345678|012345678|012345678|012345678|012345678| final class LibraryTableMediator extends AbstractTableMediator implements VerificationListener, FileDetailsProvider { private static final Log LOG = LogFactory.getLog(LibraryTableMediator.class); /** * Variables so the PopupMenu & ButtonRow can have the same listeners */ public static Action LAUNCH_ACTION; public static Action ENQUEUE_ACTION; public static Action DELETE_ACTION; public static Action ANNOTATE_ACTION; public static Action RESUME_ACTION; public static Action PUBLISH_ACTION; public static Action RENAME_ACTION; public static Action SHARE_ACTION; public static Action UNSHARE_ACTION; public static Action SHARE_FOLDER_ACTION; public static Action UNSHARE_FOLDER_ACTION; private Action BITZI_LOOKUP_ACTION; private Action MAGNET_LOOKUP_ACTION; private Action LICENSE_ACTION; private Action COPY_MAGNET_TO_CLIPBOARD_ACTION; /** * Whether or not the incomplete directory is selected. */ private boolean _isIncomplete; /** * Annotation can be turned on once XML is set up. */ private boolean _annotateEnabled = false; /** * instance, for singelton access */ private static LibraryTableMediator _instance = new LibraryTableMediator(); public static LibraryTableMediator instance() { return _instance; } /** * Build some extra listeners */ protected void buildListeners() { super.buildListeners(); LAUNCH_ACTION = new LaunchAction(); ENQUEUE_ACTION = new EnqueueAction(); DELETE_ACTION = new RemoveAction(); ANNOTATE_ACTION = new AnnotateAction(); RESUME_ACTION = new ResumeAction(); PUBLISH_ACTION = new PublishAction(); RENAME_ACTION = new RenameAction(); SHARE_ACTION = new ShareFileAction(); UNSHARE_ACTION = new UnshareFileAction(); BITZI_LOOKUP_ACTION = new BitziLookupAction(this); MAGNET_LOOKUP_ACTION = new MagnetLookupAction(); LICENSE_ACTION = new LicenseAction(); COPY_MAGNET_TO_CLIPBOARD_ACTION = new CopyMagnetLinkToClipboardAction(this); SHARE_FOLDER_ACTION = new ShareFolderAction(); UNSHARE_FOLDER_ACTION = new UnshareFolderAction(); } /** * Set up the constants */ protected void setupConstants() { MAIN_PANEL = null; DATA_MODEL = new LibraryTableModel(); TABLE = new LimeJTable(DATA_MODEL); ((LibraryTableModel)DATA_MODEL).setTable(TABLE); Action[] aa = new Action[] { LAUNCH_ACTION, ENQUEUE_ACTION, DELETE_ACTION, ANNOTATE_ACTION, PUBLISH_ACTION, RESUME_ACTION }; BUTTON_ROW = new ButtonRow(aa, ButtonRow.X_AXIS, ButtonRow.NO_GLUE); } // inherit doc comment protected JPopupMenu createPopupMenu() { if (TABLE.getSelectionModel().isSelectionEmpty()) return null; JPopupMenu menu = new JPopupMenu(); menu.add(new JMenuItem(LAUNCH_ACTION)); menu.add(new JMenuItem(ENQUEUE_ACTION)); menu.addSeparator(); menu.add(new JMenuItem(RESUME_ACTION)); menu.addSeparator(); menu.add(new JMenuItem(DELETE_ACTION)); menu.add(new JMenuItem(RENAME_ACTION)); menu.addSeparator(); DataLine[] dls = TABLE.getSelectedDataLines(); boolean dirSelected = false; boolean fileSelected = false; for (int i = 0; i < dls.length; i++) { if (((LibraryTableDataLine)dls[i]).getFile().isDirectory()) dirSelected = true; else fileSelected = true; if (dirSelected && fileSelected) break; } if (dirSelected) { if (GUIMediator.isPlaylistVisible()) ENQUEUE_ACTION.setEnabled(false); DELETE_ACTION.setEnabled(false); RENAME_ACTION.setEnabled(false); if (fileSelected) { JMenu sharingMenu = new JMenu(GUIMediator.getStringResource("LIBRARY_TABLE_SHARING_SUB_MENU")); sharingMenu.add(new JMenuItem(SHARE_ACTION)); sharingMenu.add(new JMenuItem(UNSHARE_ACTION)); sharingMenu.add(new JMenuItem(ANNOTATE_ACTION)); sharingMenu.add(new JMenuItem(PUBLISH_ACTION)); sharingMenu.addSeparator(); sharingMenu.add(new JMenuItem(SHARE_FOLDER_ACTION)); sharingMenu.add(new JMenuItem(UNSHARE_FOLDER_ACTION)); menu.add(sharingMenu); } else { menu.add(new JMenuItem(SHARE_FOLDER_ACTION)); menu.add(new JMenuItem(UNSHARE_FOLDER_ACTION)); } } else { if (GUIMediator.isPlaylistVisible()) ENQUEUE_ACTION.setEnabled(true); DELETE_ACTION.setEnabled(true); RENAME_ACTION.setEnabled(!_isIncomplete); menu.add(new JMenuItem(SHARE_ACTION)); menu.add(new JMenuItem(UNSHARE_ACTION)); menu.add(new JMenuItem(ANNOTATE_ACTION)); menu.add(new JMenuItem(PUBLISH_ACTION)); } menu.addSeparator(); menu.add(createSearchSubMenu((LibraryTableDataLine)dls[0])); menu.add(createAdvancedMenu((LibraryTableDataLine)dls[0])); LICENSE_ACTION.setEnabled(dls != null && dls[0] != null && ((LibraryTableDataLine)dls[0]).isLicensed()); return menu; } private JMenu createAdvancedMenu(LibraryTableDataLine dl) { JMenu menu = new JMenu(GUIMediator.getStringResource("GENERAL_ADVANCED_SUB_MENU")); if (dl != null) { menu.add(new JMenuItem(LICENSE_ACTION)); menu.add(new JMenuItem(BITZI_LOOKUP_ACTION)); menu.add(new JMenuItem(MAGNET_LOOKUP_ACTION)); menu.add(new JMenuItem(COPY_MAGNET_TO_CLIPBOARD_ACTION)); File file = getFile(TABLE.getSelectedRow()); menu.setEnabled(RouterService.getFileManager().isFileShared(file)); } if (menu.getItemCount() == 0) menu.setEnabled(false); return menu; } private JMenu createSearchSubMenu(LibraryTableDataLine dl) { JMenu menu = new JMenu(GUIMediator.getStringResource("LIBRARY_TABLE_SEARCH_POPUP_MENU")); if(dl != null) { File f = (File)dl.getInitializeObject(); String keywords = StringUtils.createQueryString(f.getName()); if (keywords.length() > 2) menu.add(new JMenuItem(new SearchAction(keywords))); LimeXMLDocument doc = dl.getXMLDocument(); if(doc != null) { Action[] actions = ActionUtils.createSearchActions(doc); for (int i = 0; i < actions.length; i++) menu.add(new JMenuItem(actions[i])); } } if(menu.getItemCount() == 0) menu.setEnabled(false); return menu; } /** * Upgrade getScrolledTablePane to public access. */ public JComponent getScrolledTablePane() { return super.getScrolledTablePane(); } /* Don't display anything for this. The LibraryMediator will do it. */ protected void updateSplashScreen() {} /** * Note: This is set up for this to work. * Polling is not needed though, because updates * already generate update events. */ private LibraryTableMediator() { super("LIBRARY_TABLE"); //GUIMediator.addRefreshListener(this); ThemeMediator.addThemeObserver(this); } /** * Sets up drag & drop for the table. */ protected void setupDragAndDrop() { DragManager.install(TABLE); } /** * there is no actual component that holds all of this table. * The LibraryMediator is real the holder. */ public JComponent getComponent() { return null; } /** * Sets the default editors. */ protected void setDefaultEditors() { TableColumnModel model = TABLE.getColumnModel(); TableColumn tc = model.getColumn(LibraryTableDataLine.NAME_IDX); tc.setCellEditor(new LibraryTableCellEditor(this)); } /** * Cancels all editing of fields in the tree and table. */ void cancelEditing() { if(TABLE.isEditing()) { TableCellEditor editor = TABLE.getCellEditor(); editor.cancelCellEditing(); } } /** * Adds the mouse listeners to the wrapped <tt>JTable</tt>. * * @param listener the <tt>MouseInputListener</tt> that handles mouse events * for the library */ void addMouseInputListener(final MouseInputListener listener) { TABLE.addMouseListener(listener); TABLE.addMouseMotionListener(listener); } /** * Allows annotation once XML is set up * * @param enabled whether or not annotation is allowed */ public void setAnnotateEnabled(boolean enabled) { _annotateEnabled = enabled; LibraryTableDataLine.setXMLEnabled(enabled); DATA_MODEL.refresh(); // disable the annotate buttons if we are turning annotation off if (!enabled) { ANNOTATE_ACTION.setEnabled(false); PUBLISH_ACTION.setEnabled(false); } else if (!_isIncomplete && TABLE.getSelectedRowCount() == 1 && ((LibraryTableModel)DATA_MODEL).getFileDesc(TABLE.getSelectedRow()) != null) { // if one non-incomplete item is selected, enable the annotate button ANNOTATE_ACTION.setEnabled(true); File currFile = ((LibraryTableModel)DATA_MODEL).getFile(TABLE.getSelectedRow()); if(LimeXMLUtils.isFilePublishable(currFile))PUBLISH_ACTION.setEnabled(true); } } /** * Notification that the incomplete directory is selected (or not) * * @param enabled whether or not incomplete is showing */ void setIncompleteSelected(boolean enabled) { if (enabled == _isIncomplete) return; _isIncomplete = enabled; // enable/disable the resume buttons if we're not incomplete if (!enabled) { RESUME_ACTION.setEnabled(false); } else if (!TABLE.getSelectionModel().isSelectionEmpty()) { RESUME_ACTION.setEnabled(true); } } /** * Updates the Table based on the selection of the given table. */ void updateTableFiles(DirectoryHolder dirHolder) { if (dirHolder == null) return; clearTable(); setIncompleteSelected(LibraryMediator.incompleteDirectoryIsSelected()); File[] files = dirHolder.getFiles(); for (int i = 0; i < files.length; i++) addUnsorted(files[i]); forceResort(); } /** * Handles events created by the FileManager. Adds or removes rows from * the table as necessary. */ void handleFileManagerEvent(final FileManagerEvent evt, DirectoryHolder holder) { // Need to update table only if one of the files in evt // is contained in the current directory. if (evt == null || holder == null) return; File[] files = evt.getFiles(); FileDesc[] fds = evt.getFileDescs(); if(LOG.isDebugEnabled()) LOG.debug("Handling event: " + evt); switch(evt.getKind()) { case FileManagerEvent.REMOVE: File f = fds[0].getFile(); if(holder.accept(f)) { ((LibraryTableModel)DATA_MODEL).reinitialize(f); handleSelection(-1); } else if(DATA_MODEL.contains(f)) { DATA_MODEL.remove(f); handleSelection(-1); } break; case FileManagerEvent.ADD: if(holder.accept(fds[0].getFile())) { add(fds[0].getFile()); handleSelection(-1); } break; case FileManagerEvent.CHANGE: File changed = fds[0].getFile(); ((LibraryTableModel)DATA_MODEL).reinitialize(changed); handleSelection(-1); break; case FileManagerEvent.RENAME: File old = fds[0].getFile(); File now = fds[1].getFile(); if(holder.accept(now)) { ((LibraryTableModel)DATA_MODEL).reinitialize(old, now); handleSelection(-1); } break; case FileManagerEvent.ADD_FOLDER: if (holder.accept(files[0])) { add(files[0]); handleSelection(-1); } break; case FileManagerEvent.REMOVE_FOLDER: f = files[0]; if(holder.accept(f)) { ((LibraryTableModel)DATA_MODEL).reinitialize(f); handleSelection(-1); } else if(DATA_MODEL.contains(f)) { DATA_MODEL.remove(f); handleSelection(-1); } break; } } /** * Returns the <tt>File</tt> stored at the specified row in the list. * * @param row the row of the desired <tt>File</tt> instance in the * list * * @return a <tt>File</tt> instance associated with the specified row * in the table */ File getFile(int row) { return ((LibraryTableModel)DATA_MODEL).getFile(row); } /** * Returns the file desc object for the given row or <code>null</code> if * there is none. * @param row * @return */ private FileDesc getFileDesc(int row) { return ((LibraryTableModel)DATA_MODEL).getFileDesc(row); } /** * Implements the {@link FileDescProvider} interface by returning all the * selected filedescs. */ public FileDetails[] getFileDetails() { int[] sel = TABLE.getSelectedRows(); ArrayList files = new ArrayList(sel.length); for (int i = 0; i < sel.length; i++) { FileDesc desc = getFileDesc(sel[i]); if (desc != null) { files.add(desc); } } if (files.isEmpty()) { return new FileDetails[0]; } return (FileDetails[])files.toArray(new FileDetails[0]); } /** * Accessor for the table that this class wraps. * * @return The <tt>JTable</tt> instance used by the library. */ JTable getTable() { return TABLE; } ButtonRow getButtonRow() { return BUTTON_ROW; } /** * Accessor for the <tt>ListSelectionModel</tt> for the wrapped * <tt>JTable</tt> instance. */ ListSelectionModel getSelectionModel() { return TABLE.getSelectionModel(); } /** * shows the user a meta-data for the file(if any) and allow the user * to edit it. * * @param publish true to edit the license MetaData, false otherwise */ void editMeta(boolean publish){ //get the selected file. If there are more than 1 we just use the // last one. int[] rows = TABLE.getSelectedRows(); int k = rows.length; if(k == 0) return; int index = rows[k-1];//this is the index of the last row selected FileDesc fd = ((LibraryTableModel)DATA_MODEL).getFileDesc(index); if( fd == null ) // oh well return; String fullName = ""; try{ fullName = fd.getFile().getCanonicalPath(); }catch(IOException ee){//if there is an exception return return; } //Now docsOfFile has all LimeXMLDocuments pertainint to selected file Frame mainFrame = GUIMediator.getAppFrame(); if (LimeXMLUtils.isSupportedAudioFormat(fullName) || MediaType.getVideoMediaType().matches((fullName)) || MediaType.getProgramMediaType().matches(fullName) || MediaType.getImageMediaType().matches(fullName) || MediaType.getDocumentMediaType().matches(fullName)) { MetaEditor metaEditor = new MetaEditor(fd, fullName, mainFrame,publish); metaEditor.setLocationRelativeTo(MessageService.getParentComponent()); metaEditor.setVisible(true); } else { MetaEditorFrame metaEditor = new MetaEditorFrame(fd, fullName, mainFrame); metaEditor.setLocationRelativeTo(MessageService.getParentComponent()); metaEditor.setVisible(true); } } /** * Programatically starts a rename of the selected item. */ void startRename() { int row = TABLE.getSelectedRow(); if(row == -1) return; int viewIdx = TABLE.convertColumnIndexToView(LibraryTableDataLine.NAME_IDX); TABLE.editCellAt(row, viewIdx, LibraryTableCellEditor.EVENT); } /** * Shows the license window. */ void showLicenseWindow() { DataLine dl = TABLE.getSelectedDataLine(); if(dl == null) return; LibraryTableDataLine ldl = (LibraryTableDataLine)dl; FileDesc fd = ldl.getFileDesc(); License license = fd.getLicense(); URN urn = fd.getSHA1Urn(); LimeXMLDocument doc = ldl.getXMLDocument(); LicenseWindow window = LicenseWindow.create(license, urn, doc, this); window.setVisible(true); } public void licenseVerified(License license) { DATA_MODEL.refresh(); } /** * Prepare a detail page of magnet link info for selected files * in the library. */ void doMagnetLookup() { doMagnetCommand("/magcmd/detail?"); } /** * Fire a local lookup with file/magnet details */ void doMagnetCommand(String cmd) { // get the selected files. Build up a url to display details. int[] rows = TABLE.getSelectedRows(); int k = rows.length; if(k == 0) return; boolean haveValidMagnet = false; int count = 0; int port = RouterService.getHTTPAcceptor().getPort(); int eport = RouterService.getAcceptor().getPort(true); byte[] eaddr = RouterService.getAcceptor().getAddress(true); String lookupUrl = "http://localhost:"+port+ cmd+ "addr="+NetworkUtils.ip2string(eaddr)+":"+eport; for(int i=0; i<k; i++) { FileDesc fd = ((LibraryTableModel)DATA_MODEL).getFileDesc(rows[i]); if (fd==null) { // Only report valid files continue; } URN urn = fd.getSHA1Urn(); if(urn == null) { // Only report valid sha1s continue; } String urnStr = urn.toString(); int hashstart = 1 + urnStr.indexOf(":", 4); String sha1 = urnStr.substring(hashstart); lookupUrl += "&n"+count+"="+URLEncoder.encode(fd.getFileName())+ "&u"+count+"="+sha1; count++; haveValidMagnet = true; } if (haveValidMagnet) { try { Launcher.openURL(lookupUrl); } catch (IOException ioe) { // do nothing } } } /** * Override the default removal so we can actually stop sharing * and delete the file. * Deletes the selected rows in the table. * CAUTION: THIS WILL DELETE THE FILE FROM THE DISK. */ public void removeSelection() { String msgKey = "MESSAGE_CONFIRM_FILE_DELETE"; int response = GUIMediator.showYesNoMessage(msgKey); if(response != GUIMediator.YES_OPTION) return; int[] rows = TABLE.getSelectedRows(); if(rows.length <= 0) return; Arrays.sort(rows); if(TABLE.isEditing()) { TableCellEditor editor = TABLE.getCellEditor(); editor.cancelCellEditing(); } ArrayList errors = new ArrayList(); for(int i = rows.length - 1; i >= 0; i--) { File file = ((LibraryTableModel)DATA_MODEL).getFile(rows[i]); FileDesc fd = ((LibraryTableModel)DATA_MODEL).getFileDesc(rows[i]); if (fd instanceof IncompleteFileDesc) RouterService.getDownloadManager().getIncompleteFileManager().removeEntry(file); else RouterService.getFileManager().removeFileIfShared(file); boolean removed = file.delete(); if(!removed && fd != null) { // try again, telling UploadManager to kill any uploads RouterService.getUploadManager().killUploadsForFileDesc(fd); removed = file.delete(); } if(removed) DATA_MODEL.remove(rows[i]); else errors.add(file.getName()); } clearSelection(); // go through the errors and tell them what couldn't be deleted. for(int i = 0; i < errors.size(); i++) { String name = (String)errors.get(i); final String key1 = "MESSAGE_UNABLE_TO_DELETE_FILE_START"; final String key2 = "MESSAGE_UNABLE_TO_DELETE_FILE_END"; final String msg = "'" + name + "'."; // notify the user that deletion failed GUIMediator.showError(key1, msg, key2); } } /** * Handles a name change of one of the files displayed. * * @param newName The new name of the file * * @return A <tt>String</tt> that is the name of the file * after this method is called. This is the new name if * the name change succeeded, and the old name otherwise. */ String handleNameChange(String newName) { int row = TABLE.getEditingRow(); LibraryTableModel ltm = (LibraryTableModel)DATA_MODEL; File oldFile = ltm.getFile(row); String parent = oldFile.getParent(); String nameWithExtension = newName + "." + ltm.getType(row); File newFile = new File(parent, nameWithExtension); if(!ltm.getName(row).equals(newName)) { if(!newFile.exists() && oldFile.renameTo(newFile)) { RouterService.getFileManager().renameFileIfShared(oldFile, newFile); // Ideally, renameFileIfShared should immediately send RENAME or REMOVE // callbacks. But, if it doesn't, it should atleast have immediately // internally removed the file from being shared. So, we immediately // do a reinitialize on the oldFile to mark it as being not shared. ((LibraryTableModel)DATA_MODEL).reinitialize(oldFile); return newName; } // notify the user that renaming failed GUIMediator.showError("MESSAGE_UNABLE_TO_RENAME_FILE_START", "'" + ltm.getName(row) + "'.", "MESSAGE_UNABLE_TO_RENAME_FILE_END"); return ltm.getName(row); } return newName; // newName == currentName } public void handleActionKey() { int[] rows = TABLE.getSelectedRows(); LibraryTableModel ltm = (LibraryTableModel)DATA_MODEL; File file; for (int i = 0; i < rows.length; i++) { file = ltm.getFile(rows[i]); // if it's a directory try to select it in the library tree // if it could be selected return if (file.isDirectory() && LibraryMediator.setSelectedDirectory(file)) return; } launch(); } /** * Resume incomplete downloads */ void resumeIncomplete() { //For each selected row... int[] rows = TABLE.getSelectedRows(); boolean startedDownload=false; ArrayList errors = new ArrayList(); for (int i=0; i<rows.length; i++) { //...try to download the incomplete File incomplete=((LibraryTableModel)DATA_MODEL).getFile(rows[i]); try { RouterService.download(incomplete); startedDownload=true; } catch (SaveLocationException e) { // we must cache errors to display later so we don't wait // while the table might change in the background. errors.add(e); } catch(CantResumeException e) { errors.add(e); } } // traverse back through the errors and show them. for(int i = 0; i < errors.size(); i++) { Exception e = (Exception)errors.get(i); if(e instanceof SaveLocationException) { SaveLocationException sle = (SaveLocationException)e; if (sle.getErrorCode() == SaveLocationException.FILE_ALREADY_DOWNLOADING) { GUIMediator.showFormattedError("FORMATTED_ERROR_ALREADY_DOWNLOADING", new Object[] { sle.getFile() }, QuestionsHandler.ALREADY_DOWNLOADING); } else { String msg = CoreExceptionHandler.getSaveLocationErrorString(sle); GUIMediator.showTranslatedError(msg); } } else if ( e instanceof CantResumeException ) { GUIMediator.showError("ERROR_CANT_RESUME_START", "\""+((CantResumeException)e).getFilename()+"\"", "ERROR_CANT_RESUME_END", QuestionsHandler.CANT_RESUME); } } //Switch to download tab (if we actually started anything). if (startedDownload) GUIMediator.instance().setWindow(GUIMediator.SEARCH_INDEX); } /** * Launches the associated applications for each selected file * in the library if it can. */ void launch() { int[] rows = TABLE.getSelectedRows(); boolean audioLaunched = false; for(int i = 0, l = rows.length; i < l; i++) { File currFile = ((LibraryTableModel)DATA_MODEL).getFile(rows[i]); if (!audioLaunched && GUIMediator.isPlaylistVisible() && PlaylistMediator.isPlayableFile(currFile)) { GUIMediator.instance().launchAudio(currFile); audioLaunched = true; } else { try { GUIMediator.launchFile(currFile); } catch(IOException ignored) {} } } } /** * Handles the selection of the specified row in the library window, * enabling or disabling buttons and chat menu items depending on * the values in the row. * * @param row the selected row */ public void handleSelection(int row) { if (TABLE.getSelectedRowCount() <= 0) { handleNoSelection(); return; } // always turn on Launch, Delete, Magnet Lookup, Bitzi Lookup LAUNCH_ACTION.setEnabled(true); DELETE_ACTION.setEnabled(true); // turn on Enqueue if play list is visible and a selected item is playable int[] sel = TABLE.getSelectedRows(); if (GUIMediator.isPlaylistVisible()) { boolean found = false; for (int i = 0; i < sel.length; i++) if (PlaylistMediator.isPlayableFile(((LibraryTableModel)DATA_MODEL).getFile(sel[i]))) { found = true; break; } ENQUEUE_ACTION.setEnabled(found); } else ENQUEUE_ACTION.setEnabled(false); // turn on Describe... for complete files when single selection if (!_isIncomplete && _annotateEnabled && TABLE.getSelectedRowCount() == 1 && ((LibraryTableModel)DATA_MODEL).getFileDesc(TABLE.getSelectedRow()) != null) { File currFile = ((LibraryTableModel)DATA_MODEL).getFile(TABLE.getSelectedRow()); ANNOTATE_ACTION.setEnabled(true); PUBLISH_ACTION.setEnabled(LimeXMLUtils.isFilePublishable(currFile)); } else { ANNOTATE_ACTION.setEnabled(false); PUBLISH_ACTION.setEnabled(false); } // turn on Resume button if Incomplete folder is currently selected RESUME_ACTION.setEnabled(_isIncomplete); // turn off Rename button if Incomplete folder is currently selected RENAME_ACTION.setEnabled(!_isIncomplete); // enable Share File action when any selected file is not shared boolean shareAllowed = false; boolean unshareAllowed = false; boolean shareFolderAllowed = false; boolean unshareFolderAllowed = false; boolean foundDir = false; for (int i = 0; i < sel.length; i++) { File file = getFile(sel[i]); if (file.isDirectory()) { // turn off delete (only once) if directory found if (!foundDir){ DELETE_ACTION.setEnabled(false); foundDir = true; } if (!RouterService.getFileManager().isCompletelySharedDirectory(file)) shareFolderAllowed = true; else unshareFolderAllowed = true; } else { if (!RouterService.getFileManager().isFileShared(file)) { if (!FileManager.isFilePhysicallyShareable(file) || _isIncomplete) continue; shareAllowed = true; } else { unshareAllowed = true; } if (shareAllowed && unshareAllowed && shareFolderAllowed && unshareFolderAllowed) break; } } SHARE_ACTION.setEnabled(shareAllowed); UNSHARE_ACTION.setEnabled(unshareAllowed); SHARE_FOLDER_ACTION.setEnabled(shareFolderAllowed); UNSHARE_FOLDER_ACTION.setEnabled(unshareFolderAllowed); // enable / disable advanced items if file shared / not shared File file = getFile(sel[0]); boolean firstShared = RouterService.getFileManager().isFileShared(file); MAGNET_LOOKUP_ACTION.setEnabled(firstShared); BITZI_LOOKUP_ACTION.setEnabled(firstShared); COPY_MAGNET_TO_CLIPBOARD_ACTION.setEnabled (!_isIncomplete && getFileDesc(sel[0]) != null); LibraryTableDataLine dl = (LibraryTableDataLine)TABLE.getSelectedDataLine(); boolean license = dl != null && dl.isLicensed(); LICENSE_ACTION.setEnabled(license); } /** * Handles the deselection of all rows in the library table, * disabling all necessary buttons and menu items. */ public void handleNoSelection() { LAUNCH_ACTION.setEnabled(false); ENQUEUE_ACTION.setEnabled(false); DELETE_ACTION.setEnabled(false); ANNOTATE_ACTION.setEnabled(false); PUBLISH_ACTION.setEnabled(false); RESUME_ACTION.setEnabled(false); RENAME_ACTION.setEnabled(false); SHARE_ACTION.setEnabled(false); UNSHARE_ACTION.setEnabled(false); SHARE_FOLDER_ACTION.setEnabled(false); UNSHARE_FOLDER_ACTION.setEnabled(false); COPY_MAGNET_TO_CLIPBOARD_ACTION.setEnabled(false); MAGNET_LOOKUP_ACTION.setEnabled(false); BITZI_LOOKUP_ACTION.setEnabled(false); LICENSE_ACTION.setEnabled(false); } /** * Refreshes the enabledness of the Enqueue button based * on the player enabling state. */ public void setPlayerEnabled(boolean value) { handleSelection(TABLE.getSelectedRow()); } /////////////////////////////////////////////////////// // ACTIONS /////////////////////////////////////////////////////// private final class LaunchAction extends AbstractAction { public LaunchAction () { putValue(Action.NAME, GUIMediator.getStringResource ("LIBRARY_LAUNCH_BUTTON_LABEL")); putValue(Action.SHORT_DESCRIPTION, GUIMediator.getStringResource("LIBRARY_LAUNCH_BUTTON_TIP")); putValue(LimeAction.ICON_NAME, "LIBRARY_LAUNCH"); } public void actionPerformed(ActionEvent ae) { launch(); } } private final class EnqueueAction extends AbstractAction { public EnqueueAction () { putValue(Action.NAME, GUIMediator.getStringResource ("LIBRARY_PLAYLIST_BUTTON_LABEL")); putValue(Action.SHORT_DESCRIPTION, GUIMediator.getStringResource("LIBRARY_PLAYLIST_BUTTON_TIP")); putValue(LimeAction.ICON_NAME, "LIBRARY_TO_PLAYLIST"); } public void actionPerformed(ActionEvent ae) { //get the selected file. If there are more than 1 we add all int[] rows = TABLE.getSelectedRows(); for (int i = 0; i < rows.length; i++) { int index = rows[i]; // current index to add File file = ((LibraryTableModel)DATA_MODEL).getFile(index); if (GUIMediator.isPlaylistVisible() && PlaylistMediator.isPlayableFile(file)) LibraryMediator.instance().addFileToPlayList(file); } } } private final class RemoveAction extends AbstractAction { public RemoveAction () { putValue(Action.NAME, GUIMediator.getStringResource ("LIBRARY_DELETE_BUTTON_LABEL")); putValue(Action.SHORT_DESCRIPTION, GUIMediator.getStringResource("LIBRARY_DELETE_BUTTON_TIP")); putValue(LimeAction.ICON_NAME, "LIBRARY_DELETE"); } public void actionPerformed(ActionEvent ae) { REMOVE_LISTENER.actionPerformed(ae); } } private final class AnnotateAction extends AbstractAction { public AnnotateAction() { putValue(Action.NAME, GUIMediator.getStringResource("LIBRARY_ANNOTATE_BUTTON_LABEL")); putValue(Action.SHORT_DESCRIPTION, GUIMediator.getStringResource("LIBRARY_ANNOTATE_BUTTON_TIP")); putValue(LimeAction.ICON_NAME, "LIBRARY_ANNOTATE"); } public void actionPerformed(ActionEvent ae) { editMeta(false); } } private final class PublishAction extends AbstractAction { public PublishAction() { putValue(Action.NAME, GUIMediator.getStringResource("LIBRARY_PUBLISH_BUTTON_LABEL")); putValue(Action.SHORT_DESCRIPTION, GUIMediator.getStringResource("LIBRARY_PUBLISH_BUTTON_TIP")); putValue(LimeAction.ICON_NAME, "LIBRARY_PUBLISH"); } public void actionPerformed(ActionEvent e) { editMeta(true); } } private final class ResumeAction extends AbstractAction { public ResumeAction () { putValue(Action.NAME, GUIMediator.getStringResource ("LIBRARY_RESUME_BUTTON_LABEL")); putValue(Action.SHORT_DESCRIPTION, GUIMediator.getStringResource("LIBRARY_RESUME_BUTTON_TIP")); putValue(LimeAction.ICON_NAME, "LIBRARY_RESUME"); } public void actionPerformed(ActionEvent ae) { resumeIncomplete(); } } private final class RenameAction extends AbstractAction { public RenameAction () { putValue(Action.NAME, GUIMediator.getStringResource ("LIBRARY_RENAME_BUTTON_LABEL")); // "LIBRARY_RENAME" ??? // "LIBRARY_RENAME_BUTTON_TIP" ??? } public void actionPerformed(ActionEvent ae) { startRename(); } } private class ShareFileAction extends AbstractAction { public ShareFileAction() { putValue(Action.NAME, GUIMediator.getStringResource ("SHARE_FILE_POPUP_MENU_LABEL")); } public void actionPerformed(ActionEvent e) { int[] sel = TABLE.getSelectedRows(); final File[] files = new File[sel.length]; for (int i = 0; i < sel.length; i++) { files[i] = getFile(sel[i]); } GUIMediator.instance().schedule(new Runnable() { public void run() { for (int i = 0; i < files.length; i++) { File file = files[i]; if (file == null || file.isDirectory()) continue; RouterService.getFileManager().addFileAlways(file); } } }); } } private class UnshareFileAction extends AbstractAction { public UnshareFileAction() { putValue(Action.NAME, GUIMediator.getStringResource ("UNSHARE_FILE_POPUP_MENU_LABEL")); } public void actionPerformed(ActionEvent e) { int[] sel = TABLE.getSelectedRows(); final File[] files = new File[sel.length]; for (int i = sel.length - 1; i >= 0; i--) { files[i] = getFile(sel[i]); } GUIMediator.instance().schedule(new Runnable() { public void run() { for (int i = 0; i < files.length; i++) { File file = files[i]; if (file == null || file.isDirectory()) continue; RouterService.getFileManager().stopSharingFile(file); } } }); } } private class ShareFolderAction extends AbstractAction { public ShareFolderAction() { putValue(Action.NAME, GUIMediator.getStringResource ("SHARE_FOLDER_POPUP_MENU_LABEL")); } public void actionPerformed(ActionEvent e) { int[] sel = TABLE.getSelectedRows(); final File[] files = new File[sel.length]; for (int i = 0; i < sel.length; i++) { files[i] = getFile(sel[i]); } GUIMediator.instance().schedule(new Runnable() { public void run() { for (int i = 0; i < files.length; i++) { File file = files[i]; if (file == null || !file.isDirectory()) continue; RouterService.getFileManager().addSharedFolder(file); } } }); } } private class UnshareFolderAction extends AbstractAction { public UnshareFolderAction() { putValue(Action.NAME, GUIMediator.getStringResource ("UNSHARE_FOLDER_POPUP_MENU_LABEL")); } public void actionPerformed(ActionEvent e) { int[] sel = TABLE.getSelectedRows(); final File[] files = new File[sel.length]; for (int i = sel.length - 1; i >= 0; i--) { files[i] = getFile(sel[i]); } GUIMediator.instance().schedule(new Runnable() { public void run() { for (int i = 0; i < files.length; i++) { File file = files[i]; if (file == null || !file.isDirectory()) continue; RouterService.getFileManager().removeFolderIfShared(file); } } }); } } private final class MagnetLookupAction extends AbstractAction { public MagnetLookupAction() { putValue(Action.NAME, GUIMediator.getStringResource ("SEARCH_PUBLIC_MAGNET_LOOKUP_STRING")); } public void actionPerformed(ActionEvent e) { doMagnetLookup(); } } private class LicenseAction extends AbstractAction { public LicenseAction() { putValue(Action.NAME, GUIMediator.getStringResource ("LICENSE_VIEW_LICENSE")); } public void actionPerformed(ActionEvent e) { showLicenseWindow(); } } }