package com.limegroup.gnutella.gui.upload; import java.awt.event.ActionListener; import java.util.Arrays; import java.util.HashSet; import java.util.Set; import javax.swing.JPopupMenu; import com.limegroup.gnutella.RouterService; import com.limegroup.gnutella.Uploader; import com.limegroup.gnutella.gui.GUIMediator; import com.limegroup.gnutella.gui.PaddedPanel; import com.limegroup.gnutella.gui.search.SearchMediator; import com.limegroup.gnutella.gui.tables.AbstractTableMediator; import com.limegroup.gnutella.gui.tables.DataLine; import com.limegroup.gnutella.gui.tables.LimeJTable; import com.limegroup.gnutella.gui.tables.TableSettings; import com.limegroup.gnutella.gui.themes.ThemeMediator; import com.limegroup.gnutella.settings.SharingSettings; /** * This class acts as a mediator between all of the components of the * upload window. It also constructs all of the upload window * components. */ public final class UploadMediator extends AbstractTableMediator { /** * Variable for the total number of uploads that have been added in this * session. */ private static int _totalUploads = 0; /** * Variables so we only need one listener for both ButtonRow & PopupMenu */ ActionListener CHAT_LISTENER; ActionListener CLEAR_LISTENER; ActionListener BROWSE_LISTENER; private static final String UPLOAD_TITLE = GUIMediator.getStringResource("UPLOAD_TITLE"); private static final String ACTIVE = GUIMediator.getStringResource("UPLOAD_ACTIVE"); private static final String QUEUED = GUIMediator.getStringResource("UPLOAD_QUEUED"); /** * instance, for singelton acces */ private static UploadMediator _instance = new UploadMediator(); public static UploadMediator instance() { return _instance; } /** * Variable for whether or not chat is enabled for the selected host. */ private static boolean _chatEnabled; /** * Variable for whether or not browse host is enabled for the selected * host. */ private static boolean _browseEnabled; /** * Overriden to have different default values for tooltips. */ protected void buildSettings() { SETTINGS = new TableSettings(ID) { public boolean getDefaultTooltips() { return false; } }; } /** * Build some extra listeners */ protected void buildListeners() { super.buildListeners(); CHAT_LISTENER = new ChatListener(this); CLEAR_LISTENER = new ClearListener(this); BROWSE_LISTENER = new BrowseListener(this); } /** * Set us up the constants */ protected void setupConstants() { MAIN_PANEL = new PaddedPanel(UPLOAD_TITLE); DATA_MODEL = new UploadModel(); TABLE = new LimeJTable(DATA_MODEL); BUTTON_ROW = (new UploadButtons(this)).getComponent(); } /** * Update the splash screen */ protected void updateSplashScreen() { GUIMediator.setSplashScreenString( GUIMediator.getStringResource("SPLASH_STATUS_UPLOAD_WINDOW")); } /** * Constructs all of the elements of the upload window, including * the table, the buttons, etc. */ public UploadMediator() { super("UPLOAD_MEDIATOR"); GUIMediator.addRefreshListener(this); ThemeMediator.addThemeObserver(this); } /** * Override the default refresh so we can set the clear button. */ public void doRefresh() { boolean inactivePresent = ((Boolean)DATA_MODEL.refresh()).booleanValue(); setButtonEnabled(UploadButtons.CLEAR_BUTTON, inactivePresent); MAIN_PANEL.setTitle(UPLOAD_TITLE + " (" + RouterService.getUploadManager().uploadsInProgress() + " " + ACTIVE + ", " + RouterService.getUploadManager().getNumQueuedUploads() + " " + QUEUED + ")"); } /** * Returns the total number of Uploads that have occurred in this session. * * @return the total number of Uploads that have occurred in this session */ public int getTotalUploads() { return _totalUploads; } /** * Returns the total number of current Uploads. * * @return the total number of current Uploads */ public int getCurrentUploads() { return ((UploadModel)DATA_MODEL).getCurrentUploads(); } /** * Returns the total number of active Uploads. * This includes anything that is still viewable in the Uploads view. * * @return the total number of active Uploads */ public int getActiveUploads() { return ((UploadModel)DATA_MODEL).getRowCount(); } /** * Override the default add. * * Adds a new Uploads to the list of Uploads, obtaining the necessary * information from the supplied <tt>Uploader</tt>. * * If the upload is not already in the list, then it is added. * <p> * With HTTP1.1 support, swarm downloads, and chunking, it becomes * important that the GUI should not get updated whenever a little * chunk of a file is uploaded. */ public void add(Object uploader) { if ( !DATA_MODEL.contains(uploader) ) { //attempt to update an existing uploader int idx = DATA_MODEL.update(uploader); if ( idx == -1 ) { //if we couldn't find one to update, add it as new _totalUploads++; super.add(uploader); } } } /** * Override the default remove * * Removes a upload from the list if the user has configured their system * to automatically clear completed upload and if the upload is * complete. * * @param uploader the <tt>Uploader</tt> to remove from the list if it is * complete. */ public void remove(Object uploader) { if (SharingSettings.CLEAR_UPLOAD.getValue() && ((Uploader)uploader).isInactive()) { // This is called when the upload is finished, either because // the user clicked 'Kill', something was interupted, etc.. // It doesn't matter that we always setPersistConnect(true), // because if the upload was already killed, the sockets // are already closed. // The flow of a manually killed upload goes like this: // RemoveListener.actionPerformed() -> // UploadMediator.removeSelection() -> // (for each row selected)... // UploadDataLine.cleanup() // (core notices socket closed, marks interupted) // VisualConnectionCallBack.removeUploader(Uploader) -> // UploadMediator.remove(uploader) // (if the user has clear completed checked)... // UploadDataLine.setPersistConnection(true) // AbstractTableMediator.removeRow( uploader's row ) // A remotely-terminated download follows the same path, // but starts at the 'core notices socket closed'. int i = DATA_MODEL.getRow(uploader); if( i != -1 ) { // tell the DataLine that we don't want to clean up. // necessary for chunked transfers. ((UploadDataLine)DATA_MODEL.get(i)).setPersistConnection(true); super.removeRow(i); } } else { //if we're not removing it, note the time at which it ended. UploadDataLine udl = (UploadDataLine)DATA_MODEL.get(uploader); if (udl != null) udl.setEndTime( System.currentTimeMillis() ); } } /** * Override the default remove to not actually remove, * but instead just call 'cleanup'. * If the user has 'Clear Completed Uploads' checked, * they'll be removed. Otherwise, they'll show as interupted. */ public void removeSelection() { int[] sel = TABLE.getSelectedRows(); Arrays.sort(sel); for( int counter = sel.length - 1; counter >= 0; counter--) { int i = sel[counter]; DATA_MODEL.get(i).cleanup(); } } /** * Opens up a chat session with the selected hosts in the upload * window. */ void chatWithSelectedUploads() { int[] sel = TABLE.getSelectedRows(); for (int i =0; i<sel.length; i++) { DataLine dl = DATA_MODEL.get(sel[i]); Uploader uploader=(Uploader)dl.getInitializeObject(); if (uploader.isChatEnabled() ) { String host = uploader.getHost(); int port = uploader.getGnutellaPort(); RouterService.createChat(host, port); } } } /** * Browses all selected hosts (only once per host) * Moves display to the search window if a browse host was triggered */ void browseWithSelectedUploads() { boolean found = false; int[] sel = TABLE.getSelectedRows(); Set searched = new HashSet( sel.length ); for( int i = 0; i < sel.length; i++ ) { DataLine dl = DATA_MODEL.get(sel[i]); Uploader uploader=(Uploader)dl.getInitializeObject(); if ( uploader.isBrowseHostEnabled() ) { String host = uploader.getHost(); int port = uploader.getGnutellaPort(); if ( !searched.contains( host ) ) { SearchMediator.doBrowseHost( host, port, null ); searched.add( host ); found = true; } } } if ( found ) GUIMediator.instance().setWindow(GUIMediator.SEARCH_INDEX); } /** * Don't do anything on a double click. */ public void handleActionKey() { } /** * Clears the uploads in the upload window that have completed. */ void clearCompletedUploads() { ((UploadModel)DATA_MODEL).clearCompleted(); clearSelection(); setButtonEnabled(UploadButtons.CLEAR_BUTTON, false); } // inherit doc comment protected JPopupMenu createPopupMenu() { JPopupMenu menu = (new UploadPopupMenu(this)).getComponent(); menu.getComponent(UploadPopupMenu.KILL_INDEX). setEnabled(!TABLE.getSelectionModel().isSelectionEmpty()); menu.getComponent(UploadPopupMenu.CHAT_INDEX). setEnabled(_chatEnabled); menu.getComponent(UploadPopupMenu.BROWSE_INDEX). setEnabled(_browseEnabled); return menu; } /** * Handles the selection of the specified row in the download 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) { UploadDataLine dataLine = (UploadDataLine)DATA_MODEL.get(row); _chatEnabled = dataLine.isChatEnabled(); _browseEnabled = dataLine.isBrowseEnabled(); setButtonEnabled(UploadButtons.KILL_BUTTON, !TABLE.getSelectionModel().isSelectionEmpty()); setButtonEnabled(UploadButtons.BROWSE_BUTTON, _browseEnabled); } /** * Handles the deselection of all rows in the upload table, * disabling all necessary buttons and menu items. */ public void handleNoSelection() { _chatEnabled = false; _browseEnabled = false; setButtonEnabled(UploadButtons.KILL_BUTTON, false); setButtonEnabled(UploadButtons.BROWSE_BUTTON, false); } }