1 /* 2 * Copyright (C) Azureus Software, Inc, All Rights Reserved. 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details ( see the LICENSE file ). 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 */ 18 19 package org.gudy.azureus2.ui.swt.views.table.impl; 20 21 import java.util.Arrays; 22 import java.util.HashSet; 23 import java.util.Map; 24 import java.util.Set; 25 26 import org.eclipse.swt.SWT; 27 import org.eclipse.swt.events.SelectionAdapter; 28 import org.eclipse.swt.events.SelectionEvent; 29 import org.eclipse.swt.graphics.Image; 30 import org.eclipse.swt.graphics.Rectangle; 31 import org.eclipse.swt.layout.*; 32 import org.eclipse.swt.widgets.Composite; 33 import org.eclipse.swt.widgets.Event; 34 import org.eclipse.swt.widgets.Listener; 35 import org.eclipse.swt.widgets.Sash; 36 import org.gudy.azureus2.core3.config.COConfigurationManager; 37 import org.gudy.azureus2.core3.config.impl.ConfigurationManager; 38 import org.gudy.azureus2.core3.download.DownloadManager; 39 import org.gudy.azureus2.core3.util.Constants; 40 import org.gudy.azureus2.core3.util.Debug; 41 import org.gudy.azureus2.core3.util.IndentWriter; 42 import org.gudy.azureus2.plugins.PluginInterface; 43 import org.gudy.azureus2.plugins.ui.UIManager; 44 import org.gudy.azureus2.plugins.ui.menus.MenuItem; 45 import org.gudy.azureus2.plugins.ui.menus.MenuItemFillListener; 46 import org.gudy.azureus2.plugins.ui.menus.MenuItemListener; 47 import org.gudy.azureus2.plugins.ui.menus.MenuManager; 48 import org.gudy.azureus2.pluginsimpl.local.PluginInitializer; 49 import org.gudy.azureus2.ui.swt.Utils; 50 import org.gudy.azureus2.ui.swt.debug.ObfusticateImage; 51 import org.gudy.azureus2.ui.swt.plugins.UISWTInstance; 52 import org.gudy.azureus2.ui.swt.plugins.UISWTInstance.UISWTViewEventListenerWrapper; 53 import org.gudy.azureus2.ui.swt.plugins.UISWTView; 54 import org.gudy.azureus2.ui.swt.plugins.UISWTViewEvent; 55 import org.gudy.azureus2.ui.swt.pluginsimpl.UISWTViewCore; 56 import org.gudy.azureus2.ui.swt.views.table.TableViewSWT; 57 58 import com.aelitis.azureus.ui.UIFunctions; 59 import com.aelitis.azureus.ui.UIFunctionsManager; 60 import com.aelitis.azureus.ui.common.table.TableView; 61 import com.aelitis.azureus.ui.mdi.MdiEntry; 62 import com.aelitis.azureus.ui.mdi.MdiEntryCreationListener2; 63 import com.aelitis.azureus.ui.mdi.MultipleDocumentInterface; 64 import com.aelitis.azureus.ui.selectedcontent.ISelectedContent; 65 import com.aelitis.azureus.ui.selectedcontent.SelectedContentListener; 66 import com.aelitis.azureus.ui.selectedcontent.SelectedContentManager; 67 import com.aelitis.azureus.ui.swt.UIFunctionsManagerSWT; 68 import com.aelitis.azureus.ui.swt.UIFunctionsSWT; 69 import com.aelitis.azureus.ui.swt.mdi.MdiEntrySWT; 70 import com.aelitis.azureus.ui.swt.mdi.TabbedMdiInterface; 71 import com.aelitis.azureus.ui.swt.mdi.TabbedMdiMaximizeListener; 72 73 /** 74 * 75 * @author TuxPaper 76 * 77 */ 78 public class TableViewSWT_TabsCommon implements SelectedContentListener 79 { 80 UISWTView parentView; 81 TableViewSWT<?> tv; 82 83 /** Composite that stores the table (sometimes the same as mainComposite) */ 84 public Composite tableComposite; 85 86 private TableView<?> tvOverride; 87 private Sash sash; 88 private TabbedMdiInterface tabbedMDI; 89 private Composite cTabsHolder; 90 private FormData fdHeightChanger; 91 private MenuItem menuItemShowTabs; 92 TableViewSWT_TabsCommon(UISWTView parentView, TableViewSWT<?> tv)93 public TableViewSWT_TabsCommon(UISWTView parentView, TableViewSWT<?> tv) { 94 this.parentView = parentView; 95 this.tv = tv; 96 } 97 triggerTabViewsDataSourceChanged(TableView<?> tv)98 public void triggerTabViewsDataSourceChanged(TableView<?> tv) { 99 if (tabbedMDI == null || tabbedMDI.isDisposed()) { 100 return; 101 } 102 MdiEntry[] entries = tabbedMDI.getEntries(); 103 if (entries == null || entries.length == 0) { 104 return; 105 } 106 107 Object[] ds = tv.getSelectedDataSources(true); 108 109 for (MdiEntry entry : entries) { 110 if (entry instanceof MdiEntrySWT) { 111 triggerTabViewDataSourceChanged((MdiEntrySWT) entry, tv, ds); 112 } 113 } 114 } 115 setTvOverride(TableView<?> tvOverride)116 public void setTvOverride(TableView<?> tvOverride) { 117 this.tvOverride = tvOverride; 118 selectedContent = SelectedContentManager.getCurrentlySelectedContent(); 119 } 120 triggerTabViewDataSourceChanged(MdiEntrySWT view, TableView<?> tv, Object[] dataSourcesCore)121 public void triggerTabViewDataSourceChanged(MdiEntrySWT view, TableView<?> tv, 122 Object[] dataSourcesCore) { 123 if (tvOverride != null) { 124 tv = tvOverride; 125 } 126 if (view == null) { 127 return; 128 } 129 130 // When there is not selected datasources in the TableView, send the 131 // parent's datasource 132 133 if (dataSourcesCore == null) { 134 dataSourcesCore = tv.getSelectedDataSources(true); 135 } 136 if (tabbedMDI != null) { 137 tabbedMDI.setMaximizeVisible(dataSourcesCore != null && dataSourcesCore.length == 1); 138 } 139 view.triggerEvent(UISWTViewEvent.TYPE_DATASOURCE_CHANGED, 140 dataSourcesCore.length == 0 ? tv.getParentDataSource() 141 : dataSourcesCore); 142 } 143 delete()144 public void delete() { 145 SelectedContentManager.removeCurrentlySelectedContentListener(this); 146 147 if (menuItemShowTabs != null) { 148 menuItemShowTabs.remove(); 149 } 150 /* disposal of composite should take care of tabbedMDI 151 if (tabbedMDI == null || tabbedMDI.isDisposed()) { 152 return; 153 } 154 MdiEntry[] entries = tabbedMDI.getEntries(); 155 if (entries == null || entries.length == 0) { 156 return; 157 } 158 for (MdiEntry entry : entries) { 159 if (entry instanceof MdiEntrySWT) { 160 ((MdiEntrySWT) entry).triggerEvent(UISWTViewEvent.TYPE_DESTROY, null); 161 } 162 } 163 */ 164 } 165 generate(IndentWriter writer)166 public void generate(IndentWriter writer) { 167 writer.println("# of SubViews: " 168 + (tabbedMDI == null ? "null" : tabbedMDI.getEntriesCount())); 169 } 170 localeChanged()171 public void localeChanged() { 172 if ( tabbedMDI == null ){ 173 return; 174 } 175 MdiEntry[] entries = tabbedMDI.getEntries(); 176 if (entries == null || entries.length == 0) { 177 return; 178 } 179 for (MdiEntry entry : entries) { 180 if (entry instanceof MdiEntrySWT) { 181 ((MdiEntrySWT) entry).triggerEvent(UISWTViewEvent.TYPE_LANGUAGEUPDATE, null); 182 } 183 } 184 } 185 getActiveSubView()186 public MdiEntrySWT getActiveSubView() { 187 if (!tv.isTabViewsEnabled() || tabbedMDI == null || tabbedMDI.isDisposed() 188 || tabbedMDI.getMinimized()) { 189 return null; 190 } 191 192 return tabbedMDI.getCurrentEntrySWT(); 193 } 194 195 // TabViews Functions 196 addTabView(UISWTViewEventListenerWrapper listener, String afterID)197 private MdiEntry addTabView(UISWTViewEventListenerWrapper listener, 198 String afterID) { 199 UISWTViewCore view = null; 200 MdiEntrySWT entry = (MdiEntrySWT) tabbedMDI.createEntryFromEventListener( 201 tv.getTableID(), listener, listener.getViewID(), true, null, afterID); 202 if (entry instanceof UISWTViewCore) { 203 view = (UISWTViewCore) entry; 204 205 } else { 206 return entry; 207 } 208 209 try { 210 if (parentView != null) { 211 view.setParentView(parentView); 212 } 213 214 triggerTabViewDataSourceChanged(entry, tv, null); 215 216 } catch (Throwable e) { 217 218 Debug.out(e); 219 } 220 221 return entry; 222 } 223 removeTabView(String id)224 private void removeTabView(String id) 225 { 226 boolean exists = tabbedMDI.entryExists(id); 227 if (!exists) { 228 return; 229 } 230 MdiEntry entry = tabbedMDI.getEntry(id); 231 232 // XXX 233 //removedViews.add(((MdiEntrySWT) entry).getEventListener()); 234 tabbedMDI.removeItem(entry); 235 } 236 createSashForm(final Composite composite)237 public Composite createSashForm(final Composite composite) { 238 if (!tv.isTabViewsEnabled()) { 239 tableComposite = tv.createMainPanel(composite); 240 return tableComposite; 241 } 242 243 SelectedContentManager.addCurrentlySelectedContentListener(this); 244 245 ConfigurationManager configMan = ConfigurationManager.getInstance(); 246 247 int iNumViews = 0; 248 249 UIFunctionsSWT uiFunctions = UIFunctionsManagerSWT.getUIFunctionsSWT(); 250 if (uiFunctions != null) { 251 UISWTInstance pluginUI = uiFunctions.getUISWTInstance(); 252 253 if (pluginUI != null) { 254 iNumViews += pluginUI.getViewListeners(tv.getTableID()).length; 255 } 256 } 257 258 if (iNumViews == 0) { 259 tableComposite = tv.createMainPanel(composite); 260 return tableComposite; 261 } 262 263 final String props_prefix = tv.getTableID() + "." + tv.getPropertiesPrefix(); 264 265 FormData formData; 266 267 final Composite form = new Composite(composite, SWT.NONE); 268 FormLayout flayout = new FormLayout(); 269 flayout.marginHeight = 0; 270 flayout.marginWidth = 0; 271 form.setLayout(flayout); 272 GridData gridData; 273 gridData = new GridData(GridData.FILL_BOTH); 274 form.setLayoutData(gridData); 275 276 // Create them in reverse order, so we can have the table auto-grow, and 277 // set the tabFolder's height manually 278 279 280 cTabsHolder = new Composite(form, SWT.NONE); 281 tabbedMDI = uiFunctions.createTabbedMDI(cTabsHolder, props_prefix); 282 tabbedMDI.setMaximizeVisible(true); 283 tabbedMDI.setMinimizeVisible(true); 284 285 tabbedMDI.setTabbedMdiMaximizeListener(new TabbedMdiMaximizeListener() { 286 public void maximizePressed() { 287 TableView tvToUse = tvOverride == null ? tv : tvOverride; 288 Object[] ds = tvToUse.getSelectedDataSources(true); 289 290 if (ds.length == 1 && ds[0] instanceof DownloadManager) { 291 292 UIFunctions uiFunctions = UIFunctionsManager.getUIFunctions(); 293 294 if (uiFunctions != null) { 295 296 uiFunctions.getMDI().showEntryByID( 297 MultipleDocumentInterface.SIDEBAR_SECTION_TORRENT_DETAILS, 298 ds); 299 } 300 } 301 } 302 }); 303 304 final int SASH_WIDTH = 5; 305 306 sash = Utils.createSash( form, SASH_WIDTH ); 307 308 tableComposite = tv.createMainPanel(form); 309 Composite cFixLayout = tableComposite; 310 while (cFixLayout != null && cFixLayout.getParent() != form) { 311 cFixLayout = cFixLayout.getParent(); 312 } 313 if (cFixLayout == null) { 314 cFixLayout = tableComposite; 315 } 316 GridLayout layout = new GridLayout(); 317 layout.numColumns = 1; 318 layout.horizontalSpacing = 0; 319 layout.verticalSpacing = 0; 320 layout.marginHeight = 0; 321 layout.marginWidth = 0; 322 cFixLayout.setLayout(layout); 323 324 // FormData for Folder 325 formData = new FormData(); 326 formData.left = new FormAttachment(0, 0); 327 formData.right = new FormAttachment(100, 0); 328 formData.bottom = new FormAttachment(100, 0); 329 int iSplitAt = configMan.getIntParameter(props_prefix + ".SplitAt", 330 3000); 331 // Was stored at whole 332 if (iSplitAt < 100) { 333 iSplitAt *= 100; 334 } 335 336 // pct is % bottom 337 double pct = iSplitAt / 10000.0; 338 if (pct < 0.03) { 339 pct = 0.03; 340 } else if (pct > 0.97) { 341 pct = 0.97; 342 } 343 344 // height will be set on first resize call 345 sash.setData("PCT", new Double(pct)); 346 cTabsHolder.setLayout(new FormLayout()); 347 fdHeightChanger = formData; 348 cTabsHolder.setLayoutData(formData); 349 350 // FormData for Sash 351 formData = new FormData(); 352 formData.left = new FormAttachment(0, 0); 353 formData.right = new FormAttachment(100, 0); 354 formData.bottom = new FormAttachment(cTabsHolder); 355 formData.height = SASH_WIDTH; 356 sash.setLayoutData(formData); 357 358 // FormData for table Composite 359 formData = new FormData(); 360 formData.left = new FormAttachment(0, 0); 361 formData.right = new FormAttachment(100, 0); 362 formData.top = new FormAttachment(0, 0); 363 formData.bottom = new FormAttachment(sash); 364 cFixLayout.setLayoutData(formData); 365 366 367 368 // Listeners to size the folder 369 sash.addSelectionListener(new SelectionAdapter() { 370 public void widgetSelected(SelectionEvent e) { 371 final boolean FASTDRAG = true; 372 373 if (FASTDRAG && e.detail == SWT.DRAG) { 374 return; 375 } 376 377 Rectangle area = form.getClientArea(); 378 379 int height = area.height - e.y - e.height; 380 381 if ( !Constants.isWindows ){ 382 height -= SASH_WIDTH; 383 } 384 385 // prevent sash from being dragged too far up. In the worst case it ends up 386 // overlaying the split my-torrents sash and the user can't easily separate the two... 387 388 if ( area.height - height < 100 ){ 389 height = area.height - 100; 390 } 391 392 if ( height < 0 ){ 393 height = 0; 394 } 395 396 fdHeightChanger.height = height; 397 398 Double l = new Double((double) height / area.height); 399 sash.setData("PCT", l); 400 if (e.detail != SWT.DRAG) { 401 ConfigurationManager configMan = ConfigurationManager.getInstance(); 402 configMan.setParameter(props_prefix + ".SplitAt", 403 (int) (l.doubleValue() * 10000)); 404 } 405 form.layout(); 406 // sometimes sash cheese is left 407 cTabsHolder.redraw(); 408 } 409 }); 410 411 buildFolder(form, props_prefix); 412 413 return form; 414 } 415 buildFolder(final Composite form, final String props_prefix)416 private void buildFolder(final Composite form, final String props_prefix) { 417 PluginInterface pi = PluginInitializer.getDefaultInterface(); 418 UIManager uim = pi.getUIManager(); 419 MenuManager menuManager = uim.getMenuManager(); 420 421 422 menuItemShowTabs = menuManager.addMenuItem(props_prefix + "._end_", 423 "ConfigView.section.style.ShowTabsInTorrentView"); 424 menuItemShowTabs.setStyle(MenuItem.STYLE_CHECK); 425 menuItemShowTabs.addFillListener(new MenuItemFillListener() { 426 public void menuWillBeShown(MenuItem menu, Object data) { 427 menu.setData(COConfigurationManager.getBooleanParameter( 428 "Library.ShowTabsInTorrentView")); 429 } 430 }); 431 menuItemShowTabs.addListener(new MenuItemListener() { 432 public void selected(MenuItem menu, Object target) { 433 COConfigurationManager.setParameter("Library.ShowTabsInTorrentView", 434 (Boolean) menu.getData()); 435 } 436 }); 437 438 cTabsHolder.addListener(SWT.Resize, new Listener() { 439 public void handleEvent(Event e) { 440 if (tabbedMDI.getMinimized()) { 441 fdHeightChanger.height = tabbedMDI.getFolderHeight(); 442 cTabsHolder.getParent().layout(); 443 return; 444 } 445 446 Double l = (Double) sash.getData("PCT"); 447 if (l != null) { 448 fdHeightChanger.height = (int) (form.getBounds().height * l.doubleValue()); 449 cTabsHolder.getParent().layout(); 450 } 451 } 452 }); 453 454 String[] restricted_to = tv.getTabViewsRestrictedTo(); 455 456 Set<String> rt_set = new HashSet<String>(); 457 458 if ( restricted_to != null ){ 459 460 rt_set.addAll( Arrays.asList( restricted_to )); 461 } 462 463 // Call plugin listeners 464 465 UIFunctionsSWT uiFunctions = UIFunctionsManagerSWT.getUIFunctionsSWT(); 466 if (uiFunctions != null) { 467 468 UISWTInstance pluginUI = uiFunctions.getUISWTInstance(); 469 470 if (pluginUI != null) { 471 472 UISWTViewEventListenerWrapper[] pluginViews = pluginUI.getViewListeners( 473 tv.getTableID()); 474 if (pluginViews != null) { 475 for (final UISWTViewEventListenerWrapper l : pluginViews) { 476 if (l == null) { 477 continue; 478 } 479 try { 480 String view_id = l.getViewID(); 481 482 if (restricted_to != null && !rt_set.contains(view_id)) { 483 continue; 484 } 485 486 tabbedMDI.registerEntry(view_id, new MdiEntryCreationListener2() { 487 public MdiEntry createMDiEntry(MultipleDocumentInterface mdi, String id, 488 Object datasource, Map<?, ?> params) { 489 return addTabView(l, null); 490 } 491 }); 492 493 tabbedMDI.loadEntryByID(view_id, false); 494 495 } catch (Exception e) { 496 // skip, plugin probably specifically asked to not be added 497 } 498 } 499 } 500 } 501 } 502 503 if (!tabbedMDI.getMinimized()) { 504 MdiEntry[] entries = tabbedMDI.getEntries(); 505 if (entries.length > 0) { 506 tabbedMDI.showEntry(entries[0]); 507 } 508 } 509 } 510 511 private ISelectedContent[] selectedContent; 512 swt_refresh()513 public void swt_refresh() { 514 if (tv.isTabViewsEnabled() && tabbedMDI != null && !tabbedMDI.isDisposed() 515 && !tabbedMDI.getMinimized()){ 516 517 MdiEntry entry = tabbedMDI.getCurrentEntry(); 518 if (entry != null) { 519 entry.updateUI(); 520 } 521 } 522 } 523 524 // @see com.aelitis.azureus.ui.selectedcontent.SelectedContentListener#currentlySelectedContentChanged(com.aelitis.azureus.ui.selectedcontent.ISelectedContent[], java.lang.String) currentlySelectedContentChanged(ISelectedContent[] currentContent, String viewID)525 public void currentlySelectedContentChanged(ISelectedContent[] currentContent, 526 String viewID) { 527 TableView tvToUse = tvOverride == null ? tv : tvOverride; 528 if (viewID != null && viewID.equals(tvToUse.getTableID())) { 529 selectedContent = currentContent; 530 } 531 if (currentContent.length == 0 && tv.isVisible() && selectedContent != null 532 && selectedContent.length != 0) { 533 SelectedContentManager.changeCurrentlySelectedContent( 534 tvToUse.getTableID(), selectedContent, tvToUse); 535 } 536 } 537 obfusticatedImage(Image image)538 public void obfusticatedImage(Image image) { 539 if (tabbedMDI instanceof ObfusticateImage) { 540 ObfusticateImage o = (ObfusticateImage) tabbedMDI; 541 image = o.obfusticatedImage(image); 542 } 543 } 544 } 545