/**
* Created on Aug 13, 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.lang.reflect.Constructor;
import java.util.*;
import java.util.List;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.*;
import org.gudy.azureus2.core3.config.COConfigurationManager;
import org.gudy.azureus2.core3.util.*;
import org.gudy.azureus2.ui.swt.Utils;
import org.gudy.azureus2.ui.swt.mainwindow.Colors;
import org.gudy.azureus2.ui.swt.mainwindow.SWTThread;
import org.gudy.azureus2.ui.swt.plugins.UISWTView;
import org.gudy.azureus2.ui.swt.pluginsimpl.UISWTViewCore;
import org.gudy.azureus2.ui.swt.shells.GCStringPrinter;
import org.gudy.azureus2.ui.swt.views.IView;
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.imageloader.ImageLoader;
import com.aelitis.azureus.ui.swt.mdi.BaseMdiEntry;
import com.aelitis.azureus.ui.swt.mdi.MdiSWTMenuHackListener;
import com.aelitis.azureus.ui.swt.skin.*;
import com.aelitis.azureus.ui.swt.utils.ColorCache;
/**
* @author TuxPaper
* @created Aug 13, 2008
*
*/
public class SideBarEntrySWT
extends BaseMdiEntry
implements DisposeListener
{
private static final boolean DO_OUR_OWN_TREE_INDENT = true;
private static final int SIDEBAR_SPACING = 2;
private static final int IMAGELEFT_SIZE = 20;
private static final int IMAGELEFT_GAP = 5;
private static final boolean ALWAYS_IMAGE_GAP = true;
private static final String[] default_indicator_colors = {
"#000000",
"#000000",
"#166688",
"#1c2056"
};
private static long uniqueNumber = 0;
private TreeItem swtItem;
private List<SideBarVitalityImageSWT> listVitalityImages = Collections.EMPTY_LIST;
private final SideBar sidebar;
private int maxIndicatorWidth;
private Image imgClose;
private Image imgCloseSelected;
private Color bg;
private Color fg;
private Color bgSel;
private Color fgSel;
//private Color colorFocus;
private boolean showonSWTItemSet;
private final SWTSkin skin;
private SWTSkinObjectContainer soParent;
private boolean buildonSWTItemSet;
private boolean selectable = true;
private List<MdiSWTMenuHackListener> listMenuHackListners;
private boolean neverPainted = true;
public SideBarEntrySWT(SideBar sidebar, SWTSkin _skin, String id) {
super(sidebar, id);
this.skin = _skin;
if (id == null) {
logID = "null";
} else {
int i = id.indexOf('_');
if (i > 0) {
logID = id.substring(0, i);
} else {
logID = id;
}
}
this.sidebar = sidebar;
updateColors();
}
private void updateColors() {
Utils.execSWTThread(new AERunnable() {
public void runSupport() {
SWTSkinProperties skinProperties = skin.getSkinProperties();
bg = skinProperties.getColor("color.sidebar.bg");
fg = skinProperties.getColor("color.sidebar."
+ (isSelectable() ? "text" : "header"));
bgSel = skinProperties.getColor("color.sidebar.selected.bg");
fgSel = skinProperties.getColor("color.sidebar.selected.fg");
//colorFocus = skinProperties.getColor("color.sidebar.focus");
}
});
}
public TreeItem getTreeItem() {
return swtItem;
}
public void setTreeItem(TreeItem treeItem) {
if (swtItem != null && treeItem != null) {
Debug.out("Warning: Sidebar " + id + " already has a treeitem");
return;
}
this.swtItem = treeItem;
setDisposed(false);
if (treeItem != null) {
ImageLoader imageLoader = ImageLoader.getInstance();
imgClose = imageLoader.getImage("image.sidebar.closeitem");
imgCloseSelected = imageLoader.getImage("image.sidebar.closeitem-selected");
treeItem.addDisposeListener(this);
treeItem.getParent().addTreeListener(new TreeListener() {
public void treeExpanded(TreeEvent e) {
if (e.item == swtItem) {
SideBarEntrySWT.super.setExpanded(true);
}
}
public void treeCollapsed(TreeEvent e) {
if (e.item == swtItem) {
SideBarEntrySWT.super.setExpanded(false);
}
}
});
// Some/All OSes will auto-set treeitem's expanded flag to false if there
// is no children. To workaround, we store expanded state internally and
// set parent to expanded when a child is added
TreeItem parentItem = treeItem.getParentItem();
if (parentItem != null) {
MdiEntry parentEntry = (MdiEntry) parentItem.getData("MdiEntry");
if (parentEntry.isExpanded()) {
parentItem.setExpanded(true);
}
}
setExpanded(isExpanded());
}
if (buildonSWTItemSet) {
build();
}
if (showonSWTItemSet) {
show();
}
}
// @see org.gudy.azureus2.plugins.ui.sidebar.SideBarEntry#addVitalityImage(java.lang.String)
public MdiEntryVitalityImage addVitalityImage(String imageID) {
synchronized (this) {
SideBarVitalityImageSWT vitalityImage = new SideBarVitalityImageSWT(this,
imageID);
if (listVitalityImages == Collections.EMPTY_LIST) {
listVitalityImages = new ArrayList<SideBarVitalityImageSWT>(1);
}
listVitalityImages.add(vitalityImage);
return vitalityImage;
}
}
public MdiEntryVitalityImage[] getVitalityImages() {
return listVitalityImages.toArray(new MdiEntryVitalityImage[0]);
}
public MdiEntryVitalityImage getVitalityImage(int hitX, int hitY) {
MdiEntryVitalityImage[] vitalityImages = getVitalityImages();
for (int i = 0; i < vitalityImages.length; i++) {
SideBarVitalityImageSWT vitalityImage = (SideBarVitalityImageSWT) vitalityImages[i];
if (!vitalityImage.isVisible()) {
continue;
}
Rectangle hitArea = vitalityImage.getHitArea();
if (hitArea != null && hitArea.contains(hitX, hitY)) {
return vitalityImage;
}
}
return null;
}
/* (non-Javadoc)
* @see com.aelitis.azureus.ui.mdi.MdiEntry#redraw()
*/
boolean isRedrawQueued = false;
public void redraw() {
if (neverPainted) {
return;
}
synchronized (this) {
if (isRedrawQueued) {
return;
}
isRedrawQueued = true;
}
//System.out.println("redraw " + Thread.currentThread().getName() + ":" + getId() + " via " + Debug.getCompressedStackTrace());
Utils.execSWTThreadLater(0, new AERunnable() {
public void runSupport() {
try {
if (swtItem == null || swtItem.isDisposed()) {
return;
}
Tree tree = swtItem.getParent();
if (!tree.isVisible()) {
return;
}
try {
Rectangle bounds = swtItem.getBounds();
Rectangle treeBounds = tree.getBounds();
tree.redraw(0, bounds.y, treeBounds.width, bounds.height, true);
} catch (NullPointerException npe) {
// ignore NPE. OSX seems to be spewing this when the tree size is 0
// or is invisible or something like that
}
//tree.update();
} finally {
synchronized (SideBarEntrySWT.this) {
isRedrawQueued = false;
}
}
}
});
}
protected Rectangle swt_getBounds() {
if (swtItem == null || swtItem.isDisposed()) {
return null;
}
try {
Tree tree = swtItem.getParent();
Rectangle bounds = swtItem.getBounds();
Rectangle treeBounds = tree.getBounds();
return new Rectangle(0, bounds.y, treeBounds.width, bounds.height);
} catch (NullPointerException e) {
// On OSX, we get erroneous NPE here:
//at org.eclipse.swt.widgets.Tree.sendMeasureItem(Tree.java:2443)
//at org.eclipse.swt.widgets.Tree.cellSize(Tree.java:274)
//at org.eclipse.swt.widgets.Display.windowProc(Display.java:4750)
//at org.eclipse.swt.internal.cocoa.OS.objc_msgSend_stret(Native Method)
//at org.eclipse.swt.internal.cocoa.NSCell.cellSize(NSCell.java:34)
//at org.eclipse.swt.widgets.TreeItem.getBounds(TreeItem.java:467)
Debug.outNoStack("NPE @ " + Debug.getCompressedStackTrace(), true);
} catch (Exception e) {
Debug.out(e);
}
return null;
}
/* (non-Javadoc)
* @see com.aelitis.azureus.ui.swt.mdi.BaseMdiEntry#setExpanded(boolean)
*/
public void setExpanded(final boolean expanded) {
super.setExpanded(expanded);
Utils.execSWTThread(new AERunnable() {
public void runSupport() {
if (swtItem != null && !isDisposed()) {
swtItem.setExpanded(expanded);
}
}
});
}
public void expandTo() {
Utils.execSWTThread(new AERunnable() {
public void runSupport() {
if (swtItem == null || isDisposed()) {
return;
}
TreeItem item = swtItem.getParentItem();
while (item != null) {
item.setExpanded(true);
// walk up and make sure parents are expanded
item = item.getParentItem();
}
}
});
}
/* (non-Javadoc)
* @see com.aelitis.azureus.ui.swt.mdi.BaseMdiEntry#close()
*/
public boolean close(boolean force) {
if (!super.close(force)) {
return false;
}
// remove immediately from MDI because disposal is on a delay
mdi.removeItem(SideBarEntrySWT.this);
// dispose will trigger dispose listener, which removed it from BaseMDI
Utils.execSWTThread(new AERunnable() {
public void runSupport() {
if (swtItem != null) {
try {
swtItem.setFont(null);
swtItem.dispose();
} catch (Exception e) {
// on OSX, SWT does some misguided exceptions on disposal of TreeItem
// We occasionally get SWTException of "Widget is Disposed" or
// "Argument not valid", as well as NPEs
Debug.outNoStack(
"Warning on SidebarEntry dispose: " + e.toString(), false);
} finally {
swtItem = null;
}
} else if (iview != null) {
try {
iview.delete();
} finally {
iview = null;
}
}
}
});
return true;
}
public void build() {
Utils.execSWTThread(new AERunnable() {
public void runSupport() {
swt_build();
SideBarEntrySWT.super.build();
}
});
}
public boolean swt_build() {
if (swtItem == null) {
buildonSWTItemSet = true;
return true;
}
buildonSWTItemSet = false;
if (getSkinObject() == null) {
Control control = null;
Composite parent = soParent == null ? Utils.findAnyShell()
: soParent.getComposite();
String skinRef = getSkinRef();
if (skinRef != null) {
Shell shell = parent.getShell();
Cursor cursor = shell.getCursor();
try {
shell.setCursor(shell.getDisplay().getSystemCursor(SWT.CURSOR_WAIT));
// wrap skinRef with a container that we control visibility of
// (invisible by default)
SWTSkinObjectContainer soContents = (SWTSkinObjectContainer) skin.createSkinObject(
"MdiContents." + uniqueNumber++, "mdi.content.item",
getParentSkinObject(), null);
skin.addSkinObject(soContents);
SWTSkinObject skinObject = skin.createSkinObject(id, skinRef,
soContents, getDatasourceCore());
skin.addSkinObject(soContents);
control = skinObject.getControl();
control.setLayoutData(Utils.getFilledFormData());
control.getParent().layout(true, true);
setSkinObject(skinObject, soContents);
} finally {
shell.setCursor(cursor);
}
} else if (iview != null) {
try {
SWTSkinObjectContainer soContents = (SWTSkinObjectContainer) skin.createSkinObject(
"MdiIView." + uniqueNumber++, "mdi.content.item",
getParentSkinObject());
skin.addSkinObject(soContents);
parent.setBackgroundMode(SWT.INHERIT_NONE);
Composite viewComposite = soContents.getComposite();
boolean doGridLayout = true;
if (iview instanceof UISWTView) {
UISWTView swtView = (UISWTView) iview;
if (swtView.getControlType() == UISWTViewCore.CONTROLTYPE_SKINOBJECT) {
doGridLayout = false;
}
}
// viewComposite.setBackground(parent.getDisplay().getSystemColor(
// SWT.COLOR_WIDGET_BACKGROUND));
// viewComposite.setForeground(parent.getDisplay().getSystemColor(
// SWT.COLOR_WIDGET_FOREGROUND));
if (doGridLayout) {
GridLayout gridLayout = new GridLayout();
gridLayout.horizontalSpacing = gridLayout.verticalSpacing = gridLayout.marginHeight = gridLayout.marginWidth = 0;
viewComposite.setLayout(gridLayout);
viewComposite.setLayoutData(Utils.getFilledFormData());
}
if (iview instanceof UISWTViewCore) {
UISWTViewCore uiViewCore = (UISWTViewCore) iview;
uiViewCore.setSkinObject(soContents, soContents.getComposite());
}
iview.initialize(viewComposite);
swtItem.setText(iview.getFullTitle());
Composite iviewComposite = iview.getComposite();
control = iviewComposite;
// force layout data of IView's composite to GridData, since we set
// the parent to GridLayout (most plugins use grid, so we stick with
// that instead of form)
if (doGridLayout) {
Object existingLayoutData = iviewComposite.getLayoutData();
Object existingParentLayoutData = iviewComposite.getParent().getLayoutData();
if (existingLayoutData == null
|| !(existingLayoutData instanceof GridData)
&& (existingParentLayoutData instanceof GridLayout)) {
GridData gridData = new GridData(GridData.FILL_BOTH);
iviewComposite.setLayoutData(gridData);
}
}
parent.layout(true, true);
setSkinObject(soContents, soContents);
} catch (Exception e) {
Debug.out("Error creating sidebar content area for " + id, e);
if (iview != null) {
iview.delete();
}
setIView(null);
close(true);
}
} else if (iviewClass != null) {
try {
IView view = null;
if (iviewClassArgs == null) {
view = (IView) iviewClass.newInstance();
} else {
Constructor<?> constructor = iviewClass.getConstructor(iviewClassArgs);
view = (IView) constructor.newInstance(iviewClassVals);
}
if (view != null) {
setIView(view);
// now that we have an IView, go through show one more time
return swt_build();
}
close(true);
return false;
} catch (Throwable e) {
Debug.out(e);
close(true);
}
}
if (control != null && !control.isDisposed()) {
control.setData("BaseMDIEntry", this);
control.addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
close(true);
}
});
} else {
return false;
}
} // control == null
return true;
}
/* (non-Javadoc)
* @see com.aelitis.azureus.ui.swt.mdi.BaseMdiEntry#show()
*/
public void show() {
// ensure show order by user execThreadLater
// fixes case where two showEntries are called, the first from a non
// SWT thread, and the 2nd from a SWT thread. The first one will run last
// showing itself
Utils.execSWTThreadLater(0, new AERunnable() {
public void runSupport() {
swt_show();
}
});
}
private void swt_show() {
if (swtItem == null) {
showonSWTItemSet = true;
return;
}
showonSWTItemSet = false;
if (!swt_build()) {
return;
}
triggerOpenListeners();
swtItem.getParent().select(swtItem);
swtItem.getParent().showItem(swtItem);
super.show();
}
protected void swt_paintSideBar(Event event) {
neverPainted = false;
//System.out.println(System.currentTimeMillis() + "] paint " + getId() + ";sel? " + ((event.detail & SWT.SELECTED) > 0));
TreeItem treeItem = (TreeItem) event.item;
if (treeItem.isDisposed() || isDisposed()) {
return;
}
Rectangle itemBounds = treeItem.getBounds();
Rectangle drawBounds = event.gc.getClipping();
if (drawBounds.isEmpty()) {
drawBounds = event.getBounds();
}
String text = getTitle();
if (text == null)
text = "";
//Point size = event.gc.textExtent(text);
//Rectangle treeBounds = tree.getBounds();
GC gc = event.gc;
gc.setAntialias(SWT.ON);
gc.setAdvanced(true);
//gc.setClipping((Rectangle) null);
boolean selected = (event.detail & SWT.SELECTED) > 0;
Color fgText = swt_paintEntryBG(event.detail, gc, drawBounds);
Tree tree = (Tree) event.widget;
Rectangle treeArea = tree.getClientArea();
Font font = tree.getFont();
if (font != null && !font.isDisposed()) {
gc.setFont(font);
}
if (DO_OUR_OWN_TREE_INDENT) {
TreeItem tempItem = treeItem.getParentItem();
int indent;
if (!isCollapseDisabled() && tempItem == null && !Utils.isGTK) {
indent = 22;
} else {
indent = 10;
}
while (tempItem != null) {
indent += 10;
tempItem = tempItem.getParentItem();
}
if (SideBar.USE_NATIVE_EXPANDER && Utils.isGTK) {
indent += 5;
}
itemBounds.x = indent;
}
int x1IndicatorOfs = SIDEBAR_SPACING;
int x0IndicatorOfs = itemBounds.x;
//System.out.println(System.currentTimeMillis() + "] refresh " + sideBarEntry.getId() + "; " + itemBounds + ";clip=" + event.gc.getClipping() + ";eb=" + event.getBounds());
if (viewTitleInfo != null) {
String textIndicator = null;
try {
textIndicator = (String) viewTitleInfo.getTitleInfoProperty(ViewTitleInfo.TITLE_INDICATOR_TEXT);
} catch (Exception e) {
Debug.out(e);
}
if (textIndicator != null) {
Point textSize = gc.textExtent(textIndicator);
//Point minTextSize = gc.textExtent("99");
//if (textSize.x < minTextSize.x + 2) {
// textSize.x = minTextSize.x + 2;
//}
int width = textSize.x + 10;
x1IndicatorOfs += width + SIDEBAR_SPACING;
int startX = treeArea.width - x1IndicatorOfs;
int textOffsetY = 0;
int height = textSize.y + 1;
int startY = itemBounds.y + (itemBounds.height - height) / 2;
//gc.fillRectangle(startX, startY, width, height);
Pattern pattern;
Color color1;
Color color2;
String[] colors = (String[]) viewTitleInfo.getTitleInfoProperty(ViewTitleInfo.TITLE_INDICATOR_COLOR);
if (colors == null || colors.length != 4) {
colors = default_indicator_colors;
}
/*
if (selected) {
color1 = ColorCache.getColor(gc.getDevice(), colors[0]);
color2 = ColorCache.getColor(gc.getDevice(), colors[1]);
pattern = new Pattern(gc.getDevice(), 0, startY, 0, startY + height,
color1, 127, color2, 4);
} else {
color1 = ColorCache.getColor(gc.getDevice(), colors[2]);
color2 = ColorCache.getColor(gc.getDevice(), colors[3]);
pattern = new Pattern(gc.getDevice(), 0, startY, 0, startY + height,
color1, color2);
}
gc.setBackgroundPattern(pattern);
*/
gc.setBackground(ColorCache.getColor(gc.getDevice(), "#5b6e87"));
gc.fillRoundRectangle(startX, startY, width, height, textSize.y * 2 / 3,
height * 2 / 3);
gc.setBackgroundPattern(null);
//pattern.dispose();
if (maxIndicatorWidth > width) {
maxIndicatorWidth = width;
}
gc.setForeground(Colors.white);
GCStringPrinter.printString(gc, textIndicator, new Rectangle(startX,
startY + textOffsetY, width, height), true, false, SWT.CENTER);
}
}
//if (x1IndicatorOfs < 30) {
// x1IndicatorOfs = 30;
//}
if (isCloseable()) {
Image img = selected ? imgCloseSelected : imgClose;
Rectangle closeArea = img.getBounds();
closeArea.x = treeArea.width - closeArea.width - SIDEBAR_SPACING
- x1IndicatorOfs;
closeArea.y = itemBounds.y + (itemBounds.height - closeArea.height) / 2;
x1IndicatorOfs += closeArea.width + SIDEBAR_SPACING;
//gc.setBackground(treeItem.getBackground());
//gc.fillRectangle(closeArea);
gc.drawImage(img, closeArea.x, closeArea.y);
treeItem.setData("closeArea", closeArea);
}
MdiEntryVitalityImage[] vitalityImages = getVitalityImages();
for (int i = 0; i < vitalityImages.length; i++) {
SideBarVitalityImageSWT vitalityImage = (SideBarVitalityImageSWT) vitalityImages[i];
if (vitalityImage == null || !vitalityImage.isVisible()
|| vitalityImage.getAlignment() != SWT.RIGHT) {
continue;
}
vitalityImage.switchSuffix(selected ? "-selected" : "");
Image image = vitalityImage.getImage();
if (image != null && !image.isDisposed()) {
Rectangle bounds = image.getBounds();
bounds.x = treeArea.width - bounds.width - SIDEBAR_SPACING
- x1IndicatorOfs;
bounds.y = itemBounds.y + (itemBounds.height - bounds.height) / 2;
x1IndicatorOfs += bounds.width + SIDEBAR_SPACING;
gc.drawImage(image, bounds.x, bounds.y);
// setHitArea needs it relative to entry
bounds.y -= itemBounds.y;
vitalityImage.setHitArea(bounds);
}
}
boolean greyScale = false;
if (viewTitleInfo != null) {
Object active_state = viewTitleInfo.getTitleInfoProperty(ViewTitleInfo.TITLE_ACTIVE_STATE);
if (active_state instanceof Long) {
greyScale = (Long) active_state == 2;
}
}
String suffix = selected ? "-selected" : null;
Image imageLeft = getImageLeft(suffix);
if (imageLeft == null && selected) {
releaseImageLeft(suffix);
suffix = null;
imageLeft = getImageLeft(null);
}
if (imageLeft != null) {
Rectangle bounds = imageLeft.getBounds();
int x = x0IndicatorOfs + ((IMAGELEFT_SIZE - bounds.width) / 2);
int y = itemBounds.y + ((itemBounds.height - bounds.height) / 2);
Rectangle clipping = gc.getClipping();
gc.setClipping(x0IndicatorOfs, itemBounds.y, IMAGELEFT_SIZE,
itemBounds.height);
boolean drawn = false;
if (greyScale) {
String imageLeftID = getImageLeftID();
if (imageLeftID != null) {
Image grey = ImageLoader.getInstance().getImage(imageLeftID + "-gray");
if (grey != null) {
gc.setAlpha(160);
gc.drawImage(grey, x, y);
gc.setAlpha(255);
ImageLoader.getInstance().releaseImage(imageLeftID + "-gray");
drawn = true;
}
}
}
if (!drawn) {
gc.drawImage(imageLeft, x, y);
}
releaseImageLeft(suffix);
gc.setClipping(clipping);
// 0, 0, bounds.width, bounds.height,
// x0IndicatorOfs, itemBounds.y
// + ((itemBounds.height - IMAGELEFT_SIZE) / 2), IMAGELEFT_SIZE,
// IMAGELEFT_SIZE);
x0IndicatorOfs += IMAGELEFT_SIZE + IMAGELEFT_GAP;
releaseImageLeft(suffix);
} else if (ALWAYS_IMAGE_GAP) {
if (isSelectable()) {
x0IndicatorOfs += IMAGELEFT_SIZE + IMAGELEFT_GAP;
}
} else {
if (treeItem.getParentItem() != null) {
x0IndicatorOfs += 30 - 18;
}
}
// Main Text
////////////
Rectangle clipping = new Rectangle(x0IndicatorOfs, itemBounds.y,
treeArea.width - x1IndicatorOfs - SIDEBAR_SPACING - x0IndicatorOfs,
itemBounds.height);
if (drawBounds.intersects(clipping)) {
int style= SWT.NONE;
if (!isSelectable()) {
Font headerFont = sidebar.getHeaderFont();
if (headerFont != null && !headerFont.isDisposed()) {
gc.setFont(headerFont);
}
text = text.toUpperCase();
gc.setForeground(ColorCache.getColor(gc.getDevice(), 255, 255, 255));
gc.setAlpha(100);
clipping.x++;
clipping.y++;
//style = SWT.TOP;
GCStringPrinter sp = new GCStringPrinter(gc, text, clipping, true, false,
style);
sp.printString();
gc.setAlpha(255);
clipping.x--;
clipping.y--;
gc.setForeground(fgText);
} else {
gc.setForeground(fgText);
}
//gc.setClipping(clipping);
GCStringPrinter sp = new GCStringPrinter(gc, text, clipping, true, false,
style);
sp.printString();
clipping.x += sp.getCalculatedSize().x + 5;
//gc.setClipping((Rectangle) null);
}
// Vitality Images
for (int i = 0; i < vitalityImages.length; i++) {
SideBarVitalityImageSWT vitalityImage = (SideBarVitalityImageSWT) vitalityImages[i];
if (!vitalityImage.isVisible()
|| vitalityImage.getAlignment() != SWT.LEFT) {
continue;
}
vitalityImage.switchSuffix(selected ? "-selected" : "");
Image image = vitalityImage.getImage();
if (image != null && !image.isDisposed()) {
Rectangle bounds = image.getBounds();
bounds.x = clipping.x;
bounds.y = itemBounds.y + (itemBounds.height - bounds.height) / 2;
clipping.x += bounds.width + SIDEBAR_SPACING;
if (clipping.x > (treeArea.width - x1IndicatorOfs)) {
vitalityImage.setHitArea(null);
continue;
}
gc.drawImage(image, bounds.x, bounds.y);
vitalityImage.setHitArea(bounds);
}
}
// EXPANDO
// OSX overrides the twisty, and we can't use the default twisty
// on Windows because it doesn't have transparency and looks ugly
if (treeItem.getItemCount() > 0 && !isCollapseDisabled()
&& !SideBar.USE_NATIVE_EXPANDER) {
gc.setAntialias(SWT.ON);
Color oldBG = gc.getBackground();
gc.setBackground(event.display.getSystemColor(SWT.COLOR_LIST_FOREGROUND));
int baseX = 22; // itemBounds.x;
if (treeItem.getExpanded()) {
int xStart = 12;
int arrowSize = 8;
int yStart = itemBounds.height - (itemBounds.height + arrowSize) / 2;
gc.fillPolygon(new int[] {
baseX - xStart,
itemBounds.y + yStart,
baseX - xStart + arrowSize,
itemBounds.y + yStart,
baseX - xStart + (arrowSize / 2),
itemBounds.y + yStart + arrowSize,
});
} else {
int xStart = 12;
int arrowSize = 8;
int yStart = itemBounds.height - (itemBounds.height + arrowSize) / 2;
gc.fillPolygon(new int[] {
baseX - xStart,
itemBounds.y + yStart,
baseX - xStart + arrowSize,
itemBounds.y + yStart + 4,
baseX - xStart,
itemBounds.y + yStart + 8,
});
}
gc.setBackground(oldBG);
gc.setFont(sidebar.getHeaderFont());
}
}
protected Color swt_paintEntryBG(int detail, GC gc, Rectangle drawBounds) {
neverPainted = false;
Color fgText = Colors.black;
boolean selected = (detail & SWT.SELECTED) > 0;
//boolean focused = (detail & SWT.FOCUSED) > 0;
boolean hot = (detail & SWT.HOT) > 0;
if (selected) {
//System.out.println("gmmm" + drawBounds + ": " + Debug.getCompressedStackTrace());
gc.setClipping((Rectangle) null);
if (fgSel != null) {
fgText = fgSel;
}
if (bgSel != null) {
gc.setBackground(bgSel);
}
Color color1;
Color color2;
if (sidebar.getTree().isFocusControl()) {
color1 = ColorCache.getColor(gc.getDevice(), "#166688");
color2 = ColorCache.getColor(gc.getDevice(), "#1c2458");
} else {
color1 = ColorCache.getColor(gc.getDevice(), "#447281");
color2 = ColorCache.getColor(gc.getDevice(), "#393e58");
}
gc.setBackground(color1);
gc.fillRectangle(drawBounds.x, drawBounds.y, drawBounds.width, 4);
gc.setForeground(color1);
gc.setBackground(color2);
Rectangle itemBounds = swt_getBounds();
if (itemBounds == null) {
return fgText;
}
// always need to start gradient at the same Y position
// +3 is to start gradient off 3 pixels lower
gc.fillGradientRectangle(drawBounds.x, itemBounds.y + 3,
drawBounds.width, itemBounds.height - 3, true);
} else {
if (fg != null) {
fgText = fg;
}
if (bg != null) {
gc.setBackground(bg);
}
if (this == sidebar.draggingOver || hot) {
Color c = skin.getSkinProperties().getColor("color.sidebar.drag.bg");
gc.setBackground(c);
}
gc.fillRectangle(drawBounds);
if (this == sidebar.draggingOver) {
Color c = skin.getSkinProperties().getColor("color.sidebar.drag.fg");
gc.setForeground(c);
gc.setLineWidth(5);
gc.drawRectangle(drawBounds);
}
}
return fgText;
}
public void widgetDisposed(DisposeEvent e) {
ImageLoader imageLoader = ImageLoader.getInstance();
imageLoader.releaseImage("image.sidebar.closeitem");
imageLoader.releaseImage("image.sidebar.closeitem-selected");
final TreeItem treeItem = (TreeItem) e.widget;
if (treeItem != swtItem) {
Debug.out("Warning: TreeItem changed for sidebar " + id);
return;
}
if (swtItem == null) {
return;
}
if (swtItem != null && !Constants.isOSX) {
// In theory, the disposal of swtItem will trigger the disposal of the
// children. Let's force it just in case
// On OSX this will cause disposal confusion in SWT, and possibly result
// in a SIGSEGV crash.
TreeItem[] children = swtItem.getItems();
for (TreeItem child : children) {
if (child.isDisposed()) {
continue;
}
MdiEntry entry = (MdiEntry) child.getData("MdiEntry");
if (entry != null) {
entry.close(true);
}
}
}
final Tree tree = sidebar.getTree();
if (tree.isDisposed() || swtItem.isDisposed() || tree.getShell().isDisposed()) {
return;
}
setTreeItem(null);
mdi.removeItem(SideBarEntrySWT.this);
triggerCloseListeners(!SWTThread.getInstance().isTerminated());
IView iview = getIView();
if (iview != null) {
iview.delete();
setIView(null);
}
SWTSkinObject so = getSkinObject();
if (so != null) {
setSkinObject(null, null);
so.getSkin().removeSkinObject(so);
}
// delay saving of removing of auto-open flag. If after the delay, we are
// still alive, it's assumed the user invoked the close, and we should
// remove the auto-open flag
Utils.execSWTThreadLater(0, new AERunnable() {
public void runSupport() {
// even though execThreadLater will not run on close of app because
// the display is disposed, do a double check of tree disposal just
// in case. We don't want to trigger close listeners or
// remove autoopen parameters if the user is closing the app (as
// opposed to closing the sidebar)
if (tree.isDisposed()) {
return;
}
try {
COConfigurationManager.removeParameter("SideBar.AutoOpen." + id);
// OSX doesn't select a treeitem after closing an existing one
// Force selection
if (Constants.isOSX && !tree.isDisposed()
&& tree.getSelectionCount() == 0) {
String parentid = getParentID();
if (parentid != null && mdi.getEntry(parentid) != null) {
mdi.showEntryByID(parentid);
} else {
mdi.showEntryByID(SideBar.SIDEBAR_SECTION_LIBRARY);
}
}
} catch (Exception e2) {
Debug.out(e2);
}
mdi.setEntryAutoOpen(id, false);
}
});
}
public void setParentSkinObject(SWTSkinObjectContainer soParent) {
this.soParent = soParent;
}
public SWTSkinObjectContainer getParentSkinObject() {
return soParent;
}
public void setSelectable(boolean selectable) {
this.selectable = selectable;
updateColors();
}
public boolean isSelectable() {
return selectable;
}
public boolean swt_isVisible() {
TreeItem parentItem = swtItem.getParentItem();
if (parentItem != null) {
MdiEntry parentEntry = (MdiEntry) parentItem.getData("MdiEntry");
if (!parentEntry.isExpanded()) {
return false;
}
}
return true; // todo: bounds check
}
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]);
}
}
}