1 /** 2 * Created on Jun 23, 2008 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. 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 com.aelitis.azureus.ui.swt.views.skin.sidebar; 22 23 import java.util.ArrayList; 24 import java.util.Iterator; 25 import java.util.List; 26 import java.util.Stack; 27 28 import org.eclipse.swt.SWT; 29 import org.eclipse.swt.dnd.*; 30 import org.eclipse.swt.events.*; 31 import org.eclipse.swt.graphics.*; 32 import org.eclipse.swt.layout.*; 33 import org.eclipse.swt.widgets.*; 34 import org.gudy.azureus2.core3.config.COConfigurationManager; 35 import org.gudy.azureus2.core3.config.ParameterListener; 36 import org.gudy.azureus2.core3.util.*; 37 import org.gudy.azureus2.plugins.PluginInterface; 38 import org.gudy.azureus2.plugins.PluginManager; 39 import org.gudy.azureus2.plugins.ui.*; 40 import org.gudy.azureus2.plugins.ui.menus.MenuItem; 41 import org.gudy.azureus2.plugins.ui.menus.MenuItemFillListener; 42 import org.gudy.azureus2.plugins.ui.menus.MenuItemListener; 43 import org.gudy.azureus2.plugins.ui.menus.MenuManager; 44 import org.gudy.azureus2.ui.swt.URLTransfer; 45 import org.gudy.azureus2.ui.swt.Utils; 46 import org.gudy.azureus2.ui.swt.debug.ObfusticateImage; 47 import org.gudy.azureus2.ui.swt.mainwindow.TorrentOpener; 48 import org.gudy.azureus2.ui.swt.plugins.*; 49 import org.gudy.azureus2.ui.swt.pluginsimpl.*; 50 import org.gudy.azureus2.ui.swt.pluginsimpl.UISWTInstanceImpl.SWTViewListener; 51 import org.gudy.azureus2.ui.swt.views.IViewAlwaysInitialize; 52 53 import com.aelitis.azureus.core.AzureusCoreFactory; 54 import com.aelitis.azureus.ui.UIFunctionsManager; 55 import com.aelitis.azureus.ui.common.updater.UIUpdater; 56 import com.aelitis.azureus.ui.common.viewtitleinfo.ViewTitleInfo; 57 import com.aelitis.azureus.ui.mdi.MdiEntry; 58 import com.aelitis.azureus.ui.mdi.MdiEntryVitalityImage; 59 import com.aelitis.azureus.ui.swt.UIFunctionsManagerSWT; 60 import com.aelitis.azureus.ui.swt.mdi.*; 61 import com.aelitis.azureus.ui.swt.skin.*; 62 import com.aelitis.azureus.ui.swt.skin.SWTSkinButtonUtility.ButtonListenerAdapter; 63 import com.aelitis.azureus.ui.swt.utils.FontUtils; 64 import com.aelitis.azureus.ui.swt.views.skin.SkinnedDialog; 65 66 /** 67 * @author TuxPaper 68 * @created Jun 23, 2008 69 * 70 */ 71 public class SideBar 72 extends BaseMDI 73 implements ObfusticateImage, AEDiagnosticsEvidenceGenerator 74 { 75 protected static final boolean isGTK3 = Utils.isGTK 76 && System.getProperty("org.eclipse.swt.internal.gtk.version", "2").startsWith("3"); 77 78 protected static final boolean END_INDENT = Constants.isLinux 79 || Constants.isWindows2000 || Constants.isWindows9598ME; 80 81 private static final boolean USE_PAINTITEM = !Utils.isCarbon; 82 83 // Need to use paint even on Cocoa, because there's cases where an area 84 // will become invalidated and we don't get a paintitem :( 85 private static final boolean USE_PAINT = !Constants.isWindows && !Utils.isGTK; 86 87 protected static final boolean USE_NATIVE_EXPANDER = Utils.isGTK; 88 89 private static final int GAP_BETWEEN_LEVEL_1; 90 91 92 static{ 93 GAP_BETWEEN_LEVEL_1 = Math.min( 5, Math.max( 0, COConfigurationManager.getIntParameter( "Side Bar Top Level Gap", 1 ))); 94 } 95 96 protected static final int SIDEBAR_ATTENTION_PERIOD = 500; 97 protected static final int SIDEBAR_ATTENTION_DURATION = 5000; 98 99 private SWTSkin skin; 100 101 private SWTSkinObjectContainer soSideBarContents; 102 103 private SWTSkinObject soSideBarList; 104 105 private Tree tree; 106 107 private Font fontHeader; 108 109 private Font font; 110 111 private SWTSkinObject soSideBarPopout; 112 113 private SelectionListener dropDownSelectionListener; 114 115 private DropTarget dropTarget; 116 117 protected SideBarEntrySWT draggingOver; 118 119 private Color fg; 120 121 private Color bg; 122 123 private List<SideBarEntrySWT> attention_seekers = new ArrayList<SideBarEntrySWT>(); 124 private TimerEventPeriodic attention_event; 125 126 private Composite cPluginsArea; 127 128 public static SideBar instance = null; 129 130 private List<UISWTViewCore> pluginViews = new ArrayList<UISWTViewCore>(); 131 132 SideBar()133 public SideBar() { 134 super(); 135 if (instance == null) { 136 instance = this; 137 } 138 AEDiagnostics.addEvidenceGenerator(this); 139 } 140 141 // @see com.aelitis.azureus.ui.swt.skin.SWTSkinObjectAdapter#skinObjectCreated(com.aelitis.azureus.ui.swt.skin.SWTSkinObject, java.lang.Object) skinObjectCreated(SWTSkinObject skinObject, Object params)142 public Object skinObjectCreated(SWTSkinObject skinObject, Object params) { 143 super.skinObjectCreated(skinObject, params); 144 145 skin = skinObject.getSkin(); 146 147 soSideBarContents = (SWTSkinObjectContainer) skin.getSkinObject("sidebar-contents"); 148 soSideBarList = skin.getSkinObject("sidebar-list"); 149 soSideBarPopout = skin.getSkinObject("sidebar-pop"); 150 151 SWTSkinObjectContainer soSideBarPluginsArea = (SWTSkinObjectContainer) skin.getSkinObject("sidebar-plugins"); 152 if (soSideBarPluginsArea != null) { 153 Composite composite = soSideBarPluginsArea.getComposite(); 154 cPluginsArea = new Composite(composite, SWT.NONE); 155 GridLayout layout = new GridLayout(); 156 layout.marginHeight = layout.marginWidth = 0; 157 layout.verticalSpacing = layout.horizontalSpacing = 0; 158 cPluginsArea.setLayout(layout); 159 cPluginsArea.setLayoutData(Utils.getFilledFormData()); 160 } 161 162 addGeneralMenus(); 163 164 createSideBar(); 165 166 try { 167 // don't think this is required as the SideBar constructor (well SkinView) registers it 168 169 UIUpdater updater = UIFunctionsManager.getUIFunctions().getUIUpdater(); 170 171 if ( !updater.isAdded( this )){ 172 173 updater.addUpdater(this); 174 } 175 } catch ( Throwable e) { 176 Debug.out(e); 177 } 178 179 Display.getDefault().addFilter(SWT.KeyDown, new Listener() { 180 public void handleEvent(Event event) { 181 // F9 is standard Seamonkey, but doesn't work on OSX 182 // Command Option T is standard on OSX 183 // F7 works on both 184 if (event.keyCode == SWT.F9 185 || event.keyCode == SWT.F7 186 || (event.keyCode == 116 && event.stateMask == (SWT.COMMAND | SWT.ALT))) { 187 event.doit = false; 188 event.keyCode = 0; 189 event.character = '\0'; 190 flipSideBarVisibility(); 191 }else if (event.keyCode == SWT.F4 && event.stateMask == SWT.CTRL ){ 192 MdiEntry entry = getCurrentEntry(); 193 194 if ( entry instanceof SideBarEntrySWT && entry.isCloseable()){ 195 196 ((SideBarEntrySWT)entry).getTreeItem().dispose(); 197 } 198 } 199 } 200 }); 201 202 return null; 203 } 204 205 /** 206 * 207 * 208 * @since 3.1.0.1 209 */ 210 addGeneralMenus()211 private void addGeneralMenus() { 212 213 PluginManager pm = AzureusCoreFactory.getSingleton().getPluginManager(); 214 PluginInterface pi = pm.getDefaultPluginInterface(); 215 UIManager uim = pi.getUIManager(); 216 MenuManager menuManager = uim.getMenuManager(); 217 MenuItem menuItem = menuManager.addMenuItem("sidebar._end_", "menu.pop.out"); 218 219 menuItem.addFillListener( 220 new MenuItemFillListener() { 221 222 public void menuWillBeShown(MenuItem menu, Object data) { 223 SideBarEntrySWT sbe = (SideBarEntrySWT)currentEntry; 224 225 menu.setVisible( sbe != null && sbe.canBuildStandAlone()); 226 } 227 }); 228 229 menuItem.addListener(new MenuItemListener() { 230 public void selected(MenuItem menu, Object target) { 231 SideBarEntrySWT sbe = (SideBarEntrySWT)currentEntry; 232 233 if ( sbe != null ){ 234 SkinnedDialog skinnedDialog = 235 new SkinnedDialog( 236 "skin3_dlg_sidebar_popout", 237 "shell", 238 null, // standalone 239 SWT.RESIZE | SWT.MAX | SWT.DIALOG_TRIM); 240 241 SWTSkin skin = skinnedDialog.getSkin(); 242 243 SWTSkinObjectContainer cont = sbe.buildStandAlone((SWTSkinObjectContainer)skin.getSkinObject( "content-area" )); 244 245 if ( cont != null ){ 246 247 skinnedDialog.setTitle( sbe.getTitle()); 248 249 skinnedDialog.open(); 250 251 }else{ 252 253 skinnedDialog.close(); 254 } 255 } 256 } 257 }); 258 259 } 260 261 262 /** 263 * 264 * 265 * @since 3.1.1.1 266 */ flipSideBarVisibility()267 public void flipSideBarVisibility() { 268 final SWTSkinObjectSash soSash = (SWTSkinObjectSash) skin.getSkinObject("sidebar-sash"); 269 if (soSash == null) { 270 return; 271 } 272 Utils.execSWTThreadLater(0, new AERunnable() { 273 public void runSupport() { 274 boolean visible = !soSash.isAboveVisible(); 275 276 soSash.setAboveVisible( visible ); 277 updateSidebarVisibility(); 278 279 COConfigurationManager.setParameter( "Show Side Bar", visible ); 280 } 281 }); 282 } 283 updateSidebarVisibility()284 private void updateSidebarVisibility() { 285 Utils.execSWTThread(new AERunnable() { 286 public void runSupport() { 287 final SWTSkinObjectSash soSash = (SWTSkinObjectSash) skin.getSkinObject("sidebar-sash"); 288 if (soSash == null) { 289 return; 290 } 291 if (soSash.isAboveVisible()) { 292 if (soSideBarPopout != null) { 293 Object ld = soSideBarPopout.getControl().getLayoutData(); 294 if (ld instanceof FormData) { 295 FormData fd = (FormData) ld; 296 fd.width = 0; 297 } 298 soSideBarPopout.setVisible(false); 299 300 Utils.relayout(soSideBarPopout.getControl()); 301 } 302 } else { 303 if (soSideBarPopout != null) { 304 Object ld = soSideBarPopout.getControl().getLayoutData(); 305 if (ld instanceof FormData) { 306 FormData fd = (FormData) ld; 307 fd.width = 24; 308 } 309 soSideBarPopout.setVisible(true); 310 soSideBarPopout.getControl().moveAbove(null); 311 Utils.relayout(soSideBarPopout.getControl()); 312 } 313 } 314 } 315 }); 316 } 317 isVisible()318 public boolean isVisible() { 319 SWTSkinObjectSash soSash = (SWTSkinObjectSash) skin.getSkinObject("sidebar-sash"); 320 if (soSash == null) { 321 return false; 322 } 323 return soSash.isAboveVisible(); 324 } 325 326 // @see com.aelitis.azureus.ui.swt.views.skin.SkinView#showSupport(com.aelitis.azureus.ui.swt.skin.SWTSkinObject, java.lang.Object) skinObjectInitialShow(SWTSkinObject skinObject, Object params)327 public Object skinObjectInitialShow(SWTSkinObject skinObject, Object params) { 328 329 super.skinObjectInitialShow(skinObject, params); 330 331 COConfigurationManager.addParameterListener( 332 "Show Side Bar", 333 new ParameterListener() 334 { 335 public void 336 parameterChanged( 337 String name ) 338 { 339 boolean visible = COConfigurationManager.getBooleanParameter( name ); 340 341 if ( visible != isVisible()){ 342 343 flipSideBarVisibility(); 344 } 345 } 346 }); 347 348 updateSidebarVisibility(); 349 350 return null; 351 } 352 353 /* (non-Javadoc) 354 * @see com.aelitis.azureus.ui.swt.mdi.BaseMDI#setupPluginViews() 355 */ 356 @Override setupPluginViews()357 protected void setupPluginViews() { 358 super.setupPluginViews(); 359 createSideBarPluginViews(); 360 } 361 skinObjectDestroyed(SWTSkinObject skinObject, Object params)362 public Object skinObjectDestroyed(SWTSkinObject skinObject, Object params) { 363 try { 364 UIFunctionsManager.getUIFunctions().getUIUpdater().removeUpdater(this); 365 } catch (Exception e) { 366 Debug.out(e); 367 } 368 369 return super.skinObjectDestroyed(skinObject, params); 370 } 371 createSideBar()372 private void createSideBar() { 373 if (soSideBarList == null) { 374 return; 375 } 376 Composite parent = (Composite) soSideBarList.getControl(); 377 378 tree = new Tree(parent, SWT.FULL_SELECTION | SWT.V_SCROLL 379 | SWT.DOUBLE_BUFFERED | SWT.NO_SCROLL); 380 tree.setHeaderVisible(false); 381 382 new SideBarToolTips(this, tree); 383 384 tree.setLayoutData(Utils.getFilledFormData()); 385 386 SWTSkinProperties skinProperties = skin.getSkinProperties(); 387 bg = skinProperties.getColor("color.sidebar.bg"); 388 fg = skinProperties.getColor("color.sidebar.fg"); 389 390 COConfigurationManager.addParameterListener( 391 "config.skin.color.sidebar.bg", 392 new ParameterListener() { 393 394 public void parameterChanged(String parameterName) { 395 396 Utils.execSWTThread( 397 new Runnable() 398 { 399 public void 400 run() 401 { 402 swt_updateSideBarColors(); 403 } 404 }); 405 } 406 }); 407 408 tree.setBackground(bg); 409 tree.setForeground(fg); 410 FontData[] fontData = tree.getFont().getFontData(); 411 412 int fontHeight; 413 414 if (isGTK3) { 415 fontHeight = fontData[0].getHeight(); 416 } else { 417 fontHeight = (Constants.isOSX ? 11 : 12) 418 + (tree.getItemHeight() > 18 ? tree.getItemHeight() - 18 : 0); 419 420 if (Constants.isLinux && tree.getItemHeight() >= 38) { 421 fontHeight = 13; 422 } 423 } 424 425 fontData[0].setStyle(SWT.BOLD); 426 FontUtils.getFontHeightFromPX(tree.getDisplay(), fontData, null, fontHeight); 427 fontHeader = new Font(tree.getDisplay(), fontData); 428 font = FontUtils.getFontWithHeight(tree.getFont(), null, fontHeight); 429 430 tree.setFont(font); 431 432 // after a scroll we need to recalculate the hit areas as they will have moved! 433 434 tree.getVerticalBar().addSelectionListener( 435 new SelectionAdapter() 436 { 437 public void widgetSelected(SelectionEvent e) { 438 if ( e.detail == SWT.None ){ 439 SideBarEntrySWT[] sideBarEntries = getEntries( new SideBarEntrySWT[0]); 440 swt_updateSideBarHitAreasY(sideBarEntries); 441 } 442 } 443 }); 444 445 Listener treeListener = new Listener() { 446 TreeItem lastTopItem = null; 447 448 boolean mouseDowned = false; 449 450 Rectangle lastCloseAreaClicked = null; 451 452 private boolean wasExpanded; 453 454 public void handleEvent(final Event event) { 455 TreeItem treeItem = (TreeItem) event.item; 456 Tree tree = getTree(); 457 458 try { 459 switch (event.type) { 460 case SWT.MeasureItem: { 461 int clientWidth = tree.getClientArea().width; 462 String text = treeItem.getText(event.index); 463 Point size = event.gc.textExtent(text); 464 if (event.x + event.width < clientWidth) { 465 event.width = size.x + event.x; // tree.getClientArea().width; 466 event.x = 0; 467 } 468 469 if (Constants.isWindows) { 470 event.width = clientWidth - event.x; 471 } 472 473 event.height = 20; 474 475 break; 476 } 477 case SWT.PaintItem: { 478 if (USE_PAINTITEM) { 479 SideBarEntrySWT entry = (SideBarEntrySWT) treeItem.getData("MdiEntry"); 480 //System.out.println("PaintItem: " + event.item + ";" + event.index + ";" + event.detail + ";" + id + ";" + event.getBounds() + ";" + event.gc.getClipping()); 481 if (entry != null) { 482 boolean selected = currentEntry == entry 483 && entry.isSelectable(); 484 485 if (!selected) { 486 event.detail &= ~SWT.SELECTED; 487 } else { 488 event.detail |= SWT.SELECTED; 489 } 490 entry.swt_paintSideBar(event); 491 } 492 } 493 break; 494 } 495 496 case SWT.Paint: { 497 //System.out.println("Paint: " + event.getBounds() + ";" + event.detail + ";" + event.index + ";" + event.gc.getClipping() + " " + Debug.getCompressedStackTrace()); 498 if (!USE_PAINT) { 499 return; 500 } 501 Rectangle bounds = event.getBounds(); 502 int indent = END_INDENT ? tree.getClientArea().width - 1 : 0; 503 int y = event.y + 1; 504 treeItem = tree.getItem(new Point(indent, y)); 505 506 while (treeItem != null) { 507 SideBarEntrySWT entry = (SideBarEntrySWT) treeItem.getData("MdiEntry"); 508 Rectangle itemBounds = entry == null ? null 509 : entry.swt_getBounds(); 510 511 // null itemBounds is weird, the entry must be disposed. it 512 // happened once, so let's check.. 513 if (itemBounds != null && entry != null) { 514 event.item = treeItem; 515 516 boolean selected = currentEntry == entry 517 && entry.isSelectable(); 518 event.detail = selected ? SWT.SELECTED : SWT.NONE; 519 520 Rectangle newClip = bounds.intersection(itemBounds); 521 //System.out.println("Paint " + id + " @ " + newClip); 522 event.setBounds(newClip); 523 Utils.setClipping(event.gc, newClip); 524 525 entry.swt_paintSideBar(event); 526 527 y = itemBounds.y + itemBounds.height + 1; 528 } else { 529 y += tree.getItemHeight(); 530 } 531 532 if (y > bounds.y + bounds.height) { 533 break; 534 } 535 TreeItem oldTreeItem = treeItem; 536 treeItem = tree.getItem(new Point(indent, y)); 537 if (oldTreeItem == treeItem) { 538 break; 539 } 540 } 541 542 if (tree.getTopItem() != lastTopItem) { 543 lastTopItem = tree.getTopItem(); 544 SideBarEntrySWT[] sideBarEntries = getEntries( new SideBarEntrySWT[0]); 545 swt_updateSideBarHitAreasY(sideBarEntries); 546 } 547 548 break; 549 } 550 551 case SWT.EraseItem: { 552 SideBarEntrySWT entry = (SideBarEntrySWT) treeItem.getData("MdiEntry"); 553 if (entry == null) { 554 event.detail = 0; 555 } 556 //event.detail &= ~SWT.FOREGROUND; 557 //event.detail &= ~(SWT.FOREGROUND | SWT.BACKGROUND); 558 event.doit = true; 559 break; 560 } 561 562 case SWT.Resize: { 563 tree.redraw(); 564 break; 565 } 566 567 case SWT.Selection: { 568 if (treeItem == null) { 569 return; 570 } 571 SideBarEntrySWT entry = (SideBarEntrySWT) treeItem.getData("MdiEntry"); 572 if (entry != null && entry.isSelectable()) { 573 Point cursorLocation = tree.toControl(event.display.getCursorLocation()); 574 if (lastCloseAreaClicked != null && lastCloseAreaClicked.contains(cursorLocation.x, cursorLocation.y)) { 575 return; 576 } 577 578 showEntry(entry); 579 } else if (currentEntry != null) { 580 TreeItem topItem = tree.getTopItem(); 581 582 // prevent "jumping" in the case where selection is off screen 583 // setSelection would jump the item on screen, and then 584 // showItem would jump back to where the user was. 585 tree.setRedraw(false); 586 TreeItem ti = ((SideBarEntrySWT) currentEntry).getTreeItem(); 587 if (ti != null) { 588 tree.setSelection(ti); 589 } 590 591 tree.setTopItem(topItem); 592 tree.setRedraw(true); 593 594 event.doit = false; 595 } 596 break; 597 } 598 599 case SWT.MouseMove: { 600 int indent = END_INDENT ? tree.getClientArea().width - 1 : 0; 601 treeItem = tree.getItem(new Point(indent, event.y)); 602 SideBarEntrySWT entry = (SideBarEntrySWT) ((treeItem == null || treeItem.isDisposed()) 603 ? null : treeItem.getData("MdiEntry")); 604 605 int cursorNo = SWT.CURSOR_ARROW; 606 if (treeItem != null) { 607 Rectangle closeArea = (Rectangle) treeItem.getData("closeArea"); 608 if (closeArea != null && closeArea.contains(event.x, event.y)) { 609 cursorNo = SWT.CURSOR_HAND; 610 } else if (entry != null && !entry.isCollapseDisabled() 611 && treeItem.getItemCount() > 0) { 612 cursorNo = SWT.CURSOR_HAND; 613 } 614 } 615 616 Cursor cursor = event.display.getSystemCursor(cursorNo); 617 if (tree.getCursor() != cursor) { 618 tree.setCursor(cursor); 619 } 620 621 if (treeItem != null) { 622 wasExpanded = entry != null && entry.isExpanded(); 623 } else { 624 wasExpanded = false; 625 } 626 break; 627 } 628 629 case SWT.MouseDown: { 630 mouseDowned = true; 631 lastCloseAreaClicked = null; 632 if (tree.getItemCount() == 0 || event.button != 1) { 633 return; 634 } 635 int indent = END_INDENT ? tree.getClientArea().width - 1 : 0; 636 treeItem = tree.getItem(new Point(indent, event.y)); 637 if (treeItem == null) { 638 return; 639 } 640 Rectangle closeArea = (Rectangle) treeItem.getData("closeArea"); 641 if (closeArea != null && closeArea.contains(event.x, event.y)) { 642 lastCloseAreaClicked = closeArea; 643 treeItem.dispose(); 644 // pretend we don't have a mouse down, so we don't process a showEntry 645 mouseDowned = false; 646 } 647 break; 648 } 649 650 case SWT.MouseUp: { 651 if (!mouseDowned) { 652 return; 653 } 654 mouseDowned = false; 655 if (tree.getItemCount() == 0 || event.button != 1) { 656 return; 657 } 658 int indent = END_INDENT ? tree.getClientArea().width - 1 : 0; 659 treeItem = tree.getItem(new Point(indent, event.y)); 660 if (treeItem == null) { 661 return; 662 } 663 SideBarEntrySWT entry = (SideBarEntrySWT) treeItem.getData("MdiEntry"); 664 665 Rectangle closeArea = (Rectangle) treeItem.getData("closeArea"); 666 if (closeArea != null && closeArea.contains(event.x, event.y)) { 667 //treeItem.dispose(); 668 return; 669 } else if (currentEntry != entry && Constants.isOSX) { 670 showEntry(entry); 671 } 672 673 if (entry != null) { 674 MdiEntryVitalityImage[] vitalityImages = entry.getVitalityImages(); 675 for (int i = 0; i < vitalityImages.length; i++) { 676 SideBarVitalityImageSWT vitalityImage = (SideBarVitalityImageSWT) vitalityImages[i]; 677 if (vitalityImage == null || !vitalityImage.isVisible()) { 678 continue; 679 } 680 Rectangle hitArea = vitalityImage.getHitArea(); 681 if (hitArea == null) { 682 continue; 683 } 684 // setHitArea needs it relative to entry 685 Rectangle itemBounds = entry.swt_getBounds(); 686 int relY = event.y - (itemBounds == null ? 0 : itemBounds.y); 687 688 if (hitArea.contains(event.x, relY)) { 689 vitalityImage.triggerClickedListeners(event.x, relY); 690 return; 691 } 692 } 693 694 if (!entry.isCollapseDisabled() && treeItem.getItemCount() > 0) { 695 if (!entry.isSelectable() || event.x < 20) { 696 // Note: On Windows, user can expand row by clicking the invisible area where the OS twisty would be 697 MdiEntry currentEntry = getCurrentEntry(); 698 if (currentEntry != null 699 && entry.getId().equals(currentEntry.getParentID())) { 700 showEntryByID(SIDEBAR_SECTION_LIBRARY); 701 } 702 entry.setExpanded(!wasExpanded); 703 wasExpanded = !wasExpanded; 704 } 705 } 706 } 707 708 break; 709 } 710 711 case SWT.Dispose: { 712 fontHeader.dispose(); 713 font.dispose(); 714 if (dropTarget != null && !dropTarget.isDisposed()) { 715 dropTarget.dispose(); 716 } 717 saveCloseables(); 718 719 break; 720 } 721 722 case SWT.Collapse: { 723 SideBarEntrySWT entry = (SideBarEntrySWT) treeItem.getData("MdiEntry"); 724 725 if (entry.isCollapseDisabled()) { 726 tree.setRedraw(false); 727 Display.getDefault().asyncExec(new Runnable() { 728 public void run() { 729 ((TreeItem) event.item).setExpanded(true); 730 getTree().setRedraw(true); 731 } 732 }); 733 } else { 734 MdiEntry currentEntry = getCurrentEntry(); 735 if (currentEntry != null 736 && entry.getId().equals(currentEntry.getParentID())) { 737 showEntryByID(SIDEBAR_SECTION_LIBRARY); 738 } 739 } 740 break; 741 } 742 743 } 744 } catch (Exception e) { 745 Debug.out(e); 746 } 747 } 748 }; 749 tree.addListener(SWT.MeasureItem, treeListener); 750 tree.addListener(SWT.Resize, treeListener); 751 tree.addListener(SWT.Paint, treeListener); 752 if (USE_PAINTITEM) { 753 tree.addListener(SWT.PaintItem, treeListener); 754 tree.addListener(SWT.EraseItem, treeListener); 755 } 756 757 tree.addListener(SWT.Selection, treeListener); 758 tree.addListener(SWT.Dispose, treeListener); 759 760 // For icons 761 tree.addListener(SWT.MouseUp, treeListener); 762 tree.addListener(SWT.MouseDown, treeListener); 763 764 // For cursor 765 tree.addListener(SWT.MouseMove, treeListener); 766 767 // to disable collapsing 768 tree.addListener(SWT.Collapse, treeListener); 769 770 dropTarget = new DropTarget(tree, DND.DROP_COPY); 771 dropTarget.setTransfer(new Transfer[] { 772 URLTransfer.getInstance(), 773 FileTransfer.getInstance(), 774 TextTransfer.getInstance(), 775 }); 776 777 dropTarget.addDropListener(new DropTargetAdapter() { 778 public void dropAccept(DropTargetEvent event) { 779 event.currentDataType = URLTransfer.pickBestType(event.dataTypes, 780 event.currentDataType); 781 } 782 783 public void dragEnter(DropTargetEvent event) { 784 } 785 786 public void dragOperationChanged(DropTargetEvent event) { 787 } 788 789 // @see org.eclipse.swt.dnd.DropTargetAdapter#dragOver(org.eclipse.swt.dnd.DropTargetEvent) 790 public void dragOver(DropTargetEvent event) { 791 TreeItem treeItem = (event.item instanceof TreeItem) 792 ? (TreeItem) event.item : null; 793 794 if (treeItem != null) { 795 SideBarEntrySWT entry = (SideBarEntrySWT) treeItem.getData("MdiEntry"); 796 797 draggingOver = entry; 798 } else { 799 draggingOver = null; 800 } 801 if (draggingOver == null || !draggingOver.hasDropListeners()) { 802 803 boolean isTorrent = TorrentOpener.doesDropHaveTorrents(event); 804 805 if (isTorrent) { 806 event.detail = DND.DROP_COPY; 807 } else { 808 event.detail = DND.DROP_NONE; 809 } 810 draggingOver = null; 811 } else if ((event.operations & DND.DROP_LINK) > 0) 812 event.detail = DND.DROP_LINK; 813 else if ((event.operations & DND.DROP_COPY) > 0) 814 event.detail = DND.DROP_COPY; 815 else if ((event.operations & DND.DROP_DEFAULT) > 0) 816 event.detail = DND.DROP_COPY; 817 818 if (Constants.isOSX) { 819 tree.redraw(); 820 } 821 822 event.feedback = DND.FEEDBACK_SELECT | DND.FEEDBACK_SCROLL | DND.FEEDBACK_EXPAND; 823 } 824 825 // @see org.eclipse.swt.dnd.DropTargetAdapter#dragLeave(org.eclipse.swt.dnd.DropTargetEvent) 826 public void dragLeave(DropTargetEvent event) { 827 draggingOver = null; 828 tree.redraw(); 829 } 830 831 public void drop(DropTargetEvent event) { 832 draggingOver = null; 833 tree.redraw(); 834 if (!(event.item instanceof TreeItem)) { 835 defaultDrop(event); 836 return; 837 } 838 TreeItem treeItem = (TreeItem) event.item; 839 840 SideBarEntrySWT entry = (SideBarEntrySWT) treeItem.getData("MdiEntry"); 841 842 boolean handled = entry != null && entry.triggerDropListeners(event.data); 843 if (!handled) { 844 defaultDrop(event); 845 } 846 } 847 }); 848 849 final Menu menuTree = new Menu(tree); 850 tree.setMenu(menuTree); 851 852 menuTree.addMenuListener(new MenuListener() { 853 boolean bShown = false; 854 855 public void menuHidden(MenuEvent e) { 856 bShown = false; 857 858 if (Constants.isOSX) { 859 return; 860 } 861 862 // Must dispose in an asyncExec, otherwise SWT.Selection doesn't 863 // get fired (async workaround provided by Eclipse Bug #87678) 864 Utils.execSWTThreadLater(0, new AERunnable() { 865 public void runSupport() { 866 if (bShown || menuTree.isDisposed()) { 867 return; 868 } 869 Utils.disposeSWTObjects(menuTree.getItems()); 870 } 871 }); 872 } 873 874 public void menuShown(MenuEvent e) { 875 Utils.disposeSWTObjects(menuTree.getItems()); 876 877 bShown = true; 878 879 Point ptMouse = tree.toControl(e.display.getCursorLocation()); 880 881 int indent = END_INDENT ? tree.getClientArea().width - 1 : 0; 882 TreeItem treeItem = tree.getItem(new Point(indent, ptMouse.y)); 883 if (treeItem == null) { 884 return; 885 } 886 SideBarEntrySWT entry = (SideBarEntrySWT) treeItem.getData("MdiEntry"); 887 888 fillMenu(menuTree, entry, "sidebar"); 889 890 if (menuTree.getItemCount() == 0) { 891 Utils.execSWTThreadLater(0, new AERunnable() { 892 public void runSupport() { 893 menuTree.setVisible(false); 894 } 895 }); 896 } 897 } 898 }); 899 900 if (soSideBarPopout != null) { 901 SWTSkinObject soDropDown = skin.getSkinObject("sidebar-dropdown"); 902 if (soDropDown != null) { 903 904 final Menu menuDropDown = new Menu(soDropDown.getControl()); 905 906 menuDropDown.addMenuListener(new MenuListener() { 907 boolean bShown = false; 908 909 public void menuHidden(MenuEvent e) { 910 bShown = false; 911 912 if (Constants.isOSX) { 913 return; 914 } 915 916 // Must dispose in an asyncExec, otherwise SWT.Selection doesn't 917 // get fired (async workaround provided by Eclipse Bug #87678) 918 Utils.execSWTThreadLater(0, new AERunnable() { 919 public void runSupport() { 920 if (bShown || menuDropDown.isDisposed()) { 921 return; 922 } 923 Utils.disposeSWTObjects(menuDropDown.getItems()); 924 } 925 }); 926 } 927 928 public void menuShown(MenuEvent e) { 929 Utils.disposeSWTObjects(menuDropDown.getItems()); 930 931 bShown = true; 932 933 fillDropDownMenu(menuDropDown, tree.getItems(), 0); 934 } 935 }); 936 937 dropDownSelectionListener = new SelectionListener() { 938 public void widgetSelected(SelectionEvent e) { 939 String id = (String) e.widget.getData("Plugin.viewID"); 940 showEntryByID(id); 941 } 942 943 public void widgetDefaultSelected(SelectionEvent e) { 944 } 945 }; 946 947 SWTSkinButtonUtility btnDropDown = new SWTSkinButtonUtility(soDropDown); 948 btnDropDown.addSelectionListener(new ButtonListenerAdapter() { 949 public void pressed(SWTSkinButtonUtility buttonUtility, 950 SWTSkinObject skinObject, int stateMask) { 951 Control c = buttonUtility.getSkinObject().getControl(); 952 menuDropDown.setLocation(c.getDisplay().getCursorLocation()); 953 menuDropDown.setVisible(!menuDropDown.getVisible()); 954 } 955 }); 956 } 957 958 SWTSkinObject soExpand = skin.getSkinObject("sidebar-expand"); 959 if (soExpand != null) { 960 SWTSkinButtonUtility btnExpand = new SWTSkinButtonUtility(soExpand); 961 btnExpand.addSelectionListener(new ButtonListenerAdapter() { 962 public void pressed(SWTSkinButtonUtility buttonUtility, 963 SWTSkinObject skinObject, int stateMask) { 964 flipSideBarVisibility(); 965 } 966 }); 967 } 968 969 } 970 } 971 createSideBarPluginViews()972 private void createSideBarPluginViews() { 973 if (cPluginsArea == null) { 974 return; 975 } 976 UISWTInstanceImpl uiSWTinstance = (UISWTInstanceImpl) UIFunctionsManagerSWT.getUIFunctionsSWT().getUISWTInstance(); 977 978 if (uiSWTinstance == null) { 979 return; 980 } 981 982 UISWTViewEventListenerHolder[] pluginViews = uiSWTinstance.getViewListeners(UISWTInstance.VIEW_SIDEBAR_AREA); 983 for (UISWTViewEventListenerHolder l : pluginViews) { 984 if (l != null) { 985 try { 986 UISWTViewImpl view = new UISWTViewImpl(l.getViewID(), UISWTInstance.VIEW_SIDEBAR_AREA, false); 987 view.setEventListener(l, true); 988 addSideBarView(view, cPluginsArea); 989 cPluginsArea.getParent().getParent().layout(true, true); 990 } catch (Exception e) { 991 e.printStackTrace(); 992 // skip, plugin probably specifically asked to not be added 993 } 994 } 995 } 996 997 uiSWTinstance.addSWTViewListener(new SWTViewListener() { 998 999 public void setViewAdded(final String parent, final String id, 1000 final UISWTViewEventListener l) { 1001 if (!parent.equals(UISWTInstance.VIEW_SIDEBAR_AREA)) { 1002 return; 1003 } 1004 Utils.execSWTThread(new AERunnable() { 1005 1006 public void runSupport() { 1007 try { 1008 UISWTViewImpl view = new UISWTViewImpl(id, parent, false); 1009 view.setEventListener(l, true); 1010 addSideBarView(view, cPluginsArea); 1011 } catch (Exception e) { 1012 e.printStackTrace(); 1013 // skip, plugin probably specifically asked to not be added 1014 } 1015 } 1016 }); 1017 } 1018 1019 public void setViewRemoved(final String parent, final String id, 1020 final UISWTViewEventListener l) { 1021 if (!parent.equals(UISWTInstance.VIEW_SIDEBAR_AREA)) { 1022 return; 1023 } 1024 Utils.execSWTThread(new AERunnable() { 1025 1026 public void runSupport() { 1027 try { 1028 for (UISWTViewCore view : SideBar.this.pluginViews) { 1029 if (l.equals(view.getEventListener())) { 1030 view.closeView(); 1031 }else{ 1032 if ( l instanceof UISWTViewEventListenerHolder ){ 1033 UISWTViewEventListener l2 = ((UISWTViewEventListenerHolder) l).getDelegatedEventListener(view); 1034 if ( l2 != null && l2.equals(view.getEventListener())) { 1035 view.closeView(); 1036 } 1037 } 1038 } 1039 } 1040 } catch (Exception e) { 1041 e.printStackTrace(); 1042 // skip, plugin probably specifically asked to not be added 1043 } 1044 } 1045 }); 1046 } 1047 }); 1048 1049 cPluginsArea.getParent().getParent().layout(true, true); 1050 } 1051 addSideBarView(UISWTViewImpl view, Composite cPluginsArea)1052 private void addSideBarView(UISWTViewImpl view, Composite cPluginsArea) { 1053 Composite parent = new Composite(cPluginsArea, SWT.NONE); 1054 GridData gridData = new GridData(); 1055 gridData.grabExcessHorizontalSpace = true; 1056 gridData.horizontalAlignment = SWT.FILL; 1057 parent.setLayoutData(gridData); 1058 parent.setLayout(new FormLayout()); 1059 //parent.setBackground(ColorCache.getRandomColor()); 1060 //cPluginsArea.setBackground(ColorCache.getRandomColor()); 1061 1062 view.initialize(parent); 1063 parent.setVisible(true); 1064 1065 Control[] children = parent.getChildren(); 1066 for (int i = 0; i < children.length; i++) { 1067 Control control = children[i]; 1068 Object ld = control.getLayoutData(); 1069 boolean useGridLayout = ld != null && (ld instanceof GridData); 1070 if (useGridLayout) { 1071 GridLayout gridLayout = new GridLayout(); 1072 gridLayout.horizontalSpacing = 0; 1073 gridLayout.marginHeight = 0; 1074 gridLayout.marginWidth = 0; 1075 gridLayout.verticalSpacing = 0; 1076 parent.setLayout(gridLayout); 1077 break; 1078 } else if (ld == null) { 1079 control.setLayoutData(Utils.getFilledFormData()); 1080 } 1081 } 1082 1083 pluginViews.add(view); 1084 } 1085 1086 1087 /** 1088 * @param event 1089 */ defaultDrop(DropTargetEvent event)1090 protected void defaultDrop(DropTargetEvent event) { 1091 TorrentOpener.openDroppedTorrents(event, false); 1092 } 1093 1094 /** 1095 * @param menuDropDown 1096 * 1097 * @since 3.1.1.1 1098 */ fillDropDownMenu(Menu menuDropDown, TreeItem[] items, int indent)1099 protected void fillDropDownMenu(Menu menuDropDown, TreeItem[] items, 1100 int indent) { 1101 String s = ""; 1102 for (int i = 0; i < indent; i++) { 1103 s += " "; 1104 } 1105 for (int i = 0; i < items.length; i++) { 1106 TreeItem treeItem = items[i]; 1107 1108 SideBarEntrySWT entry = (SideBarEntrySWT) treeItem.getData("MdiEntry"); 1109 if (entry == null) { 1110 continue; 1111 } 1112 org.eclipse.swt.widgets.MenuItem menuItem = new org.eclipse.swt.widgets.MenuItem( 1113 menuDropDown, entry.isSelectable() ? SWT.RADIO : SWT.CASCADE); 1114 1115 String id = entry.getId(); 1116 menuItem.setData("Plugin.viewID", id); 1117 ViewTitleInfo titleInfo = entry.getViewTitleInfo(); 1118 String ind = ""; 1119 if (titleInfo != null) { 1120 String o = (String) titleInfo.getTitleInfoProperty(ViewTitleInfo.TITLE_INDICATOR_TEXT); 1121 if (o != null) { 1122 ind = " (" + o + ")"; 1123 //ind = "\t" + o; 1124 } 1125 } 1126 menuItem.setText(s + entry.getTitle() + ind); 1127 menuItem.addSelectionListener(dropDownSelectionListener); 1128 if (currentEntry != null && currentEntry.getId().equals(id)) { 1129 menuItem.setSelection(true); 1130 } 1131 1132 TreeItem[] subItems = treeItem.getItems(); 1133 if (subItems.length > 0) { 1134 Menu parent = menuDropDown; 1135 if (!entry.isSelectable()) { 1136 parent = new Menu(menuDropDown.getParent().getShell(), SWT.DROP_DOWN); 1137 menuItem.setMenu(parent); 1138 } 1139 1140 1141 fillDropDownMenu(parent, subItems, indent + 1); 1142 } 1143 } 1144 } 1145 1146 /** 1147 * 1148 * 1149 * @since 3.1.1.1 1150 */ swt_updateSideBarHitAreasY(SideBarEntrySWT[] entries)1151 private void swt_updateSideBarHitAreasY(SideBarEntrySWT[] entries) { 1152 for (int x = 0; x < entries.length; x++) { 1153 SideBarEntrySWT entry = entries[x]; 1154 TreeItem treeItem = entry.getTreeItem(); 1155 if (treeItem == null || treeItem.isDisposed()) { 1156 continue; 1157 } 1158 Rectangle itemBounds = entry.swt_getBounds(); 1159 1160 if ( itemBounds != null ){ 1161 if (entry.isCloseable()) { 1162 Rectangle closeArea = (Rectangle) treeItem.getData("closeArea"); 1163 if (closeArea != null) { 1164 closeArea.y = itemBounds.y + (itemBounds.height - closeArea.height) 1165 / 2; 1166 } 1167 } 1168 1169 MdiEntryVitalityImage[] vitalityImages = entry.getVitalityImages(); 1170 for (int i = 0; i < vitalityImages.length; i++) { 1171 SideBarVitalityImageSWT vitalityImage = (SideBarVitalityImageSWT) vitalityImages[i]; 1172 if (!vitalityImage.isVisible()) { 1173 continue; 1174 } 1175 Image image = vitalityImage.getImage(); 1176 if (image != null) { 1177 Rectangle bounds = vitalityImage.getHitArea(); 1178 if (bounds == null) { 1179 continue; 1180 } 1181 bounds.y = (itemBounds.height - bounds.height) / 2; 1182 } 1183 } 1184 } 1185 } 1186 } 1187 1188 private void swt_updateSideBarColors()1189 swt_updateSideBarColors() 1190 { 1191 SWTSkinProperties skinProperties = skin.getSkinProperties(); 1192 1193 skinProperties.clearCache(); 1194 1195 bg = skinProperties.getColor("color.sidebar.bg"); 1196 1197 tree.setBackground(bg); 1198 1199 tree.redraw(); 1200 1201 swt_updateSideBarColors( tree.getItems()); 1202 } 1203 1204 private void swt_updateSideBarColors( TreeItem[] items )1205 swt_updateSideBarColors( 1206 TreeItem[] items ) 1207 { 1208 for ( TreeItem ti: items){ 1209 1210 SideBarEntrySWT entry = (SideBarEntrySWT) ti.getData("MdiEntry"); 1211 1212 if ( entry != null ){ 1213 1214 entry.updateColors(); 1215 1216 entry.redraw(); 1217 } 1218 1219 swt_updateSideBarColors( ti.getItems()); 1220 } 1221 } 1222 indexOf(final MdiEntry entry)1223 protected int indexOf(final MdiEntry entry) { 1224 Object o = Utils.execSWTThreadWithObject("indexOf", new AERunnableObject() { 1225 public Object runSupport() { 1226 TreeItem treeItem = ((SideBarEntrySWT) entry).getTreeItem(); 1227 if (treeItem == null) { 1228 return -1; 1229 } 1230 TreeItem parentItem = treeItem.getParentItem(); 1231 if (parentItem != null) { 1232 return parentItem.indexOf(treeItem); 1233 } 1234 return tree.indexOf(treeItem); 1235 } 1236 }, 500); 1237 if (o instanceof Number) { 1238 return ((Number) o).intValue(); 1239 } 1240 return -1; 1241 } 1242 createHeader(String id, String titleID, String preferredAfterID)1243 public MdiEntry createHeader(String id, String titleID, String preferredAfterID) { 1244 MdiEntry oldEntry = getEntry(id); 1245 if (oldEntry != null) { 1246 return oldEntry; 1247 } 1248 1249 SideBarEntrySWT entry = new SideBarEntrySWT(this, skin, id, null); 1250 entry.setSelectable(false); 1251 entry.setPreferredAfterID(preferredAfterID); 1252 entry.setTitleID(titleID); 1253 1254 setupNewEntry(entry, id, true, false); 1255 1256 return entry; 1257 } 1258 setupNewEntry(final SideBarEntrySWT entry, final String id, final boolean expandParent, final boolean closeable)1259 private void setupNewEntry(final SideBarEntrySWT entry, final String id, 1260 final boolean expandParent, final boolean closeable) { 1261 //System.out.println("createItem " + id + ";" + entry.getParentID() + ";" + Debug.getCompressedStackTrace()); 1262 addItem( entry ); 1263 1264 entry.setCloseable(closeable); 1265 entry.setParentSkinObject(soSideBarContents); 1266 entry.setDestroyOnDeactivate(false); 1267 1268 if (SIDEBAR_HEADER_PLUGINS.equals(entry.getParentID()) 1269 && entry.getImageLeftID() == null) { 1270 entry.setImageLeftID("image.sidebar.plugin"); 1271 } 1272 1273 Utils.execSWTThreadLater(0, new AERunnable() { 1274 public void runSupport() { 1275 _setupNewEntry(entry, id, expandParent, closeable); 1276 } 1277 }); 1278 } 1279 _setupNewEntry(SideBarEntrySWT entry, String id, boolean expandParent, boolean closeable)1280 protected void _setupNewEntry(SideBarEntrySWT entry, String id, 1281 boolean expandParent, boolean closeable) { 1282 String parentID = entry.getParentID(); 1283 MdiEntry parent = getEntry(parentID); 1284 TreeItem parentTreeItem = null; 1285 if (parent instanceof SideBarEntrySWT) { 1286 SideBarEntrySWT parentSWT = (SideBarEntrySWT) parent; 1287 parentTreeItem = parentSWT.getTreeItem(); 1288 if (expandParent) { 1289 parentTreeItem.setExpanded(true); 1290 } 1291 } 1292 int index = -1; 1293 String preferredAfterID = entry.getPreferredAfterID(); 1294 if (preferredAfterID != null) { 1295 if (preferredAfterID.length() == 0) { 1296 index = 0; 1297 } else { 1298 boolean hack_it = preferredAfterID.startsWith( "~" ); 1299 1300 if ( hack_it ){ 1301 1302 //hack - this means preferred BEFORE ID... 1303 1304 preferredAfterID = preferredAfterID.substring(1); 1305 } 1306 1307 MdiEntry entryAbove = getEntry(preferredAfterID); 1308 if (entryAbove != null) { 1309 index = indexOf(entryAbove); 1310 if ( hack_it ){ 1311 1312 }else{ 1313 if (index >= 0) { 1314 index++; 1315 } 1316 } 1317 //System.out.println("ENTRY " + id + " is going to go below " + entryAbove.getId() + " at " + index); 1318 } 1319 } 1320 } 1321 1322 if (index == -1 && parent == null) { 1323 index = 0; 1324 String[] order = getPreferredOrder(); 1325 for (int i = 0; i < order.length; i++) { 1326 String orderID = order[i]; 1327 if (orderID.equals(id)) { 1328 break; 1329 } 1330 MdiEntry entry2 = getEntry(orderID); 1331 if (entry2 != null) { 1332 int i2 = indexOf(entry2); 1333 if (i2 >= 0) { 1334 index = i2 + 1; 1335 } 1336 } 1337 } 1338 } 1339 1340 if (GAP_BETWEEN_LEVEL_1 > 0 && parentTreeItem == null 1341 && tree.getItemCount() > 0 && index != 0) { 1342 for (int i=0;i<GAP_BETWEEN_LEVEL_1;i++){ 1343 createTreeItem(null, index); 1344 if (index >= 0) { 1345 index++; 1346 } 1347 } 1348 } 1349 TreeItem treeItem = createTreeItem(parentTreeItem, index); 1350 if (treeItem != null) { 1351 treeItem.setData("MdiEntry", entry); 1352 entry.setTreeItem(treeItem); 1353 1354 triggerEntryLoadedListeners(entry); 1355 } 1356 if (GAP_BETWEEN_LEVEL_1 > 0 && parentTreeItem == null 1357 && tree.getItemCount() > 1 && index == 0) { 1358 for (int i=0;i<GAP_BETWEEN_LEVEL_1;i++){ 1359 createTreeItem(null, ++index); 1360 } 1361 } 1362 } 1363 createTreeItem(Object parentSwtItem, int index)1364 private TreeItem createTreeItem(Object parentSwtItem, int index) { 1365 TreeItem treeItem; 1366 1367 if (parentSwtItem == null) { 1368 parentSwtItem = tree; 1369 } 1370 1371 if (parentSwtItem instanceof Tree) { 1372 Tree tree = (Tree) parentSwtItem; 1373 if (tree.isDisposed()) { 1374 return null; 1375 } 1376 if (index >= 0 && index < tree.getItemCount()) { 1377 treeItem = new TreeItem(tree, SWT.NONE, index); 1378 } else { 1379 treeItem = new TreeItem(tree, SWT.NONE); 1380 } 1381 } else { 1382 if (((TreeItem) parentSwtItem).isDisposed()) { 1383 return null; 1384 } 1385 if (index >= 0 && index < ((TreeItem) parentSwtItem).getItemCount()) { 1386 treeItem = new TreeItem((TreeItem) parentSwtItem, SWT.NONE, index); 1387 } else { 1388 treeItem = new TreeItem((TreeItem) parentSwtItem, SWT.NONE); 1389 } 1390 } 1391 1392 return treeItem; 1393 } 1394 showEntry(MdiEntry newEntry)1395 public void showEntry(MdiEntry newEntry) { 1396 if (tree.isDisposed()) { 1397 return; 1398 } 1399 1400 if (newEntry == null || !newEntry.isSelectable()) { 1401 return; 1402 } 1403 1404 final SideBarEntrySWT oldEntry = (SideBarEntrySWT) currentEntry; 1405 1406 //System.out.println("showEntry " + newEntry.getId() + "; was " + (oldEntry == null ? "null" : oldEntry.getId()) + " via " + Debug.getCompressedStackTrace()); 1407 if (currentEntry == newEntry) { 1408 triggerSelectionListener(newEntry, newEntry); 1409 return; 1410 } 1411 1412 // show new 1413 currentEntry = (MdiEntrySWT) newEntry; 1414 1415 if (oldEntry != null && oldEntry != newEntry) { 1416 oldEntry.redraw(); 1417 } 1418 1419 if (currentEntry != null) { 1420 ((BaseMdiEntry) currentEntry).show(); 1421 } 1422 1423 // hide old 1424 if (oldEntry != null && oldEntry != newEntry) { 1425 oldEntry.hide(); 1426 oldEntry.redraw(); 1427 } 1428 1429 // as this code isn't thread safe there is a chance we end up with multiple entries visible 1430 // (well actually it happens fairly frequently) - this results in other views being rendered 1431 // during switching which is nasty - hide anything that shouldn't be visible for the moment 1432 1433 MdiEntrySWT[] entries = getEntriesSWT(); 1434 for (MdiEntrySWT entry : entries) { 1435 if (entry == null) { 1436 continue; 1437 } 1438 if ( entry != currentEntry ){ 1439 1440 SWTSkinObject obj = ((SideBarEntrySWT)entry).getSkinObjectMaster(); 1441 1442 if ( obj != null && obj.isVisible()){ 1443 1444 entry.hide(); 1445 entry.redraw(); 1446 } 1447 } 1448 } 1449 1450 newEntry.redraw(); 1451 1452 triggerSelectionListener(newEntry, oldEntry); 1453 } 1454 1455 /** 1456 * @see com.aelitis.azureus.ui.swt.mdi.BaseMDI#createEntryFromEventListener(java.lang.String, org.gudy.azureus2.ui.swt.plugins.UISWTViewEventListener, java.lang.String, boolean, java.lang.Object) 1457 */ createEntryFromEventListener(String parentEntryID, String parentViewID, UISWTViewEventListener l, String id, boolean closeable, Object datasource, String preferredAfterID)1458 public MdiEntry createEntryFromEventListener(String parentEntryID, String parentViewID, 1459 UISWTViewEventListener l, String id, boolean closeable, Object datasource, String preferredAfterID) { 1460 1461 MdiEntry oldEntry = getEntry(id); 1462 if (oldEntry != null) { 1463 return oldEntry; 1464 } 1465 1466 SideBarEntrySWT entry = new SideBarEntrySWT(this, skin, id, parentViewID); 1467 try { 1468 // hack: setEventListner will create the UISWTView. 1469 // We need to have the entry available for the view to use 1470 // if it wants 1471 1472 addItem( entry ); 1473 1474 entry.setEventListener(l, true); 1475 entry.setParentID(parentEntryID); 1476 entry.setDatasource(datasource); 1477 entry.setPreferredAfterID(preferredAfterID); 1478 setupNewEntry(entry, id, false, closeable); 1479 1480 1481 if (l instanceof IViewAlwaysInitialize) { 1482 entry.build(); 1483 } 1484 } catch (Exception e) { 1485 Debug.out(e); 1486 entry.close(true); 1487 entry = null; 1488 } 1489 1490 return entry; 1491 } 1492 1493 // @see com.aelitis.azureus.ui.swt.mdi.BaseMDI#createEntryFromSkinRef(java.lang.String, java.lang.String, java.lang.String, java.lang.String, com.aelitis.azureus.ui.common.viewtitleinfo.ViewTitleInfo, java.lang.Object, boolean, java.lang.String) createEntryFromSkinRef(String parentID, String id, String configID, String title, ViewTitleInfo titleInfo, Object params, boolean closeable, String preferredAfterID)1494 public MdiEntry createEntryFromSkinRef(String parentID, String id, 1495 String configID, String title, ViewTitleInfo titleInfo, Object params, 1496 boolean closeable, String preferredAfterID) { 1497 1498 MdiEntry oldEntry = getEntry(id); 1499 if (oldEntry != null) { 1500 return oldEntry; 1501 } 1502 1503 SideBarEntrySWT entry = new SideBarEntrySWT(this, skin, id, null); 1504 1505 entry.setTitle(title); 1506 entry.setSkinRef(configID, params); 1507 entry.setParentID(parentID); 1508 entry.setViewTitleInfo(titleInfo); 1509 entry.setPreferredAfterID(preferredAfterID); 1510 1511 setupNewEntry(entry, id, false, closeable); 1512 1513 return entry; 1514 } 1515 1516 // @see com.aelitis.azureus.ui.swt.utils.UIUpdatable#updateUI() updateUI()1517 public void updateUI() { 1518 Object[] views = pluginViews.toArray(); 1519 for (int i = 0; i < views.length; i++) { 1520 try { 1521 UISWTViewCore view = (UISWTViewCore) views[i]; 1522 Composite composite = view.getComposite(); 1523 if ( composite == null ){ 1524 continue; 1525 } 1526 if (composite.isDisposed()) { 1527 pluginViews.remove(view); 1528 continue; 1529 } 1530 if (composite.isVisible()) { 1531 view.triggerEvent(UISWTViewEvent.TYPE_REFRESH, null); 1532 } 1533 } catch (Exception e) { 1534 Debug.out(e); 1535 } 1536 } 1537 1538 if (tree.getSelectionCount() == 0) { 1539 return; 1540 } 1541 super.updateUI(); 1542 } 1543 wasEntryLoadedOnce(String id)1544 protected boolean wasEntryLoadedOnce(String id) { 1545 @SuppressWarnings("deprecation") 1546 boolean loadedOnce = COConfigurationManager.getBooleanParameter("sb.once." 1547 + id, false); 1548 return loadedOnce; 1549 } 1550 setEntryLoadedOnce(String id)1551 protected void setEntryLoadedOnce(String id) { 1552 COConfigurationManager.setParameter("sb.once." + id, true); 1553 } 1554 getHeaderFont()1555 public Font getHeaderFont() { 1556 return fontHeader; 1557 } 1558 getTree()1559 protected Tree getTree() { 1560 return tree; 1561 } 1562 1563 // @see com.aelitis.azureus.ui.swt.mdi.MultipleDocumentInterfaceSWT#getEntryFromSkinObject(org.gudy.azureus2.ui.swt.plugins.PluginUISWTSkinObject) getEntryFromSkinObject( PluginUISWTSkinObject pluginSkinObject)1564 public MdiEntrySWT getEntryFromSkinObject( 1565 PluginUISWTSkinObject pluginSkinObject) { 1566 if (pluginSkinObject instanceof SWTSkinObject) { 1567 Control control = ((SWTSkinObject) pluginSkinObject).getControl(); 1568 while (control != null && !control.isDisposed()) { 1569 Object entry = control.getData("BaseMDIEntry"); 1570 if (entry instanceof BaseMdiEntry) { 1571 BaseMdiEntry mdiEntry = (BaseMdiEntry) entry; 1572 return mdiEntry; 1573 } 1574 control = control.getParent(); 1575 } 1576 } 1577 return null; 1578 } 1579 1580 protected void requestAttention( SideBarEntrySWT entry )1581 requestAttention( 1582 SideBarEntrySWT entry ) 1583 { 1584 synchronized( attention_seekers ){ 1585 1586 if ( !attention_seekers.contains( entry )){ 1587 1588 attention_seekers.add( entry ); 1589 } 1590 1591 if ( attention_event == null ){ 1592 1593 attention_event = 1594 SimpleTimer.addPeriodicEvent( 1595 "SideBar:attention", 1596 SIDEBAR_ATTENTION_PERIOD, 1597 new TimerEventPerformer() 1598 { 1599 int tick_count = 0; 1600 1601 public void 1602 perform( 1603 TimerEvent event ) 1604 { 1605 tick_count++; 1606 1607 final List<SideBarEntrySWT> repaints = new ArrayList<SideBarEntrySWT>(); 1608 1609 synchronized( attention_seekers ){ 1610 1611 Iterator<SideBarEntrySWT> it = attention_seekers.iterator(); 1612 1613 while ( it.hasNext()){ 1614 1615 SideBarEntrySWT entry = it.next(); 1616 1617 if ( entry.isDisposed()){ 1618 1619 it.remove(); 1620 1621 }else{ 1622 1623 if ( !entry.attentionUpdate( tick_count )){ 1624 1625 it.remove(); 1626 } 1627 1628 repaints.add( entry ); 1629 } 1630 } 1631 1632 if ( attention_seekers.size() == 0 ){ 1633 1634 TimerEventPeriodic ev = attention_event; 1635 1636 if ( ev != null ){ 1637 1638 ev.cancel(); 1639 1640 attention_event = null; 1641 } 1642 } 1643 } 1644 1645 if ( repaints.size() > 0 ){ 1646 1647 Utils.execSWTThread( 1648 new AERunnable() 1649 { 1650 @Override 1651 public void 1652 runSupport() 1653 { 1654 for ( SideBarEntrySWT entry: repaints ){ 1655 1656 entry.redraw(); 1657 } 1658 } 1659 }); 1660 } 1661 } 1662 }); 1663 1664 } 1665 } 1666 } 1667 1668 // track entry additions and selection so we can switch to previous entry when one is closed 1669 1670 private Stack<SideBarEntrySWT> stack = new Stack<SideBarEntrySWT>(); 1671 addItem(MdiEntry entry)1672 public void addItem(MdiEntry entry) { 1673 super.addItem( entry ); 1674 if ( entry instanceof SideBarEntrySWT ){ 1675 synchronized( stack ){ 1676 stack.remove( entry ); 1677 if ( entry.isSelectable()){ 1678 stack.push( (SideBarEntrySWT)entry ); 1679 } 1680 } 1681 } 1682 } 1683 1684 protected void itemSelected(MdiEntry entry )1685 itemSelected(MdiEntry entry ){ 1686 super.itemSelected( entry ); 1687 if ( entry instanceof SideBarEntrySWT ){ 1688 synchronized( stack ){ 1689 stack.remove( entry ); 1690 if ( entry.isSelectable()){ 1691 stack.push( (SideBarEntrySWT)entry ); 1692 } 1693 } 1694 } 1695 } 1696 removeItem(MdiEntry entry)1697 public void removeItem(MdiEntry entry) { 1698 super.removeItem( entry ); 1699 if ( entry instanceof SideBarEntrySWT ){ 1700 1701 MdiEntry current = getCurrentEntry(); 1702 1703 SideBarEntrySWT next = null; 1704 1705 synchronized( stack ){ 1706 1707 stack.remove( entry ); 1708 1709 if ( current == null || 1710 current == entry ){ 1711 1712 while( !stack.isEmpty()){ 1713 next = stack.pop(); 1714 if ( next.isDisposed()){ 1715 next = null; 1716 }else{ 1717 break; 1718 } 1719 } 1720 } 1721 } 1722 if ( next != null ){ 1723 showEntry( next ); 1724 } 1725 } 1726 } 1727 generate(IndentWriter writer)1728 public void generate(IndentWriter writer) { 1729 MdiEntrySWT[] entries = getEntriesSWT(); 1730 for (MdiEntrySWT entry : entries) { 1731 if (entry == null) { 1732 continue; 1733 } 1734 1735 if (!(entry instanceof AEDiagnosticsEvidenceGenerator)) { 1736 writer.println("Sidebar View (No Generator): " + entry.getId()); 1737 try { 1738 writer.indent(); 1739 1740 writer.println("Parent: " + entry.getParentID()); 1741 writer.println("Title: " + entry.getTitle()); 1742 } catch (Exception e) { 1743 1744 } finally { 1745 1746 writer.exdent(); 1747 } 1748 } 1749 1750 } 1751 } 1752 1753 // @see org.gudy.azureus2.ui.swt.debug.ObfusticateImage#obfusticatedImage(org.eclipse.swt.graphics.Image) obfusticatedImage(Image image)1754 public Image obfusticatedImage(Image image) { 1755 1756 Rectangle treeBounds = tree.getBounds(); 1757 SideBarEntrySWT[] sideBarEntries = getEntries( 1758 new SideBarEntrySWT[0]); 1759 for (SideBarEntrySWT entry : sideBarEntries) { 1760 Rectangle entryBounds = entry.swt_getBounds(); 1761 if (entryBounds != null && treeBounds.intersects(entryBounds)) { 1762 entry.obfusticatedImage(image); 1763 } 1764 } 1765 return image; 1766 } 1767 } 1768