1 /*
2  * Created on 30 juin 2003
3  *
4  * Copyright (C) Azureus Software, Inc, All Rights Reserved.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details ( see the LICENSE file ).
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 
21 package org.gudy.azureus2.ui.swt.views;
22 
23 import java.io.File;
24 import java.net.URL;
25 import java.util.*;
26 import java.util.List;
27 import java.util.regex.Pattern;
28 
29 import org.eclipse.swt.SWT;
30 import org.eclipse.swt.dnd.*;
31 import org.eclipse.swt.events.*;
32 import org.eclipse.swt.graphics.*;
33 import org.eclipse.swt.layout.GridData;
34 import org.eclipse.swt.layout.GridLayout;
35 import org.eclipse.swt.layout.RowData;
36 import org.eclipse.swt.layout.RowLayout;
37 import org.eclipse.swt.widgets.*;
38 import org.gudy.azureus2.core3.category.Category;
39 import org.gudy.azureus2.core3.category.CategoryManager;
40 import org.gudy.azureus2.core3.config.COConfigurationManager;
41 import org.gudy.azureus2.core3.config.ParameterListener;
42 import org.gudy.azureus2.core3.disk.DiskManagerFileInfo;
43 import org.gudy.azureus2.core3.disk.DiskManagerFileInfoSet;
44 import org.gudy.azureus2.core3.download.DownloadManager;
45 import org.gudy.azureus2.core3.download.DownloadManagerListener;
46 import org.gudy.azureus2.core3.download.DownloadManagerState;
47 import org.gudy.azureus2.core3.download.DownloadManagerStats;
48 import org.gudy.azureus2.core3.global.GlobalManager;
49 import org.gudy.azureus2.core3.global.GlobalManagerEvent;
50 import org.gudy.azureus2.core3.global.GlobalManagerEventListener;
51 import org.gudy.azureus2.core3.global.GlobalManagerListener;
52 import org.gudy.azureus2.core3.internat.MessageText;
53 import org.gudy.azureus2.core3.logging.LogEvent;
54 import org.gudy.azureus2.core3.logging.LogIDs;
55 import org.gudy.azureus2.core3.logging.Logger;
56 import org.gudy.azureus2.core3.torrent.TOTorrent;
57 import org.gudy.azureus2.core3.torrent.TOTorrentAnnounceURLSet;
58 import org.gudy.azureus2.core3.torrent.TOTorrentException;
59 import org.gudy.azureus2.core3.util.*;
60 import org.gudy.azureus2.plugins.PluginInterface;
61 import org.gudy.azureus2.plugins.PluginManager;
62 import org.gudy.azureus2.plugins.download.Download;
63 import org.gudy.azureus2.plugins.download.DownloadTypeComplete;
64 import org.gudy.azureus2.plugins.download.DownloadTypeIncomplete;
65 import org.gudy.azureus2.plugins.ui.UIPluginViewToolBarListener;
66 import org.gudy.azureus2.plugins.ui.tables.TableManager;
67 import org.gudy.azureus2.plugins.ui.tables.TableRow;
68 import org.gudy.azureus2.plugins.ui.tables.TableRowRefreshListener;
69 import org.gudy.azureus2.plugins.ui.toolbar.UIToolBarActivationListener;
70 import org.gudy.azureus2.ui.swt.*;
71 import org.gudy.azureus2.ui.swt.URLTransfer;
72 import org.gudy.azureus2.ui.swt.components.CompositeMinSize;
73 import org.gudy.azureus2.ui.swt.help.HealthHelpWindow;
74 import org.gudy.azureus2.ui.swt.mainwindow.TorrentOpener;
75 import org.gudy.azureus2.ui.swt.minibar.DownloadBar;
76 import org.gudy.azureus2.ui.swt.plugins.UISWTInstance;
77 import org.gudy.azureus2.ui.swt.plugins.UISWTViewEvent;
78 import org.gudy.azureus2.ui.swt.pluginsimpl.UISWTViewCore;
79 import org.gudy.azureus2.ui.swt.views.piece.PieceInfoView;
80 import org.gudy.azureus2.ui.swt.views.table.TableViewSWT;
81 import org.gudy.azureus2.ui.swt.views.table.TableViewSWTMenuFillListener;
82 import org.gudy.azureus2.ui.swt.views.table.TableViewSWTPanelCreator;
83 import org.gudy.azureus2.ui.swt.views.table.impl.TableViewFactory;
84 import org.gudy.azureus2.ui.swt.views.table.impl.TableViewSWT_TabsCommon;
85 import org.gudy.azureus2.ui.swt.views.table.impl.TableViewTab;
86 import org.gudy.azureus2.ui.swt.views.table.painted.TableRowPainted;
87 import org.gudy.azureus2.ui.swt.views.utils.CategoryUIUtils;
88 import org.gudy.azureus2.ui.swt.views.utils.ManagerUtils;
89 import org.gudy.azureus2.ui.swt.views.utils.TagUIUtils;
90 
91 import com.aelitis.azureus.core.AzureusCore;
92 import com.aelitis.azureus.core.AzureusCoreFactory;
93 import com.aelitis.azureus.core.tag.*;
94 import com.aelitis.azureus.core.util.RegExUtil;
95 import com.aelitis.azureus.ui.UIFunctions;
96 import com.aelitis.azureus.ui.UIFunctionsManager;
97 import com.aelitis.azureus.ui.common.ToolBarItem;
98 import com.aelitis.azureus.ui.common.table.*;
99 import com.aelitis.azureus.ui.common.table.impl.TableViewImpl;
100 import com.aelitis.azureus.ui.mdi.MultipleDocumentInterface;
101 import com.aelitis.azureus.ui.selectedcontent.ISelectedContent;
102 import com.aelitis.azureus.ui.selectedcontent.SelectedContent;
103 import com.aelitis.azureus.ui.selectedcontent.SelectedContentManager;
104 import com.aelitis.azureus.ui.swt.UIFunctionsManagerSWT;
105 import com.aelitis.azureus.ui.swt.UIFunctionsSWT;
106 import com.aelitis.azureus.ui.swt.mdi.MdiEntrySWT;
107 
108 /** Displays a list of torrents in a table view.
109  *
110  * @author Olivier
111  * @author TuxPaper
112  *         2004/Apr/18: Use TableRowImpl instead of PeerRow
113  *         2004/Apr/20: Remove need for tableItemToObject
114  *         2004/Apr/21: extends TableView instead of IAbstractView
115  *         2005/Oct/01: Column moving in SWT >= 3.1
116  */
117 public class MyTorrentsView
118        extends TableViewTab<DownloadManager>
119        implements GlobalManagerListener,
120                   ParameterListener,
121                   DownloadManagerListener,
122                   TagTypeListener,
123                   TagListener,
124                   KeyListener,
125                   TableLifeCycleListener,
126                   TableViewSWTPanelCreator,
127                   TableSelectionListener,
128                   TableViewSWTMenuFillListener,
129                   TableRefreshListener,
130                   TableViewFilterCheck.TableViewFilterCheckEx<DownloadManager>,
131                   TableRowRefreshListener,
132                   TableCountChangeListener,
133                   TableExpansionChangeListener,
134                   UIPluginViewToolBarListener
135 {
136 	private static final LogIDs LOGID = LogIDs.GUI;
137 
138 	public static volatile Set<String>	preferred_tracker_names;
139 	public static volatile boolean		eta_absolute;
140 	public static volatile boolean		progress_eta_absolute;
141 
142 	static{
COConfigurationManager.addAndFireParameterListeners( new String[]{ R, R, R, }, new ParameterListener() { public void parameterChanged( String name ) { String prefs = COConfigurationManager.getStringParameter( R, null ); Set<String> new_vals = new HashSet<String>(); if ( prefs != null ){ String[] bits = prefs.split( R ); for ( String s: bits ){ s = s.trim(); if ( s.length() > 0 ){ new_vals.add( s ); } } } preferred_tracker_names = new_vals; eta_absolute = COConfigurationManager.getBooleanParameter( R, false ); progress_eta_absolute = COConfigurationManager.getBooleanParameter( R, false ); } })143 		COConfigurationManager.addAndFireParameterListeners(
144 			new String[]{
145 				"mtv.trackername.pref.hosts",
146 				"mtv.eta.show_absolute",
147 				"mtv.progress_eta.show_absolute",
148 			},
149 			new ParameterListener()
150 			{
151 				public void
152 				parameterChanged(
153 					String name )
154 				{
155 					String prefs = COConfigurationManager.getStringParameter( "mtv.trackername.pref.hosts", null );
156 
157 					Set<String>	new_vals = new HashSet<String>();
158 
159 					if ( prefs != null ){
160 
161 						String[] bits = prefs.split( ";" );
162 
163 						for ( String s: bits ){
164 
165 							s = s.trim();
166 
167 							if ( s.length() > 0 ){
168 
169 								new_vals.add( s );
170 							}
171 						}
172 					}
173 
174 					preferred_tracker_names = new_vals;
175 
176 					eta_absolute			= COConfigurationManager.getBooleanParameter( "mtv.eta.show_absolute", false );
177 					progress_eta_absolute	= COConfigurationManager.getBooleanParameter( "mtv.progress_eta.show_absolute", false );
178 				}
179 			});
180 	}
181 
182 	private AzureusCore		azureus_core;
183 
184   private GlobalManager globalManager;
185 
186   	// keep this listener separate class as there is confusion within the globalmanager
187   	// if the same instance is registered as both a GlobalManagerListener and a GlobalManagerEventListener
188   	// yes, I know
189 
190   private GlobalManagerEventListener gm_event_listener =
191 	  new GlobalManagerEventListener()
192   	{
193 		public void
194 		eventOccurred(
195 			GlobalManagerEvent event )
196 		{
197 			if ( event.getEventType() == GlobalManagerEvent.ET_REQUEST_ATTENTION ){
198 
199 				DownloadManager dm = event.getDownload();
200 
201 				if ( isOurDownloadManager( dm )){
202 
203 					TableRowCore row = tv.getRow( dm );
204 
205 					if ( row != null ){
206 
207 						TableRowCore[] existing = tv.getSelectedRows();
208 
209 						if ( existing != null ){
210 
211 							for ( TableRowCore e: existing ){
212 
213 								if ( e != row ){
214 
215 									e.setSelected( false );
216 								}
217 							}
218 						}
219 
220 						if ( !row.isSelected()){
221 
222 							row.setSelected( true );
223 						}
224 
225 					}
226 				}
227 			}
228 		}
229   	};
230 
231   private boolean	supportsTabs;
232   private Composite cTablePanel;
233   private Font fontButton = null;
234   protected Composite cCategoriesAndTags;
235   private DragSource dragSource = null;
236   private DropTarget dropTarget = null;
237   protected Text txtFilter = null;
238   private Menu	tableHeaderMenu = null;
239   private TimerEventPeriodic	txtFilterUpdateEvent;
240 
241 
242   private Tag[]		currentTags;
243   private List<Tag>	allTags;
244 
245   // table item index, where the drag has started
246   private int drag_drop_line_start = -1;
247   private TableRowCore[] drag_drop_rows = null;
248 
249 	private boolean bDNDalwaysIncomplete;
250 	private TableViewSWT<DownloadManager> tv;
251 	private Composite cTableParentPanel;
252 	protected boolean viewActive;
253 	private TableSelectionListener defaultSelectedListener;
254 
255 	private Composite filterParent;
256 
257 	protected boolean neverShowCatOrTagButtons;
258 
259 	private boolean rebuildListOnFocusGain = false;
260 
261 	private Menu oldMenu;
262 
263 	private boolean isCompletedOnly;
264 
265 	private Class<?> forDataSourceType;
266 
267 	private SelectionListener buttonSelectionListener;
268 
269 	private Listener buttonHoverListener;
270 
271 	private DropTargetListener buttonDropTargetListener;
272 
273 	protected boolean isEmptyListOnNullDS;
274 
MyTorrentsView( boolean supportsTabs )275 	public MyTorrentsView( boolean supportsTabs ) {
276 		super("MyTorrentsView");
277 		this.supportsTabs = supportsTabs;
278 	}
279 
MyTorrentsView(String propertiesPrefix, boolean supportsTabs)280 	public MyTorrentsView(String propertiesPrefix, boolean supportsTabs) {
281 		super(propertiesPrefix);
282 		this.supportsTabs = supportsTabs;
283 	}
284 
285   /**
286    * Initialize
287    *
288    * @param _azureus_core
289    * @param isSeedingView
290    * @param basicItems
291    * @param cCats
292    */
293   public
MyTorrentsView( AzureusCore _azureus_core, String tableID, boolean isSeedingView, TableColumnCore[] basicItems, Text txtFilter, Composite cCatsAndTags, boolean supportsTabs )294   MyTorrentsView(
295   		AzureusCore			_azureus_core,
296   		String				tableID,
297   		boolean 			isSeedingView,
298   		TableColumnCore[]	basicItems,
299   		Text 				txtFilter,
300   		Composite 			cCatsAndTags,
301   		boolean				supportsTabs )
302   {
303 		super("MyTorrentsView");
304 		this.txtFilter = txtFilter;
305 		this.cCategoriesAndTags = cCatsAndTags;
306 		this.supportsTabs = supportsTabs;
307 		init(_azureus_core, tableID, isSeedingView
308 				? DownloadTypeComplete.class : DownloadTypeIncomplete.class, basicItems);
309   }
310 
311   // @see org.gudy.azureus2.ui.swt.views.table.impl.TableViewTab#initYourTableView()
initYourTableView()312   public TableViewSWT<DownloadManager> initYourTableView() {
313   	return tv;
314   }
315 
316   // @see org.gudy.azureus2.ui.swt.views.table.impl.TableViewTab#tableViewTabInitComplete()
tableViewTabInitComplete()317   public void tableViewTabInitComplete() {
318   	if (COConfigurationManager.getBooleanParameter("Library.showFancyMenu", true)) {
319     	Composite tableComposite = tv.getComposite();
320     	oldMenu = tableComposite.getMenu();
321     	Menu menu = new Menu(tableComposite);
322     	tableComposite.setMenu(menu);
323     	menu.addMenuListener(new MenuListener() {
324 
325   			public void menuShown(MenuEvent e) {
326   				if (!showMyOwnMenu(e)) {
327   					oldMenu.setVisible(true);
328   				}
329   			}
330 
331   			public void menuHidden(MenuEvent e) {
332   			}
333   		});
334   	}
335   	super.tableViewTabInitComplete();
336   }
337 
showMyOwnMenu(MenuEvent e)338 	protected boolean showMyOwnMenu(MenuEvent e) {
339 		Display d = e.widget.getDisplay();
340 		if (d == null)
341 			return false;
342 
343 		Object[] dataSources = tv.getSelectedDataSources(true);
344 		final DownloadManager[] dms = getSelectedDownloads();
345 
346 		boolean hasSelection = (dms.length > 0);
347 
348 		if (!hasSelection) {
349 			return false;
350 		}
351 		Point pt = e.display.getCursorLocation();
352 		pt = tv.getTableComposite().toControl(pt.x, pt.y);
353 		TableColumnCore column = tv.getTableColumnByOffset(pt.x);
354 
355 		boolean isSeedingView = Download.class.equals(forDataSourceType) || DownloadTypeComplete.class.equals(forDataSourceType);
356 		new TorrentMenuFancy(tv, isSeedingView, getComposite().getShell(), dms,
357 				tv.getTableID()).showMenu(column, oldMenu);
358 		return true;
359 	}
360 
init(AzureusCore _azureus_core, String tableID, Class<?> forDataSourceType, TableColumnCore[] basicItems)361 	public void init(AzureusCore _azureus_core, String tableID,
362 			Class<?> forDataSourceType, TableColumnCore[] basicItems) {
363 
364 		this.forDataSourceType = forDataSourceType;
365 		this.isCompletedOnly = forDataSourceType.equals(DownloadTypeComplete.class);
366 
367     tv = createTableView(forDataSourceType, tableID, basicItems);
368 
369     /*
370      * 'Big' table has taller row height
371      */
372     if (getRowDefaultHeight() > 0) {
373 			tv.setRowDefaultHeightPX(getRowDefaultHeight());
374 		} else {
375 	    tv.setRowDefaultHeightEM(1);
376 		}
377 
378     azureus_core		= _azureus_core;
379     this.globalManager 	= azureus_core.getGlobalManager();
380 
381 
382     if (currentTags == null) {
383 			currentTags = new Tag[] {
384 				CategoryManager.getCategory(Category.TYPE_ALL)
385 			};
386     }
387     tv.addLifeCycleListener(this);
388     tv.setMainPanelCreator(this);
389     tv.addSelectionListener(this, false);
390     tv.addMenuFillListener(this);
391     tv.addRefreshListener(this, false);
392     if (tv.canHaveSubItems()) {
393     	tv.addRefreshListener(this);
394     	tv.addCountChangeListener(this);
395     	tv.addExpansionChangeListener(this);
396     }
397 
398     tv.addTableDataSourceChangedListener(new TableDataSourceChangedListener() {
399 			public void tableDataSourceChanged(Object newDataSource) {
400 				if (newDataSource instanceof Tag[]) {
401 					neverShowCatOrTagButtons = true;
402 					setCurrentTags((Tag[]) newDataSource);
403 					return;
404 				}
405 
406 				if (newDataSource instanceof Object[]) {
407 					Object[] datasources = ((Object[]) newDataSource);
408 					Object firstDS = datasources.length > 0 ? datasources[0] : null;
409 					if (firstDS instanceof Tag) {
410 						Tag[] tags = new Tag[datasources.length];
411 						System.arraycopy(datasources, 0, tags, 0, datasources.length);
412 						setCurrentTags(tags);
413 						return;
414 					}
415 				}
416 
417 				if ( newDataSource instanceof Tag ){
418 					neverShowCatOrTagButtons = true;
419 					setCurrentTags(new Tag[] {
420 						(Tag) newDataSource
421 					});
422 				}
423 
424 				if (newDataSource == null && isEmptyListOnNullDS) {
425 					setCurrentTags(new Tag[] { });
426 				}
427 			}
428 		}, true);
429 
430 		if (txtFilter != null) {
431 			filterParent = txtFilter.getParent();
432 			if (Constants.isWindows) {
433 				// dirty hack because window's filter box is within a bubble of it's own
434 				filterParent = filterParent.getParent();
435 			}
436 
437 			Menu menuFilterHeader = getHeaderMenu(txtFilter);
438 			filterParent.setMenu( menuFilterHeader );
439 			Control[] children = filterParent.getChildren();
440 			for (Control control : children) {
441 				if (control != txtFilter) {
442 					control.setMenu(menuFilterHeader);
443 				}
444 			}
445 		}
446 	}
447 
448   // @see com.aelitis.azureus.ui.common.table.TableLifeCycleListener#tableViewInitialized()
tableViewInitialized()449   public void tableViewInitialized() {
450   	tv.addKeyListener(this);
451 
452     createTabs();
453 
454     if (txtFilter == null) {
455     	tv.enableFilterCheck(null, this);
456     }
457 
458     createDragDrop();
459 
460     Utils.getOffOfSWTThread(new AERunnable() {
461 
462 			public void runSupport() {
463 		    COConfigurationManager.addAndFireParameterListeners(new String[] {
464 					"DND Always In Incomplete",
465 					"User Mode",
466 					"Library.ShowCatButtons", "Library.ShowTagButtons", "Library.ShowTagButtons.CompOnly",
467 				}, MyTorrentsView.this);
468 
469 
470 		    if ( currentTags != null ){
471 		    	for (Tag tag : currentTags) {
472 		    		tag.addTagListener(MyTorrentsView.this, false);
473 					}
474 		    }
475 		    TagManager tagManager = TagManagerFactory.getTagManager();
476 		    TagType ttManual = tagManager.getTagType(TagType.TT_DOWNLOAD_MANUAL);
477 		    TagType ttCat = tagManager.getTagType(TagType.TT_DOWNLOAD_CATEGORY);
478 		    ttManual.addTagTypeListener(MyTorrentsView.this, false);
479 		    ttCat.addTagTypeListener(MyTorrentsView.this, false);
480 
481 		    globalManager.addListener(MyTorrentsView.this, false);
482 		    globalManager.addEventListener( gm_event_listener );
483 		    DownloadManager[] dms = globalManager.getDownloadManagers().toArray(new DownloadManager[0]);
484 		    for (int i = 0; i < dms.length; i++) {
485 					DownloadManager dm = dms[i];
486 					dm.addListener(MyTorrentsView.this);
487 					if (!isOurDownloadManager(dm)) {
488 						dms[i] = null;
489 					}
490 				}
491 		    tv.addDataSources(dms);
492 		    tv.processDataSourceQueue();
493 			}
494 		});
495 
496     cTablePanel.layout();
497   }
498 
499   private Menu
getHeaderMenu( Control control )500   getHeaderMenu(
501 		Control		control )
502   {
503 	  if ( tableHeaderMenu != null ){
504 
505 		  return( tableHeaderMenu );
506 	  }
507 
508 	  tableHeaderMenu = new Menu(control.getShell(), SWT.POP_UP );
509 
510 	  // show uptime
511 
512 	  final MenuItem menuItemShowUptime = new MenuItem(tableHeaderMenu, SWT.CHECK);
513 	  Messages.setLanguageText( menuItemShowUptime, "ConfigView.label.showuptime" );
514 
515 	  menuItemShowUptime.addSelectionListener(new SelectionAdapter() {
516 		  public void widgetSelected(SelectionEvent e) {
517 			  COConfigurationManager.setParameter(
518 					  "MyTorrentsView.showuptime", menuItemShowUptime.getSelection());
519 		  }
520 	  });
521 
522 	  // selected download rates
523 
524 	  final MenuItem menuItemShowRates = new MenuItem(tableHeaderMenu, SWT.CHECK);
525 	  Messages.setLanguageText( menuItemShowRates, "label.show.selected.rates" );
526 
527 	  menuItemShowRates.addSelectionListener(new SelectionAdapter() {
528 		  public void widgetSelected(SelectionEvent e) {
529 			  COConfigurationManager.setParameter(
530 					  "MyTorrentsView.showrates", menuItemShowRates.getSelection());
531 		  }
532 	  });
533 	  // show category buttons
534 
535 	  final MenuItem menuItemShowCatBut = new MenuItem(tableHeaderMenu, SWT.CHECK);
536 	  Messages.setLanguageText( menuItemShowCatBut, "ConfigView.label.show.cat.but" );
537 
538 	  menuItemShowCatBut.addSelectionListener(new SelectionAdapter() {
539 		  public void widgetSelected(SelectionEvent e) {
540 			  COConfigurationManager.setParameter(
541 					  "Library.ShowCatButtons", menuItemShowCatBut.getSelection());
542 		  }
543 	  });
544 
545 
546 	  // show tag buttons
547 
548 	  final MenuItem menuItemShowTagBut = new MenuItem(tableHeaderMenu, SWT.CHECK);
549 	  Messages.setLanguageText( menuItemShowTagBut, "ConfigView.label.show.tag.but" );
550 
551 	  menuItemShowTagBut.addSelectionListener(new SelectionAdapter() {
552 		  public void widgetSelected(SelectionEvent e) {
553 			  COConfigurationManager.setParameter(
554 					  "Library.ShowTagButtons", menuItemShowTagBut.getSelection());
555 		  }
556 	  });
557 
558 	  new MenuItem( tableHeaderMenu, SWT.SEPARATOR );
559 
560 	  	// enable simple views
561 
562 	  String rr = MessageText.getString( "ConfigView.section.security.restart.title" );
563 
564 	  final MenuItem menuEnableSimple = new MenuItem(tableHeaderMenu, SWT.CHECK);
565 
566 	  menuEnableSimple.setText( MessageText.getString( "ConfigView.section.style.EnableSimpleView" ) + " (" + rr + ")" );
567 
568 	  menuEnableSimple.addSelectionListener(new SelectionAdapter() {
569 		  public void widgetSelected(SelectionEvent e) {
570 			  COConfigurationManager.setParameter(
571 					  "Library.EnableSimpleView", menuEnableSimple.getSelection());
572 		  }
573 	  });
574 
575 
576 	  // hooks
577 
578 	  tableHeaderMenu.addMenuListener(new MenuListener() {
579 		  public void menuShown(MenuEvent e) {
580 			  menuItemShowUptime.setSelection(COConfigurationManager.getBooleanParameter( "MyTorrentsView.showuptime" ));
581 			  menuItemShowRates.setSelection(COConfigurationManager.getBooleanParameter( "MyTorrentsView.showrates" ));
582 			  menuItemShowCatBut.setSelection(COConfigurationManager.getBooleanParameter( "Library.ShowCatButtons" ));
583 			  menuItemShowTagBut.setSelection(COConfigurationManager.getBooleanParameter( "Library.ShowTagButtons" ));
584 
585 			  menuItemShowCatBut.setEnabled( !neverShowCatOrTagButtons );
586 			  menuItemShowTagBut.setEnabled( !neverShowCatOrTagButtons );
587 
588 			  menuEnableSimple.setSelection(COConfigurationManager.getBooleanParameter( "Library.EnableSimpleView" ));
589 
590 		  }
591 
592 		  public void menuHidden(MenuEvent e) {
593 		  }
594 	  });
595 
596 	  return( tableHeaderMenu );
597   }
598 
599   // @see com.aelitis.azureus.ui.common.table.TableLifeCycleListener#tableViewDestroyed()
tableViewDestroyed()600   public void tableViewDestroyed() {
601     tv.removeKeyListener(this);
602 
603   	Utils.execSWTThread(new AERunnable() {
604 			public void runSupport() {
605 				try {
606 					Utils.disposeSWTObjects(new Object[] {
607 						dragSource,
608 						dropTarget,
609 						fontButton,
610 						tableHeaderMenu
611 					});
612 					dragSource 		= null;
613 					dropTarget 		= null;
614 					fontButton		= null;
615 					tableHeaderMenu = null;
616 
617 				} catch (Exception e) {
618 					Debug.out(e);
619 				}
620 			}
621 		});
622     Object[] dms = globalManager.getDownloadManagers().toArray();
623     for (int i = 0; i < dms.length; i++) {
624 			DownloadManager dm = (DownloadManager) dms[i];
625 			dm.removeListener(this);
626 		}
627 
628 		if (currentTags != null) {
629 			for (Tag tag : currentTags) {
630 				tag.removeTagListener(this);
631 			}
632 		}
633     TagManager tagManager = TagManagerFactory.getTagManager();
634     TagType ttManual = tagManager.getTagType(TagType.TT_DOWNLOAD_MANUAL);
635     TagType ttCat = tagManager.getTagType(TagType.TT_DOWNLOAD_CATEGORY);
636     ttManual.removeTagTypeListener(MyTorrentsView.this);
637     ttCat.removeTagTypeListener(MyTorrentsView.this);
638 
639     globalManager.removeListener(this);
640     globalManager.removeEventListener( gm_event_listener );
641     COConfigurationManager.removeParameterListener("DND Always In Incomplete", this);
642     COConfigurationManager.removeParameterListener("Library.ShowCatButtons", this);
643     COConfigurationManager.removeParameterListener("Library.ShowTagButtons", this);
644     COConfigurationManager.removeParameterListener("Library.ShowTagButtons.CompOnly", this);
645   }
646 
647 
648   // @see org.gudy.azureus2.ui.swt.views.table.TableViewSWTPanelCreator#createTableViewPanel(org.eclipse.swt.widgets.Composite)
createTableViewPanel(Composite composite)649   public Composite createTableViewPanel(Composite composite) {
650 
651     GridData gridData;
652     cTableParentPanel = new Composite(composite, SWT.NONE);
653     GridLayout layout = new GridLayout();
654     layout.horizontalSpacing = 0;
655     layout.verticalSpacing = 0;
656     layout.marginHeight = 0;
657     layout.marginWidth = 0;
658     cTableParentPanel.setLayout(layout);
659     if (composite.getLayout() instanceof GridLayout) {
660     	cTableParentPanel.setLayoutData(new GridData(GridData.FILL_BOTH));
661     }
662 
663     cTablePanel = new Composite(cTableParentPanel, SWT.NULL);
664 
665     cTablePanel.addListener(SWT.Activate, new Listener() {
666 		public void handleEvent(Event event) {
667 			viewActive = true;
668 	    updateSelectedContent();
669 	    //refreshIconBar();
670 		}
671 	});
672     cTablePanel.addListener(SWT.Deactivate, new Listener() {
673 		public void handleEvent(Event event) {
674 			viewActive = false;
675 			// don't updateSelectedContent() because we may have switched
676 			// to a button or a text field, and we still want out content to be
677 			// selected
678 		}
679 	});
680 
681     gridData = new GridData(GridData.FILL_BOTH);
682     cTablePanel.setLayoutData(gridData);
683 
684     layout = new GridLayout(1, false);
685     layout.marginHeight = 0;
686     layout.marginWidth = 0;
687     layout.verticalSpacing = 0;
688     layout.horizontalSpacing = 0;
689     cTablePanel.setLayout(layout);
690 
691     cTablePanel.layout();
692     return cTablePanel;
693   }
694 
createTabs()695   private void createTabs() {
696 		Utils.execSWTThread(new AERunnable() {
697 			public void runSupport() {
698 				swt_createTabs();
699 			}
700 		});
701   }
702 
swt_createTabs()703   private void swt_createTabs() {
704 
705     boolean catButtonsDisabled = neverShowCatOrTagButtons;
706     if ( !catButtonsDisabled){
707     	catButtonsDisabled = !COConfigurationManager.getBooleanParameter( "Library.ShowCatButtons" );
708     }
709 
710     List<Tag> tags_to_show = new ArrayList<Tag>();
711 
712     boolean tagButtonsDisabled = neverShowCatOrTagButtons;
713     if ( !tagButtonsDisabled){
714     	tagButtonsDisabled = !COConfigurationManager.getBooleanParameter( "Library.ShowTagButtons" );
715 
716     	if ( !tagButtonsDisabled ){
717     		if ( !isCompletedOnly ){
718     			tagButtonsDisabled = COConfigurationManager.getBooleanParameter( "Library.ShowTagButtons.CompOnly" );
719     		}
720     	}
721     }
722 
723     if ( !tagButtonsDisabled ){
724 			ArrayList<Tag> tagsManual = new ArrayList<Tag>(
725 					TagManagerFactory.getTagManager().getTagType(
726 							TagType.TT_DOWNLOAD_MANUAL).getTags());
727 			for (Tag tag : tagsManual) {
728 				if (tag.isVisible()) {
729 					tags_to_show.add(tag);
730 				}
731 			}
732     }
733 
734     if (!catButtonsDisabled) {
735 			ArrayList<Tag> tagsCat = new ArrayList<Tag>(
736 					TagManagerFactory.getTagManager().getTagType(
737 							TagType.TT_DOWNLOAD_CATEGORY).getTags());
738 			for (Tag tag : tagsCat) {
739 				if (tag.isVisible()) {
740 					tags_to_show.add(tag);
741 				}
742 			}
743 
744     }
745 
746     tags_to_show = TagUIUtils.sortTags( tags_to_show );
747 
748    	buildHeaderArea();
749   	if (cCategoriesAndTags != null && !cCategoriesAndTags.isDisposed()) {
750   		Utils.disposeComposite(cCategoriesAndTags, false);
751   	}
752 
753     if (tags_to_show.size() > 0 ) {
754     	buildCatAndTag(tags_to_show);
755     } else if (cTableParentPanel != null && !cTableParentPanel.isDisposed()) {
756   		cTableParentPanel.layout();
757   	}
758   }
759 
buildHeaderArea()760 	private void buildHeaderArea() {
761 		if (cCategoriesAndTags == null) {
762 			cCategoriesAndTags = new CompositeMinSize(cTableParentPanel, SWT.NONE);
763 			((CompositeMinSize) cCategoriesAndTags).setMinSize(new Point(SWT.DEFAULT, 24));
764 			GridData gridData = new GridData(SWT.RIGHT, SWT.CENTER, true, false);
765 			cCategoriesAndTags.setLayoutData(gridData);
766 			cCategoriesAndTags.moveAbove(null);
767 
768 			if ( filterParent != null ){
769 					// inherit the background of the search filter - best that can be done to make things look ok
770 				Color background = filterParent.getBackground();
771 				if ( background != null ){
772 					cCategoriesAndTags.setBackground( background );
773 					cTableParentPanel.setBackground( background );
774 				}
775 			}
776 
777 			cCategoriesAndTags.setBackgroundMode(SWT.INHERIT_FORCE);
778 		}else if ( cCategoriesAndTags.isDisposed()){
779 			return;
780 		}
781 
782 		RowLayout rowLayout;
783 
784 		if (cCategoriesAndTags.getLayout() instanceof RowLayout){
785 		  rowLayout = (RowLayout)cCategoriesAndTags.getLayout();
786 		}else{
787 	      rowLayout = new RowLayout();
788 	      cCategoriesAndTags.setLayout(rowLayout);
789 		}
790 	    rowLayout.marginTop = 0;
791 	    rowLayout.marginBottom = 0;
792 	    rowLayout.marginLeft = Utils.adjustPXForDPI(3);
793 	    rowLayout.marginRight = Utils.adjustPXForDPI(3);
794 	    rowLayout.spacing = 0;
795 	    rowLayout.wrap = true;
796 
797 
798 	    Menu menu = getHeaderMenu(cTableParentPanel);
799 	    cTableParentPanel.setMenu( menu );
800 
801 	    if ( Constants.isOSX ){
802 
803 	    		/* bug on OSX whereby the table is allowing menu-detect events to fire both on the table itself and the composite it
804 	    		 * sits on - this results in the header-area menu appearing after a menu appears for the table itself
805 	    		 * Doesn't happen on 10.6.8 but observed to happen on 10.9.4
806 	    		 */
807 
808 		    cTableParentPanel.addListener(
809 					SWT.MenuDetect,
810 					new Listener() {
811 
812 						public void
813 						handleEvent(
814 							Event event )
815 						{
816 							Display display = cTableParentPanel.getDisplay();
817 
818 							Point pp_rel = display.map( null, cTableParentPanel, event.x, event.y );
819 
820 							Control hit = Utils.findChild(cTableParentPanel, pp_rel.x, pp_rel.y );
821 
822 							event.doit = hit == cTableParentPanel;
823 						}
824 					});
825 	    }
826 
827 	    tv.enableFilterCheck(txtFilter, this);
828 	}
829 
830   /**
831 	 *
832 	 *
833 	 * @param categories
834    * @since 3.1.1.1
835 	 */
buildCatAndTag(List<Tag> tags)836 	private void buildCatAndTag(List<Tag> tags) {
837 
838 		if (tags.size() == 0 || cCategoriesAndTags.isDisposed()){
839 			return;
840 		}
841 
842 		int iFontPixelsHeight = Utils.adjustPXForDPI(10);
843 		int iFontPointHeight = (iFontPixelsHeight * 72)	/ cCategoriesAndTags.getDisplay().getDPI().y;
844 
845 		Label spacer = null;
846 
847 		int	max_rd_height = 0;
848 
849 		allTags = tags;
850 
851 		if (buttonSelectionListener == null) {
852 			buttonSelectionListener = new SelectionAdapter() {
853 				public void widgetSelected(SelectionEvent e) {
854 					boolean add = (e.stateMask == SWT.MOD1);
855 
856 					Button curButton = (Button) e.widget;
857 					boolean isEnabled = curButton.getSelection();
858 
859 					Tag tag = (Tag) curButton.getData("Tag");
860 
861 					if (!isEnabled) {
862 						removeTagFromCurrent(tag);
863 					} else {
864 						if (add) {
865 							Category catAll = CategoryManager.getCategory(Category.TYPE_ALL);
866 
867 							if (tag.equals(catAll)) {
868 								setCurrentTags(new Tag[] { catAll });
869 							} else {
870   							Tag[] newTags = new Tag[currentTags.length + 1];
871   							System.arraycopy(currentTags, 0, newTags, 0, currentTags.length);
872   							newTags[currentTags.length] = tag;
873 
874   							newTags = (Tag[]) removeFromArray(newTags, catAll);
875   							setCurrentTags(newTags);
876 							}
877 						} else {
878 							setCurrentTags(new Tag[] {
879 								(Tag) curButton.getData("Tag")
880 							});
881 						}
882 					}
883 
884 					Control[] controls = curButton.getParent().getChildren();
885 					for (int i = 0; i < controls.length; i++) {
886 						if (!(controls[i] instanceof Button)) {
887 							continue;
888 						}
889 						Button b = (Button) controls[i];
890 						Tag btag = (Tag) b.getData("Tag");
891 						b.setSelection(isCurrent(btag));
892 					}
893 				}
894 			};
895 
896 			buttonHoverListener = new Listener() {
897 				public void handleEvent(Event event) {
898 					Button curButton = (Button) event.widget;
899 					Tag tag = (Tag) curButton.getData("Tag");
900 
901 					if (!(tag instanceof Category)) {
902 						curButton.setToolTipText(TagUIUtils.getTagTooltip(tag, true));
903 						return;
904 					}
905 
906 					Category category = (Category) tag;
907 
908 					List<DownloadManager> dms = category.getDownloadManagers(
909 							globalManager.getDownloadManagers());
910 
911 					long ttlActive = 0;
912 					long ttlSize = 0;
913 					long ttlRSpeed = 0;
914 					long ttlSSpeed = 0;
915 					int count = 0;
916 					for (DownloadManager dm : dms) {
917 
918 						if (!category.hasTaggable(dm)) {
919 							continue;
920 						}
921 
922 						count++;
923 						if (dm.getState() == DownloadManager.STATE_DOWNLOADING
924 								|| dm.getState() == DownloadManager.STATE_SEEDING) {
925 							ttlActive++;
926 						}
927 						DownloadManagerStats stats = dm.getStats();
928 						ttlSize += stats.getSizeExcludingDND();
929 						ttlRSpeed += stats.getDataReceiveRate();
930 						ttlSSpeed += stats.getDataSendRate();
931 					}
932 
933 					String up_details = "";
934 					String down_details = "";
935 
936 					if (category.getType() != Category.TYPE_ALL) {
937 
938 						String up_str = MessageText.getString(
939 								"GeneralView.label.maxuploadspeed");
940 						String down_str = MessageText.getString(
941 								"GeneralView.label.maxdownloadspeed");
942 						String unlimited_str = MessageText.getString(
943 								"MyTorrentsView.menu.setSpeed.unlimited");
944 
945 						int up_speed = category.getUploadSpeed();
946 						int down_speed = category.getDownloadSpeed();
947 
948 						up_details = up_str + ": " + (up_speed == 0 ? unlimited_str
949 								: DisplayFormatters.formatByteCountToKiBEtc(up_speed));
950 						down_details = down_str + ": " + (down_speed == 0 ? unlimited_str
951 								: DisplayFormatters.formatByteCountToKiBEtc(down_speed));
952 					}
953 
954 					if (count == 0) {
955 						curButton.setToolTipText(
956 								down_details + "\n" + up_details + "\nTotal: 0");
957 						return;
958 					}
959 
960 					curButton.setToolTipText((up_details.length() == 0 ? ""
961 							: (down_details + "\n" + up_details + "\n")) + "Total: " + count
962 							+ "\n" + "Downloading/Seeding: " + ttlActive + "\n" + "\n"
963 							+ "Total Speed: "
964 							+ DisplayFormatters.formatByteCountToKiBEtcPerSec(ttlRSpeed)
965 							+ " / "
966 							+ DisplayFormatters.formatByteCountToKiBEtcPerSec(ttlSSpeed)
967 							+ "\n" + "Average Speed: "
968 							+ DisplayFormatters.formatByteCountToKiBEtcPerSec(
969 									ttlRSpeed / (ttlActive == 0 ? 1 : ttlActive))
970 							+ " / "
971 							+ DisplayFormatters.formatByteCountToKiBEtcPerSec(
972 									ttlSSpeed / (ttlActive == 0 ? 1 : ttlActive))
973 							+ "\n" + "Size: "
974 							+ DisplayFormatters.formatByteCountToKiBEtc(ttlSize));
975 
976 				}
977 			};
978 
979 			buttonDropTargetListener = new DropTargetAdapter() {
980 				public void dragOver(DropTargetEvent e) {
981 
982 					if (drag_drop_line_start >= 0) {
983 						boolean doAdd = false;
984 
985 						Control curButton = ((DropTarget) e.widget).getControl();
986 						Tag tag = (Tag) curButton.getData("Tag");
987 						Object[] ds = tv.getSelectedDataSources().toArray();
988 						if (tag != null) {
989   						for (Object obj : ds) {
990 
991   							if (obj instanceof DownloadManager) {
992 
993   								DownloadManager dm = (DownloadManager) obj;
994 
995   								if (!tag.hasTaggable(dm)) {
996   									doAdd = true;
997   									break;
998   								}
999   							}
1000   						}
1001 						}
1002 
1003 						e.detail = doAdd ? DND.DROP_COPY : DND.DROP_MOVE;
1004 
1005 					} else {
1006 						e.detail = DND.DROP_NONE;
1007 					}
1008 				}
1009 
1010 				public void drop(DropTargetEvent e) {
1011 					e.detail = DND.DROP_NONE;
1012 
1013 					if (drag_drop_line_start >= 0) {
1014 						drag_drop_line_start = -1;
1015 						drag_drop_rows = null;
1016 
1017 						Object[] ds = tv.getSelectedDataSources().toArray();
1018 
1019 						Control curButton = ((DropTarget) e.widget).getControl();
1020 
1021 						Tag tag = (Tag) curButton.getData("Tag");
1022 
1023 						if (tag instanceof Category) {
1024 							TorrentUtil.assignToCategory(ds, (Category) tag);
1025 							return;
1026 						}
1027 
1028 						boolean doAdd = false;
1029 						for (Object obj : ds) {
1030 
1031 							if (obj instanceof DownloadManager) {
1032 
1033 								DownloadManager dm = (DownloadManager) obj;
1034 
1035 								if (!tag.hasTaggable(dm)) {
1036 									doAdd = true;
1037 									break;
1038 								}
1039 							}
1040 						}
1041 
1042 						for (Object obj : ds) {
1043 
1044 							if (obj instanceof DownloadManager) {
1045 
1046 								DownloadManager dm = (DownloadManager) obj;
1047 
1048 								if (doAdd) {
1049 									tag.addTaggable(dm);
1050 								} else {
1051 									tag.removeTaggable(dm);
1052 								}
1053 							}
1054 						}
1055 					}
1056 				}
1057 			};
1058 		}
1059 
1060 		for ( final Tag tag: tags ){
1061 			boolean isCat = (tag instanceof Category);
1062 
1063 			final Button button = new Button(cCategoriesAndTags, SWT.TOGGLE);
1064 
1065 			if (isCat) {
1066   			if (spacer == null) {
1067   				spacer = new Label(cCategoriesAndTags, SWT.NONE);
1068   				RowData rd = new RowData();
1069   				rd.width = 8;
1070   				spacer.setLayoutData(rd);
1071   				spacer.moveAbove(null);
1072   			}
1073   			button.moveAbove(spacer);
1074 			}
1075 
1076 			button.addKeyListener(this);
1077 			if ( fontButton == null) {
1078 				Font f = button.getFont();
1079 				FontData fd = f.getFontData()[0];
1080 				fd.setHeight(iFontPointHeight);
1081 				fontButton = new Font(cCategoriesAndTags.getDisplay(), fd);
1082 			}
1083 			button.setText("|");
1084 			button.setFont(fontButton);
1085 			button.pack(true);
1086 			if (button.computeSize(100, SWT.DEFAULT).y > 0) {
1087 				RowData rd = new RowData();
1088 				int rd_height = button.computeSize(100, SWT.DEFAULT).y - 2 + button.getBorderWidth() * 2;
1089 				rd.height = rd_height;
1090 				max_rd_height = Math.max( max_rd_height, rd_height );
1091 				button.setLayoutData(rd);
1092 			}
1093 
1094 			String tag_name = tag.getTagName( true );
1095 
1096 			button.setText(tag_name);
1097 
1098 			button.setData("Tag", tag);
1099 			if (isCurrent(tag)) {
1100 				button.setSelection(true);
1101 			}
1102 
1103 			button.addSelectionListener(buttonSelectionListener);
1104 
1105 
1106 			button.addListener(SWT.MouseHover, buttonHoverListener);
1107 
1108 			final DropTarget tabDropTarget = new DropTarget(button,
1109 					DND.DROP_DEFAULT | DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_LINK);
1110 			Transfer[] types = new Transfer[] {
1111 				TextTransfer.getInstance()
1112 			};
1113 			tabDropTarget.setTransfer(types);
1114 			tabDropTarget.addDropListener(buttonDropTargetListener);
1115 
1116 			button.addDisposeListener(new DisposeListener() {
1117 				public void widgetDisposed(DisposeEvent e) {
1118 					if (!tabDropTarget.isDisposed()) {
1119 						tabDropTarget.dispose();
1120 					}
1121 				}
1122 			});
1123 
1124 			Menu menu = new Menu( button );
1125 
1126 			button.setMenu( menu );
1127 
1128 			if (isCat) {
1129 				CategoryUIUtils.setupCategoryMenu(menu, (Category) tag);
1130 			} else {
1131 				TagUIUtils.createSideBarMenuItems(menu, tag);
1132 			}
1133 		}
1134 
1135 		if ( max_rd_height > 0 ){
1136 			RowLayout layout = (RowLayout)cCategoriesAndTags.getLayout();
1137 			int top_margin = ( 24 - max_rd_height + 1 )/2;
1138 			if (top_margin > 0 ){
1139 				layout.marginTop = top_margin;
1140 			}
1141 		}
1142 
1143 		cCategoriesAndTags.getParent().layout(true, true);
1144 	}
1145 
isOurDownloadManager(DownloadManager dm)1146 	public boolean isOurDownloadManager(DownloadManager dm) {
1147 		if (!isInTags(dm, currentTags)) {
1148 			return false;
1149 		}
1150 
1151 		if (Download.class.equals(forDataSourceType)) {
1152 			return true;
1153 		}
1154 
1155 		boolean bCompleted = dm.isDownloadComplete(bDNDalwaysIncomplete);
1156 		boolean bOurs = (bCompleted && isCompletedOnly)
1157 				|| (!bCompleted && !isCompletedOnly);
1158 
1159 		//System.out.println("ourDM? " + tv.getTableID() + "; " + dm.getDisplayName()
1160 		//		+ "; Complete=" + bCompleted + ";Ours=" + bOurs + ";bc"
1161 		//		+ dm.getStats().getDownloadCompleted(false) + ";"
1162 		//		+ dm.getStats().getDownloadCompleted(true));
1163 
1164 		return bOurs;
1165 	}
1166 
filterCheck(DownloadManager dm, String sLastSearch, boolean bRegexSearch)1167 	public boolean filterCheck(DownloadManager dm, String sLastSearch, boolean bRegexSearch) {
1168 		if ( dm == null ){
1169 			return( false );
1170 		}
1171 		boolean bOurs;
1172 		if (sLastSearch.length() > 0) {
1173 			try {
1174 				String	comment = dm.getDownloadState().getUserComment();
1175 				if ( comment == null ){
1176 					comment = "";
1177 				}
1178 
1179 				String[][] name_mapping = {
1180 					{
1181 						"",
1182 						dm.getDisplayName()
1183 					},
1184 					{
1185 						"t:",
1186 						"", 	// defer (index = 1)this as costly dm.getTorrent().getAnnounceURL().getHost()
1187 					},
1188 					{
1189 						"st:",
1190 						"" + dm.getState()
1191 					},
1192 					{
1193 						"c:",
1194 						comment
1195 					},
1196 					{
1197 						"f:",
1198 						"",		//defer (index = 4)
1199 					},
1200 				};
1201 
1202 				Object o_name = name_mapping[0][1];
1203 
1204 				String tmpSearch = sLastSearch;
1205 
1206 				for ( int i = 1; i < name_mapping.length; i++ ){
1207 
1208 					if ( tmpSearch.startsWith(name_mapping[i][0])) {
1209 
1210 						tmpSearch = tmpSearch.substring(name_mapping[i][0].length());
1211 
1212 						if ( i == 1 ){
1213 
1214 							List<String> names = new ArrayList<String>();
1215 
1216 							o_name = names;
1217 
1218 							TOTorrent t = dm.getTorrent();
1219 
1220 							if ( t != null ){
1221 
1222 								names.add( t.getAnnounceURL().getHost());
1223 
1224 								TOTorrentAnnounceURLSet[] sets = t.getAnnounceURLGroup().getAnnounceURLSets();
1225 
1226 								for ( TOTorrentAnnounceURLSet set: sets ){
1227 
1228 									URL[] urls = set.getAnnounceURLs();
1229 
1230 									for ( URL u: urls ){
1231 
1232 										names.add( u.getHost());
1233 									}
1234 								}
1235 
1236 								try{
1237 									byte[] hash = t.getHash();
1238 
1239 									names.add( ByteFormatter.encodeString( hash ));
1240 									names.add( Base32.encode( hash ));
1241 
1242 								}catch( Throwable e ){
1243 
1244 								}
1245 							}
1246 						}else if ( i == 4 ){
1247 
1248 							List<String> names = new ArrayList<String>();
1249 
1250 							o_name = names;
1251 
1252 							DiskManagerFileInfoSet file_set = dm.getDiskManagerFileInfoSet();
1253 
1254 							DiskManagerFileInfo[] files = file_set.getFiles();
1255 
1256 							for ( DiskManagerFileInfo f: files ){
1257 
1258 								File file = f.getFile(true);
1259 
1260 								String name = tmpSearch.contains( File.separator )?file.getAbsolutePath():file.getName();
1261 
1262 								names.add( name );
1263 							}
1264 
1265 						}else{
1266 							o_name = name_mapping[i][1];
1267 						}
1268 					}
1269 				}
1270 
1271 				String s = bRegexSearch ? tmpSearch : "\\Q"
1272 						+ tmpSearch.replaceAll("[|;]", "\\\\E|\\\\Q") + "\\E";
1273 
1274 				boolean	match_result = true;
1275 
1276 				if ( bRegexSearch && s.startsWith( "!" )){
1277 					s = s.substring(1);
1278 
1279 					match_result = false;
1280 				}
1281 
1282 				Pattern pattern = RegExUtil.getCachedPattern( "tv:search", s, Pattern.CASE_INSENSITIVE);
1283 
1284 				if ( o_name instanceof String ){
1285 
1286 					bOurs = pattern.matcher((String)o_name).find() == match_result;
1287 
1288 				}else{
1289 					List<String>	names = (List<String>)o_name;
1290 
1291 						// match_result: true -> at least one match; false -> any fail
1292 
1293 					bOurs = !match_result;
1294 
1295 					for ( String name: names ){
1296 						if ( pattern.matcher( name ).find()){
1297 							bOurs = match_result;
1298 							break;
1299 						}
1300 					}
1301 				}
1302 			} catch (Exception e) {
1303 				// Future: report PatternSyntaxException message to user.
1304 
1305 				bOurs = true;
1306 			}
1307 		}else{
1308 
1309 			bOurs = true;
1310 		}
1311 
1312 		return bOurs;
1313 	}
1314 
1315 	// @see org.gudy.azureus2.ui.swt.views.table.TableViewFilterCheck#filterSet(java.lang.String)
filterSet(final String filter)1316 	public void filterSet(final String filter) {
1317 		Utils.execSWTThread(new AERunnable() {
1318 
1319 			public void runSupport() {
1320 				if (txtFilter != null) {
1321 					Object x = filterParent.getData( "ViewUtils:ViewTitleExtraInfo" );
1322 
1323 					if ( x instanceof ViewUtils.ViewTitleExtraInfo ){
1324 
1325 						boolean	enabled = filter.length() > 0;
1326 
1327 						if ( enabled ){
1328 
1329 							if ( txtFilterUpdateEvent == null ){
1330 
1331 								txtFilterUpdateEvent =
1332 									SimpleTimer.addPeriodicEvent(
1333 										"MTV:updater",
1334 										1000,
1335 										new TimerEventPerformer()
1336 										{
1337 											public void
1338 											perform(
1339 												TimerEvent event )
1340 											{
1341 												Utils.execSWTThread(
1342 													new AERunnable()
1343 													{
1344 														public void
1345 														runSupport()
1346 														{
1347 															if ( txtFilterUpdateEvent != null ){
1348 
1349 																if ( tv.isDisposed()){
1350 
1351 																	txtFilterUpdateEvent.cancel();
1352 
1353 																	txtFilterUpdateEvent = null;
1354 
1355 																}else{
1356 
1357 																	viewChanged( tv );
1358 																}
1359 															}
1360 														}
1361 													});
1362 											}
1363 										});
1364 							}
1365 						}else{
1366 
1367 							if ( txtFilterUpdateEvent != null ){
1368 
1369 								txtFilterUpdateEvent.cancel();
1370 
1371 								txtFilterUpdateEvent = null;
1372 							}
1373 						}
1374 
1375 						((ViewUtils.ViewTitleExtraInfo)x).setEnabled( tv.getComposite(), enabled );
1376 					}
1377 				}
1378 			}
1379 		});
1380 	}
1381 
1382 	public void
viewChanged( final TableView<DownloadManager> view )1383 	viewChanged(
1384 		final TableView<DownloadManager> view )
1385 	{
1386 		Utils.execSWTThread(new AERunnable() {
1387 			public void runSupport() {
1388 				swt_viewChanged(view);
1389 			}
1390 		});
1391 	}
1392 
swt_viewChanged(final TableView<DownloadManager> view)1393 	private void swt_viewChanged(final TableView<DownloadManager> view) {
1394 
1395 		if ( filterParent != null && !filterParent.isDisposed()){
1396 			Object x = filterParent.getData( "ViewUtils:ViewTitleExtraInfo" );
1397 
1398 			if ( x instanceof ViewUtils.ViewTitleExtraInfo ){
1399 
1400 				TableRowCore[] rows = view.getRows();
1401 
1402 				int	active = 0;
1403 
1404 				for ( TableRowCore row: rows ){
1405 
1406 					DownloadManager dm = (DownloadManager)row.getDataSource( true );
1407 
1408 					int	state = dm.getState();
1409 
1410 					if ( state == DownloadManager.STATE_DOWNLOADING || state == DownloadManager.STATE_SEEDING ){
1411 
1412 						active++;
1413 					}
1414 				}
1415 
1416 				((ViewUtils.ViewTitleExtraInfo)x).update( tv.getComposite(), rows.length, active );
1417 			}
1418 		}
1419 	}
1420 
1421   // @see com.aelitis.azureus.ui.common.table.TableSelectionListener#selected(com.aelitis.azureus.ui.common.table.TableRowCore[])
selected(TableRowCore[] rows)1422   public void selected(TableRowCore[] rows) {
1423   	updateSelectedContent();
1424   	refreshTorrentMenu();
1425   }
1426 
1427 	// @see com.aelitis.azureus.ui.common.table.TableSelectionListener#deselected(com.aelitis.azureus.ui.common.table.TableRowCore[])
deselected(TableRowCore[] rows)1428 	public void deselected(TableRowCore[] rows) {
1429   	updateSelectedContent();
1430   	refreshTorrentMenu();
1431 	}
1432 
1433 	// @see com.aelitis.azureus.ui.common.table.TableSelectionListener#focusChanged(com.aelitis.azureus.ui.common.table.TableRowCore)
focusChanged(TableRowCore focus)1434 	public void focusChanged(TableRowCore focus) {
1435 		updateSelectedContent();
1436   	refreshTorrentMenu();
1437 	}
1438 
1439 	// @see com.aelitis.azureus.ui.common.table.TableSelectionListener#mouseEnter(com.aelitis.azureus.ui.common.table.TableRowCore)
mouseEnter(TableRowCore row)1440 	public void mouseEnter(TableRowCore row) {
1441 	}
1442 
1443 	// @see com.aelitis.azureus.ui.common.table.TableSelectionListener#mouseExit(com.aelitis.azureus.ui.common.table.TableRowCore)
mouseExit(TableRowCore row)1444 	public void mouseExit(TableRowCore row) {
1445 	}
1446 
1447 	private FrequencyLimitedDispatcher refresh_limiter = new FrequencyLimitedDispatcher(
1448 			new AERunnable() {
1449 				public void runSupport() {
1450 					Utils.getOffOfSWTThread(new AERunnable() {
1451 						public void runSupport() {
1452 							updateSelectedContent();
1453 						}
1454 					});
1455 				}
1456 			}, 250 );
1457 
1458 	{
refresh_limiter.setSingleThreaded()1459 		refresh_limiter.setSingleThreaded();
1460 	}
1461 
1462 	private void
updateSelectedContentRateLimited()1463 	updateSelectedContentRateLimited()
1464 	{
1465 			// we can get a lot of these in succession when lots of rows are selected and we, for example, right-click or stop the torrents etc
1466 
1467 		refresh_limiter.dispatch();
1468 	}
1469 
updateSelectedContent()1470 	public void updateSelectedContent() {
1471 		updateSelectedContent( false );
1472 	}
1473 
updateSelectedContent( boolean force )1474 	public void updateSelectedContent( boolean force ) {
1475 		if (cTablePanel == null || cTablePanel.isDisposed()) {
1476 			return;
1477 		}
1478 			// if we're not active then ignore this update as we don't want invisible components
1479 			// updating the toolbar with their invisible selection. Note that unfortunately the
1480 			// call we get here when activating a view does't yet have focus
1481 
1482 		if ( !isTableFocus()){
1483 			if ( !force ){
1484 				return;
1485 			}
1486 		}
1487 		Object[] dataSources = tv.getSelectedDataSources(true);
1488 		List<SelectedContent> listSelected = new ArrayList<SelectedContent>(dataSources.length);
1489 		for (Object ds : dataSources) {
1490 			if (ds instanceof DownloadManager) {
1491 				listSelected.add(new SelectedContent((DownloadManager) ds));
1492 			} else if (ds instanceof DiskManagerFileInfo) {
1493 				DiskManagerFileInfo fileInfo = (DiskManagerFileInfo) ds;
1494 				listSelected.add(new SelectedContent(fileInfo.getDownloadManager(), fileInfo.getIndex()));
1495 			}
1496 		}
1497 		SelectedContent[] content = listSelected.toArray(new SelectedContent[0]);
1498 		SelectedContentManager.changeCurrentlySelectedContent(tv.getTableID(), content, tv);
1499 	}
1500 
refreshTorrentMenu()1501 	private void refreshTorrentMenu() {
1502 		UIFunctions uiFunctions = UIFunctionsManager.getUIFunctions();
1503 		if (uiFunctions != null && uiFunctions instanceof UIFunctionsSWT) {
1504 			((UIFunctionsSWT)uiFunctions).refreshTorrentMenu();
1505 		}
1506 	}
1507 
getSelectedDownloads()1508 	public DownloadManager[] getSelectedDownloads() {
1509 		Object[] data_sources = tv.getSelectedDataSources().toArray();
1510 		List<DownloadManager> list = new ArrayList<DownloadManager>();
1511 		for (Object ds : data_sources) {
1512 			if (ds instanceof DownloadManager) {
1513 				list.add((DownloadManager) ds);
1514 			}
1515 		}
1516 		return list.toArray(new DownloadManager[0]);
1517 	}
1518 
1519   // @see com.aelitis.azureus.ui.common.table.TableSelectionListener#defaultSelected(com.aelitis.azureus.ui.common.table.TableRowCore[])
defaultSelected(TableRowCore[] rows, int keyMask)1520   public void defaultSelected(TableRowCore[] rows, int keyMask) {
1521   	if (defaultSelectedListener != null) {
1522   		defaultSelectedListener.defaultSelected(rows, keyMask);
1523   		return;
1524   	}
1525   	showSelectedDetails();
1526 	}
1527 
showSelectedDetails()1528   private void showSelectedDetails() {
1529 		Object[] dm_sources = tv.getSelectedDataSources().toArray();
1530 		UIFunctions uiFunctions = UIFunctionsManager.getUIFunctions();
1531 		for (int i = 0; i < dm_sources.length; i++) {
1532 			if (!(dm_sources[i] instanceof DownloadManager)) {
1533 				continue;
1534 			}
1535 			if (uiFunctions != null) {
1536 				uiFunctions.getMDI().showEntryByID(
1537 						MultipleDocumentInterface.SIDEBAR_SECTION_TORRENT_DETAILS,
1538 						dm_sources[i]);
1539 			}
1540 		}
1541   }
1542 
overrideDefaultSelected(TableSelectionListener defaultSelectedListener)1543   public void overrideDefaultSelected(TableSelectionListener defaultSelectedListener) {
1544 		this.defaultSelectedListener = defaultSelectedListener;
1545   }
1546 
1547 
1548 
1549   /* SubMenu for column specific tasks.
1550    */
1551   // @see org.gudy.azureus2.ui.swt.views.table.TableViewSWTMenuFillListener#addThisColumnSubMenu(java.lang.String, org.eclipse.swt.widgets.Menu)
addThisColumnSubMenu(String sColumnName, Menu menuThisColumn)1552   public void addThisColumnSubMenu(String sColumnName, Menu menuThisColumn) {
1553     if (sColumnName.equals("health")) {
1554       MenuItem item = new MenuItem(menuThisColumn, SWT.PUSH);
1555       Messages.setLanguageText(item, "MyTorrentsView.menu.health");
1556       Utils.setMenuItemImage(item, "st_explain");
1557       item.addListener(SWT.Selection, new Listener() {
1558         public void handleEvent(Event e) {
1559           HealthHelpWindow.show(Display.getDefault());
1560         }
1561       });
1562 
1563     }else if (sColumnName.equals("trackername")) {
1564         MenuItem item = new MenuItem(menuThisColumn, SWT.PUSH);
1565         Messages.setLanguageText(item, "MyTorrentsView.menu.trackername.editprefs");
1566         item.addListener(SWT.Selection, new Listener() {
1567           public void handleEvent(Event e) {
1568       		SimpleTextEntryWindow entryWindow = new SimpleTextEntryWindow(
1569     				"trackername.prefs.title", "trackername.prefs.message");
1570       		entryWindow.setPreenteredText( COConfigurationManager.getStringParameter( "mtv.trackername.pref.hosts", "" ), true );
1571       		entryWindow.selectPreenteredText( false );
1572     		entryWindow.prompt();
1573     		if (entryWindow.hasSubmittedInput()) {
1574     			String text = entryWindow.getSubmittedInput();
1575 
1576     			COConfigurationManager.setParameter( "mtv.trackername.pref.hosts", text.trim());
1577     		}
1578           }
1579         });
1580 
1581     }else if (sColumnName.equals("eta") || sColumnName.equals("smootheta")) {
1582         final MenuItem item = new MenuItem(menuThisColumn, SWT.CHECK );
1583         Messages.setLanguageText(item, "MyTorrentsView.menu.eta.abs");
1584         item.setSelection( eta_absolute );
1585 
1586         item.addListener(SWT.Selection, new Listener() {
1587           public void handleEvent(Event e) {
1588         	eta_absolute = item.getSelection();
1589             tv.columnInvalidate("eta");
1590             tv.refreshTable(false);
1591             COConfigurationManager.setParameter( "mtv.eta.show_absolute", eta_absolute );
1592           }
1593         });
1594     }else if ( sColumnName.equals( "ProgressETA" )) {
1595         final MenuItem item = new MenuItem(menuThisColumn, SWT.CHECK );
1596         Messages.setLanguageText(item, "MyTorrentsView.menu.eta.abs");
1597         item.setSelection( progress_eta_absolute );
1598 
1599         item.addListener(SWT.Selection, new Listener() {
1600           public void handleEvent(Event e) {
1601         	progress_eta_absolute = item.getSelection();
1602             tv.columnInvalidate("ProgressETA");
1603             tv.refreshTable(false);
1604             COConfigurationManager.setParameter( "mtv.progress_eta.show_absolute", progress_eta_absolute );
1605           }
1606         });
1607     }
1608   }
1609 
1610 	// @see org.gudy.azureus2.ui.swt.views.table.TableViewSWTMenuFillListener#fillMenu(java.lang.String, org.eclipse.swt.widgets.Menu)
fillMenu(String sColumnName, final Menu menu)1611 	public void fillMenu(String sColumnName, final Menu menu) {
1612 		Object[] dataSources = tv.getSelectedDataSources(true);
1613 		DownloadManager[] dms = getSelectedDownloads();
1614 
1615 		if (dms.length == 0 && dataSources.length > 0) {
1616   		List<DiskManagerFileInfo> listFileInfos = new ArrayList<DiskManagerFileInfo>();
1617   		DownloadManager firstFileDM = null;
1618   		for (Object ds : dataSources) {
1619   			if (ds instanceof DiskManagerFileInfo) {
1620   				DiskManagerFileInfo info = (DiskManagerFileInfo) ds;
1621   				// for now, FilesViewMenuUtil.fillmenu can only handle one DM
1622   				if (firstFileDM != null && !firstFileDM.equals(info.getDownloadManager())) {
1623   					break;
1624   				}
1625   				firstFileDM = info.getDownloadManager();
1626   				listFileInfos.add(info);
1627   			}
1628   		}
1629   		if (listFileInfos.size() > 0) {
1630   			FilesViewMenuUtil.fillMenu(
1631   					tv,
1632   					menu,
1633   					new DownloadManager[]{ firstFileDM },
1634   					new DiskManagerFileInfo[][]{ listFileInfos.toArray(new DiskManagerFileInfo[0])});
1635   			return;
1636   		}
1637 		}
1638 
1639 		boolean hasSelection = (dms.length > 0);
1640 
1641 		if (hasSelection) {
1642 			boolean isSeedingView = Download.class.equals(forDataSourceType) || DownloadTypeComplete.class.equals(forDataSourceType);
1643 			TorrentUtil.fillTorrentMenu(menu, dms, azureus_core, cTablePanel, true,
1644 					(isSeedingView) ? 2 : 1, tv);
1645 
1646 			// ---
1647 			new MenuItem(menu, SWT.SEPARATOR);
1648 		}
1649 	}
1650 
createDragDrop()1651 	private void createDragDrop() {
1652 		try {
1653 
1654 			Transfer[] types = new Transfer[] { TextTransfer.getInstance() };
1655 
1656 			if (dragSource != null && !dragSource.isDisposed()) {
1657 				dragSource.dispose();
1658 			}
1659 
1660 			if (dropTarget != null && !dropTarget.isDisposed()) {
1661 				dropTarget.dispose();
1662 			}
1663 
1664 			dragSource = tv.createDragSource(DND.DROP_MOVE | DND.DROP_COPY);
1665 			if (dragSource != null) {
1666 				dragSource.setTransfer(types);
1667 				dragSource.addDragListener(new DragSourceAdapter() {
1668 					private String eventData;
1669 
1670 					public void dragStart(DragSourceEvent event) {
1671 						TableRowCore[] rows = tv.getSelectedRows();
1672 						if (rows.length != 0) {
1673 							event.doit = true;
1674 							//System.out.println("DragStart");
1675 							drag_drop_line_start = rows[0].getIndex();
1676 							drag_drop_rows = rows;
1677 						} else {
1678 							event.doit = false;
1679 							drag_drop_line_start = -1;
1680 							drag_drop_rows = null;
1681 						}
1682 
1683 						// Build eventData here because on OSX, selection gets cleared
1684 						// by the time dragSetData occurs
1685 						boolean onlyDMs = true;
1686 						StringBuffer sb = new StringBuffer();
1687 						Object[] selectedDataSources = tv.getSelectedDataSources(true);
1688 						for (Object ds : selectedDataSources) {
1689 							if (ds instanceof DownloadManager) {
1690 								DownloadManager dm = (DownloadManager) ds;
1691 								TOTorrent torrent = dm.getTorrent();
1692 								if (torrent != null) {
1693 									try {
1694 										sb.append(torrent.getHashWrapper().toBase32String());
1695 										sb.append('\n');
1696 									} catch (TOTorrentException e) {
1697 									}
1698 								}
1699 							} else if (ds instanceof DiskManagerFileInfo) {
1700 								DiskManagerFileInfo fileInfo = (DiskManagerFileInfo) ds;
1701 								DownloadManager dm = fileInfo.getDownloadManager();
1702 								TOTorrent torrent = dm.getTorrent();
1703 								if (torrent != null) {
1704 									try {
1705 										sb.append(torrent.getHashWrapper().toBase32String());
1706 										sb.append(';');
1707 										sb.append(fileInfo.getIndex());
1708 										sb.append('\n');
1709 										onlyDMs = false;
1710 									} catch (TOTorrentException e) {
1711 									}
1712 								}
1713 							}
1714 						}
1715 
1716 						eventData = (onlyDMs ? "DownloadManager\n" : "DiskManagerFileInfo\n") + sb.toString();
1717 					}
1718 
1719 					public void dragSetData(DragSourceEvent event) {
1720 						// System.out.println("DragSetData");
1721 						event.data = eventData;
1722 					}
1723 				});
1724 			}
1725 
1726 			dropTarget = tv.createDropTarget(DND.DROP_DEFAULT | DND.DROP_MOVE
1727 					| DND.DROP_COPY | DND.DROP_LINK | DND.DROP_TARGET_MOVE);
1728 			if (dropTarget != null) {
1729 				dropTarget.setTransfer(new Transfer[] { HTMLTransfer.getInstance(),
1730 						URLTransfer.getInstance(), FileTransfer.getInstance(),
1731 						TextTransfer.getInstance() });
1732 
1733 				dropTarget.addDropListener(new DropTargetAdapter() {
1734 					Point enterPoint = null;
1735 					public void dropAccept(DropTargetEvent event) {
1736 						event.currentDataType = URLTransfer.pickBestType(event.dataTypes,
1737 								event.currentDataType);
1738 					}
1739 
1740 					public void dragEnter(DropTargetEvent event) {
1741 						// no event.data on dragOver, use drag_drop_line_start to determine
1742 						// if ours
1743 						if (drag_drop_line_start < 0) {
1744 							if (event.detail != DND.DROP_COPY) {
1745 								if ((event.operations & DND.DROP_LINK) > 0)
1746 									event.detail = DND.DROP_LINK;
1747 								else if ((event.operations & DND.DROP_COPY) > 0)
1748 									event.detail = DND.DROP_COPY;
1749 							}
1750 						} else if (TextTransfer.getInstance().isSupportedType(
1751 								event.currentDataType)) {
1752 							event.detail = tv.getTableRowWithCursor() == null ? DND.DROP_NONE : DND.DROP_MOVE;
1753 							event.feedback = DND.FEEDBACK_SCROLL;
1754 							enterPoint = new Point(event.x, event.y);
1755 						}
1756 					}
1757 
1758 					// @see org.eclipse.swt.dnd.DropTargetAdapter#dragLeave(org.eclipse.swt.dnd.DropTargetEvent)
1759 					public void dragLeave(DropTargetEvent event) {
1760 						super.dragLeave(event);
1761 
1762 						tv.getComposite().redraw();
1763 					}
1764 
1765 					public void dragOver(DropTargetEvent event) {
1766 						if (drag_drop_line_start >= 0) {
1767 							if (drag_drop_rows.length > 0
1768 									&& !(drag_drop_rows[0].getDataSource(true) instanceof DownloadManager)) {
1769 								event.detail = DND.DROP_NONE;
1770 								return;
1771 							}
1772 							TableRowCore row = tv.getTableRowWithCursor();
1773 							if (row instanceof TableRowPainted) {
1774 								boolean dragging_down = row.getIndex() > drag_drop_line_start;
1775 	  							Rectangle bounds = ((TableRowPainted) row).getBounds();
1776 	  							tv.getComposite().redraw();
1777 	  							tv.getComposite().update();
1778 	  							GC gc = new GC(tv.getComposite());
1779 	  							gc.setLineWidth(2);
1780 	  							int y_pos = bounds.y;
1781 	  							if ( dragging_down ){
1782 	  								y_pos +=bounds.height;
1783 	  							}
1784 	  							gc.drawLine(bounds.x, y_pos, bounds.x + bounds.width, y_pos );
1785 	  							gc.dispose();
1786 							}
1787 							event.detail = row == null ? DND.DROP_NONE : DND.DROP_MOVE;
1788 							event.feedback = DND.FEEDBACK_SCROLL
1789 									| ((enterPoint != null && enterPoint.y > event.y)
1790 											? DND.FEEDBACK_INSERT_BEFORE : DND.FEEDBACK_INSERT_AFTER);
1791 						}
1792 					}
1793 
1794 					public void drop(DropTargetEvent event) {
1795 						if (!(event.data instanceof String)) {
1796 							TorrentOpener.openDroppedTorrents(event, true);
1797 							return;
1798 						}
1799 						String data = (String) event.data;
1800 						if (data.startsWith("DiskManagerFileInfo\n")) {
1801 							return;
1802 						}
1803 						if (!data.startsWith("DownloadManager\n")) {
1804 							TorrentOpener.openDroppedTorrents(event, true);
1805 							return;
1806 						}
1807 
1808 						event.detail = DND.DROP_NONE;
1809 						// Torrent file from shell dropped
1810 						if (drag_drop_line_start >= 0) { // event.data == null
1811 							event.detail = DND.DROP_NONE;
1812 							TableRowCore row = tv.getRow(event);
1813 							if (row == null)
1814 								return;
1815 							if (row.getParentRowCore() != null) {
1816 								row = row.getParentRowCore();
1817 							}
1818 							int drag_drop_line_end = row.getIndex();
1819 							if (drag_drop_line_end != drag_drop_line_start) {
1820 								DownloadManager dm = (DownloadManager) row.getDataSource(true);
1821 								moveRowsTo(drag_drop_rows, dm.getPosition());
1822 								event.detail = DND.DROP_MOVE;
1823 							}
1824 							drag_drop_line_start = -1;
1825 							drag_drop_rows = null;
1826 						}
1827 					}
1828 				});
1829 			}
1830 
1831 		} catch (Throwable t) {
1832 			Logger.log(new LogEvent(LOGID, "failed to init drag-n-drop", t));
1833 		}
1834 	}
1835 
moveRowsTo(TableRowCore[] rows, int iNewPos)1836   private void moveRowsTo(TableRowCore[] rows, int iNewPos) {
1837     if (rows == null || rows.length == 0) {
1838       return;
1839     }
1840 
1841     TableColumnCore sortColumn = tv.getSortColumn();
1842     boolean isSortAscending = sortColumn == null ? true
1843 				: sortColumn.isSortAscending();
1844 
1845     for (int i = 0; i < rows.length; i++) {
1846 			TableRowCore row = rows[i];
1847       Object ds = row.getDataSource(true);
1848       if (!(ds instanceof DownloadManager)) {
1849       	continue;
1850       }
1851       DownloadManager dm = (DownloadManager) ds;
1852       int iOldPos = dm.getPosition();
1853       globalManager.moveTo(dm, iNewPos);
1854       if (isSortAscending) {
1855         if (iOldPos > iNewPos)
1856           iNewPos++;
1857       } else {
1858         if (iOldPos < iNewPos)
1859           iNewPos--;
1860       }
1861     }
1862 
1863     boolean bForceSort = sortColumn == null ? false : sortColumn.getName().equals("#");
1864     tv.columnInvalidate("#");
1865     tv.refreshTable(bForceSort);
1866   }
1867 
1868   // @see com.aelitis.azureus.ui.common.table.TableRefreshListener#tableRefresh()
tableRefresh()1869   public void tableRefresh() {
1870     if (tv.isDisposed())
1871       return;
1872 
1873     refreshTorrentMenu();
1874   }
1875 
1876 
1877 	// @see org.eclipse.swt.events.KeyListener#keyPressed(org.eclipse.swt.events.KeyEvent)
keyPressed(KeyEvent e)1878 	public void keyPressed(KeyEvent e) {
1879 		viewActive = true;
1880 		int key = e.character;
1881 		if (key <= 26 && key > 0)
1882 			key += 'a' - 1;
1883 
1884 		if (e.stateMask == (SWT.CTRL | SWT.SHIFT)) {
1885 			// CTRL+SHIFT+S stop all Torrents
1886 			if (key == 's') {
1887 				ManagerUtils.asyncStopAll();
1888 				e.doit = false;
1889 				return;
1890 			}
1891 
1892 			// Can't capture Ctrl-PGUP/DOWN for moving up/down in chunks
1893 			// (because those keys move through tabs), so use shift-ctrl-up/down
1894 			if (e.keyCode == SWT.ARROW_DOWN) {
1895 				moveSelectedTorrents(10);
1896 				e.doit = false;
1897 				return;
1898 			}
1899 
1900 			if (e.keyCode == SWT.ARROW_UP) {
1901 				moveSelectedTorrents(-10);
1902 				e.doit = false;
1903 				return;
1904 			}
1905 		}
1906 
1907 		if (e.stateMask == SWT.MOD1) {
1908 			switch (key) {
1909 				case 'a': // CTRL+A select all Torrents
1910 					if (e.widget != txtFilter) {
1911 						tv.selectAll();
1912 						e.doit = false;
1913 					}
1914 					break;
1915 				case 'c': // CTRL+C
1916 					if (e.widget != txtFilter) {
1917 						tv.clipboardSelected();
1918 						e.doit = false;
1919 					}
1920 					break;
1921 				case 'i': // CTRL+I Info/Details
1922 					showSelectedDetails();
1923 					e.doit = false;
1924 					break;
1925 			}
1926 
1927 			if (!e.doit)
1928 				return;
1929 		}
1930 
1931 		if (e.stateMask == SWT.CTRL) {
1932 			switch (e.keyCode) {
1933 				case SWT.ARROW_UP:
1934 					moveSelectedTorrentsUp();
1935 					e.doit = false;
1936 					break;
1937 				case SWT.ARROW_DOWN:
1938 					moveSelectedTorrentsDown();
1939 					e.doit = false;
1940 					break;
1941 				case SWT.HOME:
1942 					moveSelectedTorrentsTop();
1943 					e.doit = false;
1944 					break;
1945 				case SWT.END:
1946 					moveSelectedTorrentsEnd();
1947 					e.doit = false;
1948 					break;
1949 			}
1950 			if (!e.doit)
1951 				return;
1952 
1953 			switch (key) {
1954 				case 'r': // CTRL+R resume/start selected Torrents
1955 					TorrentUtil.resumeTorrents(tv.getSelectedDataSources().toArray());
1956 					e.doit = false;
1957 					break;
1958 				case 's': // CTRL+S stop selected Torrents
1959 					Utils.getOffOfSWTThread(new AERunnable() {
1960 						public void runSupport() {
1961 							TorrentUtil.stopDataSources(tv.getSelectedDataSources().toArray());
1962 						}
1963 					});
1964 					e.doit = false;
1965 					break;
1966 			}
1967 
1968 			if (!e.doit)
1969 				return;
1970 		}
1971 
1972 		if (e.keyCode == SWT.F2 && (e.stateMask & SWT.MODIFIER_MASK) == 0) {
1973 			FilesViewMenuUtil.rename(tv, tv.getSelectedDataSources(true), true, false);
1974 			e.doit = false;
1975 			return;
1976 		}
1977 
1978 
1979 		// DEL remove selected Torrents
1980 		if (e.stateMask == 0 && e.keyCode == SWT.DEL && e.widget != txtFilter) {
1981 			Utils.getOffOfSWTThread(new AERunnable() {
1982 				public void runSupport() {
1983 					TorrentUtil.removeDataSources(tv.getSelectedDataSources().toArray());
1984 				}
1985 			});
1986 			e.doit = false;
1987 			return;
1988 		}
1989 
1990 		if (e.keyCode != SWT.BS) {
1991 			if ((e.stateMask & (~SWT.SHIFT)) != 0 || e.character < 32)
1992 				return;
1993 		}
1994 	}
1995 
keyReleased(KeyEvent e)1996 	public void keyReleased(KeyEvent e) {
1997 		// ignore
1998 	}
1999 
2000 
2001 
2002 
2003 
moveSelectedTorrentsDown()2004   private void moveSelectedTorrentsDown() {
2005     // Don't use runForSelectDataSources to ensure the order we want
2006   	DownloadManager[] dms = getSelectedDownloads();
2007     Arrays.sort(dms, new Comparator<DownloadManager>() {
2008 			public int compare(DownloadManager a, DownloadManager b) {
2009         return a.getPosition() - b.getPosition();
2010 			}
2011     });
2012     for (int i = dms.length - 1; i >= 0; i--) {
2013       DownloadManager dm = dms[i];
2014       if (dm.getGlobalManager().isMoveableDown(dm)) {
2015         dm.getGlobalManager().moveDown(dm);
2016       }
2017     }
2018 
2019     boolean bForceSort = tv.getSortColumn().getName().equals("#");
2020     tv.columnInvalidate("#");
2021     tv.refreshTable(bForceSort);
2022   }
2023 
moveSelectedTorrentsUp()2024   private void moveSelectedTorrentsUp() {
2025     // Don't use runForSelectDataSources to ensure the order we want
2026   	DownloadManager[] dms = getSelectedDownloads();
2027     Arrays.sort(dms, new Comparator<DownloadManager>() {
2028     	public int compare(DownloadManager a, DownloadManager b) {
2029         return a.getPosition() - b.getPosition();
2030       }
2031     });
2032     for (int i = 0; i < dms.length; i++) {
2033       DownloadManager dm = dms[i];
2034       if (dm.getGlobalManager().isMoveableUp(dm)) {
2035         dm.getGlobalManager().moveUp(dm);
2036       }
2037     }
2038 
2039     boolean bForceSort = tv.getSortColumn().getName().equals("#");
2040     tv.columnInvalidate("#");
2041     tv.refreshTable(bForceSort);
2042   }
2043 
moveSelectedTorrents(int by)2044 	private void moveSelectedTorrents(int by) {
2045 		// Don't use runForSelectDataSources to ensure the order we want
2046   	DownloadManager[] dms = getSelectedDownloads();
2047 		if (dms.length <= 0)
2048 			return;
2049 
2050 		int[] newPositions = new int[dms.length];
2051 
2052 		if (by < 0) {
2053 			Arrays.sort(dms, new Comparator<DownloadManager>() {
2054 				public int compare(DownloadManager a, DownloadManager b) {
2055 					return a.getPosition() - b.getPosition();
2056 				}
2057 			});
2058 		} else {
2059 			Arrays.sort(dms, new Comparator<DownloadManager>() {
2060 				public int compare(DownloadManager a, DownloadManager b) {
2061 					return b.getPosition() - a.getPosition();
2062 				}
2063 			});
2064 		}
2065 
2066 		for (int i = 0; i < dms.length; i++) {
2067 			DownloadManager dm = dms[i];
2068 			boolean complete = dm.isDownloadComplete(false);
2069 			int count = globalManager.downloadManagerCount(complete);
2070 			int pos = dm.getPosition() + by;
2071 			if (pos < i + 1)
2072 				pos = i + 1;
2073 			else if (pos > count - i)
2074 				pos = count - i;
2075 
2076 			newPositions[i] = pos;
2077 		}
2078 
2079 		for (int i = 0; i < dms.length; i++) {
2080 			DownloadManager dm = dms[i];
2081 			globalManager.moveTo(dm, newPositions[i]);
2082 		}
2083 
2084     boolean bForceSort = tv.getSortColumn().getName().equals("#");
2085     tv.columnInvalidate("#");
2086     tv.refreshTable(bForceSort);
2087 	}
2088 
moveSelectedTorrentsTop()2089   private void moveSelectedTorrentsTop() {
2090     moveSelectedTorrentsTopOrEnd(true);
2091   }
2092 
moveSelectedTorrentsEnd()2093   private void moveSelectedTorrentsEnd() {
2094     moveSelectedTorrentsTopOrEnd(false);
2095   }
2096 
moveSelectedTorrentsTopOrEnd(boolean moveToTop)2097   private void moveSelectedTorrentsTopOrEnd(boolean moveToTop) {
2098   	DownloadManager[] dms = getSelectedDownloads();
2099     if (dms.length == 0)
2100       return;
2101 
2102     if(moveToTop)
2103       globalManager.moveTop(dms);
2104     else
2105       globalManager.moveEnd(dms);
2106 
2107     boolean bForceSort = tv.getSortColumn().getName().equals("#");
2108     if (bForceSort) {
2109     	tv.columnInvalidate("#");
2110     	tv.refreshTable(bForceSort);
2111     }
2112   }
2113 
2114   /**
2115    * @param parameterName the name of the parameter that has changed
2116    * @see org.gudy.azureus2.core3.config.ParameterListener#parameterChanged(java.lang.String)
2117    */
parameterChanged(String parameterName)2118   public void parameterChanged(String parameterName) {
2119 		if (parameterName == null || parameterName.equals("DND Always In Incomplete")) {
2120 			bDNDalwaysIncomplete = COConfigurationManager.getBooleanParameter("DND Always In Incomplete");
2121 		}
2122 
2123 		if (parameterName != null &&
2124 				( 	parameterName.equals("Library.ShowCatButtons") ||
2125 					parameterName.equals("Library.ShowTagButtons" ) ||
2126 					parameterName.equals("Library.ShowTagButtons.CompOnly" ))){
2127 
2128 			createTabs();
2129 		}
2130 	}
2131 
getActiveView()2132 	private MdiEntrySWT getActiveView() {
2133 		TableViewSWT_TabsCommon tabsCommon = tv.getTabsCommon();
2134 		if (tabsCommon != null) {
2135 			return tabsCommon.getActiveSubView();
2136 		}
2137 		return null;
2138 	}
2139 
refreshToolBarItems(Map<String, Long> list)2140 	public void refreshToolBarItems(Map<String, Long> list) {
2141 		ISelectedContent[] datasource = SelectedContentManager.getCurrentlySelectedContent();
2142 
2143 		if (!isTableFocus()) {
2144   		UISWTViewCore active_view = getActiveView();
2145   		if (active_view != null) {
2146   			UIPluginViewToolBarListener l = active_view.getToolBarListener();
2147   			if (l != null) {
2148   				Map<String, Long> activeViewList = new HashMap<String, Long>();
2149   				l.refreshToolBarItems(activeViewList);
2150   				if (activeViewList.size() > 0) {
2151   					list.putAll(activeViewList);
2152   					return;
2153   				}
2154   			}
2155   		}
2156 		}
2157   }
2158 
toolBarItemActivated(ToolBarItem item, long activationType, Object datasource)2159   public boolean toolBarItemActivated(ToolBarItem item, long activationType, Object datasource) {
2160 	  boolean isTableSelected = false;
2161 	  if (tv instanceof TableViewImpl) {
2162 	  	isTableSelected = ((TableViewImpl) tv).isTableSelected();
2163 	  }
2164 	  if (!isTableSelected) {
2165   		UISWTViewCore active_view = getActiveView();
2166   		if (active_view != null) {
2167   			UIPluginViewToolBarListener l = active_view.getToolBarListener();
2168   			if (l != null && l.toolBarItemActivated(item, activationType, datasource)) {
2169   				return true;
2170   			}
2171   		}
2172   		return false;
2173 	  }
2174 
2175 		String itemKey = item.getID();
2176   	if (activationType == UIToolBarActivationListener.ACTIVATIONTYPE_HELD) {
2177       if(itemKey.equals("up")) {
2178         moveSelectedTorrentsTop();
2179         return true;
2180       }
2181       if(itemKey.equals("down")){
2182         moveSelectedTorrentsEnd();
2183         return true;
2184       }
2185       return false;
2186   	}
2187 
2188   	if (activationType != UIToolBarActivationListener.ACTIVATIONTYPE_NORMAL) {
2189   		return false;
2190   	}
2191     if(itemKey.equals("top")) {
2192       moveSelectedTorrentsTop();
2193       return true;
2194     }
2195     if(itemKey.equals("bottom")){
2196       moveSelectedTorrentsEnd();
2197       return true;
2198     }
2199     if(itemKey.equals("up")) {
2200       moveSelectedTorrentsUp();
2201       return true;
2202     }
2203     if(itemKey.equals("down")){
2204       moveSelectedTorrentsDown();
2205       return true;
2206     }
2207     if(itemKey.equals("run")){
2208       TorrentUtil.runDataSources(tv.getSelectedDataSources().toArray());
2209       return true;
2210     }
2211     if(itemKey.equals("start")){
2212       TorrentUtil.queueDataSources(tv.getSelectedDataSources().toArray(), true);
2213       return true;
2214     }
2215     if(itemKey.equals("stop")){
2216       TorrentUtil.stopDataSources(tv.getSelectedDataSources().toArray());
2217       return true;
2218     }
2219     if (itemKey.equals("startstop")) {
2220     	TorrentUtil.stopOrStartDataSources(tv.getSelectedDataSources().toArray());
2221     	return true;
2222     }
2223     if(itemKey.equals("remove")){
2224       TorrentUtil.removeDataSources(tv.getSelectedDataSources().toArray());
2225       return true;
2226     }
2227     return false;
2228   }
2229 
2230   // DownloadManagerListener Functions
stateChanged(DownloadManager manager, int state)2231   public void stateChanged(DownloadManager manager, int state) {
2232     final TableRowCore row = tv.getRow(manager);
2233     if (row != null) {
2234     	Utils.getOffOfSWTThread(new AERunnable() {
2235 				public void runSupport() {
2236 		    	row.refresh(true);
2237 		    	if (row.isSelected()) {
2238 		    		updateSelectedContentRateLimited();
2239 		    	}
2240 				}
2241     	});
2242     }
2243   }
2244 
2245   // DownloadManagerListener
positionChanged(DownloadManager download, int oldPosition, int newPosition)2246   public void positionChanged(DownloadManager download, int oldPosition, int newPosition) {
2247   	if (isOurDownloadManager(download)) {
2248     	Utils.execSWTThreadLater(0, new AERunnable() {
2249 				public void runSupport() {
2250 					updateSelectedContent();
2251 				}
2252     	});
2253   	}
2254   }
2255 
2256   // DownloadManagerListener
filePriorityChanged(DownloadManager download, DiskManagerFileInfo file)2257   public void filePriorityChanged(DownloadManager download,
2258 			DiskManagerFileInfo file) {
2259 	}
2260 
2261   // DownloadManagerListener
completionChanged(DownloadManager manager, boolean bCompleted)2262 	public void completionChanged(DownloadManager manager, boolean bCompleted) {
2263 		// manager has moved lists
2264 
2265 		if (isOurDownloadManager(manager)) {
2266 			tv.addDataSource(manager);
2267 		} else {
2268 
2269 			tv.removeDataSource(manager);
2270 		}
2271 	}
2272 
2273   // DownloadManagerListener
downloadComplete(DownloadManager manager)2274   public void downloadComplete(DownloadManager manager) {
2275   }
2276 
2277 
2278 	public void
tagTypeChanged( TagType tag_type )2279 	tagTypeChanged(
2280 		TagType		tag_type )
2281 	{
2282 	}
2283 
2284 	public void
tagAdded( Tag tag )2285 	tagAdded(
2286 		Tag			tag )
2287 	{
2288 		createTabs();
2289 	}
2290 
2291 	private Set<Tag> pending_tag_changes = new HashSet<Tag>();
2292 
2293 	private boolean currentTagsAny = true;
2294 
2295 	public void
tagChanged( Tag tag )2296 	tagChanged(
2297 		Tag			tag )
2298 	{
2299 			// we can get a lot of hits here, limit tab rebuilds somewhat
2300 
2301 		synchronized( pending_tag_changes ){
2302 
2303 			pending_tag_changes.add( tag );
2304 		}
2305 
2306 		Utils.execSWTThread(new AERunnable() {
2307 			@Override
2308 			public void runSupport() {
2309 
2310 				if ( allTags != null ){
2311 
2312 					boolean create_tabs = false;
2313 
2314 					synchronized( pending_tag_changes ){
2315 
2316 						for ( Tag t: pending_tag_changes ){
2317 
2318 							boolean should_be_visible	= t.isVisible();
2319 							boolean is_visible			= allTags.contains( t );
2320 
2321 							if ( should_be_visible != is_visible ){
2322 
2323 								create_tabs = true;
2324 
2325 								break;
2326 							}
2327 						}
2328 
2329 						pending_tag_changes.clear();
2330 					}
2331 
2332 					if ( create_tabs ){
2333 
2334 						createTabs();
2335 					}
2336 				}
2337 			}
2338 		});
2339 	}
2340 
2341 	public void
tagRemoved( Tag tag )2342 	tagRemoved(
2343 		Tag			tag )
2344 	{
2345 		if (currentTags == null) {
2346 			return;
2347 		}
2348 
2349 		removeTagFromCurrent(tag);
2350 		createTabs();
2351 	}
2352 
2353 
removeTagFromCurrent(Tag tag)2354 	private void removeTagFromCurrent(Tag tag) {
2355 		boolean found = false;
2356 		for (int i = 0; i < currentTags.length; i++) {
2357 			Tag curTag = currentTags[i];
2358 			if (curTag.equals(tag)) {
2359 				Tag[] tags;
2360 				if (currentTags.length == 1) {
2361 					tags = new Tag[] {
2362 						CategoryManager.getCategory(Category.TYPE_ALL)
2363 					};
2364 				} else {
2365   				tags = new Tag[currentTags.length - 1];
2366   				if (i > 0) {
2367   					System.arraycopy(currentTags, 0, tags, 0, i);
2368   				}
2369   				if (tags.length - i > 0) {
2370   					System.arraycopy(currentTags, i + 1, tags, 0, tags.length - i);
2371   				}
2372 				}
2373 
2374 				setCurrentTags(tags);
2375 				found = true;
2376 				break;
2377 			}
2378 		}
2379 
2380 		if (!found) {
2381 			// always activate as deletion of this one might have
2382 			// affected the current view
2383 			setCurrentTags(currentTags);
2384 		}
2385 	}
2386 
removeFromArray(Object[] array, Object o)2387 	private Object[] removeFromArray(Object[] array, Object o) {
2388 		for (int i = 0; i < array.length; i++) {
2389 			Object cur = array[i];
2390 			if (cur.equals(o)) {
2391 				Tag[] newArray = new Tag[array.length - 1];
2392 				if (i > 0) {
2393 					System.arraycopy(array, 0, newArray, 0, i);
2394 				}
2395 				if (newArray.length - i > 0) {
2396 					System.arraycopy(array, i + 1, newArray, 0, newArray.length - i);
2397 				}
2398 
2399 				return newArray;
2400 			}
2401 		}
2402 
2403 		return array;
2404 	}
2405 
2406 			// tags
2407 
getCurrentTags()2408 	protected Tag[] getCurrentTags() {
2409 		return currentTags;
2410 	}
2411 
setCurrentTags(Tag[] tags)2412 	protected void setCurrentTags(Tag[] tags) {
2413 		if (currentTags != null) {
2414 			for (Tag tag : currentTags) {
2415 				tag.removeTagListener(this);
2416 			}
2417 		}
2418 
2419 		currentTags = tags;
2420 		if (currentTags != null) {
2421 			Set<Tag> to_remove = null;
2422 			for (Tag tag : currentTags) {
2423 				if ( tag.getTaggableTypes() != Taggable.TT_DOWNLOAD ){
2424 						// hmm, not a download related tag (e.g. peer-set), remove from the set. We can get this in the
2425 						// TagsOverview 'torrents' sub-view when peer-sets are selected in the main tag table
2426 					if (  to_remove == null ){
2427 						to_remove = new HashSet<Tag>();
2428 					}
2429 					to_remove.add( tag );
2430 				}else{
2431 					tag.addTagListener(this, false);
2432 				}
2433 			}
2434 			if ( to_remove != null ){
2435 				Tag[] updated_tags = new Tag[currentTags.length-to_remove.size()];
2436 
2437 				int	pos = 0;
2438 				for (Tag tag : currentTags) {
2439 					if ( !to_remove.contains( tag )){
2440 						updated_tags[pos++] = tag;
2441 					}
2442 				}
2443 				currentTags = updated_tags;
2444 			}
2445 		}
2446 
2447   		tv.processDataSourceQueue();
2448   		Object[] managers = globalManager.getDownloadManagers().toArray();
2449   		List<DownloadManager> listRemoves = new ArrayList<DownloadManager>();
2450   		List<DownloadManager> listAdds = new ArrayList<DownloadManager>();
2451 
2452   		for (int i = 0; i < managers.length; i++) {
2453   			DownloadManager dm = (DownloadManager) managers[i];
2454 
2455   			boolean bHave = tv.isUnfilteredDataSourceAdded(dm);
2456   			if (!isOurDownloadManager(dm)) {
2457   				if (bHave) {
2458   					listRemoves.add(dm);
2459   				}
2460   			} else {
2461   				if (!bHave) {
2462   					listAdds.add(dm);
2463   				}
2464   			}
2465   		}
2466   		tv.removeDataSources(listRemoves.toArray(new DownloadManager[0]));
2467   		tv.addDataSources(listAdds.toArray(new DownloadManager[0]));
2468 
2469   		tv.processDataSourceQueue();
2470   		//tv.refreshTable(false);
2471   	}
2472 
2473   	private boolean
isInTags( DownloadManager manager, Tag[] tags )2474   	isInTags(
2475   		DownloadManager		manager,
2476   		Tag[] 				tags )
2477   	{
2478   		if ( tags == null ){
2479   			return true;
2480   		}
2481 
2482   		if (currentTagsAny) {
2483     		for (Tag tag : tags) {
2484   				if (tag.hasTaggable(manager)) {
2485   					return true;
2486   				}
2487   			}
2488     		return false;
2489   		} else {
2490     		for (Tag tag : tags) {
2491   				if (!tag.hasTaggable(manager)) {
2492   					return false;
2493   				}
2494   			}
2495     		return true;
2496   		}
2497   	}
2498 
2499   	public boolean
isInCurrentTag( DownloadManager manager )2500   	isInCurrentTag(
2501   		DownloadManager 	manager )
2502   	{
2503   		return( isInTags(manager, currentTags ));
2504   	}
2505 
2506 	public void
taggableAdded( Tag tag, Taggable tagged )2507 	taggableAdded(
2508 		Tag			tag,
2509 		Taggable	tagged )
2510 	{
2511 		DownloadManager	manager = (DownloadManager)tagged;
2512 
2513 	 	if ( isOurDownloadManager(manager)){
2514 
2515 	 		tv.addDataSource( manager );
2516 	    }
2517 	}
2518 
2519 	public void
taggableSync( Tag tag )2520 	taggableSync(
2521 		Tag 		tag )
2522 	{
2523 		// request to fully resync this tag
2524 
2525 		List<DownloadManager> dataSources = tv.getDataSources();
2526 
2527 		for ( DownloadManager dm : dataSources ){
2528 
2529 			if ( !isOurDownloadManager(dm)){
2530 
2531 				tv.removeDataSource(dm);
2532 			}
2533 		}
2534 
2535 		for ( Taggable t: tag.getTagged()){
2536 
2537 			DownloadManager	manager = (DownloadManager)t;
2538 
2539 			if ( isOurDownloadManager( manager ) && !tv.dataSourceExists(manager)){
2540 
2541 				tv.addDataSource(manager);
2542 			}
2543 		}
2544 	}
2545 
2546 	public void
taggableRemoved( Tag tag, Taggable tagged )2547 	taggableRemoved(
2548 		Tag			tag,
2549 		Taggable	tagged )
2550 	{
2551 		DownloadManager	manager = (DownloadManager)tagged;
2552 
2553 		tv.removeDataSource( manager );
2554 	}
2555 
2556 
2557 
2558   // globalmanagerlistener Functions
2559   // @see org.gudy.azureus2.core3.global.GlobalManagerListener#downloadManagerAdded(org.gudy.azureus2.core3.download.DownloadManager)
downloadManagerAdded( DownloadManager dm )2560   public void downloadManagerAdded( DownloadManager dm ) {
2561     dm.addListener( this );
2562   	if (isOurDownloadManager(dm)) {
2563       tv.addDataSource(dm);
2564     }
2565   }
2566 
2567   // @see org.gudy.azureus2.core3.global.GlobalManagerListener#downloadManagerRemoved(org.gudy.azureus2.core3.download.DownloadManager)
downloadManagerRemoved( DownloadManager dm )2568   public void downloadManagerRemoved( DownloadManager dm ) {
2569     dm.removeListener( this );
2570     DownloadBar.close(dm);
2571     tv.removeDataSource(dm);
2572   }
2573 
destroyInitiated()2574   public void destroyInitiated() {  }
destroyed()2575   public void destroyed() { }
seedingStatusChanged( boolean seeding_only_mode, boolean b )2576   public void seedingStatusChanged( boolean seeding_only_mode, boolean b ){}
2577 
2578   // End of globalmanagerlistener Functions
2579 
2580 
2581 
2582 	// @see org.gudy.azureus2.ui.swt.views.table.impl.TableViewTab#updateLanguage()
updateLanguage()2583 	public void updateLanguage() {
2584 		super.updateLanguage();
2585 		getComposite().layout(true, true);
2586 	}
2587 
isTableFocus()2588 	public boolean isTableFocus() {
2589 		return viewActive;
2590 		//return tv.isTableFocus();
2591 	}
2592 
obfusticatedImage(final Image image)2593 	public Image obfusticatedImage(final Image image) {
2594 		return tv.obfusticatedImage(image);
2595 	}
2596 
2597 	/**
2598 	 * Creates and return an <code>TableViewSWT</code>
2599 	 * Subclasses my override to return a different TableViewSWT if needed
2600 	 * @param basicItems
2601 	 * @return
2602 	 */
2603 
2604 	private static boolean registeredCoreSubViews = false;
2605 
2606 	protected TableViewSWT<DownloadManager>
createTableView( Class<?> forDataSourceType, String tableID, TableColumnCore[] basicItems )2607 	createTableView(
2608 		Class<?> 			forDataSourceType,
2609 		String 				tableID,
2610 		TableColumnCore[] 	basicItems )
2611 	{
2612 		int tableExtraStyle = COConfigurationManager.getIntParameter("MyTorrentsView.table.style");
2613 		TableViewSWT<DownloadManager> table =
2614 			TableViewFactory.createTableViewSWT(forDataSourceType, tableID,
2615 				getPropertiesPrefix(), basicItems, "#", tableExtraStyle | SWT.MULTI
2616 						| SWT.FULL_SELECTION | SWT.VIRTUAL | SWT.CASCADE);
2617 
2618 			// config??
2619 
2620 		boolean	enable_tab_views =
2621 			!Utils.isAZ2UI() &&
2622 			supportsTabs &&
2623 			COConfigurationManager.getBooleanParameter( "Library.ShowTabsInTorrentView" );
2624 
2625 		List<String> restrictTo = new ArrayList<String>();
2626 		restrictTo.addAll(Arrays.asList(
2627 			GeneralView.MSGID_PREFIX,
2628 			TrackerView.MSGID_PREFIX,
2629 			PeersView.MSGID_PREFIX,
2630 			PeersGraphicView.MSGID_PREFIX,
2631 			PiecesView.MSGID_PREFIX,
2632 			DownloadActivityView.MSGID_PREFIX,
2633 			PieceInfoView.MSGID_PREFIX,
2634 			FilesView.MSGID_PREFIX,
2635 			TaggingView.MSGID_PREFIX,
2636 			PrivacyView.MSGID_PREFIX
2637 		));
2638 
2639 		// sub-tab hacks
2640 		restrictTo.add( "azbuddy.ui.menu.chat" );
2641 		PluginManager pm = AzureusCoreFactory.getSingleton().getPluginManager();
2642 		PluginInterface pi = pm.getPluginInterfaceByID("aercm", true);
2643 
2644 		if (pi != null) {
2645 			String pluginInfo = pi.getPluginconfig().getPluginStringParameter(
2646 					"plugin.info", "");
2647 			if (pluginInfo.equals("e")) {
2648 				restrictTo.add("rcm.subview.torrentdetails.name");
2649 			}
2650 		}
2651 
2652 		if ( Logger.isEnabled()){
2653 
2654 			restrictTo.add( LoggerView.MSGID_PREFIX );
2655 		}
2656 
2657 		table.setEnableTabViews(enable_tab_views, false,
2658 				restrictTo.toArray(new String[0]));
2659 
2660 		UIFunctionsSWT uiFunctions = UIFunctionsManagerSWT.getUIFunctionsSWT();
2661 		if (uiFunctions != null) {
2662 			UISWTInstance pluginUI = uiFunctions.getUISWTInstance();
2663 
2664 			registerPluginViews( pluginUI );
2665 		}
2666 
2667 		return( table );
2668 	}
2669 
2670 	public static void
registerPluginViews( UISWTInstance pluginUI )2671 	registerPluginViews(
2672 		UISWTInstance pluginUI )
2673 	{
2674 		if ( pluginUI != null && !registeredCoreSubViews ){
2675 
2676 			String[] views_with_tabs = {
2677 					TableManager.TABLE_MYTORRENTS_ALL_BIG,			// all simple views
2678 					TableManager.TABLE_MYTORRENTS_INCOMPLETE,		// downloading view
2679 					TableManager.TABLE_MYTORRENTS_INCOMPLETE_BIG,	// downloading view
2680 					TableManager.TABLE_MYTORRENTS_COMPLETE,			// bottom part of split views (hack of course)
2681 			};
2682 
2683 			boolean hasTags = false;
2684 			try {
2685 				// gotta be a simpler way?
2686 				hasTags = TagManagerFactory.getTagManager().getTagType(TagType.TT_DOWNLOAD_MANUAL).getTags().size() > 0;
2687 			} catch (Throwable t) {
2688 			}
2689 
2690 			for ( String id: views_with_tabs ){
2691 
2692 				pluginUI.addView( id, GeneralView.MSGID_PREFIX, GeneralView.class, null);
2693 				pluginUI.addView( id, TrackerView.MSGID_PREFIX, TrackerView.class, null);
2694 				pluginUI.addView( id, PeersView.MSGID_PREFIX,	PeersView.class, null);
2695 				pluginUI.addView( id, PeersGraphicView.MSGID_PREFIX, PeersGraphicView.class, null);
2696 				pluginUI.addView( id, PiecesView.MSGID_PREFIX, PiecesView.class, null);
2697 				pluginUI.addView( id, PieceInfoView.MSGID_PREFIX, PieceInfoView.class, null);
2698 				pluginUI.addView( id, DownloadActivityView.MSGID_PREFIX, DownloadActivityView.class, null);
2699 				pluginUI.addView( id, FilesView.MSGID_PREFIX,	FilesView.class, null);
2700 				pluginUI.addView( id, TorrentInfoView.MSGID_PREFIX, TorrentInfoView.class, null);
2701 				pluginUI.addView( id, TorrentOptionsView.MSGID_PREFIX, TorrentOptionsView.class, null);
2702 				if (hasTags) {
2703 					pluginUI.addView( id, TaggingView.MSGID_PREFIX, TaggingView.class, null);
2704 				}
2705 				pluginUI.addView( id, PrivacyView.MSGID_PREFIX, PrivacyView.class, null);
2706 
2707 				if (Logger.isEnabled()) {
2708 					pluginUI.addView( id, LoggerView.MSGID_PREFIX, LoggerView.class, null);
2709 				}
2710 			}
2711 
2712 			registeredCoreSubViews = true;
2713 		}
2714 	}
2715 	/**
2716 	 * Returns the default row height for the table
2717 	 * Subclasses my override to return a different height if needed; a height of -1 means use default
2718 	 * @return
2719 	 */
getRowDefaultHeight()2720 	protected int getRowDefaultHeight(){
2721 		return -1;
2722 	}
2723 
2724 	// @see org.gudy.azureus2.plugins.ui.tables.TableRowRefreshListener#rowRefresh(org.gudy.azureus2.plugins.ui.tables.TableRow)
rowRefresh(TableRow row)2725 	public void rowRefresh(TableRow row) {
2726 		if (!(row instanceof TableRowCore)) {
2727 			return;
2728 		}
2729 
2730 		TableRowCore rowCore = (TableRowCore) row;
2731 		Object ds = rowCore.getDataSource(true);
2732 		if (!(ds instanceof DownloadManager)) {
2733 			return;
2734 		}
2735 
2736 		DownloadManager dm = (DownloadManager) ds;
2737 		if (rowCore.getSubItemCount() == 0 && dm.getTorrent() != null
2738 				&& !dm.getTorrent().isSimpleTorrent() && rowCore.isVisible()
2739 				&& dm.getNumFileInfos() > 0) {
2740 			DiskManagerFileInfoSet fileInfos = dm.getDiskManagerFileInfoSet();
2741 			if (fileInfos != null) {
2742 				DiskManagerFileInfo[] files = fileInfos.getFiles();
2743 				boolean copied = false;
2744 				int pos = 0;
2745 				for (int i = 0; i < files.length; i++) {
2746 					DiskManagerFileInfo fileInfo = files[i];
2747 					if (fileInfo.isSkipped()
2748 							&& (fileInfo.getStorageType() == DiskManagerFileInfo.ST_COMPACT || fileInfo.getStorageType() == DiskManagerFileInfo.ST_REORDER_COMPACT)) {
2749 						continue;
2750 					}
2751 					if (pos != i) {
2752 						if ( !copied ){
2753 								// we *MUSTN'T* modify the returned array!!!!
2754 
2755 							DiskManagerFileInfo[] oldFiles = files;
2756 							files = new DiskManagerFileInfo[files.length];
2757 							System.arraycopy(oldFiles, 0, files, 0, files.length);
2758 
2759 							copied = true;
2760 						}
2761 
2762 						files[pos] = files[i];
2763 					}
2764 					pos++;
2765 				}
2766 				if (pos != files.length) {
2767 					DiskManagerFileInfo[] oldFiles = files;
2768 					files = new DiskManagerFileInfo[pos];
2769 					System.arraycopy(oldFiles, 0, files, 0, pos);
2770 				}
2771 				rowCore.setSubItems(files);
2772 			}
2773 		}
2774 	}
2775 
eventOccurred(UISWTViewEvent event)2776 	public boolean eventOccurred(UISWTViewEvent event) {
2777 		boolean b = super.eventOccurred(event);
2778 		if (event.getType() == UISWTViewEvent.TYPE_FOCUSGAINED) {
2779 			if (rebuildListOnFocusGain) {
2780   			List<?> dms = globalManager.getDownloadManagers();
2781   			List<DownloadManager> listAdds = new ArrayList<DownloadManager>();
2782   			List<DownloadManager> listRemoves = new ArrayList<DownloadManager>();
2783   			for (Iterator<?> iter = dms.iterator(); iter.hasNext();) {
2784   				DownloadManager dm = (DownloadManager) iter.next();
2785 
2786   				if (!isOurDownloadManager(dm)) {
2787   					listRemoves.add(dm);
2788   				} else {
2789   					listAdds.add(dm);
2790   				}
2791   			}
2792   			tv.removeDataSources(listRemoves.toArray(new DownloadManager[0]));
2793   			tv.addDataSources(listAdds.toArray(new DownloadManager[0]));
2794 			}
2795 	    updateSelectedContent(true);
2796 		} else if (event.getType() == UISWTViewEvent.TYPE_FOCUSLOST) {
2797 		}
2798 		return b;
2799 	}
2800 
setRebuildListOnFocusGain(boolean rebuildListOnFocusGain)2801 	public void setRebuildListOnFocusGain(boolean rebuildListOnFocusGain) {
2802 		this.rebuildListOnFocusGain = rebuildListOnFocusGain;
2803 	}
2804 
rowAdded(TableRowCore row)2805 	public void rowAdded(TableRowCore row) {
2806 		if (row.getParentRowCore() == null) {
2807 			DownloadManager dm = (DownloadManager) row.getDataSource(true);
2808 			if ( dm.getDownloadState().getBooleanAttribute( DownloadManagerState.AT_FILES_EXPANDED )){
2809 				row.setExpanded(true);
2810 			}
2811 		}
2812 		//if (getRowDefaultHeight() > 0 && row.getParentRowCore() != null) {
2813 		//	row.setHeight(20);
2814 		//}
2815 	}
2816 
rowRemoved(TableRowCore row)2817 	public void rowRemoved(TableRowCore row) {
2818 	}
2819 
2820 	public void
rowExpanded( TableRowCore row )2821 	rowExpanded(
2822 		TableRowCore 	row )
2823 	{
2824 		if ( row.getParentRowCore() == null ){
2825 
2826 			DownloadManager dm = (DownloadManager) row.getDataSource(true);
2827 
2828 			dm.getDownloadState().setBooleanAttribute( DownloadManagerState.AT_FILES_EXPANDED, true );
2829 		}
2830 	}
2831 
2832 	public void
rowCollapsed( TableRowCore row )2833 	rowCollapsed(
2834 		TableRowCore 	row )
2835 	{
2836 		if ( row.getParentRowCore() == null ){
2837 
2838 			DownloadManager dm = (DownloadManager) row.getDataSource(true);
2839 
2840 			dm.getDownloadState().setBooleanAttribute( DownloadManagerState.AT_FILES_EXPANDED, false );
2841 		}
2842 	}
2843 
getForDataSourceType()2844 	protected Class<?> getForDataSourceType() {
2845 		return forDataSourceType;
2846 	}
2847 
isCurrent(Tag tag)2848 	private boolean isCurrent(Tag tag) {
2849 		if (currentTags != null) {
2850   		for (Tag curTag : currentTags) {
2851   			if (tag.equals(curTag)) {
2852   				return true;
2853   			}
2854   		}
2855 		}
2856 		return false;
2857 	}
2858 
isCurrentTagsAny()2859 	public boolean isCurrentTagsAny() {
2860 		return currentTagsAny;
2861 	}
2862 
setCurrentTagsAny(boolean currentTagsAny)2863 	public void setCurrentTagsAny(boolean currentTagsAny) {
2864 		if (this.currentTagsAny == currentTagsAny) {
2865 			return;
2866 		}
2867 		this.currentTagsAny = currentTagsAny;
2868 		setCurrentTags(currentTags);
2869 	}
2870 }
2871