/**
* Created on Jun 23, 2008
*
* Copyright 2008 Vuze, Inc. All rights reserved.
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License only.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.aelitis.azureus.ui.swt.views.skin.sidebar;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.*;
import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.widgets.*;
import org.gudy.azureus2.core3.config.COConfigurationManager;
import org.gudy.azureus2.core3.config.ParameterListener;
import org.gudy.azureus2.core3.util.*;
import org.gudy.azureus2.plugins.PluginInterface;
import org.gudy.azureus2.plugins.ui.*;
import org.gudy.azureus2.plugins.ui.menus.MenuItem;
import org.gudy.azureus2.plugins.ui.menus.MenuItemListener;
import org.gudy.azureus2.pluginsimpl.local.PluginInitializer;
import org.gudy.azureus2.pluginsimpl.local.ui.config.ConfigSectionHolder;
import org.gudy.azureus2.pluginsimpl.local.ui.config.ConfigSectionRepository;
import org.gudy.azureus2.ui.common.util.MenuItemManager;
import org.gudy.azureus2.ui.swt.MenuBuildUtils;
import org.gudy.azureus2.ui.swt.URLTransfer;
import org.gudy.azureus2.ui.swt.Utils;
import org.gudy.azureus2.ui.swt.debug.ObfusticateImage;
import org.gudy.azureus2.ui.swt.mainwindow.TorrentOpener;
import org.gudy.azureus2.ui.swt.plugins.*;
import org.gudy.azureus2.ui.swt.pluginsimpl.UISWTViewCore;
import org.gudy.azureus2.ui.swt.views.IViewAlwaysInitialize;
import com.aelitis.azureus.ui.UIFunctions;
import com.aelitis.azureus.ui.UIFunctionsManager;
import com.aelitis.azureus.ui.common.updater.UIUpdater;
import com.aelitis.azureus.ui.common.viewtitleinfo.ViewTitleInfo;
import com.aelitis.azureus.ui.mdi.MdiEntry;
import com.aelitis.azureus.ui.mdi.MdiEntryVitalityImage;
import com.aelitis.azureus.ui.swt.mdi.*;
import com.aelitis.azureus.ui.swt.skin.*;
import com.aelitis.azureus.ui.swt.skin.SWTSkinButtonUtility.ButtonListenerAdapter;
import com.aelitis.azureus.ui.swt.utils.FontUtils;
/**
* @author TuxPaper
* @created Jun 23, 2008
*
*/
public class SideBar
extends BaseMDI
implements ObfusticateImage, AEDiagnosticsEvidenceGenerator
{
protected static final boolean END_INDENT = Constants.isLinux
|| Constants.isWindows2000 || Constants.isWindows9598ME;
private static final boolean USE_PAINTITEM = !Utils.isCarbon;
// Need to use paint even on Cocoa, because there's cases where an area
// will become invalidated and we don't get a paintitem :(
private static final boolean USE_PAINT = !Constants.isWindows && !Utils.isGTK;
protected static final boolean USE_NATIVE_EXPANDER = Utils.isGTK;
private static final int GAP_BETWEEN_LEVEL_1;
static{
GAP_BETWEEN_LEVEL_1 = Math.min( 5, Math.max( 0, COConfigurationManager.getIntParameter( "Side Bar Top Level Gap", 1 )));
}
protected static final int SIDEBAR_ATTENTION_PERIOD = 500;
protected static final int SIDEBAR_ATTENTION_DURATION = 5000;
private SWTSkin skin;
private SWTSkinObjectContainer soSideBarContents;
private SWTSkinObject soSideBarList;
private Tree tree;
private Font fontHeader;
private Font font;
private SWTSkinObject soSideBarPopout;
private SelectionListener dropDownSelectionListener;
private DropTarget dropTarget;
protected SideBarEntrySWT draggingOver;
private Color fg;
private Color bg;
private List<MdiSWTMenuHackListener> listMenuHackListners;
private List<SideBarEntrySWT> attention_seekers = new ArrayList<SideBarEntrySWT>();
private TimerEventPeriodic attention_event;
public static SideBar instance = null;
public SideBar() {
super();
if (instance == null) {
instance = this;
}
AEDiagnostics.addEvidenceGenerator(this);
}
// @see com.aelitis.azureus.ui.swt.skin.SWTSkinObjectAdapter#skinObjectCreated(com.aelitis.azureus.ui.swt.skin.SWTSkinObject, java.lang.Object)
public Object skinObjectCreated(SWTSkinObject skinObject, Object params) {
super.skinObjectCreated(skinObject, params);
skin = skinObject.getSkin();
soSideBarContents = (SWTSkinObjectContainer) skin.getSkinObject("sidebar-contents");
soSideBarList = skin.getSkinObject("sidebar-list");
soSideBarPopout = skin.getSkinObject("sidebar-pop");
// addTestMenus();
createSideBar();
try {
// don't think this is required as the SideBar constructor (well SkinView) registers it
UIUpdater updater = UIFunctionsManager.getUIFunctions().getUIUpdater();
if ( !updater.isAdded( this )){
updater.addUpdater(this);
}
} catch ( Throwable e) {
Debug.out(e);
}
Display.getDefault().addFilter(SWT.KeyDown, new Listener() {
public void handleEvent(Event event) {
// F9 is standard Seamonkey, but doesn't work on OSX
// Command Option T is standard on OSX
// F7 works on both
if (event.keyCode == SWT.F9
|| event.keyCode == SWT.F7
|| (event.keyCode == 116 && event.stateMask == (SWT.COMMAND | SWT.ALT))) {
event.doit = false;
event.keyCode = 0;
event.character = '\0';
flipSideBarVisibility();
}
}
});
return null;
}
/**
*
*
* @since 3.1.0.1
*/
/*
private void addTestMenus() {
// Add some test menus
PluginManager pm = AzureusCoreFactory.getSingleton().getPluginManager();
PluginInterface pi = pm.getDefaultPluginInterface();
UIManager uim = pi.getUIManager();
MenuManager menuManager = uim.getMenuManager();
MenuItem menuItem = menuManager.addMenuItem("sidebar", "test menu");
menuItem.addListener(new MenuItemListener() {
public void selected(MenuItem menu, Object target) {
ToolBarView tb = (ToolBarView) SkinViewManager.getByClass(ToolBarView.class);
if (tb != null) {
System.out.println("Found download Toolbar");
ToolBarItem dlItem = tb.getToolBarItem("download");
System.out.println("Download ToolBar Item is " + dlItem);
if (dlItem != null) {
System.out.println(dlItem.getSkinButton().getSkinObject());
}
dlItem.setEnabled(!dlItem.isEnabled());
}
if (target instanceof SideBarEntry) {
SideBarEntry info = (SideBarEntry) target;
System.err.println(info.getId() + " of " + info.getParentID()
+ ";ds=" + info.getDatasource());
}
}
});
menuItem = menuManager.addMenuItem("sidebar." + SIDEBAR_SECTION_ACTIVITIES,
"Activity Only Menu");
menuItem.addListener(new MenuItemListener() {
public void selected(MenuItem menu, Object target) {
if (target instanceof SideBarEntry) {
SideBarEntry info = (SideBarEntry) target;
System.err.println(info.getId() + " of " + info.getParentID()
+ ";ds=" + info.getDatasource());
}
}
});
}
*/
/**
*
*
* @since 3.1.1.1
*/
public void flipSideBarVisibility() {
final SWTSkinObjectSash soSash = (SWTSkinObjectSash) skin.getSkinObject("sidebar-sash");
if (soSash == null) {
return;
}
Utils.execSWTThreadLater(0, new AERunnable() {
public void runSupport() {
boolean visible = !soSash.isAboveVisible();
soSash.setAboveVisible( visible );
updateSidebarVisibility();
COConfigurationManager.setParameter( "Show Side Bar", visible );
}
});
}
private void updateSidebarVisibility() {
Utils.execSWTThread(new AERunnable() {
public void runSupport() {
final SWTSkinObjectSash soSash = (SWTSkinObjectSash) skin.getSkinObject("sidebar-sash");
if (soSash == null) {
return;
}
if (soSash.isAboveVisible()) {
if (soSideBarPopout != null) {
Object ld = soSideBarPopout.getControl().getLayoutData();
if (ld instanceof FormData) {
FormData fd = (FormData) ld;
fd.width = 0;
}
soSideBarPopout.setVisible(false);
Utils.relayout(soSideBarPopout.getControl());
}
} else {
if (soSideBarPopout != null) {
Object ld = soSideBarPopout.getControl().getLayoutData();
if (ld instanceof FormData) {
FormData fd = (FormData) ld;
fd.width = 24;
}
soSideBarPopout.setVisible(true);
soSideBarPopout.getControl().moveAbove(null);
Utils.relayout(soSideBarPopout.getControl());
}
}
}
});
}
public boolean isVisible() {
SWTSkinObjectSash soSash = (SWTSkinObjectSash) skin.getSkinObject("sidebar-sash");
if (soSash == null) {
return false;
}
return soSash.isAboveVisible();
}
// @see com.aelitis.azureus.ui.swt.views.skin.SkinView#showSupport(com.aelitis.azureus.ui.swt.skin.SWTSkinObject, java.lang.Object)
public Object skinObjectInitialShow(SWTSkinObject skinObject, Object params) {
UIManager ui_manager = PluginInitializer.getDefaultInterface().getUIManager();
ui_manager.addUIListener(new UIManagerListener() {
public void UIDetached(UIInstance instance) {
}
public void UIAttached(UIInstance instance) {
if (instance instanceof UISWTInstance) {
final AESemaphore wait_sem = new AESemaphore( "SideBar:wait" );
Utils.execSWTThread(new AERunnable() {
public void runSupport() {
try{
try {
loadCloseables();
} catch (Throwable t) {
Debug.out(t);
}
setupPluginViews();
}finally{
wait_sem.release();
}
}
});
// we need to wait for the loadCloseables to complete as there is code in MainMDISetup that runs on the 'UIAttachedComplete'
// callback that needs the closables to be loaded (when setting 'start tab') otherwise the order gets broken
if ( !wait_sem.reserve(10*1000)){
Debug.out( "eh?");
}
}
}
});
COConfigurationManager.addParameterListener(
"Show Side Bar",
new ParameterListener()
{
public void
parameterChanged(
String name )
{
boolean visible = COConfigurationManager.getBooleanParameter( name );
if ( visible != isVisible()){
flipSideBarVisibility();
}
}
});
updateSidebarVisibility();
return null;
}
public Object skinObjectDestroyed(SWTSkinObject skinObject, Object params) {
try {
UIFunctionsManager.getUIFunctions().getUIUpdater().removeUpdater(this);
} catch (Exception e) {
Debug.out(e);
}
return super.skinObjectDestroyed(skinObject, params);
}
private void createSideBar() {
if (soSideBarList == null) {
return;
}
Composite parent = (Composite) soSideBarList.getControl();
tree = new Tree(parent, SWT.FULL_SELECTION | SWT.V_SCROLL
| SWT.DOUBLE_BUFFERED | SWT.NO_SCROLL);
tree.setHeaderVisible(false);
new SideBarToolTips(this, tree);
tree.setLayoutData(Utils.getFilledFormData());
SWTSkinProperties skinProperties = skin.getSkinProperties();
bg = skinProperties.getColor("color.sidebar.bg");
fg = skinProperties.getColor("color.sidebar.fg");
tree.setBackground(bg);
tree.setForeground(fg);
FontData[] fontData = tree.getFont().getFontData();
int fontHeight = (Constants.isOSX ? 11 : 12)
+ (tree.getItemHeight() > 18 ? tree.getItemHeight() - 18 : 0);
fontData[0].setStyle(SWT.BOLD);
FontUtils.getFontHeightFromPX(tree.getDisplay(), fontData, null, fontHeight);
fontHeader = new Font(tree.getDisplay(), fontData);
font = FontUtils.getFontWithHeight(tree.getFont(), null, fontHeight);
tree.setFont(font);
// after a scroll we need to recalculate the hit areas as they will have moved!
tree.getVerticalBar().addSelectionListener(
new SelectionAdapter()
{
public void widgetSelected(SelectionEvent e) {
if ( e.detail == SWT.None ){
SideBarEntrySWT[] sideBarEntries = mapIdToEntry.values().toArray(
new SideBarEntrySWT[0]);
swt_updateSideBarHitAreasY(sideBarEntries);
}
}
});
Listener treeListener = new Listener() {
TreeItem lastTopItem = null;
boolean mouseDowned = false;
private boolean wasExpanded;
public void handleEvent(final Event event) {
TreeItem treeItem = (TreeItem) event.item;
Tree tree = getTree();
try {
switch (event.type) {
case SWT.MeasureItem: {
int clientWidth = tree.getClientArea().width;
String text = treeItem.getText(event.index);
Point size = event.gc.textExtent(text);
if (event.x + event.width < clientWidth) {
event.width = size.x + event.x; // tree.getClientArea().width;
event.x = 0;
}
if (Constants.isWindows) {
event.width = clientWidth - event.x;
}
event.height = 20;
break;
}
case SWT.PaintItem: {
if (USE_PAINTITEM) {
SideBarEntrySWT entry = (SideBarEntrySWT) treeItem.getData("MdiEntry");
//System.out.println("PaintItem: " + event.item + ";" + event.index + ";" + event.detail + ";" + id + ";" + event.getBounds() + ";" + event.gc.getClipping());
if (entry != null) {
boolean selected = currentEntry == entry
&& entry.isSelectable();
if (!selected) {
event.detail &= ~SWT.SELECTED;
} else {
event.detail |= SWT.SELECTED;
}
entry.swt_paintSideBar(event);
}
}
break;
}
case SWT.Paint: {
//System.out.println("Paint: " + event.getBounds() + ";" + event.detail + ";" + event.index + ";" + event.gc.getClipping() + " " + Debug.getCompressedStackTrace());
if (!USE_PAINT) {
return;
}
Rectangle bounds = event.getBounds();
int indent = END_INDENT ? tree.getClientArea().width - 1 : 0;
int y = event.y + 1;
treeItem = tree.getItem(new Point(indent, y));
while (treeItem != null) {
SideBarEntrySWT entry = (SideBarEntrySWT) treeItem.getData("MdiEntry");
Rectangle itemBounds = entry == null ? null
: entry.swt_getBounds();
// null itemBounds is weird, the entry must be disposed. it
// happened once, so let's check..
if (itemBounds != null && entry != null) {
event.item = treeItem;
boolean selected = currentEntry == entry
&& entry.isSelectable();
event.detail = selected ? SWT.SELECTED : SWT.NONE;
Rectangle newClip = bounds.intersection(itemBounds);
//System.out.println("Paint " + id + " @ " + newClip);
event.setBounds(newClip);
event.gc.setClipping(newClip);
entry.swt_paintSideBar(event);
y = itemBounds.y + itemBounds.height + 1;
} else {
y += tree.getItemHeight();
}
if (y > bounds.y + bounds.height) {
break;
}
TreeItem oldTreeItem = treeItem;
treeItem = tree.getItem(new Point(indent, y));
if (oldTreeItem == treeItem) {
break;
}
}
if (tree.getTopItem() != lastTopItem) {
lastTopItem = tree.getTopItem();
SideBarEntrySWT[] sideBarEntries = mapIdToEntry.values().toArray(
new SideBarEntrySWT[0]);
swt_updateSideBarHitAreasY(sideBarEntries);
}
break;
}
case SWT.EraseItem: {
SideBarEntrySWT entry = (SideBarEntrySWT) treeItem.getData("MdiEntry");
if (entry == null) {
event.detail = 0;
}
//event.detail &= ~SWT.FOREGROUND;
//event.detail &= ~(SWT.FOREGROUND | SWT.BACKGROUND);
event.doit = true;
break;
}
case SWT.Resize: {
tree.redraw();
break;
}
case SWT.Selection: {
if (treeItem == null) {
return;
}
SideBarEntrySWT entry = (SideBarEntrySWT) treeItem.getData("MdiEntry");
if (entry != null && entry.isSelectable()) {
showEntry(entry);
} else if (currentEntry != null) {
TreeItem topItem = tree.getTopItem();
// prevent "jumping" in the case where selection is off screen
// setSelection would jump the item on screen, and then
// showItem would jump back to where the user was.
tree.setRedraw(false);
TreeItem ti = ((SideBarEntrySWT) currentEntry).getTreeItem();
if (ti != null) {
tree.setSelection(ti);
}
tree.setTopItem(topItem);
tree.setRedraw(true);
event.doit = false;
}
break;
}
case SWT.MouseMove: {
int indent = END_INDENT ? tree.getClientArea().width - 1 : 0;
treeItem = tree.getItem(new Point(indent, event.y));
SideBarEntrySWT entry = (SideBarEntrySWT) ((treeItem == null || treeItem.isDisposed())
? null : treeItem.getData("MdiEntry"));
int cursorNo = SWT.CURSOR_ARROW;
if (treeItem != null) {
Rectangle closeArea = (Rectangle) treeItem.getData("closeArea");
if (closeArea != null && closeArea.contains(event.x, event.y)) {
cursorNo = SWT.CURSOR_HAND;
} else if (entry != null && !entry.isCollapseDisabled()
&& treeItem.getItemCount() > 0) {
cursorNo = SWT.CURSOR_HAND;
}
}
Cursor cursor = event.display.getSystemCursor(cursorNo);
if (tree.getCursor() != cursor) {
tree.setCursor(cursor);
}
if (treeItem != null) {
wasExpanded = entry != null && entry.isExpanded();
} else {
wasExpanded = false;
}
break;
}
case SWT.MouseDown: {
mouseDowned = true;
break;
}
case SWT.MouseUp: {
if (!mouseDowned) {
return;
}
mouseDowned = false;
if (tree.getItemCount() == 0 || event.button != 1) {
return;
}
int indent = END_INDENT ? tree.getClientArea().width - 1 : 0;
treeItem = tree.getItem(new Point(indent, event.y));
if (treeItem == null) {
return;
}
SideBarEntrySWT entry = (SideBarEntrySWT) treeItem.getData("MdiEntry");
Rectangle closeArea = (Rectangle) treeItem.getData("closeArea");
if (closeArea != null && closeArea.contains(event.x, event.y)) {
treeItem.dispose();
return;
} else if (currentEntry != entry && Constants.isOSX) {
showEntry(entry);
}
if (entry != null) {
MdiEntryVitalityImage[] vitalityImages = entry.getVitalityImages();
for (int i = 0; i < vitalityImages.length; i++) {
SideBarVitalityImageSWT vitalityImage = (SideBarVitalityImageSWT) vitalityImages[i];
if (vitalityImage == null || !vitalityImage.isVisible()) {
continue;
}
Rectangle hitArea = vitalityImage.getHitArea();
if (hitArea == null) {
continue;
}
// setHitArea needs it relative to entry
Rectangle itemBounds = entry.swt_getBounds();
int relY = event.y - (itemBounds == null ? 0 : itemBounds.y);
if (hitArea.contains(event.x, relY)) {
vitalityImage.triggerClickedListeners(event.x, relY);
return;
}
}
if (!entry.isCollapseDisabled() && treeItem.getItemCount() > 0) {
if (!entry.isSelectable() || event.x < 20) {
// Note: On Windows, user can expand row by clicking the invisible area where the OS twisty would be
MdiEntry currentEntry = getCurrentEntry();
if (currentEntry != null
&& entry.getId().equals(currentEntry.getParentID())) {
showEntryByID(SIDEBAR_SECTION_LIBRARY);
}
entry.setExpanded(!wasExpanded);
wasExpanded = !wasExpanded;
}
}
}
break;
}
case SWT.Dispose: {
fontHeader.dispose();
font.dispose();
if (dropTarget != null && !dropTarget.isDisposed()) {
dropTarget.dispose();
}
saveCloseables();
break;
}
case SWT.Collapse: {
SideBarEntrySWT entry = (SideBarEntrySWT) treeItem.getData("MdiEntry");
if (entry.isCollapseDisabled()) {
tree.setRedraw(false);
Display.getDefault().asyncExec(new Runnable() {
public void run() {
((TreeItem) event.item).setExpanded(true);
getTree().setRedraw(true);
}
});
} else {
MdiEntry currentEntry = getCurrentEntry();
if (currentEntry != null
&& entry.getId().equals(currentEntry.getParentID())) {
showEntryByID(SIDEBAR_SECTION_LIBRARY);
}
}
break;
}
}
} catch (Exception e) {
Debug.out(e);
}
}
};
tree.addListener(SWT.MeasureItem, treeListener);
tree.addListener(SWT.Resize, treeListener);
tree.addListener(SWT.Paint, treeListener);
if (USE_PAINTITEM) {
tree.addListener(SWT.PaintItem, treeListener);
tree.addListener(SWT.EraseItem, treeListener);
}
tree.addListener(SWT.Selection, treeListener);
tree.addListener(SWT.Dispose, treeListener);
// For icons
tree.addListener(SWT.MouseUp, treeListener);
tree.addListener(SWT.MouseDown, treeListener);
// For cursor
tree.addListener(SWT.MouseMove, treeListener);
// to disable collapsing
tree.addListener(SWT.Collapse, treeListener);
dropTarget = new DropTarget(tree, DND.DROP_COPY);
dropTarget.setTransfer(new Transfer[] {
URLTransfer.getInstance(),
FileTransfer.getInstance(),
TextTransfer.getInstance(),
});
dropTarget.addDropListener(new DropTargetAdapter() {
public void dropAccept(DropTargetEvent event) {
event.currentDataType = URLTransfer.pickBestType(event.dataTypes,
event.currentDataType);
}
public void dragEnter(DropTargetEvent event) {
}
public void dragOperationChanged(DropTargetEvent event) {
}
// @see org.eclipse.swt.dnd.DropTargetAdapter#dragOver(org.eclipse.swt.dnd.DropTargetEvent)
public void dragOver(DropTargetEvent event) {
TreeItem treeItem = (event.item instanceof TreeItem)
? (TreeItem) event.item : null;
if (treeItem != null) {
SideBarEntrySWT entry = (SideBarEntrySWT) treeItem.getData("MdiEntry");
draggingOver = entry;
} else {
draggingOver = null;
}
if (draggingOver == null || !draggingOver.hasDropListeners()) {
boolean isTorrent = TorrentOpener.doesDropHaveTorrents(event);
if (isTorrent) {
event.detail = DND.DROP_COPY;
} else {
event.detail = DND.DROP_NONE;
}
draggingOver = null;
} else if ((event.operations & DND.DROP_LINK) > 0)
event.detail = DND.DROP_LINK;
else if ((event.operations & DND.DROP_COPY) > 0)
event.detail = DND.DROP_COPY;
else if ((event.operations & DND.DROP_DEFAULT) > 0)
event.detail = DND.DROP_COPY;
if (Constants.isOSX) {
tree.redraw();
}
event.feedback = DND.FEEDBACK_SELECT | DND.FEEDBACK_SCROLL | DND.FEEDBACK_EXPAND;
}
// @see org.eclipse.swt.dnd.DropTargetAdapter#dragLeave(org.eclipse.swt.dnd.DropTargetEvent)
public void dragLeave(DropTargetEvent event) {
draggingOver = null;
tree.redraw();
}
public void drop(DropTargetEvent event) {
draggingOver = null;
tree.redraw();
if (!(event.item instanceof TreeItem)) {
defaultDrop(event);
return;
}
TreeItem treeItem = (TreeItem) event.item;
SideBarEntrySWT entry = (SideBarEntrySWT) treeItem.getData("MdiEntry");
boolean handled = entry.triggerDropListeners(event.data);
if (!handled) {
defaultDrop(event);
}
}
});
final Menu menuTree = new Menu(tree);
tree.setMenu(menuTree);
menuTree.addMenuListener(new MenuListener() {
boolean bShown = false;
public void menuHidden(MenuEvent e) {
bShown = false;
if (Constants.isOSX) {
return;
}
// Must dispose in an asyncExec, otherwise SWT.Selection doesn't
// get fired (async workaround provided by Eclipse Bug #87678)
Utils.execSWTThreadLater(0, new AERunnable() {
public void runSupport() {
if (bShown || menuTree.isDisposed()) {
return;
}
Utils.disposeSWTObjects(menuTree.getItems());
}
});
}
public void menuShown(MenuEvent e) {
Utils.disposeSWTObjects(menuTree.getItems());
bShown = true;
Point ptMouse = tree.toControl(e.display.getCursorLocation());
int indent = END_INDENT ? tree.getClientArea().width - 1 : 0;
TreeItem treeItem = tree.getItem(new Point(indent, ptMouse.y));
if (treeItem == null) {
return;
}
SideBarEntrySWT entry = (SideBarEntrySWT) treeItem.getData("MdiEntry");
fillMenu(menuTree, entry);
if (menuTree.getItemCount() == 0) {
Utils.execSWTThreadLater(0, new AERunnable() {
public void runSupport() {
menuTree.setVisible(false);
}
});
}
}
});
if (soSideBarPopout != null) {
SWTSkinObject soDropDown = skin.getSkinObject("sidebar-dropdown");
if (soDropDown != null) {
final Menu menuDropDown = new Menu(soDropDown.getControl());
menuDropDown.addMenuListener(new MenuListener() {
boolean bShown = false;
public void menuHidden(MenuEvent e) {
bShown = false;
if (Constants.isOSX) {
return;
}
// Must dispose in an asyncExec, otherwise SWT.Selection doesn't
// get fired (async workaround provided by Eclipse Bug #87678)
Utils.execSWTThreadLater(0, new AERunnable() {
public void runSupport() {
if (bShown || menuDropDown.isDisposed()) {
return;
}
Utils.disposeSWTObjects(menuDropDown.getItems());
}
});
}
public void menuShown(MenuEvent e) {
Utils.disposeSWTObjects(menuDropDown.getItems());
bShown = true;
fillDropDownMenu(menuDropDown, tree.getItems(), 0);
}
});
dropDownSelectionListener = new SelectionListener() {
public void widgetSelected(SelectionEvent e) {
String id = (String) e.widget.getData("Plugin.viewID");
showEntryByID(id);
}
public void widgetDefaultSelected(SelectionEvent e) {
}
};
SWTSkinButtonUtility btnDropDown = new SWTSkinButtonUtility(soDropDown);
btnDropDown.addSelectionListener(new ButtonListenerAdapter() {
public void pressed(SWTSkinButtonUtility buttonUtility,
SWTSkinObject skinObject, int stateMask) {
Control c = buttonUtility.getSkinObject().getControl();
menuDropDown.setLocation(c.getDisplay().getCursorLocation());
menuDropDown.setVisible(!menuDropDown.getVisible());
}
});
}
SWTSkinObject soExpand = skin.getSkinObject("sidebar-expand");
if (soExpand != null) {
SWTSkinButtonUtility btnExpand = new SWTSkinButtonUtility(soExpand);
btnExpand.addSelectionListener(new ButtonListenerAdapter() {
public void pressed(SWTSkinButtonUtility buttonUtility,
SWTSkinObject skinObject, int stateMask) {
flipSideBarVisibility();
}
});
}
}
}
/**
* @param event
*/
protected void defaultDrop(DropTargetEvent event) {
TorrentOpener.openDroppedTorrents(event, false);
}
/**
* @param menuDropDown
*
* @since 3.1.1.1
*/
protected void fillDropDownMenu(Menu menuDropDown, TreeItem[] items,
int indent) {
String s = "";
for (int i = 0; i < indent; i++) {
s += " ";
}
for (int i = 0; i < items.length; i++) {
TreeItem treeItem = items[i];
SideBarEntrySWT entry = (SideBarEntrySWT) treeItem.getData("MdiEntry");
if (entry == null) {
continue;
}
org.eclipse.swt.widgets.MenuItem menuItem = new org.eclipse.swt.widgets.MenuItem(
menuDropDown, entry.isSelectable() ? SWT.RADIO : SWT.CASCADE);
String id = entry.getId();
menuItem.setData("Plugin.viewID", id);
ViewTitleInfo titleInfo = entry.getViewTitleInfo();
String ind = "";
if (titleInfo != null) {
String o = (String) titleInfo.getTitleInfoProperty(ViewTitleInfo.TITLE_INDICATOR_TEXT);
if (o != null) {
ind = " (" + o + ")";
//ind = "\t" + o;
}
}
menuItem.setText(s + entry.getTitle() + ind);
menuItem.addSelectionListener(dropDownSelectionListener);
if (currentEntry != null && currentEntry.getId().equals(id)) {
menuItem.setSelection(true);
}
TreeItem[] subItems = treeItem.getItems();
if (subItems.length > 0) {
Menu parent = menuDropDown;
if (!entry.isSelectable()) {
parent = new Menu(menuDropDown.getParent().getShell(), SWT.DROP_DOWN);
menuItem.setMenu(parent);
}
fillDropDownMenu(parent, subItems, indent + 1);
}
}
}
/**
* @param menuTree
*
* @since 3.1.0.1
*/
protected void fillMenu(Menu menuTree, final MdiEntry entry) {
org.gudy.azureus2.plugins.ui.menus.MenuItem[] menu_items;
menu_items = MenuItemManager.getInstance().getAllAsArray("sidebar");
MenuBuildUtils.addPluginMenuItems((Composite) soMain.getControl(),
menu_items, menuTree, false, true,
new MenuBuildUtils.MenuItemPluginMenuControllerImpl(new Object[] {
entry
}));
if (entry != null) {
menu_items = MenuItemManager.getInstance().getAllAsArray(
"sidebar." + entry.getId());
if (menu_items.length == 0) {
UIPluginView view = entry.getView();
if (view instanceof UISWTView) {
PluginInterface pi = ((UISWTView) view).getPluginInterface();
if (pi != null) {
final List<String> relevant_sections = new ArrayList<String>();
List<ConfigSectionHolder> sections = ConfigSectionRepository.getInstance().getHolderList();
for (ConfigSectionHolder cs : sections) {
if (pi == cs.getPluginInterface()) {
relevant_sections.add(cs.configSectionGetName());
}
}
if (relevant_sections.size() > 0) {
MenuItem mi = pi.getUIManager().getMenuManager().addMenuItem(
"sidebar." + entry.getId(),
"MainWindow.menu.view.configuration");
mi.addListener(new MenuItemListener() {
public void selected(MenuItem menu, Object target) {
UIFunctions uif = UIFunctionsManager.getUIFunctions();
if (uif != null) {
for (String s : relevant_sections) {
uif.openView(UIFunctions.VIEW_CONFIG, s);
}
}
}
});
menu_items = MenuItemManager.getInstance().getAllAsArray(
"sidebar." + entry.getId());
}
}
}
}
MenuBuildUtils.addPluginMenuItems((Composite) soMain.getControl(),
menu_items, menuTree, false, true,
new MenuBuildUtils.MenuItemPluginMenuControllerImpl(new Object[] {
entry
}));
MdiSWTMenuHackListener[] menuHackListeners = getMenuHackListeners();
for (MdiSWTMenuHackListener l : menuHackListeners) {
try {
l.menuWillBeShown(entry, menuTree);
} catch (Exception e) {
Debug.out(e);
}
}
if (currentEntry instanceof SideBarEntrySWT) {
menuHackListeners = ((SideBarEntrySWT) entry).getMenuHackListeners();
for (MdiSWTMenuHackListener l : menuHackListeners) {
try {
l.menuWillBeShown(entry, menuTree);
} catch (Exception e) {
Debug.out(e);
}
}
}
}
}
public void addListener(MdiSWTMenuHackListener l) {
synchronized (this) {
if (listMenuHackListners == null) {
listMenuHackListners = new ArrayList<MdiSWTMenuHackListener>(1);
}
if (!listMenuHackListners.contains(l)) {
listMenuHackListners.add(l);
}
}
}
public void removeListener(MdiSWTMenuHackListener l) {
synchronized (this) {
if (listMenuHackListners == null) {
listMenuHackListners = new ArrayList<MdiSWTMenuHackListener>(1);
}
listMenuHackListners.remove(l);
}
}
public MdiSWTMenuHackListener[] getMenuHackListeners() {
synchronized (this) {
if (listMenuHackListners == null) {
return new MdiSWTMenuHackListener[0];
}
return listMenuHackListners.toArray(new MdiSWTMenuHackListener[0]);
}
}
/**
*
*
* @since 3.1.1.1
*/
private void swt_updateSideBarHitAreasY(SideBarEntrySWT[] entries) {
for (int x = 0; x < entries.length; x++) {
SideBarEntrySWT entry = entries[x];
TreeItem treeItem = entry.getTreeItem();
if (treeItem == null || treeItem.isDisposed()) {
continue;
}
Rectangle itemBounds = entry.swt_getBounds();
if ( itemBounds != null ){
if (entry.isCloseable()) {
Rectangle closeArea = (Rectangle) treeItem.getData("closeArea");
if (closeArea != null) {
closeArea.y = itemBounds.y + (itemBounds.height - closeArea.height)
/ 2;
}
}
MdiEntryVitalityImage[] vitalityImages = entry.getVitalityImages();
for (int i = 0; i < vitalityImages.length; i++) {
SideBarVitalityImageSWT vitalityImage = (SideBarVitalityImageSWT) vitalityImages[i];
if (!vitalityImage.isVisible()) {
continue;
}
Image image = vitalityImage.getImage();
if (image != null) {
Rectangle bounds = vitalityImage.getHitArea();
if (bounds == null) {
continue;
}
bounds.y = (itemBounds.height - bounds.height) / 2;
}
}
}
}
}
protected int indexOf(final MdiEntry entryLibrary) {
Object o = Utils.execSWTThreadWithObject("indexOf", new AERunnableObject() {
public Object runSupport() {
TreeItem treeItem = ((SideBarEntrySWT) entryLibrary).getTreeItem();
if (treeItem == null) {
return -1;
}
TreeItem parentItem = treeItem.getParentItem();
if (parentItem != null) {
return parentItem.indexOf(treeItem);
}
return tree.indexOf(treeItem);
}
}, 500);
if (o instanceof Number) {
return ((Number) o).intValue();
}
return -1;
}
public MdiEntry createHeader(String id, String titleID, String preferredAfterID) {
MdiEntry oldEntry = getEntry(id);
if (oldEntry != null) {
return oldEntry;
}
SideBarEntrySWT entry = new SideBarEntrySWT(this, skin, id);
entry.setSelectable(false);
entry.setPreferredAfterID(preferredAfterID);
entry.setTitleID(titleID);
setupNewEntry(entry, id, true, false);
return entry;
}
public MdiEntry createEntryFromView(String parentID, UISWTViewCore iview, String id,
Object datasource, boolean closeable, boolean show, boolean expand) {
if (id == null) {
id = iview.getClass().getName();
int i = id.lastIndexOf('.');
if (i > 0) {
id = id.substring(i + 1);
}
}
MdiEntry oldEntry = getEntry(id);
if (oldEntry != null) {
if (show) {
showEntry(oldEntry);
}
return oldEntry;
}
SideBarEntrySWT entry = new SideBarEntrySWT(this, skin, id);
entry.setCoreView(iview);
entry.setDatasource(datasource);
entry.setParentID(parentID);
setupNewEntry(entry, id, expand, closeable);
if (iview instanceof IViewAlwaysInitialize) {
entry.build();
}
if (show) {
showEntry(entry);
}
return entry;
}
private void setupNewEntry(final SideBarEntrySWT entry, final String id,
final boolean expandParent, final boolean closeable) {
//System.out.println("createItem " + id + ";" + Debug.getCompressedStackTrace());
synchronized (mapIdToEntry) {
mapIdToEntry.put(id, entry);
}
entry.setCloseable(closeable);
entry.setParentSkinObject(soSideBarContents);
if (SIDEBAR_HEADER_PLUGINS.equals(entry.getParentID())
&& entry.getImageLeftID() == null) {
entry.setImageLeftID("image.sidebar.plugin");
}
Utils.execSWTThreadLater(0, new AERunnable() {
public void runSupport() {
_setupNewEntry(entry, id, expandParent, closeable);
}
});
}
protected void _setupNewEntry(SideBarEntrySWT entry, String id,
boolean expandParent, boolean closeable) {
String parentID = entry.getParentID();
MdiEntry parent = getEntry(parentID);
TreeItem parentTreeItem = null;
if (parent instanceof SideBarEntrySWT) {
SideBarEntrySWT parentSWT = (SideBarEntrySWT) parent;
parentTreeItem = parentSWT.getTreeItem();
if (expandParent) {
parentTreeItem.setExpanded(true);
}
}
int index = -1;
String preferredAfterID = entry.getPreferredAfterID();
if (preferredAfterID != null) {
if (preferredAfterID.length() == 0) {
index = 0;
} else {
boolean hack_it = preferredAfterID.startsWith( "~" );
if ( hack_it ){
//hack - this means preferred BEFORE ID...
preferredAfterID = preferredAfterID.substring(1);
}
MdiEntry entryAbove = getEntry(preferredAfterID);
if (entryAbove != null) {
index = indexOf(entryAbove);
if ( hack_it ){
}else{
if (index >= 0) {
index++;
}
}
//System.out.println("ENTRY " + id + " is going to go below " + entryAbove.getId() + " at " + index);
}
}
}
if (index == -1 && parent == null) {
index = 0;
String[] order = getPreferredOrder();
for (int i = 0; i < order.length; i++) {
String orderID = order[i];
if (orderID.equals(id)) {
break;
}
MdiEntry entry2 = getEntry(orderID);
if (entry2 != null) {
int i2 = indexOf(entry2);
if (i2 >= 0) {
index = i2 + 1;
}
}
}
}
if (GAP_BETWEEN_LEVEL_1 > 0 && parentTreeItem == null
&& tree.getItemCount() > 0 && index != 0) {
for (int i=0;i<GAP_BETWEEN_LEVEL_1;i++){
createTreeItem(null, index);
if (index >= 0) {
index++;
}
}
}
TreeItem treeItem = createTreeItem(parentTreeItem, index);
if (treeItem != null) {
treeItem.setData("MdiEntry", entry);
entry.setTreeItem(treeItem);
triggerEntryLoadedListeners(entry);
}
if (GAP_BETWEEN_LEVEL_1 > 0 && parentTreeItem == null
&& tree.getItemCount() > 1 && index == 0) {
for (int i=0;i<GAP_BETWEEN_LEVEL_1;i++){
createTreeItem(null, ++index);
}
}
}
private TreeItem createTreeItem(Object parentSwtItem, int index) {
TreeItem treeItem;
if (parentSwtItem == null) {
parentSwtItem = tree;
}
if (parentSwtItem instanceof Tree) {
Tree tree = (Tree) parentSwtItem;
if (tree.isDisposed()) {
return null;
}
if (index >= 0 && index < tree.getItemCount()) {
treeItem = new TreeItem(tree, SWT.NONE, index);
} else {
treeItem = new TreeItem(tree, SWT.NONE);
}
} else {
if (((TreeItem) parentSwtItem).isDisposed()) {
return null;
}
if (index >= 0 && index < ((TreeItem) parentSwtItem).getItemCount()) {
treeItem = new TreeItem((TreeItem) parentSwtItem, SWT.NONE, index);
} else {
treeItem = new TreeItem((TreeItem) parentSwtItem, SWT.NONE);
}
}
return treeItem;
}
public void showEntry(MdiEntry newEntry) {
if (tree.isDisposed()) {
return;
}
if (newEntry == null || !newEntry.isSelectable()) {
return;
}
final SideBarEntrySWT oldEntry = (SideBarEntrySWT) currentEntry;
//System.out.println("showEntry " + newEntry.getId() + "; was " + (oldEntry == null ? "null" : oldEntry.getId()) + " via " + Debug.getCompressedStackTrace());
if (currentEntry == newEntry) {
triggerSelectionListener(newEntry, newEntry);
return;
}
// show new
currentEntry = (MdiEntrySWT) newEntry;
if (oldEntry != null && oldEntry != newEntry) {
oldEntry.redraw();
}
if (currentEntry != null) {
((BaseMdiEntry) currentEntry).show();
}
// hide old
if (oldEntry != null && oldEntry != newEntry) {
oldEntry.hide();
oldEntry.redraw();
}
newEntry.redraw();
triggerSelectionListener(newEntry, oldEntry);
}
/**
* @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)
*/
public MdiEntry createEntryFromEventListener(String parentID,
UISWTViewEventListener l, String id, boolean closeable, Object datasource, String preferredAfterID) {
MdiEntry oldEntry = getEntry(id);
if (oldEntry != null) {
return oldEntry;
}
SideBarEntrySWT entry = new SideBarEntrySWT(this, skin, id);
try {
// hack: setEventListner will create the UISWTView.
// We need to have the entry available for the view to use
// if it wants
synchronized (mapIdToEntry) {
mapIdToEntry.put(id, entry);
}
entry.setParentID(parentID);
entry.setDatasource(datasource);
entry.setPreferredAfterID(preferredAfterID);
setupNewEntry(entry, id, false, closeable);
entry.setEventListener(l);
if (l instanceof IViewAlwaysInitialize) {
entry.build();
}
} catch (Exception e) {
Debug.out(e);
entry.close(true);
}
return entry;
}
// @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)
public MdiEntry createEntryFromSkinRef(String parentID, String id,
String configID, String title, ViewTitleInfo titleInfo, Object params,
boolean closeable, String preferredAfterID) {
MdiEntry oldEntry = getEntry(id);
if (oldEntry != null) {
return oldEntry;
}
SideBarEntrySWT entry = new SideBarEntrySWT(this, skin, id);
entry.setTitle(title);
entry.setSkinRef(configID, params);
entry.setParentID(parentID);
entry.setViewTitleInfo(titleInfo);
entry.setPreferredAfterID(preferredAfterID);
setupNewEntry(entry, id, false, closeable);
return entry;
}
// @see com.aelitis.azureus.ui.swt.utils.UIUpdatable#updateUI()
public void updateUI() {
if (currentEntry == null || currentEntry.getView() == null
|| tree.getSelectionCount() == 0) {
return;
}
currentEntry.updateUI();
}
protected boolean wasEntryLoadedOnce(String id) {
@SuppressWarnings("deprecation")
boolean loadedOnce = COConfigurationManager.getBooleanParameter("sb.once."
+ id, false);
return loadedOnce;
}
protected void setEntryLoadedOnce(String id) {
COConfigurationManager.setParameter("sb.once." + id, true);
}
public Font getHeaderFont() {
return fontHeader;
}
protected Tree getTree() {
return tree;
}
// @see com.aelitis.azureus.ui.swt.mdi.MultipleDocumentInterfaceSWT#getEntryFromSkinObject(org.gudy.azureus2.ui.swt.plugins.PluginUISWTSkinObject)
public MdiEntrySWT getEntryFromSkinObject(
PluginUISWTSkinObject pluginSkinObject) {
if (pluginSkinObject instanceof SWTSkinObject) {
Control control = ((SWTSkinObject) pluginSkinObject).getControl();
while (control != null && !control.isDisposed()) {
Object entry = control.getData("BaseMDIEntry");
if (entry instanceof BaseMdiEntry) {
BaseMdiEntry mdiEntry = (BaseMdiEntry) entry;
return mdiEntry;
}
control = control.getParent();
}
}
return null;
}
protected void
requestAttention(
SideBarEntrySWT entry )
{
synchronized( attention_seekers ){
if ( !attention_seekers.contains( entry )){
attention_seekers.add( entry );
}
if ( attention_event == null ){
attention_event =
SimpleTimer.addPeriodicEvent(
"SideBar:attention",
SIDEBAR_ATTENTION_PERIOD,
new TimerEventPerformer()
{
int tick_count = 0;
public void
perform(
TimerEvent event )
{
tick_count++;
final List<SideBarEntrySWT> repaints = new ArrayList<SideBarEntrySWT>();
synchronized( attention_seekers ){
Iterator<SideBarEntrySWT> it = attention_seekers.iterator();
while ( it.hasNext()){
SideBarEntrySWT entry = it.next();
if ( entry.isDisposed()){
it.remove();
}else{
if ( !entry.attentionUpdate( tick_count )){
it.remove();
}
repaints.add( entry );
}
}
if ( attention_seekers.size() == 0 ){
TimerEventPeriodic ev = attention_event;
if ( ev != null ){
ev.cancel();
attention_event = null;
}
}
}
if ( repaints.size() > 0 ){
Utils.execSWTThread(
new AERunnable()
{
@Override
public void
runSupport()
{
for ( SideBarEntrySWT entry: repaints ){
entry.redraw();
}
}
});
}
}
});
}
}
}
public void generate(IndentWriter writer) {
MdiEntrySWT[] entries = getEntriesSWT();
for (MdiEntrySWT entry : entries) {
if (entry == null) {
continue;
}
UISWTViewCore view = entry.getCoreView();
if (!(view instanceof AEDiagnosticsEvidenceGenerator)) {
writer.println("Sidebar View (No Generator): " + entry.getId());
try {
writer.indent();
writer.println("Parent: " + entry.getParentID());
writer.println("Title: " + entry.getTitle());
} catch (Exception e) {
} finally {
writer.exdent();
}
}
}
}
// @see org.gudy.azureus2.ui.swt.debug.ObfusticateImage#obfusticatedImage(org.eclipse.swt.graphics.Image)
public Image obfusticatedImage(Image image) {
Rectangle treeBounds = tree.getBounds();
SideBarEntrySWT[] sideBarEntries = mapIdToEntry.values().toArray(
new SideBarEntrySWT[0]);
for (SideBarEntrySWT entry : sideBarEntries) {
Rectangle entryBounds = entry.swt_getBounds();
if (entryBounds != null && treeBounds.intersects(entryBounds)) {
entry.obfusticatedImage(image);
}
}
return image;
}
}