| /******************************************************************************* |
| * Copyright (c) 2001, 2009 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| * Mariot Chauvin <mariot.chauvin@obeo.fr> - bug 259553 |
| *******************************************************************************/ |
| package org.eclipse.ui.internal.views.properties.tabbed.view; |
| |
| import org.eclipse.jface.resource.JFaceResources; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.events.ControlAdapter; |
| import org.eclipse.swt.events.ControlEvent; |
| import org.eclipse.swt.events.FocusEvent; |
| import org.eclipse.swt.events.FocusListener; |
| import org.eclipse.swt.events.MouseAdapter; |
| import org.eclipse.swt.events.MouseEvent; |
| import org.eclipse.swt.events.PaintEvent; |
| import org.eclipse.swt.events.PaintListener; |
| import org.eclipse.swt.graphics.Color; |
| import org.eclipse.swt.graphics.FontMetrics; |
| import org.eclipse.swt.graphics.GC; |
| import org.eclipse.swt.graphics.Point; |
| import org.eclipse.swt.graphics.RGB; |
| import org.eclipse.swt.graphics.Rectangle; |
| import org.eclipse.swt.layout.FormAttachment; |
| import org.eclipse.swt.layout.FormData; |
| import org.eclipse.swt.layout.FormLayout; |
| import org.eclipse.swt.widgets.Canvas; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.Event; |
| import org.eclipse.ui.forms.FormColors; |
| import org.eclipse.ui.internal.views.properties.tabbed.l10n.TabbedPropertyMessages; |
| import org.eclipse.ui.views.properties.tabbed.ITabItem; |
| import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetWidgetFactory; |
| |
| |
| /** |
| * Shows the list of tabs in the tabbed property sheet page. |
| * |
| * @author Anthony Hunter |
| */ |
| public class TabbedPropertyList |
| extends Composite { |
| |
| private static final ListElement[] ELEMENTS_EMPTY = new ListElement[0]; |
| |
| protected static final int NONE = -1; |
| |
| protected static final int INDENT = 7; |
| |
| private boolean focus = false; |
| |
| private ListElement[] elements; |
| |
| private int selectedElementIndex = NONE; |
| |
| private int topVisibleIndex = NONE; |
| |
| private int bottomVisibleIndex = NONE; |
| |
| private TopNavigationElement topNavigationElement; |
| |
| private BottomNavigationElement bottomNavigationElement; |
| |
| private int widestLabelIndex = NONE; |
| |
| private int tabsThatFitInComposite = NONE; |
| |
| private Color widgetForeground; |
| |
| private Color widgetBackground; |
| |
| private Color widgetNormalShadow; |
| |
| private Color widgetDarkShadow; |
| |
| private Color listBackground; |
| |
| private Color hoverGradientStart; |
| |
| private Color hoverGradientEnd; |
| |
| private Color defaultGradientStart; |
| |
| private Color defaultGradientEnd; |
| |
| private Color indentedDefaultBackground; |
| |
| private Color indentedHoverBackground; |
| |
| private Color navigationElementShadowStroke; |
| |
| private Color bottomNavigationElementShadowStroke1; |
| |
| private Color bottomNavigationElementShadowStroke2; |
| |
| private TabbedPropertySheetWidgetFactory factory; |
| |
| /** |
| * One of the tabs in the tabbed property list. |
| */ |
| public class ListElement extends Canvas { |
| |
| private ITabItem tab; |
| |
| private int index; |
| |
| private boolean selected; |
| |
| private boolean hover; |
| |
| /** |
| * Constructor for ListElement. |
| * |
| * @param parent |
| * the parent Composite. |
| * @param tab |
| * the tab item for the element. |
| * @param index |
| * the index in the list. |
| */ |
| public ListElement(Composite parent, final ITabItem tab, int index) { |
| super(parent, SWT.NO_FOCUS); |
| this.tab = tab; |
| hover = false; |
| selected = false; |
| this.index = index; |
| |
| addPaintListener(new PaintListener() { |
| |
| public void paintControl(PaintEvent e) { |
| paint(e); |
| } |
| }); |
| addMouseListener(new MouseAdapter() { |
| |
| public void mouseUp(MouseEvent e) { |
| if (!selected) { |
| select(getIndex(ListElement.this)); |
| /* |
| * We set focus to the tabbed property composite so that |
| * focus is moved to the appropriate widget in the |
| * section. |
| */ |
| Composite tabbedPropertyComposite = getParent(); |
| while (!(tabbedPropertyComposite instanceof TabbedPropertyComposite)) { |
| tabbedPropertyComposite = tabbedPropertyComposite |
| .getParent(); |
| } |
| tabbedPropertyComposite.setFocus(); |
| } |
| } |
| }); |
| // RAP does not support this yet |
| // addMouseMoveListener(new MouseMoveListener() { |
| // |
| // public void mouseMove(MouseEvent e) { |
| // if (!hover) { |
| // hover = true; |
| // redraw(); |
| // } |
| // } |
| // }); |
| // addMouseTrackListener(new MouseTrackAdapter() { |
| // |
| // public void mouseExit(MouseEvent e) { |
| // hover = false; |
| // redraw(); |
| // } |
| // }); |
| // /RAP |
| } |
| |
| /** |
| * Set selected value for this element. |
| * |
| * @param selected |
| * the selected value. |
| */ |
| public void setSelected(boolean selected) { |
| this.selected = selected; |
| redraw(); |
| } |
| |
| /** |
| * Paint the element. |
| * |
| * @param e |
| * the paint event. |
| */ |
| private void paint(PaintEvent e) { |
| /* |
| * draw the top two lines of the tab, same for selected, hover and |
| * default |
| */ |
| Rectangle bounds = getBounds(); |
| e.gc.setForeground(widgetNormalShadow); |
| e.gc.drawLine(0, 0, bounds.width - 1, 0); |
| e.gc.setForeground(listBackground); |
| e.gc.drawLine(0, 1, bounds.width - 1, 1); |
| |
| /* draw the fill in the tab */ |
| if (selected) { |
| e.gc.setBackground(listBackground); |
| e.gc.fillRectangle(0, 2, bounds.width, bounds.height - 1); |
| } else if (hover && tab.isIndented()) { |
| e.gc.setBackground(indentedHoverBackground); |
| e.gc.fillRectangle(0, 2, bounds.width - 1, bounds.height - 1); |
| } else if (hover) { |
| e.gc.setForeground(hoverGradientStart); |
| e.gc.setBackground(hoverGradientEnd); |
| e.gc.fillGradientRectangle(0, 2, bounds.width - 1, |
| bounds.height - 1, true); |
| } else if (tab.isIndented()) { |
| e.gc.setBackground(indentedDefaultBackground); |
| e.gc.fillRectangle(0, 2, bounds.width - 1, bounds.height - 1); |
| } else { |
| e.gc.setForeground(defaultGradientStart); |
| e.gc.setBackground(defaultGradientEnd); |
| e.gc.fillGradientRectangle(0, 2, bounds.width - 1, |
| bounds.height - 1, true); |
| } |
| |
| if (!selected) { |
| e.gc.setForeground(widgetNormalShadow); |
| e.gc.drawLine(bounds.width - 1, 1, bounds.width - 1, |
| bounds.height + 1); |
| } |
| |
| int textIndent = INDENT; |
| FontMetrics fm = e.gc.getFontMetrics(); |
| int height = fm.getHeight(); |
| int textMiddle = (bounds.height - height) / 2; |
| |
| if (selected && tab.getImage() != null |
| && !tab.getImage().isDisposed()) { |
| /* draw the icon for the selected tab */ |
| if (tab.isIndented()) { |
| textIndent = textIndent + INDENT; |
| } else { |
| textIndent = textIndent - 3; |
| } |
| e.gc.drawImage(tab.getImage(), textIndent, textMiddle - 1); |
| textIndent = textIndent + 16 + 5; |
| } else if (tab.isIndented()) { |
| textIndent = textIndent + INDENT; |
| } |
| |
| /* draw the text */ |
| e.gc.setForeground(widgetForeground); |
| if (selected) { |
| /* selected tab is bold font */ |
| e.gc.setFont(JFaceResources.getFontRegistry().getBold( |
| JFaceResources.DEFAULT_FONT)); |
| } |
| e.gc.drawText(tab.getText(), textIndent, textMiddle, true); |
| if (((TabbedPropertyList) getParent()).focus && selected) { |
| /* draw a line if the tab has focus */ |
| Point point = e.gc.textExtent(tab.getText()); |
| e.gc.drawLine(textIndent, bounds.height - 4, textIndent |
| + point.x, bounds.height - 4); |
| } |
| |
| /* draw the bottom line on the tab for selected and default */ |
| if (!hover) { |
| e.gc.setForeground(listBackground); |
| e.gc.drawLine(0, bounds.height - 1, bounds.width - 2, |
| bounds.height - 1); |
| } |
| } |
| |
| /** |
| * Get the tab item. |
| * |
| * @return the tab item. |
| */ |
| public ITabItem getTabItem() { |
| return tab; |
| } |
| |
| public String toString() { |
| return tab.getText(); |
| } |
| } |
| |
| /** |
| * The top navigation element in the tabbed property list. It looks like a |
| * scroll button when scrolling is needed or is just a spacer when no |
| * scrolling is required. |
| */ |
| public class TopNavigationElement extends Canvas { |
| |
| /** |
| * Constructor for TopNavigationElement. |
| * |
| * @param parent |
| * the parent Composite. |
| */ |
| public TopNavigationElement(Composite parent) { |
| super(parent, SWT.NO_FOCUS); |
| addPaintListener(new PaintListener() { |
| |
| public void paintControl(PaintEvent e) { |
| paint(e); |
| } |
| }); |
| addMouseListener(new MouseAdapter() { |
| |
| public void mouseUp(MouseEvent e) { |
| if (isUpScrollRequired()) { |
| bottomVisibleIndex--; |
| if (topVisibleIndex != 0) { |
| topVisibleIndex--; |
| } |
| layoutTabs(); |
| topNavigationElement.redraw(); |
| bottomNavigationElement.redraw(); |
| } |
| } |
| }); |
| } |
| |
| /** |
| * Paint the element. |
| * |
| * @param e |
| * the paint event. |
| */ |
| private void paint(PaintEvent e) { |
| e.gc.setBackground(widgetBackground); |
| e.gc.setForeground(widgetForeground); |
| Rectangle bounds = getBounds(); |
| |
| if (elements.length != 0) { |
| e.gc.fillRectangle(0, 0, bounds.width, bounds.height); |
| e.gc.setForeground(widgetNormalShadow); |
| e.gc.drawLine(bounds.width - 1, 0, bounds.width - 1, |
| bounds.height - 1); |
| } else { |
| e.gc.setBackground(listBackground); |
| e.gc.fillRectangle(0, 0, bounds.width, bounds.height); |
| int textIndent = INDENT; |
| FontMetrics fm = e.gc.getFontMetrics(); |
| int height = fm.getHeight(); |
| int textMiddle = (bounds.height - height) / 2; |
| e.gc.setForeground(widgetForeground); |
| String properties_not_available = TabbedPropertyMessages.TabbedPropertyList_properties_not_available; |
| e.gc.drawText(properties_not_available, textIndent, textMiddle); |
| } |
| |
| if (isUpScrollRequired()) { |
| e.gc.setForeground(widgetDarkShadow); |
| int middle = bounds.width / 2; |
| e.gc.drawLine(middle + 1, 3, middle + 5, 7); |
| e.gc.drawLine(middle, 3, middle - 4, 7); |
| e.gc.drawLine(middle - 3, 7, middle + 4, 7); |
| |
| e.gc.setForeground(listBackground); |
| e.gc.drawLine(middle, 4, middle + 1, 4); |
| e.gc.drawLine(middle - 1, 5, middle + 2, 5); |
| e.gc.drawLine(middle - 2, 6, middle + 3, 6); |
| |
| e.gc.setForeground(widgetNormalShadow); |
| e.gc.drawLine(0, 0, bounds.width - 2, 0); |
| e.gc.setForeground(navigationElementShadowStroke); |
| e.gc.drawLine(0, 1, bounds.width - 2, 1); |
| e.gc.drawLine(0, bounds.height - 1, bounds.width - 2, |
| bounds.height - 1); |
| } |
| } |
| } |
| |
| /** |
| * The top navigation element in the tabbed property list. It looks like a |
| * scroll button when scrolling is needed or is just a spacer when no |
| * scrolling is required. |
| */ |
| public class BottomNavigationElement extends Canvas { |
| |
| /** |
| * Constructor for BottomNavigationElement. |
| * |
| * @param parent |
| * the parent Composite. |
| */ |
| public BottomNavigationElement(Composite parent) { |
| super(parent, SWT.NO_FOCUS); |
| addPaintListener(new PaintListener() { |
| |
| public void paintControl(PaintEvent e) { |
| paint(e); |
| } |
| }); |
| addMouseListener(new MouseAdapter() { |
| |
| public void mouseUp(MouseEvent e) { |
| if (isDownScrollRequired()) { |
| topVisibleIndex++; |
| if (bottomVisibleIndex != elements.length - 1) { |
| bottomVisibleIndex++; |
| } |
| layoutTabs(); |
| topNavigationElement.redraw(); |
| bottomNavigationElement.redraw(); |
| } |
| } |
| }); |
| } |
| |
| /** |
| * Paint the element. |
| * |
| * @param e |
| * the paint event. |
| */ |
| private void paint(PaintEvent e) { |
| e.gc.setBackground(widgetBackground); |
| e.gc.setForeground(widgetForeground); |
| Rectangle bounds = getBounds(); |
| |
| if (elements.length != 0) { |
| e.gc.fillRectangle(0, 0, bounds.width, bounds.height); |
| e.gc.setForeground(widgetNormalShadow); |
| e.gc.drawLine(bounds.width - 1, 0, bounds.width - 1, |
| bounds.height - 1); |
| e.gc.drawLine(0, 0, bounds.width - 1, 0); |
| |
| e.gc.setForeground(bottomNavigationElementShadowStroke1); |
| e.gc.drawLine(0, 1, bounds.width - 2, 1); |
| e.gc.setForeground(bottomNavigationElementShadowStroke2); |
| e.gc.drawLine(0, 2, bounds.width - 2, 2); |
| } else { |
| e.gc.setBackground(listBackground); |
| e.gc.fillRectangle(0, 0, bounds.width, bounds.height); |
| } |
| |
| if (isDownScrollRequired()) { |
| e.gc.setForeground(widgetDarkShadow); |
| int middle = bounds.width / 2; |
| int bottom = bounds.height - 3; |
| e.gc.drawLine(middle + 1, bottom, middle + 5, bottom - 4); |
| e.gc.drawLine(middle, bottom, middle - 4, bottom - 4); |
| e.gc.drawLine(middle - 3, bottom - 4, middle + 4, bottom - 4); |
| |
| e.gc.setForeground(listBackground); |
| e.gc.drawLine(middle, bottom - 1, middle + 1, bottom - 1); |
| e.gc.drawLine(middle - 1, bottom - 2, middle + 2, bottom - 2); |
| e.gc.drawLine(middle - 2, bottom - 3, middle + 3, bottom - 3); |
| |
| e.gc.setForeground(widgetNormalShadow); |
| e.gc.drawLine(0, bottom - 7, bounds.width - 2, bottom - 7); |
| e.gc.setForeground(navigationElementShadowStroke); |
| e.gc.drawLine(0, bottom + 2, bounds.width - 2, bottom + 2); |
| e.gc.drawLine(0, bottom - 6, bounds.width - 2, bottom - 6); |
| } |
| } |
| } |
| |
| /** |
| * Constructor for TabbedPropertyList. |
| * |
| * @param parent |
| * the parent widget. |
| * @param factory |
| * the widget factory. |
| */ |
| public TabbedPropertyList(Composite parent, |
| TabbedPropertySheetWidgetFactory factory) { |
| super(parent, SWT.NO_FOCUS); |
| this.factory = factory; |
| removeAll(); |
| setLayout(new FormLayout()); |
| initColours(); |
| initAccessible(); |
| topNavigationElement = new TopNavigationElement(this); |
| bottomNavigationElement = new BottomNavigationElement(this); |
| |
| this.addFocusListener(new FocusListener() { |
| |
| public void focusGained(FocusEvent e) { |
| focus = true; |
| int i = getSelectionIndex(); |
| if (i >= 0) { |
| elements[i].redraw(); |
| } |
| } |
| |
| public void focusLost(FocusEvent e) { |
| focus = false; |
| int i = getSelectionIndex(); |
| if (i >= 0) { |
| elements[i].redraw(); |
| } |
| } |
| }); |
| this.addControlListener(new ControlAdapter() { |
| |
| public void controlResized(ControlEvent e) { |
| computeTopAndBottomTab(); |
| } |
| }); |
| // RAP not supported yet |
| // this.addTraverseListener(new TraverseListener() { |
| // |
| // public void keyTraversed(TraverseEvent e) { |
| // if (e.detail == SWT.TRAVERSE_ARROW_PREVIOUS |
| // || e.detail == SWT.TRAVERSE_ARROW_NEXT) { |
| // int nMax = elements.length - 1; |
| // int nCurrent = getSelectionIndex(); |
| // if (e.detail == SWT.TRAVERSE_ARROW_PREVIOUS) { |
| // nCurrent -= 1; |
| // nCurrent = Math.max(0, nCurrent); |
| // } else if (e.detail == SWT.TRAVERSE_ARROW_NEXT) { |
| // nCurrent += 1; |
| // nCurrent = Math.min(nCurrent, nMax); |
| // } |
| // select(nCurrent); |
| // redraw(); |
| // } else { |
| // e.doit = true; |
| // } |
| // } |
| // }); |
| // /RAP |
| } |
| |
| /** |
| * Calculate the number of tabs that will fit in the tab list composite. |
| */ |
| protected void computeTabsThatFitInComposite() { |
| tabsThatFitInComposite = Math |
| .round((getSize().y - 22) / getTabHeight()); |
| if (tabsThatFitInComposite <= 0) { |
| tabsThatFitInComposite = 1; |
| } |
| } |
| |
| /** |
| * Returns the element with the given index from this list viewer. Returns |
| * <code>null</code> if the index is out of range. |
| * |
| * @param index |
| * the zero-based index |
| * @return the element at the given index, or <code>null</code> if the |
| * index is out of range |
| */ |
| public Object getElementAt(int index) { |
| if (index >= 0 && index < elements.length) { |
| return elements[index]; |
| } |
| return null; |
| } |
| |
| /** |
| * Returns the zero-relative index of the item which is currently selected |
| * in the receiver, or -1 if no item is selected. |
| * |
| * @return the index of the selected item |
| */ |
| public int getSelectionIndex() { |
| return selectedElementIndex; |
| } |
| |
| /** |
| * Removes all elements from this list. |
| */ |
| public void removeAll() { |
| if (elements != null) { |
| for (int i = 0; i < elements.length; i++) { |
| elements[i].dispose(); |
| } |
| } |
| elements = ELEMENTS_EMPTY; |
| selectedElementIndex = NONE; |
| widestLabelIndex = NONE; |
| topVisibleIndex = NONE; |
| bottomVisibleIndex = NONE; |
| } |
| |
| /** |
| * Sets the new list elements. |
| * |
| * @param children |
| */ |
| public void setElements(Object[] children) { |
| if (elements != ELEMENTS_EMPTY) { |
| removeAll(); |
| } |
| elements = new ListElement[children.length]; |
| if (children.length == 0) { |
| widestLabelIndex = NONE; |
| } else { |
| widestLabelIndex = 0; |
| for (int i = 0; i < children.length; i++) { |
| elements[i] = new ListElement(this, (ITabItem) children[i], i); |
| elements[i].setVisible(false); |
| elements[i].setLayoutData(null); |
| |
| if (i != widestLabelIndex) { |
| String label = ((ITabItem) children[i]).getText(); |
| int width = getTextDimension(label).x; |
| if (((ITabItem) children[i]).isIndented()) { |
| width = width + INDENT; |
| } |
| if (width > getTextDimension(((ITabItem) children[widestLabelIndex]) |
| .getText()).x) { |
| widestLabelIndex = i; |
| } |
| } |
| } |
| } |
| |
| computeTopAndBottomTab(); |
| } |
| |
| /** |
| * Selects one of the elements in the list. |
| * |
| * @param index |
| * the index of the element to select. |
| */ |
| protected void select(int index) { |
| if (getSelectionIndex() == index) { |
| /* |
| * this index is already selected. |
| */ |
| return; |
| } |
| if (index >= 0 && index < elements.length) { |
| int lastSelected = getSelectionIndex(); |
| elements[index].setSelected(true); |
| selectedElementIndex = index; |
| if (lastSelected != NONE) { |
| elements[lastSelected].setSelected(false); |
| if (getSelectionIndex() != elements.length - 1) { |
| /* |
| * redraw the next tab to fix the border by calling |
| * setSelected() |
| */ |
| elements[getSelectionIndex() + 1].setSelected(false); |
| } |
| } |
| topNavigationElement.redraw(); |
| bottomNavigationElement.redraw(); |
| |
| if (selectedElementIndex < topVisibleIndex |
| || selectedElementIndex > bottomVisibleIndex) { |
| computeTopAndBottomTab(); |
| } |
| } |
| notifyListeners(SWT.Selection, new Event()); |
| } |
| |
| /** |
| * Deselects all the elements in the list. |
| */ |
| public void deselectAll() { |
| if (getSelectionIndex() != NONE) { |
| elements[getSelectionIndex()].setSelected(false); |
| selectedElementIndex = NONE; |
| } |
| } |
| |
| private int getIndex(ListElement element) { |
| return element.index; |
| } |
| |
| public Point computeSize(int wHint, int hHint, boolean changed) { |
| Point result = super.computeSize(hHint, wHint, changed); |
| if (widestLabelIndex == -1) { |
| String properties_not_available = TabbedPropertyMessages.TabbedPropertyList_properties_not_available; |
| result.x = getTextDimension(properties_not_available).x + INDENT; |
| } else { |
| ITabItem widestTab = elements[widestLabelIndex].getTabItem(); |
| int width = getTextDimension(widestTab.getText()).x + INDENT; |
| /* |
| * To anticipate for the icon placement we should always keep the |
| * space available after the label. So when the active tab includes |
| * an icon the width of the tab doesn't change. |
| */ |
| if (widestTab.getImage() != null) { |
| width = width + 16 + 4; |
| } |
| if (widestTab.isIndented()) { |
| width = width + 10; |
| } |
| /* |
| * Add 10 pixels to the right of the longest string as a margin. |
| */ |
| result.x = width + 10; |
| } |
| return result; |
| } |
| |
| /** |
| * Get the dimensions of the provided string. |
| * |
| * @param text |
| * the string. |
| * @return the dimensions of the provided string. |
| */ |
| private Point getTextDimension(String text) { |
| GC gc = new GC(this); |
| gc.setFont(JFaceResources.getFontRegistry().getBold( |
| JFaceResources.DEFAULT_FONT)); |
| Point point = gc.textExtent(text); |
| point.x++; |
| gc.dispose(); |
| return point; |
| } |
| |
| /** |
| * Initialize the colours used in the list. |
| */ |
| private void initColours() { |
| /* |
| * Colour 3 COLOR_LIST_BACKGROUND |
| */ |
| listBackground = Display.getCurrent().getSystemColor( |
| SWT.COLOR_LIST_BACKGROUND); |
| |
| /* |
| * Colour 13 COLOR_WIDGET_BACKGROUND |
| */ |
| widgetBackground = Display.getCurrent().getSystemColor( |
| SWT.COLOR_WIDGET_BACKGROUND); |
| |
| /* |
| * Colour 15 COLOR_WIDGET_DARK_SHADOW |
| */ |
| widgetDarkShadow = Display.getCurrent().getSystemColor( |
| SWT.COLOR_WIDGET_DARK_SHADOW); |
| |
| /* |
| * Colour 16 COLOR_WIDGET_FOREGROUND |
| */ |
| widgetForeground = Display.getCurrent().getSystemColor( |
| SWT.COLOR_WIDGET_FOREGROUND); |
| |
| /* |
| * Colour 19 COLOR_WIDGET_NORMAL_SHADOW |
| */ |
| widgetNormalShadow = Display.getCurrent().getSystemColor( |
| SWT.COLOR_WIDGET_NORMAL_SHADOW); |
| |
| RGB infoBackground = Display.getCurrent().getSystemColor( |
| SWT.COLOR_INFO_BACKGROUND).getRGB(); |
| RGB white = Display.getCurrent().getSystemColor(SWT.COLOR_WHITE) |
| .getRGB(); |
| RGB black = Display.getCurrent().getSystemColor(SWT.COLOR_BLACK) |
| .getRGB(); |
| |
| /* |
| * gradient in the default tab: start colour WIDGET_NORMAL_SHADOW 100% + |
| * white 20% + INFO_BACKGROUND 60% end colour WIDGET_NORMAL_SHADOW 100% + |
| * INFO_BACKGROUND 40% |
| */ |
| defaultGradientStart = factory.getColors().createColor( |
| "TabbedPropertyList.defaultTabGradientStart", //$NON-NLS-1$ |
| FormColors.blend(infoBackground, FormColors.blend(white, |
| widgetNormalShadow.getRGB(), 20), 60)); |
| defaultGradientEnd = factory.getColors().createColor( |
| "TabbedPropertyList.defaultTabGradientEnd", //$NON-NLS-1$ |
| FormColors.blend(infoBackground, widgetNormalShadow.getRGB(), |
| 40)); |
| |
| navigationElementShadowStroke = factory.getColors().createColor( |
| "TabbedPropertyList.shadowStroke", //$NON-NLS-1$ |
| FormColors.blend(white, widgetNormalShadow.getRGB(), 55)); |
| bottomNavigationElementShadowStroke1 = factory.getColors().createColor( |
| "TabbedPropertyList.tabShadowStroke1", //$NON-NLS-1$ |
| FormColors.blend(black, widgetBackground.getRGB(), 10)); |
| bottomNavigationElementShadowStroke2 = factory.getColors().createColor( |
| "TabbedPropertyList.tabShadowStroke2", //$NON-NLS-1$ |
| FormColors.blend(black, widgetBackground.getRGB(), 5)); |
| |
| /* |
| * gradient in the hover tab: start colour WIDGET_BACKGROUND 100% + |
| * white 20% end colour WIDGET_BACKGROUND 100% + WIDGET_NORMAL_SHADOW |
| * 10% |
| */ |
| hoverGradientStart = factory.getColors().createColor( |
| "TabbedPropertyList.hoverBackgroundGradientStart", //$NON-NLS-1$ |
| FormColors.blend(white, widgetBackground.getRGB(), 20)); |
| hoverGradientEnd = factory.getColors().createColor( |
| "TabbedPropertyList.hoverBackgroundGradientEnd", //$NON-NLS-1$ |
| FormColors.blend(widgetNormalShadow.getRGB(), widgetBackground |
| .getRGB(), 10)); |
| |
| indentedDefaultBackground = factory.getColors().createColor( |
| "TabbedPropertyList.indentedDefaultBackground", //$NON-NLS-1$ |
| FormColors.blend(white, widgetBackground.getRGB(), 10)); |
| indentedHoverBackground = factory.getColors().createColor( |
| "TabbedPropertyList.indentedHoverBackground", //$NON-NLS-1$ |
| FormColors.blend(white, widgetBackground.getRGB(), 75)); |
| } |
| |
| /** |
| * Get the height of a tab. The height of the tab is the height of the text |
| * plus buffer. |
| * |
| * @return the height of a tab. |
| */ |
| private int getTabHeight() { |
| int tabHeight = getTextDimension("").y + INDENT; //$NON-NLS-1$ |
| if (tabsThatFitInComposite == 1) { |
| /* |
| * if only one tab will fix, reduce the size of the tab height so |
| * that the navigation elements fit. |
| */ |
| int ret = getBounds().height - 20; |
| return (ret > tabHeight) ? tabHeight |
| : (ret < 5) ? 5 |
| : ret; |
| } |
| return tabHeight; |
| } |
| |
| /** |
| * Determine if a downward scrolling is required. |
| * |
| * @return true if downward scrolling is required. |
| */ |
| private boolean isDownScrollRequired() { |
| return elements.length > tabsThatFitInComposite |
| && bottomVisibleIndex != elements.length - 1; |
| } |
| |
| /** |
| * Determine if an upward scrolling is required. |
| * |
| * @return true if upward scrolling is required. |
| */ |
| private boolean isUpScrollRequired() { |
| return elements.length > tabsThatFitInComposite && topVisibleIndex != 0; |
| } |
| |
| /** |
| * Based on available space, figure out the top and bottom tabs in the list. |
| */ |
| private void computeTopAndBottomTab() { |
| computeTabsThatFitInComposite(); |
| if (elements.length == 0) { |
| /* |
| * no tabs to display. |
| */ |
| topVisibleIndex = 0; |
| bottomVisibleIndex = 0; |
| } else if (tabsThatFitInComposite >= elements.length) { |
| /* |
| * all the tabs fit. |
| */ |
| topVisibleIndex = 0; |
| bottomVisibleIndex = elements.length - 1; |
| } else if (getSelectionIndex() == NONE) { |
| /* |
| * there is no selected tab yet, assume that tab one would |
| * be selected for now. |
| */ |
| topVisibleIndex = 0; |
| bottomVisibleIndex = tabsThatFitInComposite - 1; |
| } else if (getSelectionIndex() + tabsThatFitInComposite > elements.length) { |
| /* |
| * the selected tab is near the bottom. |
| */ |
| bottomVisibleIndex = elements.length - 1; |
| topVisibleIndex = bottomVisibleIndex - tabsThatFitInComposite + 1; |
| } else { |
| /* |
| * the selected tab is near the top. |
| */ |
| topVisibleIndex = selectedElementIndex; |
| bottomVisibleIndex = selectedElementIndex + tabsThatFitInComposite |
| - 1; |
| } |
| layoutTabs(); |
| } |
| |
| /** |
| * Layout the tabs. |
| */ |
| private void layoutTabs() { |
| //System.out.println("TabFit " + tabsThatFitInComposite + " length " |
| // + elements.length + " top " + topVisibleIndex + " bottom " |
| // + bottomVisibleIndex); |
| if (tabsThatFitInComposite == NONE || elements.length == 0) { |
| FormData formData = new FormData(); |
| formData.left = new FormAttachment(0, 0); |
| formData.right = new FormAttachment(100, 0); |
| formData.top = new FormAttachment(0, 0); |
| formData.height = getTabHeight(); |
| topNavigationElement.setLayoutData(formData); |
| |
| formData = new FormData(); |
| formData.left = new FormAttachment(0, 0); |
| formData.right = new FormAttachment(100, 0); |
| formData.top = new FormAttachment(topNavigationElement, 0); |
| formData.bottom = new FormAttachment(100, 0); |
| bottomNavigationElement.setLayoutData(formData); |
| } else { |
| |
| FormData formData = new FormData(); |
| formData.left = new FormAttachment(0, 0); |
| formData.right = new FormAttachment(100, 0); |
| formData.top = new FormAttachment(0, 0); |
| formData.height = 10; |
| topNavigationElement.setLayoutData(formData); |
| |
| /* |
| * use nextElement to attach the layout to the previous canvas |
| * widget in the list. |
| */ |
| Canvas nextElement = topNavigationElement; |
| |
| for (int i = 0; i < elements.length; i++) { |
| //System.out.print(i + " [" + elements[i].getText() + "]"); |
| if (i < topVisibleIndex || i > bottomVisibleIndex) { |
| /* |
| * this tab is not visible |
| */ |
| elements[i].setLayoutData(null); |
| elements[i].setVisible(false); |
| } else { |
| /* |
| * this tab is visible. |
| */ |
| //System.out.print(" visible"); |
| formData = new FormData(); |
| formData.height = getTabHeight(); |
| formData.left = new FormAttachment(0, 0); |
| formData.right = new FormAttachment(100, 0); |
| formData.top = new FormAttachment(nextElement, 0); |
| nextElement = elements[i]; |
| elements[i].setLayoutData(formData); |
| elements[i].setVisible(true); |
| } |
| |
| //if (i == selectedElementIndex) { |
| // System.out.print(" selected"); |
| //} |
| //System.out.println(""); |
| } |
| formData = new FormData(); |
| formData.left = new FormAttachment(0, 0); |
| formData.right = new FormAttachment(100, 0); |
| formData.top = new FormAttachment(nextElement, 0); |
| formData.bottom = new FormAttachment(100, 0); |
| formData.height = 10; |
| bottomNavigationElement.setLayoutData(formData); |
| } |
| //System.out.println(""); |
| |
| // layout so that we have enough space for the new labels |
| Composite grandparent = getParent().getParent(); |
| grandparent.layout(true); |
| layout(true); |
| } |
| |
| /** |
| * Initialize the accessibility adapter. |
| */ |
| private void initAccessible() { |
| // RAP does not support this |
| // final Accessible accessible = getAccessible(); |
| // accessible.addAccessibleListener(new AccessibleAdapter() { |
| // |
| // public void getName(AccessibleEvent e) { |
| // if (getSelectionIndex() != NONE) { |
| // e.result = elements[getSelectionIndex()].getTabItem() |
| // .getText(); |
| // } |
| // } |
| // |
| // public void getHelp(AccessibleEvent e) { |
| // if (getSelectionIndex() != NONE) { |
| // e.result = elements[getSelectionIndex()].getTabItem() |
| // .getText(); |
| // } |
| // } |
| // }); |
| // |
| // accessible.addAccessibleControlListener(new AccessibleControlAdapter() { |
| // |
| // public void getChildAtPoint(AccessibleControlEvent e) { |
| // Point pt = toControl(new Point(e.x, e.y)); |
| // e.childID = (getBounds().contains(pt)) ? ACC.CHILDID_SELF |
| // : ACC.CHILDID_NONE; |
| // } |
| // |
| // public void getLocation(AccessibleControlEvent e) { |
| // if (getSelectionIndex() != NONE) { |
| // Rectangle location = elements[getSelectionIndex()] |
| // .getBounds(); |
| // Point pt = toDisplay(new Point(location.x, location.y)); |
| // e.x = pt.x; |
| // e.y = pt.y; |
| // e.width = location.width; |
| // e.height = location.height; |
| // } |
| // } |
| // |
| // public void getChildCount(AccessibleControlEvent e) { |
| // e.detail = 0; |
| // } |
| // |
| // public void getRole(AccessibleControlEvent e) { |
| // e.detail = ACC.ROLE_TABITEM; |
| // } |
| // |
| // public void getState(AccessibleControlEvent e) { |
| // e.detail = ACC.STATE_NORMAL | ACC.STATE_SELECTABLE |
| // | ACC.STATE_SELECTED | ACC.STATE_FOCUSED |
| // | ACC.STATE_FOCUSABLE; |
| // } |
| // }); |
| // |
| // addListener(SWT.Selection, new Listener() { |
| // |
| // public void handleEvent(Event event) { |
| // if (isFocusControl()) { |
| // accessible.setFocus(ACC.CHILDID_SELF); |
| // } |
| // } |
| // }); |
| // |
| // addListener(SWT.FocusIn, new Listener() { |
| // |
| // public void handleEvent(Event event) { |
| // accessible.setFocus(ACC.CHILDID_SELF); |
| // } |
| // }); |
| // /RAP |
| } |
| } |