/* * Created on 2 juil. 2003 * * Copyright (C) 2004, 2005, 2006 Aelitis SAS, All rights Reserved * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details ( see the LICENSE file ). * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * AELITIS, SAS au capital de 46,603.30 euros, * 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France. */ package org.gudy.azureus2.ui.swt.views; import java.util.Map; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.MenuItem; import org.eclipse.swt.widgets.Shell; import org.gudy.azureus2.core3.config.COConfigurationManager; import org.gudy.azureus2.core3.disk.DiskManagerFileInfo; import org.gudy.azureus2.core3.download.DownloadManager; import org.gudy.azureus2.core3.download.DownloadManagerPeerListener; import org.gudy.azureus2.core3.global.GlobalManager; import org.gudy.azureus2.core3.internat.MessageText; import org.gudy.azureus2.core3.ipfilter.IpFilterManagerFactory; import org.gudy.azureus2.core3.peer.PEPeer; import org.gudy.azureus2.core3.peer.PEPeerManager; import org.gudy.azureus2.core3.util.Debug; import org.gudy.azureus2.core3.util.HashWrapper; import org.gudy.azureus2.core3.util.TorrentUtils; import org.gudy.azureus2.plugins.peers.Peer; import org.gudy.azureus2.plugins.ui.UIInputReceiver; import org.gudy.azureus2.plugins.ui.UIInputReceiverListener; import org.gudy.azureus2.plugins.ui.tables.TableManager; import org.gudy.azureus2.ui.swt.Messages; import org.gudy.azureus2.ui.swt.SimpleTextEntryWindow; import org.gudy.azureus2.ui.swt.Utils; import org.gudy.azureus2.ui.swt.plugins.UISWTInstance; import org.gudy.azureus2.ui.swt.plugins.UISWTViewEvent; import org.gudy.azureus2.ui.swt.pluginsimpl.UISWTViewEventImpl; import org.gudy.azureus2.ui.swt.views.peer.PeerFilesView; import org.gudy.azureus2.ui.swt.views.peer.PeerInfoView; import org.gudy.azureus2.ui.swt.views.peer.RemotePieceDistributionView; import org.gudy.azureus2.ui.swt.views.table.TableSelectedRowsListener; import org.gudy.azureus2.ui.swt.views.table.TableViewSWT; import org.gudy.azureus2.ui.swt.views.table.TableViewSWTMenuFillListener; import org.gudy.azureus2.ui.swt.views.table.impl.TableViewFactory; import org.gudy.azureus2.ui.swt.views.table.impl.TableViewTab; import org.gudy.azureus2.ui.swt.views.tableitems.peers.*; import com.aelitis.azureus.core.AzureusCoreFactory; import com.aelitis.azureus.core.networkmanager.NetworkManager; import com.aelitis.azureus.core.util.IdentityHashSet; import com.aelitis.azureus.ui.UIFunctions; import com.aelitis.azureus.ui.UIFunctionsManager; import com.aelitis.azureus.ui.common.ToolBarItem; import com.aelitis.azureus.ui.common.table.*; import com.aelitis.azureus.ui.common.table.impl.TableColumnManager; import com.aelitis.azureus.ui.selectedcontent.SelectedContent; import com.aelitis.azureus.ui.selectedcontent.SelectedContentManager; import com.aelitis.azureus.ui.swt.UIFunctionsManagerSWT; import com.aelitis.azureus.ui.swt.UIFunctionsSWT; /** * @author Olivier * @author TuxPaper * 2004/Apr/20: Use TableRowImpl instead of PeerRow * 2004/Apr/20: Remove need for tableItemToObject * 2004/Apr/21: extends TableView instead of IAbstractView * @author MjrTom * 2005/Oct/08: Add PieceItem */ public class PeersView extends TableViewTab<PEPeer> implements DownloadManagerPeerListener, TableDataSourceChangedListener, TableLifeCycleListener, TableViewSWTMenuFillListener { static TableColumnCore[] getBasicColumnItems(String table_id) { return new TableColumnCore[] { new IpItem(table_id), new ClientItem(table_id), new TypeItem(table_id), new MessagingItem(table_id), new EncryptionItem(table_id), new ProtocolItem(table_id), new PiecesItem(table_id), new PercentItem(table_id), new DownSpeedItem(table_id), new UpSpeedItem(table_id), new PeerSourceItem(table_id), new HostNameItem(table_id), new PortItem(table_id), new InterestedItem(table_id), new ChokedItem(table_id), new DownItem(table_id), new InterestingItem(table_id), new ChokingItem(table_id), new OptimisticUnchokeItem(table_id), new UpItem(table_id), new UpDownRatioItem(table_id), new GainItem(table_id), new StatUpItem(table_id), new SnubbedItem(table_id), new TotalDownSpeedItem(table_id), new TimeUntilCompleteItem(table_id), new DiscardedItem(table_id), new UniquePieceItem(table_id), new TimeToSendPieceItem(table_id), new DLedFromOthersItem(table_id), new UpRatioItem(table_id), new StateItem(table_id), new ConnectedTimeItem(table_id), new PieceItem(table_id), new IncomingRequestCountItem(table_id), new OutgoingRequestCountItem(table_id), new UpSpeedLimitItem(table_id), new DownSpeedLimitItem(table_id), new LANItem(table_id), new PeerIDItem(table_id), new PeerByteIDItem(table_id), new HandshakeReservedBytesItem(table_id), new ClientIdentificationItem(table_id), new ASItem(table_id), }; } private static final TableColumnCore[] basicItems = getBasicColumnItems(TableManager.TABLE_TORRENT_PEERS); static{ TableColumnManager tcManager = TableColumnManager.getInstance(); tcManager.setDefaultColumnNames( TableManager.TABLE_TORRENT_PEERS, basicItems ); } public static final String MSGID_PREFIX = "PeersView"; private DownloadManager manager; private TableViewSWT<PEPeer> tv; private Shell shell; private boolean enable_tabs = true; private static boolean registeredCoreSubViews = false; private boolean comp_focused; private Object focus_pending_ds; private PEPeer select_peer_pending; /** * Initialize * */ public PeersView() { super(MSGID_PREFIX); } // @see org.gudy.azureus2.ui.swt.views.table.impl.TableViewTab#initYourTableView() public TableViewSWT<PEPeer> initYourTableView() { tv = TableViewFactory.createTableViewSWT(Peer.class, TableManager.TABLE_TORRENT_PEERS, getPropertiesPrefix(), basicItems, "pieces", SWT.MULTI | SWT.FULL_SELECTION | SWT.VIRTUAL); tv.setRowDefaultHeight(16); tv.setEnableTabViews(enable_tabs,true,null); UIFunctionsSWT uiFunctions = UIFunctionsManagerSWT.getUIFunctionsSWT(); if (uiFunctions != null) { UISWTInstance pluginUI = uiFunctions.getUISWTInstance(); if (pluginUI != null && !registeredCoreSubViews) { pluginUI.addView(TableManager.TABLE_TORRENT_PEERS, "PeerInfoView", PeerInfoView.class, null); pluginUI.addView(TableManager.TABLE_TORRENT_PEERS, "RemotePieceDistributionView", RemotePieceDistributionView.class, null); pluginUI.addView(TableManager.TABLE_TORRENT_PEERS, "PeerFilesView", PeerFilesView.class, null); pluginUI.addView(TableManager.TABLE_TORRENT_PEERS, "LoggerView", LoggerView.class, true); registeredCoreSubViews = true; } } tv.addTableDataSourceChangedListener(this, true); tv.addLifeCycleListener(this); tv.addMenuFillListener(this); return tv; } private void setFocused( boolean foc ) { if ( foc ){ comp_focused = true; dataSourceChanged( focus_pending_ds ); }else{ focus_pending_ds = manager; dataSourceChanged( null ); comp_focused = false; } } public void tableDataSourceChanged(Object newDataSource) { if ( !comp_focused ){ focus_pending_ds = newDataSource; return; } DownloadManager old_manager = manager; if (newDataSource == null){ manager = null; }else if (newDataSource instanceof Object[]){ Object temp = ((Object[])newDataSource)[0]; if ( temp instanceof DownloadManager ){ manager = (DownloadManager)temp; }else if ( temp instanceof DiskManagerFileInfo){ manager = ((DiskManagerFileInfo)temp).getDownloadManager(); }else{ return; } }else{ if ( newDataSource instanceof DownloadManager ){ manager = (DownloadManager)newDataSource; }else if ( newDataSource instanceof DiskManagerFileInfo){ manager = ((DiskManagerFileInfo)newDataSource).getDownloadManager(); }else{ return; } } if ( old_manager == manager ){ return; } if (old_manager != null){ old_manager.removePeerListener(this); } if ( !tv.isDisposed()){ tv.removeAllTableRows(); if (manager != null ){ manager.addPeerListener(this, false); addExistingDatasources(); } } } // @see com.aelitis.azureus.ui.common.table.TableLifeCycleListener#tableViewInitialized() public void tableViewInitialized() { shell = tv.getComposite().getShell(); if (manager != null) { manager.removePeerListener(this); manager.addPeerListener(this, false); } addExistingDatasources(); } public void tableViewDestroyed() { if (manager != null) { manager.removePeerListener(this); } select_peer_pending = null; } public void fillMenu(String sColumnName, Menu menu) {fillMenu(menu, tv, shell, manager);} public static void fillMenu( final Menu menu, final TableView<?> tv, final Shell shell, DownloadManager download_specific ) { Object[] peers = tv.getSelectedDataSources().toArray(); boolean hasSelection = (peers.length > 0); boolean downSpeedDisabled = false; boolean downSpeedUnlimited = false; long totalDownSpeed = 0; long downSpeedSetMax = 0; long maxDown = 0; boolean upSpeedDisabled = false; boolean upSpeedUnlimited = false; long totalUpSpeed = 0; long upSpeedSetMax = 0; long maxUp = 0; GlobalManager gm = AzureusCoreFactory.getSingleton().getGlobalManager(); final IdentityHashSet<DownloadManager> download_managers = new IdentityHashSet<DownloadManager>(); if ( hasSelection ){ for (int i = 0; i < peers.length; i++) { PEPeer peer = (PEPeer)peers[i]; PEPeerManager m = peer.getManager(); if ( m != null ){ if ( gm != null ){ DownloadManager dm = gm.getDownloadManager( new HashWrapper( m.getHash())); if ( dm != null ){ download_managers.add( dm ); } } } try { int maxul = peer.getStats().getUploadRateLimitBytesPerSecond(); maxUp += maxul * 4; if (maxul == 0) { upSpeedUnlimited = true; }else{ if ( maxul > upSpeedSetMax ){ upSpeedSetMax = maxul; } } if (maxul == -1) { maxul = 0; upSpeedDisabled = true; } totalUpSpeed += maxul; int maxdl = peer.getStats().getDownloadRateLimitBytesPerSecond(); maxDown += maxdl * 4; if (maxdl == 0) { downSpeedUnlimited = true; }else{ if ( maxdl > downSpeedSetMax ){ downSpeedSetMax = maxdl; } } if (maxdl == -1) { maxdl = 0; downSpeedDisabled = true; } totalDownSpeed += maxdl; } catch (Exception ex) { Debug.printStackTrace(ex); } } } if (download_specific != null) { final MenuItem block_item = new MenuItem(menu, SWT.CHECK); PEPeer peer = (PEPeer) tv.getFirstSelectedDataSource(); if ( peer == null || peer.getManager().getDiskManager().getRemainingExcludingDND() > 0 ){ // disallow peer upload blocking when downloading block_item.setSelection(false); block_item.setEnabled(false); } else { block_item.setEnabled(true); block_item.setSelection(peer.isSnubbed()); } if (peer != null) { final boolean newSnubbedValue = !peer.isSnubbed(); Messages.setLanguageText(block_item, "PeersView.menu.blockupload"); block_item.addListener(SWT.Selection, new TableSelectedRowsListener(tv) { public void run(TableRowCore row) { PEPeer peer = ((PEPeer) row.getDataSource(true)); peer.setSnubbed(newSnubbedValue); } }); } }else{ if ( download_managers.size() > 0 ){ MenuItem itemDetails = new MenuItem(menu, SWT.PUSH); Messages.setLanguageText(itemDetails, "PeersView.menu.showdownload"); Utils.setMenuItemImage(itemDetails, "details"); itemDetails.addListener( SWT.Selection, new Listener() { public void handleEvent( Event event) { UIFunctions uiFunctions = UIFunctionsManager.getUIFunctions(); if (uiFunctions != null) { for ( DownloadManager dm: download_managers ){ uiFunctions.openView(UIFunctions.VIEW_DM_DETAILS, dm); } } } }); new MenuItem(menu, SWT.SEPARATOR); } } final MenuItem ban_item = new MenuItem(menu, SWT.PUSH); Messages.setLanguageText(ban_item, "PeersView.menu.kickandban"); ban_item.addListener(SWT.Selection, new TableSelectedRowsListener(tv) { public void run(TableRowCore row) { PEPeer peer = (PEPeer) row.getDataSource(true); String msg = MessageText.getString("PeersView.menu.kickandban.reason"); IpFilterManagerFactory.getSingleton().getIPFilter().ban(peer.getIp(), msg, true ); peer.getManager().removePeer(peer); } }); // === advanced menu === final MenuItem itemAdvanced = new MenuItem(menu, SWT.CASCADE); Messages.setLanguageText(itemAdvanced, "MyTorrentsView.menu.advancedmenu"); itemAdvanced.setEnabled(hasSelection); final Menu menuAdvanced = new Menu(shell, SWT.DROP_DOWN); itemAdvanced.setMenu(menuAdvanced); // advanced > Download Speed Menu // ViewUtils.addSpeedMenu( shell, menuAdvanced, true, true, false, hasSelection, downSpeedDisabled, downSpeedUnlimited, totalDownSpeed, downSpeedSetMax, maxDown, upSpeedDisabled, upSpeedUnlimited, totalUpSpeed, upSpeedSetMax, maxUp, peers.length, new ViewUtils.SpeedAdapter() { public void setDownSpeed( int speed ) { setSelectedPeersDownSpeed( speed, tv ); } public void setUpSpeed( int speed ) { setSelectedPeersUpSpeed( speed, tv ); } }); addPeersMenu( download_specific, menu ); new MenuItem (menu, SWT.SEPARATOR); } public void addThisColumnSubMenu(String columnName, Menu menuThisColumn) { if ( addPeersMenu( manager, menuThisColumn )){ new MenuItem( menuThisColumn, SWT.SEPARATOR ); } } private static boolean addPeersMenu( final DownloadManager man, Menu menu ) { if ( man == null ){ return( false ); } PEPeerManager pm = man.getPeerManager(); if ( pm == null ){ return( false ); } if ( TorrentUtils.isReallyPrivate(man.getTorrent())){ return( false ); } new MenuItem( menu, SWT.SEPARATOR); MenuItem add_peers_item = new MenuItem( menu, SWT.PUSH ); Messages.setLanguageText( add_peers_item, "menu.add.peers"); add_peers_item.addListener( SWT.Selection, new Listener() { public void handleEvent( Event event) { SimpleTextEntryWindow entryWindow = new SimpleTextEntryWindow( "dialog.add.peers.title", "dialog.add.peers.msg"); String def = COConfigurationManager.getStringParameter( "add.peers.default", "" ); entryWindow.setPreenteredText( String.valueOf( def ), false ); entryWindow.prompt( new UIInputReceiverListener() { public void UIInputReceiverClosed( UIInputReceiver entryWindow) { if ( !entryWindow.hasSubmittedInput()){ return; } String sReturn = entryWindow.getSubmittedInput(); if ( sReturn == null ){ return; } COConfigurationManager.setParameter( "add.peers.default", sReturn ); PEPeerManager pm = man.getPeerManager(); if ( pm == null ){ return; } String[] bits = sReturn.split( "," ); for ( String bit: bits ){ bit = bit.trim(); int pos = bit.lastIndexOf( ':' ); if ( pos != -1 ){ String host = bit.substring( 0, pos ).trim(); String port = bit.substring( pos+1 ).trim(); try{ int i_port = Integer.parseInt( port ); pm.addPeer( host, i_port, 0, NetworkManager.getCryptoRequired( NetworkManager.CRYPTO_OVERRIDE_NONE ), null ); }catch( Throwable e ){ } } } } }); } }); return( true ); } private static void setSelectedPeersUpSpeed(int speed, TableView<?> tv) { Object[] peers = tv.getSelectedDataSources().toArray(); if(peers.length > 0) { for (int i = 0; i < peers.length; i++) { try { PEPeer peer = (PEPeer)peers[i]; peer.getStats().setUploadRateLimitBytesPerSecond(speed); } catch (Exception e) { Debug.printStackTrace( e ); } } } } private static void setSelectedPeersDownSpeed(int speed, TableView<?> tv) { Object[] peers = tv.getSelectedDataSources().toArray(); if(peers.length > 0) { for (int i = 0; i < peers.length; i++) { try { PEPeer peer = (PEPeer)peers[i]; peer.getStats().setDownloadRateLimitBytesPerSecond(speed); } catch (Exception e) { Debug.printStackTrace( e ); } } } } /* DownloadManagerPeerListener implementation */ public void peerAdded(PEPeer created) { tv.addDataSource(created); } public void peerRemoved(PEPeer removed) { tv.removeDataSource(removed); } public void selectPeer( PEPeer peer ) { showPeer( peer, 0 ); } private void showPeer( final PEPeer peer, final int attempt ) { if ( attempt > 10 ){ return; } // need to insert an async here as if we are in the process of switching to this view the // selection sometimes get lost. grrr // also, due to the way things work, as the table is building it is possible to select the entry // only to have the selection get lost due to the table re-calculating stuff, so we keep trying for // a while until we get an affirmation that it really is visible Utils.execSWTThreadLater( attempt==0?1:10, new Runnable() { public void run() { TableRowCore row = tv.getRow( peer ); if ( row == null ){ if ( attempt == 0 ){ select_peer_pending = peer; return; } }else{ tv.setSelectedRows( new TableRowCore[]{ row } ); tv.showRow( row ); if ( row.isVisible()){ return; } } showPeer( peer, attempt+1 ); } }); } public void peerManagerWillBeAdded( PEPeerManager peer_manager ){} public void peerManagerAdded(PEPeerManager manager) { } public void peerManagerRemoved(PEPeerManager manager) { tv.removeAllTableRows(); } /** * Add datasources already in existance before we called addListener. * Faster than allowing addListener to call us one datasource at a time. */ private void addExistingDatasources() { if (manager == null || tv.isDisposed()) { return; } PEPeer[] dataSources = manager.getCurrentPeers(); if (dataSources != null && dataSources.length > 0) { tv.addDataSources(dataSources); tv.processDataSourceQueue(); } if ( select_peer_pending != null ){ showPeer( select_peer_pending, 1 ); select_peer_pending = null; } } public boolean eventOccurred(UISWTViewEvent event) { switch (event.getType()) { case UISWTViewEvent.TYPE_CREATE:{ if ( event instanceof UISWTViewEventImpl ){ String parent = ((UISWTViewEventImpl)event).getParentID(); enable_tabs = parent != null && parent.equals( UISWTInstance.VIEW_TORRENT_DETAILS ); } break; } case UISWTViewEvent.TYPE_FOCUSGAINED: String id = "DMDetails_Peers"; setFocused( true ); // do this here to pick up corrent manager before rest of code if (manager != null) { if (manager.getTorrent() != null) { id += "." + manager.getInternalName(); } else { id += ":" + manager.getSize(); } } SelectedContentManager.changeCurrentlySelectedContent(id, new SelectedContent[] { new SelectedContent(manager) }); break; case UISWTViewEvent.TYPE_FOCUSLOST: setFocused( false ); break; } return( super.eventOccurred(event)); } public boolean toolBarItemActivated(ToolBarItem item, long activationType, Object datasource) { if ( ViewUtils.toolBarItemActivated(manager, item, activationType, datasource)){ return( true ); } return( super.toolBarItemActivated(item, activationType, datasource)); } public void refreshToolBarItems(Map<String, Long> list) { ViewUtils.refreshToolBarItems(manager, list); super.refreshToolBarItems(list); } }