diff options
Diffstat (limited to 'bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabFolder.java')
-rwxr-xr-x | bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabFolder.java | 4198 |
1 files changed, 2099 insertions, 2099 deletions
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabFolder.java b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabFolder.java index 7406e5a0f1..029413724f 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabFolder.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabFolder.java @@ -1,2102 +1,2102 @@ -package org.eclipse.swt.custom;
-
-/*
+package org.eclipse.swt.custom; + +/* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html
- */
-
-import org.eclipse.swt.*;
-import org.eclipse.swt.events.*;
-import org.eclipse.swt.graphics.*;
-import org.eclipse.swt.widgets.*;
-import org.eclipse.swt.accessibility.*;
-
-/**
- * Instances of this class implement the notebook user interface
- * metaphor. It allows the user to select a notebook page from
- * set of pages.
- * <p>
- * The item children that may be added to instances of this class
- * must be of type <code>CTabItem</code>.
- * <code>Control</code> children are created and then set into a
- * tab item using <code>CTabItem#setControl</code>.
- * </p><p>
- * Note that although this class is a subclass of <code>Composite</code>,
- * it does not make sense to set a layout on it.
- * </p><p>
- * <dl>
- * <dt><b>Styles:</b></dt>
- * <dd>TOP, BOTTOM, FLAT</dd>
- * <dt><b>Events:</b></dt>
- * <dd>Selection</dd>
- * <dd>"CTabFolder"</dd>
- * </dl>
- * <p>
- * Note: Only one of the styles TOP and BOTTOM
- * may be specified.
- * </p><p>
- * IMPORTANT: This class is <em>not</em> intended to be subclassed.
- * </p>
- */
-
-public class CTabFolder extends Composite {
-
- /**
- * marginWidth specifies the number of pixels of horizontal margin
- * that will be placed along the left and right edges of the form.
- *
- * The default value is 0.
- */
- public int marginWidth = 0;
- /**
- * marginHeight specifies the number of pixels of vertical margin
- * that will be placed along the top and bottom edges of the form.
- *
- * The default value is 0.
- */
- public int marginHeight = 0;
-
- /**
- * Color of innermost line of drop shadow border.
- */
- public static RGB borderInsideRGB = new RGB (132, 130, 132);
- /**
- * Color of middle line of drop shadow border.
- */
- public static RGB borderMiddleRGB = new RGB (143, 141, 138);
- /**
- * Color of outermost line of drop shadow border.
- */
- public static RGB borderOutsideRGB = new RGB (171, 168, 165);
-
- /*
- * A multiple of the tab height that specifies the minimum width to which a tab
- * will be compressed before scrolling arrows are used to navigate the tabs.
- */
- public int MIN_TAB_WIDTH = 3;
-
- /* sizing, positioning */
- int xClient, yClient;
- boolean onBottom = false;
- boolean fixedTabHeight;
- int tabHeight;
-
- /* item management */
- private CTabItem items[] = new CTabItem[0];
- private int selectedIndex = -1;
- int topTabIndex = -1; // index of the left most visible tab.
-
- /* External Listener management */
- private CTabFolderListener[] tabListeners = new CTabFolderListener[0];
-
- /* Color appearance */
- Image backgroundImage;
- Color[] gradientColors;
- int[] gradientPercents;
- Color selectionForeground;
- Color background;
-
- // internal constants
- private static final int DEFAULT_WIDTH = 64;
- private static final int DEFAULT_HEIGHT = 64;
-
- // scrolling arrows
- private ToolBar arrowBar;
- private Image arrowLeftImage;
- private Image arrowRightImage;
-
- private Control topRight;
-
- // close button
- boolean showClose = false;
- private Image closeImage;
- ToolBar closeBar;
- private ToolBar inactiveCloseBar;
- private CTabItem inactiveItem;
-
- // borders
- boolean showBorders = false;
- private int borderBottom = 0;
- private int borderLeft = 0;
- private int borderRight = 0;
- private int borderTop = 0;
- private Color borderColor1;
- private Color borderColor2;
- private Color borderColor3;
-
- // when disposing CTabFolder, don't try to layout the items or
- // change the selection as each child is destroyed.
- private boolean inDispose = false;
-
- // keep track of size changes in order to redraw only affected area
- // on Resize
- private Point oldSize;
- private Font oldFont;
-
- // insertion marker
- int insertionIndex = -2; // Index of insert marker. Marker always shown after index.
- // -2 means no insert marker
-
- // tool tip
- private Shell tip;
- private Label label;
- private boolean showToolTip = false;
- private CTabItem toolTipItem;
-
-/**
- * Constructs a new instance of this class given its parent
- * and a style value describing its behavior and appearance.
- * <p>
- * The style value is either one of the style constants defined in
- * class <code>SWT</code> which is applicable to instances of this
- * class, or must be built by <em>bitwise OR</em>'ing together
- * (that is, using the <code>int</code> "|" operator) two or more
- * of those <code>SWT</code> style constants. The class description
- * lists the style constants that are applicable to the class.
- * Style bits are also inherited from superclasses.
- * </p>
- *
- * @param parent a widget which will be the parent of the new instance (cannot be null)
- * @param style the style of widget to construct
- *
- * @exception IllegalArgumentException <ul>
- * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
- * </ul>
- * @exception SWTException <ul>
- * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
- * </ul>
- *
- * @see SWT#TOP
- * @see SWT#BOTTOM
- * @see SWT#FLAT
- * @see #getStyle
- */
-public CTabFolder(Composite parent, int style) {
- super(parent, checkStyle (style));
-
- onBottom = (getStyle() & SWT.BOTTOM) != 0;
-
- borderColor1 = new Color(getDisplay(), borderInsideRGB);
- borderColor2 = new Color(getDisplay(), borderMiddleRGB);
- borderColor3 = new Color(getDisplay(), borderOutsideRGB);
-
- // tool tip support
- tip = new Shell (getShell(), SWT.ON_TOP);
- label = new Label (tip, SWT.CENTER);
-
- // Add all listeners
- Listener listener = new Listener() {
- public void handleEvent(Event event) {
- switch (event.type) {
- case SWT.Dispose: onDispose(); break;
- case SWT.Paint: onPaint(event); break;
- case SWT.Resize: onResize(); break;
- case SWT.MouseDoubleClick: onMouseDoubleClick(event); break;
- case SWT.MouseDown: onMouseDown(event); break;
- case SWT.MouseExit: onMouseExit(event); break;
- case SWT.MouseHover: onMouseHover(event); break;
- case SWT.MouseMove: onMouseMove(event); break;
- case SWT.FocusIn: onFocus(event); break;
- case SWT.FocusOut: onFocus(event); break;
- case SWT.KeyDown: onKeyDown(event); break;
- case SWT.Traverse: onTraverse(event); break;
- }
- }
- };
-
- int[] folderEvents = new int[]{
- SWT.Dispose,
- SWT.Paint,
- SWT.Resize,
- SWT.MouseDoubleClick,
- SWT.MouseDown,
- SWT.MouseExit,
- SWT.MouseHover,
- SWT.MouseMove,
- SWT.FocusIn,
- SWT.FocusOut,
- SWT.KeyDown,
- SWT.Traverse,
- };
- for (int i = 0; i < folderEvents.length; i++) {
- addListener(folderEvents[i], listener);
- }
-
- createArrowBar();
- createCloseBar();
-
- setBorderVisible((style & SWT.BORDER) != 0);
-
- initAccessible();
-
-}
-private static int checkStyle (int style) {
- int mask = SWT.TOP | SWT.BOTTOM | SWT.FLAT;
- style = style & mask;
- // TOP and BOTTOM are mutually exlusive.
- // TOP is the default
- if ((style & SWT.TOP) != 0)
- style = style & ~(SWT.TOP | SWT.BOTTOM) | SWT.TOP;
- // reduce the flash by not redrawing the entire area on a Resize event
- style |= SWT.NO_REDRAW_RESIZE;
- return style;
-}
-/**
-* Adds the listener to receive events.
-* <p>
-*
-* @param listener the listener
-*
-* @exception SWTError <ul>
-* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
-* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
-* <li>ERROR_NULL_ARGUMENT when listener is null</li>
-* </ul>
-*/
-public void addSelectionListener(SelectionListener listener) {
- checkWidget();
- if (listener == null) {
- SWT.error(SWT.ERROR_NULL_ARGUMENT);
- }
- TypedListener typedListener = new TypedListener(listener);
- addListener(SWT.Selection, typedListener);
- addListener(SWT.DefaultSelection, typedListener);
-}
-/**
- * Adds the listener to the collection of listeners who will
- * be notified when a tab item is closed.
- *
- * @param listener the listener which should be notified
- *
- * @exception IllegalArgumentException <ul>
- * <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
- * <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
- * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
- * </ul>
- *
- * @see CTabFolderListener
- * @see #removeCTabFolderListener
- */
-public void addCTabFolderListener(CTabFolderListener listener) {
- checkWidget();
- if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
- // add to array
- CTabFolderListener[] newTabListeners = new CTabFolderListener[tabListeners.length + 1];
- System.arraycopy(tabListeners, 0, newTabListeners, 0, tabListeners.length);
- tabListeners = newTabListeners;
- tabListeners[tabListeners.length - 1] = listener;
- showClose = true;
- setButtonBounds();
-}
-private void closeNotify(CTabItem item, int time) {
- if (item == null) return;
-
- CTabFolderEvent event = new CTabFolderEvent(this);
- event.widget = this;
- event.time = time;
- event.item = item;
- event.doit = true;
- if (tabListeners != null) {
- for (int i = 0; i < tabListeners.length; i++) {
- tabListeners[i].itemClosed(event);
- }
- }
- if (event.doit) {
- item.dispose();
- }
-}
-public Point computeSize (int wHint, int hHint, boolean changed) {
- checkWidget();
- int minWidth = 0;
- int minHeight = 0;
-
- // preferred width of tab area to show all tabs
- GC gc = new GC(this);
- for (int i = 0; i < items.length; i++) {
- minWidth += items[i].preferredWidth(gc);
- }
- gc.dispose();
-
- // preferred size of controls in tab items
- for (int i = 0; i < items.length; i++) {
- Control control = items[i].getControl();
- if (control != null && !control.isDisposed()){
- Point size = control.computeSize (wHint, hHint);
- minWidth = Math.max (minWidth, size.x);
- minHeight = Math.max (minHeight, size.y);
- }
- }
- if (minWidth == 0) minWidth = DEFAULT_WIDTH;
- if (minHeight == 0) minHeight = DEFAULT_HEIGHT;
-
- if (wHint != SWT.DEFAULT) minWidth = wHint;
- if (hHint != SWT.DEFAULT) minHeight = hHint;
-
- Rectangle trim = computeTrim(0, 0, minWidth, minHeight);
- return new Point (trim.width, trim.height);
-}
-public Rectangle computeTrim (int x, int y, int width, int height) {
- checkWidget();
- if (items.length == 0) {
- if (!showBorders) return new Rectangle(x, y, width, height);
- int trimX = x - borderRight - 1;
- int trimY = y - borderBottom - 1;
- int trimWidth = width + borderRight + 2;
- int trimHeight = height + borderBottom + 2;
- return new Rectangle (trimX, trimY, trimWidth, trimHeight);
- } else {
- int trimX = x - marginWidth - borderLeft;
- int trimY = y - marginHeight - tabHeight - borderTop - 1;
- // -1 is for the line at the bottom of the tabs
- if (onBottom) {
- trimY = y - marginHeight - borderTop;
- }
- int trimWidth = width + borderLeft + borderRight + 2*marginWidth;
- int trimHeight = height + borderTop + borderBottom + 2*marginHeight + tabHeight + 1;
- return new Rectangle (trimX, trimY, trimWidth, trimHeight);
- }
-}
-/**
- * Create the specified item at 'index'.
- */
-void createItem (CTabItem item, int index) {
- if (0 > index || index > getItemCount ()){
- SWT.error (SWT.ERROR_INVALID_RANGE);
- }
- // grow by one and rearrange the array.
- CTabItem[] newItems = new CTabItem [items.length + 1];
- System.arraycopy(items, 0, newItems, 0, index);
- newItems[index] = item;
- System.arraycopy(items, index, newItems, index + 1, items.length - index);
- items = newItems;
-
- item.parent = this;
-
- if (selectedIndex >= index) {
- selectedIndex ++;
- }
- if (items.length == 1) {
- topTabIndex = 0;
- resetTabSize(true);
- } else {
- setItemBounds();
- showItem(item);
- }
-
- if (items.length == 1) {
- redraw();
- } else {
- redrawTabArea(-1);
- }
-}
-
-private void createArrowBar() {
- // create arrow buttons for scrolling
- arrowBar = new ToolBar(this, SWT.FLAT);
- arrowBar.setVisible(false);
- arrowBar.setBackground(background);
- ToolItem scrollLeft = new ToolItem(arrowBar, SWT.PUSH);
- scrollLeft.setEnabled(false);
- ToolItem scrollRight = new ToolItem(arrowBar, SWT.PUSH);
- scrollRight.setEnabled(false);
-
- scrollLeft.addListener(SWT.Selection, new Listener() {
- public void handleEvent(Event event) {
- scroll_scrollLeft();
- }
- });
- scrollRight.addListener(SWT.Selection, new Listener() {
- public void handleEvent(Event event) {
- scroll_scrollRight();
- }
- });
-
-}
-private void createCloseBar() {
- closeBar = new ToolBar(this, SWT.FLAT);
- closeBar.setVisible(false);
- if (gradientColors != null && gradientColors.length > 0) {
- closeBar.setBackground(gradientColors[gradientColors.length - 1]);
- } else {
- closeBar.setBackground(background);
- }
- ToolItem closeItem = new ToolItem(closeBar, SWT.PUSH);
-
- inactiveCloseBar = new ToolBar(this, SWT.FLAT);
- inactiveCloseBar.setVisible(false);
- inactiveCloseBar.setBackground(background);
- ToolItem inactiveCloseItem = new ToolItem(inactiveCloseBar, SWT.PUSH);
-
- closeItem.addListener(SWT.Selection, new Listener() {
- public void handleEvent(Event event) {
- closeNotify(getSelection(), event.time);
- }
- });
- inactiveCloseItem.addListener(SWT.Selection, new Listener() {
- public void handleEvent(Event event) {
- closeNotify(inactiveItem, event.time);
- inactiveCloseBar.setVisible(false);
- inactiveItem = null;
- }
- });
- inactiveCloseBar.addListener (SWT.MouseExit, new Listener() {
- public void handleEvent(Event event) {
- if (inactiveItem != null) {
- Rectangle itemBounds = inactiveItem.getBounds();
- if (itemBounds.contains(event.x, event.y)) return;
- }
- inactiveCloseBar.setVisible(false);
- inactiveItem = null;
- }
- });
-
-}
-/**
- * Destroy the specified item.
- */
-void destroyItem (CTabItem item) {
- if (inDispose) return;
-
- int index = indexOf(item);
- if (index == -1) return; // should this trigger an error?
-
- insertionIndex = -2;
-
- if (items.length == 1) {
- items = new CTabItem[0];
- selectedIndex = -1;
- topTabIndex = 0;
-
- Control control = item.getControl();
- if (control != null && !control.isDisposed()) {
- control.setVisible(false);
- }
- closeBar.setVisible(false);
- if (!fixedTabHeight) tabHeight = 0;
- redraw();
- return;
- }
-
- // shrink by one and rearrange the array.
- CTabItem[] newItems = new CTabItem [items.length - 1];
- System.arraycopy(items, 0, newItems, 0, index);
- System.arraycopy(items, index + 1, newItems, index, items.length - index - 1);
- items = newItems;
-
- if (topTabIndex == items.length) {
- --topTabIndex;
- }
-
- // move the selection if this item is selected
- if (selectedIndex == index) {
- Control control = item.getControl();
- if (control != null && !control.isDisposed()) {
- control.setVisible(false);
- }
- selectedIndex = -1;
- setSelection(Math.max(0, index - 1), true);
- } else if (selectedIndex > index) {
- selectedIndex --;
- }
-
- setItemBounds();
- redrawTabArea(-1);
-}
-private void onKeyDown(Event e) {
- if (e.keyCode == SWT.ARROW_LEFT) {
- if (selectedIndex > 0) {
- setSelection(selectedIndex - 1, true);
- }
- }
- if (e.keyCode == SWT.ARROW_RIGHT) {
- if (selectedIndex < items.length - 1) {
- setSelection(selectedIndex + 1, true);
- }
- }
-}
-/**
- * Dispose the items of the receiver
- */
-private void onDispose() {
- /*
- * Usually when an item is disposed, destroyItem will change the size of the items array,
- * reset the bounds of all the tabs and manage the widget associated with the tab.
- * Since the whole folder is being disposed, this is not necessary. For speed
- * the inDispose flag is used to skip over this part of the item dispose.
- */
- inDispose = true;
-
- int length = items.length;
- for (int i = 0; i < length; i++) {
- if (items[i] != null) {
- items[i].dispose();
- }
- }
-
- // clean up resources
- if (tip != null && !tip.isDisposed()) {
- tip.dispose();
- tip = null;
- label = null;
- }
-
- if (arrowLeftImage != null) arrowLeftImage.dispose();
- arrowLeftImage = null;
- if (arrowRightImage != null) arrowRightImage.dispose();
- arrowRightImage = null;
- if (closeImage != null) closeImage.dispose();
- closeImage = null;
-
- gradientColors = null;
- gradientPercents = null;
- backgroundImage = null;
-
- if (borderColor1 != null) borderColor1.dispose();
- borderColor1 = null;
-
- if (borderColor2 != null) borderColor2.dispose();
- borderColor2 = null;
-
- if (borderColor3 != null) borderColor3.dispose();
- borderColor3 = null;
-}
-private void onFocus(Event e) {
- checkWidget();
- if (selectedIndex >= 0) {
- redrawTabArea(selectedIndex);
- } else {
- setSelection(0, true);
- }
-}
-/**
- * Draw a border around the receiver.
- */
-private void drawBorder(GC gc) {
-
- Rectangle d = super.getClientArea();
-
- if (showBorders) {
- if ((getStyle() & SWT.FLAT) != 0) {
- gc.setForeground(borderColor1);
- gc.drawRectangle(d.x, d.y, d.x + d.width - 1, d.y + d.height - 1);
- } else {
- gc.setForeground(borderColor1);
- gc.drawRectangle(d.x, d.y, d.x + d.width - 3, d.y + d.height - 3);
-
- gc.setForeground(borderColor2);
- gc.drawLine(d.x + 1, d.y + d.height - 2, d.x + d.width - 1, d.y + d.height - 2);
- gc.drawLine(d.x + d.width - 2, d.y + 1, d.x + d.width - 2, d.y + d.height - 1);
-
- gc.setForeground(borderColor3);
- gc.drawLine(d.x + 2, d.y + d.height - 1, d.x + d.width - 2, d.y + d.height - 1);
- gc.drawLine(d.x + d.width - 1, d.y + 2, d.x + d.width - 1, d.y + d.height - 2);
-
- // fill in corners with parent's background
- gc.setForeground(getParent().getBackground());
- gc.drawLine(d.x + d.width - 2, d.y, d.x + d.width - 1, d.y);
- gc.drawLine(d.x + d.width - 1, d.y + 1, d.x + d.width - 1, d.y + 1);
-
- gc.drawLine(d.x, d.y + d.height - 2, d.x, d.y + d.height - 2);
- gc.drawLine(d.x, d.y + d.height - 1, d.x + 1, d.y + d.height - 1);
-
- gc.drawLine(d.x + d.width - 1, d.y + d.height - 1, d.x + d.width - 1, d.y + d.height - 1);
- }
-
- }
-
- // draw a separator line
- if (items.length > 0) {
- int lineY = d.y + borderTop + tabHeight;
- if (onBottom) {
- lineY = d.y + d.height - borderBottom - tabHeight - 1;
- }
- gc.setForeground(borderColor1);
- gc.drawLine(d.x + borderLeft, lineY, d.x + d.width - borderRight, lineY);
- }
-
- gc.setForeground(getForeground());
-}
-public Rectangle getClientArea() {
- checkWidget();
- Point size = getSize();
- if (items.length == 0) {
- if (!showBorders) return super.getClientArea();
- int width = size.x - borderRight - 2;
- int height = size.y - borderBottom - 2;
- return new Rectangle(borderRight + 1, borderBottom + 1, width, height);
- } else {
- int width = size.x - 2*marginWidth - borderLeft - borderRight;
- int height = size.y - 2*marginHeight - borderTop - borderBottom - tabHeight - 1;
- return new Rectangle(xClient, yClient, width, height);
- }
-}
-/**
- * Returns the height of the tab
- *
- * @return the height of the tab
- *
- * @exception SWTError <ul>
- * <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
- * <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
- * </ul>
- */
-public int getTabHeight(){
- checkWidget();
- return tabHeight;
-}
-
-/**
- * Return the tab that is located at the specified index.
- *
- * @return the item at the specified index
- */
-public CTabItem getItem (int index) {
- //checkWidget();
- if (index < 0 || index >= items.length)
- SWT.error(SWT.ERROR_INVALID_RANGE);
- return items [index];
-}
-/**
-* Gets the item at a point in the widget.
-* <p>
-*
-* @return the item at a point
-*/
-public CTabItem getItem (Point pt) {
- //checkWidget();
- if (items.length == 0) return null;
- int lastItem = getLastItem();
- lastItem = Math.min(items.length - 1, lastItem + 1);
- for (int i = topTabIndex; i <= lastItem; i++) {
- Rectangle bounds = items[i].getBounds();
- if (bounds.contains(pt)) return items[i];
- }
- return null;
-}
-/**
- * Return the number of tabs in the folder.
- *
- * @return the number of tabs in the folder
- */
-public int getItemCount(){
- //checkWidget();
- return items.length;
-}
-/**
- * Return the tab items.
- *
- * @return the tab items
- */
-public CTabItem [] getItems() {
- //checkWidget();
- CTabItem[] tabItems = new CTabItem [items.length];
- System.arraycopy(items, 0, tabItems, 0, items.length);
- return tabItems;
-}
-
-private int getLastItem(){
- if (items.length == 0) return -1;
- Rectangle area = getClientArea();
- if (area.width <= 0) return 0;
- Rectangle toolspace = getToolSpace();
- if (toolspace.width == 0) return items.length -1;
- int width = area.width - toolspace.width;
- int index = topTabIndex;
- int tabWidth = items[index].width;
- while (index < items.length - 1) {
- tabWidth += items[index + 1].width;
- if (tabWidth > width) break;
- index++;
- }
- return index;
-}
-/**
- * Return the selected tab item, or an empty array if there
- * is no selection.
- *
- * @return the selected tab item
- */
-public CTabItem getSelection() {
- //checkWidget();
- if (selectedIndex == -1) return null;
- return items[selectedIndex];
-}
-/**
- * Return the index of the selected tab item, or -1 if there
- * is no selection.
- *
- * @return the index of the selected tab item or -1
- */
-public int getSelectionIndex() {
- //checkWidget();
- return selectedIndex;
-}
-private Rectangle getToolSpace() {
- boolean showArrows = scroll_leftVisible() || scroll_rightVisible();
- if (!showArrows && topRight == null) return new Rectangle(0, 0, 0, 0);
- Rectangle toolspace;
- if (showArrows) {
- toolspace = arrowBar.getBounds();
- toolspace.width += borderRight;
- if (topRight != null) toolspace.width += topRight.getSize().x;
- } else {
- toolspace = topRight.getBounds();
- toolspace.width += borderRight;
- }
- return toolspace;
-}
-/**
- * Returns the control in the top right corner of the tab folder.
- * Typically this is a close button or a composite with a menu and close button.
- *
- * @since 2.1
- *
- * @return the control in the top right corner of the tab folder or null
- *
- * @exception SWTError <ul>
- * <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
- * <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
- * </ul>
- */
-public Control getTopRight() {
- checkWidget();
- return topRight;
-}
-
-/**
- * Return the index of the specified tab or -1 if the tab is not
- * in the receiver.
- *
- * @return the index of the specified tab item or -1
- *
- * @exception SWTError <ul>
- * <li>ERROR_NULL_ARGUMENT when the item is null</li>
- * </ul>
- */
-public int indexOf(CTabItem item) {
- //checkWidget();
- if (item == null) {
- SWT.error(SWT.ERROR_NULL_ARGUMENT);
- }
- for (int i = 0; i < items.length; i++) {
- if (items[i] == item) return i;
- }
- return -1;
-}
-
-private void initAccessible() {
- final Accessible accessible = getAccessible();
- accessible.addAccessibleListener(new AccessibleAdapter() {
- public void getName(AccessibleEvent e) {
- String name = null;
- int childID = e.childID;
- if (childID >= 0 && childID < items.length) {
- name = items[childID].getText();
- int index = name.indexOf('&');
- if (index > 0) {
- name = name.substring(0, index) + name.substring(index + 1);
- }
- }
- e.result = name;
- }
-
- public void getHelp(AccessibleEvent e) {
- String help = null;
- int childID = e.childID;
- if (childID == ACC.CHILDID_SELF) {
- help = getToolTipText();
- } else if (childID >= 0 && childID < items.length) {
- help = items[childID].getToolTipText();
- }
- e.result = help;
- }
-
- public void getKeyboardShortcut(AccessibleEvent e) {
- String shortcut = null;
- int childID = e.childID;
- if (childID >= 0 && childID < items.length) {
- String text = items[childID].getText();
- if (text != null) {
- char mnemonic = getMnemonic(text);
- if (mnemonic != '\0') {
- shortcut = "Alt+"+mnemonic; //$NON-NLS-1$
- }
- }
- }
- e.result = shortcut;
- }
- });
-
- accessible.addAccessibleControlListener(new AccessibleControlAdapter() {
- public void getChildAtPoint(AccessibleControlEvent e) {
- Point testPoint = toControl(new Point(e.x, e.y));
- int childID = ACC.CHILDID_NONE;
- for (int i = 0; i < items.length; i++) {
- if (items[i].getBounds().contains(testPoint)) {
- childID = i;
- break;
- }
- }
- if (childID == ACC.CHILDID_NONE) {
- Rectangle location = getBounds();
- location.height = location.height - getClientArea().height;
- if (location.contains(testPoint)) {
- childID = ACC.CHILDID_SELF;
- }
- }
- e.childID = childID;
- }
-
-
- public void getLocation(AccessibleControlEvent e) {
- Rectangle location = null;
- int childID = e.childID;
- if (childID == ACC.CHILDID_SELF) {
- location = getBounds();
- }
- if (childID >= 0 && childID < items.length) {
- location = items[childID].getBounds();
- }
- if (location != null) {
- 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 = items.length;
- }
-
- public void getDefaultAction(AccessibleControlEvent e) {
- String action = null;
- int childID = e.childID;
- if (childID >= 0 && childID < items.length) {
- action = "Switch"; //$NON-NLS-1$
- }
- e.result = action;
- }
-
- public void getFocus(AccessibleControlEvent e) {
- int childID = ACC.CHILDID_NONE;
- if (isFocusControl()) {
- if (selectedIndex == -1) {
- childID = ACC.CHILDID_SELF;
- } else {
- childID = selectedIndex;
- }
- }
- e.childID = childID;
- }
-
- public void getRole(AccessibleControlEvent e) {
- int role = 0;
- int childID = e.childID;
- if (childID == ACC.CHILDID_SELF) {
- role = ACC.ROLE_TABFOLDER;
- } else if (childID >= 0 && childID < items.length) {
- role = ACC.ROLE_TABITEM;
- }
- e.detail = role;
- }
-
- public void getSelection(AccessibleControlEvent e) {
- e.childID = (selectedIndex == -1) ? ACC.CHILDID_NONE : selectedIndex;
- }
-
- public void getState(AccessibleControlEvent e) {
- int state = 0;
- int childID = e.childID;
- if (childID == ACC.CHILDID_SELF) {
- state = ACC.STATE_NORMAL;
- } else if (childID >= 0 && childID < items.length) {
- state = ACC.STATE_SELECTABLE;
- if (isFocusControl()) {
- state |= ACC.STATE_FOCUSABLE;
- }
- if (selectedIndex == childID) {
- state |= ACC.STATE_SELECTED;
- if (isFocusControl()) {
- state |= ACC.STATE_FOCUSED;
- }
- }
- }
- e.detail = state;
- }
-
- public void getChildren(AccessibleControlEvent e) {
- Object[] children = new Object[items.length];
- for (int i = 0; i < items.length; i++) {
- children[i] = new Integer(i);
- }
- e.children = children;
- }
- });
-
- addListener(SWT.Selection, new Listener() {
- public void handleEvent(Event event) {
- if (isFocusControl()) {
- if (selectedIndex == -1) {
- accessible.setFocus(ACC.CHILDID_SELF);
- } else {
- accessible.setFocus(selectedIndex);
- }
- }
- }
- });
-
- addListener(SWT.FocusIn, new Listener() {
- public void handleEvent(Event event) {
- if (selectedIndex == -1) {
- accessible.setFocus(ACC.CHILDID_SELF);
- } else {
- accessible.setFocus(selectedIndex);
- }
- }
- });
-}
-
-private void setButtonBounds() {
-
- updateArrowBar();
- updateCloseBar();
-
- Rectangle area = super.getClientArea();
-
- int offset = 0;
- if (topRight != null) {
- Point size = topRight.computeSize(SWT.DEFAULT, tabHeight);
- int x = area.x + area.width - borderRight - size.x;
- int y = onBottom ? area.y + area.height - borderBottom - size.y : area.y + borderTop;
- topRight.setBounds(x, y, size.x, size.y);
- offset = size.x;
- }
- boolean leftVisible = scroll_leftVisible();
- boolean rightVisible = scroll_rightVisible();
- if (leftVisible || rightVisible) {
- Point size = arrowBar.computeSize(SWT.DEFAULT, tabHeight);
- int x = area.x + area.width - borderRight - size.x - offset;
- int y = (onBottom) ? area.y + area.height - borderBottom - size.y : area.y + borderTop;
-
- arrowBar.setBounds(x, y, size.x, size.y);
- ToolItem[] items = arrowBar.getItems();
- items[0].setEnabled(leftVisible);
- items[1].setEnabled(rightVisible);
- arrowBar.setVisible(true);
- } else {
- arrowBar.setVisible(false);
- }
-
- // When the close button is right at the edge of the Tab folder, hide it because
- // otherwise it may block off a part of the border on the right
- if (showClose) {
- inactiveCloseBar.setVisible(false);
- CTabItem item = getSelection();
- if (item == null) {
- closeBar.setVisible(false);
- } else {
- int toolbarHeight = tabHeight - CTabItem.TOP_MARGIN - CTabItem.BOTTOM_MARGIN + 2; // +2 to ignore gap between focus rectangle
- Point size = closeBar.computeSize(SWT.DEFAULT, toolbarHeight);
- int x = item.x + item.width - size.x - 2; // -2 to not overlap focus rectangle and trim
- int y = item.y + Math.max(0, (item.height - toolbarHeight)/2);
- closeBar.setBounds(x, y, size.x, toolbarHeight);
- Rectangle toolspace = getToolSpace();
- Point folderSize = getSize();
- boolean visible = (toolspace.width == 0 || x < toolspace.x) && x + size.x < folderSize.x - borderRight;
- closeBar.setVisible(visible);
- }
- }
-}
-private boolean setItemLocation() {
- if (items.length == 0) return false;
- Rectangle area = super.getClientArea();
- int x = area.x;
- int y = area.y + borderTop;
- if (onBottom) y = Math.max(0, area.y + area.height - borderBottom - tabHeight);
-
- boolean changed = false;
- for (int i = topTabIndex - 1; i>=0; i--) {
- // if the first visible tab is not the first tab
- CTabItem tab = items[i];
- x -= tab.width;
- if (!changed && (tab.x != x || tab.y != y) ) changed = true;
- // layout tab items from right to left thus making them invisible
- tab.x = x;
- tab.y = y;
- }
-
- x = area.x + borderLeft;
- for (int i = topTabIndex; i < items.length; i++) {
- // continue laying out remaining, visible items left to right
- CTabItem tab = items[i];
- tab.x = x;
- tab.y = y;
- x = x + tab.width;
- }
- setButtonBounds();
- return changed;
-}
-private void setLastItem(int index) {
- if (index < 0 || index > items.length - 1) return;
- Rectangle area = getClientArea();
- if (area.width <= 0) return;
- int maxWidth = area.width;
- Rectangle toolspace = getToolSpace();
- if (toolspace.width > 0){
- maxWidth -= toolspace.width;
- }
- int tabWidth = items[index].width;
- while (index > 0) {
- tabWidth += items[index - 1].width;
- if (tabWidth > maxWidth) break;
- index--;
- }
- topTabIndex = index;
- setItemLocation();
- redrawTabArea(-1);
-}
-/**
- * Layout the items and store the client area size.
- */
-boolean setItemBounds() {
- boolean changed = false;
- if (isDisposed()) return changed;
- Rectangle area = super.getClientArea();
-
- xClient = area.x + borderLeft + marginWidth;
- if (onBottom) {
- yClient = area.y + borderTop + marginHeight;
- } else {
- yClient = area.y + borderTop + tabHeight + 1 + marginHeight;
- // +1 is for the line at the bottom of the tabs
- }
-
- if (area.width <= 0 || area.height <= 0 || items.length == 0) return changed;
-
- int[] widths = new int[items.length];
- GC gc = new GC(this);
- for (int i = 0; i < items.length; i++) {
- widths[i] = items[i].preferredWidth(gc);
- }
- gc.dispose();
-
- int oldAverageWidth = 0;
- int averageWidth = (area.width - borderLeft - borderRight) / items.length;
- while (averageWidth > oldAverageWidth) {
- int width = area.width - borderLeft - borderRight;
- int count = items.length;
- for (int i = 0; i < items.length; i++) {
- if (widths[i] < averageWidth) {
- width -= widths[i];
- count--;
- }
- }
- oldAverageWidth = averageWidth;
- if (count > 0) {
- averageWidth = width / count;
- }
- }
- averageWidth = Math.max(averageWidth, MIN_TAB_WIDTH * tabHeight);
- for (int i = 0; i < items.length; i++) {
- if (widths[i] > averageWidth) {
- widths[i] = averageWidth;
- }
- }
-
- int totalWidth = 0;
- for (int i = 0; i < items.length; i++) {
- CTabItem tab = items[i];
- if (tab.height != tabHeight || tab.width != widths[i]) changed = true;
- tab.height = tabHeight;
- tab.width = widths[i];
- totalWidth += widths[i];
- }
-
- int areaWidth = area.x + area.width - borderRight;
- if (totalWidth <= areaWidth) {
- topTabIndex = 0;
- }
- if (setItemLocation()) changed = true;
-
- // Is there a gap after last item showing
- if (correctLastItem()) changed = true;
- return changed;
-}
-private boolean onMnemonic (Event event) {
- char key = event.character;
- for (int i = 0; i < items.length; i++) {
- if (items[i] != null) {
- char mnemonic = getMnemonic (items[i].getText ());
- if (mnemonic != '\0') {
- if (Character.toUpperCase (key) == Character.toUpperCase (mnemonic)) {
- setSelection(i, true);
- return true;
- }
- }
- }
- }
- return false;
-}
-/**
- * Paint the receiver.
- */
-private void onPaint(Event event) {
- Font font = getFont();
- if (oldFont == null || !oldFont.equals(font)) {
- oldFont = font;
- resetTabSize(true);
- }
- GC gc = event.gc;
- Rectangle rect = super.getClientArea();
- if (items.length == 0) {
- if (showBorders) {
- if ((getStyle() & SWT.FLAT) != 0) {
- gc.setForeground(borderColor1);
- gc.drawRectangle(rect.x, rect.y, rect.x + rect.width - 1, rect.y + rect.height - 1);
- } else {
- gc.setForeground(borderColor1);
- gc.drawRectangle(rect.x, rect.y, rect.x + rect.width - 3, rect.y + rect.height - 3);
-
- // fill in right and bottom edges with parent's background
- gc.setBackground(getParent().getBackground());
- gc.fillRectangle(rect.x + rect.width - 2, rect.y, 2, rect.height);
- gc.fillRectangle(rect.x, rect.y + rect.height - 2, rect.width, 2);
- }
- gc.setForeground(getForeground());
- }
- return;
- }
-
- // redraw the Border
- drawBorder(gc);
-
- rect.x += borderLeft;
- rect.y += borderTop;
- rect.width -= borderLeft + borderRight;
- rect.height -= borderTop + borderBottom;
- Rectangle clip = gc.getClipping ();
- gc.setClipping(clip.intersection(rect));
-
- // Draw the unselected tabs first.
- for (int i=0; i < items.length; i++) {
- if (i != selectedIndex && event.getBounds().intersects(items[i].getBounds())) {
- items[i].onPaint(gc, false);
- }
- }
- // Selected tab comes last
- if (selectedIndex != -1) {
- items[selectedIndex].onPaint(gc, true);
- }
-
- // draw insertion mark
- if (insertionIndex > -2) {
- gc.setForeground(getDisplay().getSystemColor(SWT.COLOR_LIST_SELECTION));
- if (insertionIndex == -1) {
- Rectangle bounds = items[0].getBounds();
- gc.drawLine(bounds.x, bounds.y, bounds.x, bounds.y + bounds.height - 1);
- gc.drawLine(bounds.x - 2, bounds.y, bounds.x + 2, bounds.y);
- gc.drawLine(bounds.x - 1, bounds.y + 1, bounds.x + 1, bounds.y + 1);
- gc.drawLine(bounds.x - 1, bounds.y + bounds.height - 2, bounds.x + 1, bounds.y + bounds.height - 2);
- gc.drawLine(bounds.x - 2, bounds.y + bounds.height - 1, bounds.x + 2, bounds.y + bounds.height - 1);
-
- } else {
- Rectangle bounds = items[insertionIndex].getBounds();
- gc.drawLine(bounds.x + bounds.width, bounds.y, bounds.x + bounds.width, bounds.y + bounds.height - 1);
- gc.drawLine(bounds.x + bounds.width - 2, bounds.y, bounds.x + bounds.width + 2, bounds.y);
- gc.drawLine(bounds.x + bounds.width - 1, bounds.y + 1, bounds.x + bounds.width + 1, bounds.y + 1);
- gc.drawLine(bounds.x + bounds.width - 1, bounds.y + bounds.height - 2, bounds.x + bounds.width + 1, bounds.y + bounds.height - 2);
- gc.drawLine(bounds.x + bounds.width - 2, bounds.y + bounds.height - 1, bounds.x + bounds.width + 2, bounds.y + bounds.height - 1);
- }
- }
-
- gc.setForeground(getForeground());
- gc.setBackground(getBackground());
-}
-private void redrawTabArea(int index) {
- int x = 0, y = 0, width = 0, height = 0;
- if (index == -1) {
- Rectangle area = super.getClientArea();
- if (area.width == 0 || area.height == 0) return;
- width = area.x + area.width - borderLeft - borderRight;
- height = tabHeight + 1; // +1 causes top line between content and tabs to be redrawn
- x = area.x + borderLeft;
- y = area.y + borderTop;
- if (onBottom) {
- y = Math.max(0, area.y + area.height - borderBottom - height);
- }
- } else {
- CTabItem item = items[index];
- x = item.x;
- y = item.y;
- Rectangle area = super.getClientArea();
- width = area.x + area.width - x;
- height = item.height;
- }
- redraw(x, y, width, height, false);
-}
-
-/**
- * Removes the listener.
- *
- * @param listener the listener
- *
- * @exception SWTError
- * <ul><li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
- * <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
- * <li>ERROR_NULL_ARGUMENT when listener is null</li></ul>
- */
-public void removeSelectionListener(SelectionListener listener) {
- checkWidget();
- if (listener == null) {
- SWT.error(SWT.ERROR_NULL_ARGUMENT);
- }
- removeListener(SWT.Selection, listener);
- removeListener(SWT.DefaultSelection, listener);
-}
-/**
- * Removes the listener.
- *
- * @param listener the listener
- *
- * @exception SWTError
- * <ul><li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
- * <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
- * <li>ERROR_NULL_ARGUMENT when listener is null</li></ul>
- */
-public void removeCTabFolderListener(CTabFolderListener listener) {
- checkWidget();
- if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
- if (tabListeners.length == 0) return;
- int index = -1;
- for (int i = 0; i < tabListeners.length; i++) {
- if (listener == tabListeners[i]){
- index = i;
- break;
- }
- }
- if (index == -1) return;
- if (tabListeners.length == 1) {
- tabListeners = new CTabFolderListener[0];
- showClose = false;
- setButtonBounds();
- return;
- }
- CTabFolderListener[] newTabListeners = new CTabFolderListener[tabListeners.length - 1];
- System.arraycopy(tabListeners, 0, newTabListeners, 0, index);
- System.arraycopy(tabListeners, index + 1, newTabListeners, index, tabListeners.length - index - 1);
- tabListeners = newTabListeners;
-}
-
-/**
- * The widget was resized. Adjust the size of the currently selected page.
- */
-private void onResize() {
-
- if (items.length == 0) {
- redraw();
- return;
- }
-
- if (setItemBounds()) {
- redrawTabArea(-1);
- }
-
- Point size = getSize();
- if (oldSize == null) {
- redraw();
- } else {
- if (onBottom && size.y != oldSize.y) {
- redraw();
- } else {
- int x1 = Math.min(size.x, oldSize.x);
- if (size.x != oldSize.x) x1 -= 10;
- int y1 = Math.min(size.y, oldSize.y);
- if (size.y != oldSize.y) y1 -= 10;
- int x2 = Math.max(size.x, oldSize.x);
- int y2 = Math.max(size.y, oldSize.y);
- redraw(0, y1, x2 + 10, y2 - y1, false);
- redraw(x1, 0, x2 - x1, y2, false);
- }
- }
- oldSize = size;
-
- // resize content
- if (selectedIndex != -1) {
- Control control = items[selectedIndex].getControl();
- if (control != null && !control.isDisposed()) {
- control.setBounds(getClientArea());
- }
- }
-}
-
-public void setBackground (Color color) {
- super.setBackground(color);
- background = color;
- // init inactive close button
- inactiveCloseBar.setBackground(color);
-
- // init scroll buttons
- arrowBar.setBackground(color);
-
- //init topRight control
- if (topRight != null)
- topRight.setBackground(color);
-
- // init close button
- if (gradientColors == null) {
- closeBar.setBackground(color);
- }
-}
-/**
- * Specify a gradient of colours to be draw in the background of the selected tab.
- * For example to draw a gradient that varies from dark blue to blue and then to
- * white, use the following call to setBackground:
- * <pre>
- * cfolder.setBackground(new Color[]{display.getSystemColor(SWT.COLOR_DARK_BLUE),
- * display.getSystemColor(SWT.COLOR_BLUE),
- * display.getSystemColor(SWT.COLOR_WHITE),
- * display.getSystemColor(SWT.COLOR_WHITE)},
- * new int[] {25, 50, 100});
- * </pre>
- *
- * @param colors an array of Color that specifies the colors to appear in the gradient
- * in order of appearance left to right. The value <code>null</code> clears the
- * background gradient. The value <code>null</code> can be used inside the array of
- * Color to specify the background color.
- * @param percents an array of integers between 0 and 100 specifying the percent of the width
- * of the widget at which the color should change. The size of the percents array must be one
- * less than the size of the colors array.
- *
- * @exception SWTError <ul>
- * <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
- * <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
- * </ul>
- */
-
-public void setSelectionBackground(Color[] colors, int[] percents) {
- checkWidget();
- if (colors != null) {
- if (percents == null || percents.length != colors.length - 1) {
- SWT.error(SWT.ERROR_INVALID_ARGUMENT);
- }
- if (getDisplay().getDepth() < 15) {
- // Don't use gradients on low color displays
- colors = new Color[] { colors[0] };
- percents = new int[] { };
- }
- for (int i = 0; i < percents.length; i++) {
- if (percents[i] < 0 || percents[i] > 100) {
- SWT.error(SWT.ERROR_INVALID_ARGUMENT);
- }
- if (i > 0 && percents[i] < percents[i-1]) {
- SWT.error(SWT.ERROR_INVALID_ARGUMENT);
- }
- }
- }
-
- // Are these settings the same as before?
- if (backgroundImage == null) {
- if ((gradientColors != null) && (colors != null) &&
- (gradientColors.length == colors.length)) {
- boolean same = false;
- for (int i = 0; i < gradientColors.length; i++) {
- if (gradientColors[i] == null) {
- same = colors[i] == null;
- } else {
- same = gradientColors[i].equals(colors[i]);
- }
- if (!same) break;
- }
- if (same) {
- for (int i = 0; i < gradientPercents.length; i++) {
- same = gradientPercents[i] == percents[i];
- if (!same) break;
- }
- }
- if (same) return;
- }
- } else {
- backgroundImage = null;
- }
- // Store the new settings
- if (colors == null) {
- gradientColors = null;
- gradientPercents = null;
- closeBar.setBackground(background);
- } else {
- gradientColors = new Color[colors.length];
- for (int i = 0; i < colors.length; ++i)
- gradientColors[i] = colors[i];
- gradientPercents = new int[percents.length];
- for (int i = 0; i < percents.length; ++i)
- gradientPercents[i] = percents[i];
- if (getDisplay().getDepth() < 15) closeBar.setBackground(background);
- else closeBar.setBackground(gradientColors[gradientColors.length - 1]);
- }
-
- // Refresh with the new settings
- if (selectedIndex > -1) redrawTabArea(selectedIndex);
-}
-
-/**
- * Set the image to be drawn in the background of the selected tab.
- *
- * @param image the image to be drawn in the background
- *
- * @exception SWTException <ul>
- * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
- * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
- * </ul>
- */
-public void setSelectionBackground(Image image) {
- checkWidget();
- if (image == backgroundImage) return;
- if (image != null) {
- gradientColors = null;
- gradientPercents = null;
- }
- backgroundImage = image;
- redrawTabArea(selectedIndex);
-}
-/**
- * Toggle the visibility of the border
- *
- * @param show true if the border should be displayed
- *
- * @exception SWTException <ul>
- * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
- * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
- * </ul>
- */
-public void setBorderVisible(boolean show) {
- checkWidget();
- if (showBorders == show) return;
-
- showBorders = show;
- if (showBorders) {
- if ((getStyle() & SWT.FLAT) != 0) {
- borderBottom = borderTop = borderLeft = borderRight = 1;
- } else {
- borderLeft = borderTop = 1;
- borderRight = borderBottom = 3;
- }
- } else {
- borderBottom = borderTop = borderLeft = borderRight = 0;
- }
- oldSize = null;
- notifyListeners(SWT.Resize, new Event());
-}
-public void setFont(Font font) {
- checkWidget();
- if (font != null && font.equals(getFont())) return;
- super.setFont(font);
- oldFont = getFont();
- resetTabSize(true);
-}
-/**
- * Set the foreground color of the selected tab.
- *
- * @param color the color of the text displayed in the selected tab
- *
- * @exception SWTException <ul>
- * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
- * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
- * </ul>
- */
-public void setSelectionForeground (Color color) {
- checkWidget();
- if (selectionForeground == color) return;
- if (color == null) color = getForeground();
- selectionForeground = color;
- if (selectedIndex > -1) {
- redrawTabArea(selectedIndex);
- }
-}
-/**
- * Display an insert marker before or after the specified tab item.
- * Null will clear the mark.
- *
- * @param item the item with which the mark is associated or null
- *
- * @param after true if the mark should be displayed after the specified item
- *
- * @exception SWTException <ul>
- * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
- * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
- * </ul>
- */
-public void setInsertMark(CTabItem item, boolean after) {
- checkWidget();
- int index = -1;
- if (item != null) {
- index = indexOf(item);
- }
- setInsertMark(index, after);
-}
-/**
- * Display an insert marker before or after the specified tab item.
- * -1 will clear the mark.
- *
- * @param item the index of the item with which the mark is associated or null
- *
- * @param after true if the mark should be displayed after the specified item
- *
- * @exception SWTException <ul>
- * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
- * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
- * </ul>
- */
-public void setInsertMark(int index, boolean after) {
- checkWidget();
- if (index < -1 || index >= getItemCount()) {
- SWT.error(SWT.ERROR_INVALID_ARGUMENT);
- }
-
- if (index == -1) {
- index = -2;
- } else {
- index = after ? index : --index;
- }
-
- if (insertionIndex == index) return;
- int oldIndex = insertionIndex;
- insertionIndex = index;
- if (index > -1) redrawTabArea(index);
- if (oldIndex > 1) redrawTabArea(oldIndex);
-}
-
-/**
- * Set the selection to the tab at the specified index.
- *
- * @param index the index of the tab item to be selected
- *
- * @exception SWTException <ul>
- * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
- * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
- * </ul>
- */
-public void setSelection(int index) {
- checkWidget();
- if (index < 0 || index >= items.length) return;
- if (selectedIndex == index) return;
-
- int oldIndex = selectedIndex;
- selectedIndex = index;
-
- Control control = items[index].control;
- if (control != null && !control.isDisposed()) {
- control.setBounds(getClientArea());
- control.setVisible(true);
- }
-
- if (oldIndex != -1) {
- control = items[oldIndex].control;
- if (control != null && !control.isDisposed()) {
- control.setVisible(false);
- }
- }
- showItem(items[selectedIndex]);
- setButtonBounds();
- redrawTabArea(-1);
-}
-/**
- * Set the control that appears in the top right corner of the tab folder.
- * Typically this is a close button or a composite with a Menu and close button.
- * The topRight control is optional. Setting the top right control to null will remove it from the tab folder.
- *
- * @since 2.1
- *
- * @param control the control to be displayed in the top right corner or null
- *
- * @exception SWTException <ul>
- * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
- * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
- * <li>ERROR_INVALID_ARGUMENT - if the control is not a child of this CTabFolder</li>
- * </ul>
- */
-public void setTopRight(Control control) {
- checkWidget();
- if (control != null && control.getParent() != this) {
- SWT.error(SWT.ERROR_INVALID_ARGUMENT);
- }
- topRight = control;
- resetTabSize(true);
-}
-
-/**
- * Shows the item. If the item is already showing in the receiver,
- * this method simply returns. Otherwise, the items are scrolled until
- * the item is visible.
- *
- * @param item the item to be shown
- *
- * @exception IllegalArgumentException <ul>
- * <li>ERROR_NULL_ARGUMENT - if the item is null</li>
- * <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
- * </ul>
- * @exception SWTException <ul>
- * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
- * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
- * </ul>
- *
- * @see CTabFolder#showSelection()
- *
- * @since 2.0
- */
-public void showItem (CTabItem item) {
- checkWidget();
- if (item == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
- if (item.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
-
- int index = indexOf(item);
- if (index < topTabIndex) {
- topTabIndex = index;
- setItemLocation();
- redrawTabArea(-1);
- return;
- }
- Rectangle area = getClientArea();
- if (area.width <= 0) {
- topTabIndex = index;
- return;
- }
- int rightEdge = area.x + area.width;
- Rectangle rect = getToolSpace();
- if (rect.width > 0) {
- rightEdge -= rect.width;
- }
- if (item.x + item.width < rightEdge) return;
- setLastItem(index);
-}
-/**
- * Shows the selection. If the selection is already showing in the receiver,
- * this method simply returns. Otherwise, the items are scrolled until
- * the selection is visible.
- *
- * @exception IllegalArgumentException <ul>
- * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
- * </ul>
- * @exception SWTException <ul>
- * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
- * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
- * </ul>
- *
- * @see CTabFolder#showItem(CTabItem)
- *
- * @since 2.0
- *
- */
-public void showSelection () {
- checkWidget ();
- if (selectedIndex != -1) {
- showItem(getSelection());
- }
-}
-
-char getMnemonic (String string) {
- int index = 0;
- int length = string.length ();
- do {
- while ((index < length) && (string.charAt (index) != '&')) index++;
- if (++index >= length) return '\0';
- if (string.charAt (index) != '&') return string.charAt (index);
- index++;
- } while (index < length);
- return '\0';
-}
-/**
- * Set the selection to the tab at the specified item.
- *
- * @param index the tab item to be selected
- *
- * @exception SWTException <ul>
- * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
- * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
- * <li>ERROR_NULL_ARGUMENT - if argument is null</li>
- * </ul>
- */
-public void setSelection(CTabItem item) {
- checkWidget();
- if (item == null)
- SWT.error(SWT.ERROR_NULL_ARGUMENT);
- int index = indexOf(item);
- setSelection(index);
-}
-/**
- * Set the selection to the tab at the specified index.
- */
-private void setSelection(int index, boolean notify) {
- int oldSelectedIndex = selectedIndex;
- setSelection(index);
- if (notify && selectedIndex != oldSelectedIndex && selectedIndex != -1) {
- Event event = new Event();
- event.item = getItem(selectedIndex);
- notifyListeners(SWT.Selection, event);
- }
-}
-
-private void updateCloseBar() {
- int imageHeight = tabHeight - CTabItem.TOP_MARGIN - CTabItem.BOTTOM_MARGIN - 4;
- if (imageHeight < 8) return;
-
- if (closeImage != null && closeImage.getBounds().height == imageHeight) return;
-
- if (closeBar != null) closeBar.dispose();
- closeBar = null;
- if (inactiveCloseBar != null) inactiveCloseBar.dispose();
- inactiveCloseBar = null;
- createCloseBar();
-
- ToolItem closeItem = closeBar.getItems()[0];
- ToolItem inactiveCloseItem = inactiveCloseBar.getItems()[0];
-
- if (closeImage != null) closeImage.dispose();
-
- Display display = getDisplay();
- Color foreground = getForeground();
- Color black = display.getSystemColor(SWT.COLOR_BLACK);
- Color background = getBackground();
-
- PaletteData palette = new PaletteData(new RGB[]{foreground.getRGB(), background.getRGB(), black.getRGB()});
- ImageData imageData = new ImageData(imageHeight, imageHeight, 4, palette);
- imageData.transparentPixel = 1;
- closeImage = new Image(display, imageData);
- GC gc = new GC(closeImage);
- gc.setBackground(background);
- gc.fillRectangle(0, 0, imageHeight, imageHeight);
- gc.setForeground(black);
-
- //draw an 8x7 'x' centered in image
- int h = (imageHeight / 2 )* 2;
- int inset = (h - 8) / 2;
- gc.drawLine( inset, inset, h - inset - 1, h - inset - 1);
- gc.drawLine( inset + 1, inset, h - inset, h - inset - 1);
- gc.drawLine( inset, h - inset - 1, h - inset - 1, inset);
- gc.drawLine( inset + 1, h - inset - 1, h - inset, inset);
-
- gc.dispose();
-
- closeItem.setImage(closeImage);
- inactiveCloseItem.setImage(closeImage);
-}
-private void updateArrowBar() {
-
- int imageHeight = tabHeight - 6;
- if (imageHeight < 10) return;
-
- if (arrowLeftImage != null && arrowLeftImage.getBounds().height == imageHeight) return;
-
- if (arrowBar != null) arrowBar.dispose();
- arrowBar = null;
- if (arrowLeftImage != null) arrowLeftImage.dispose();
- if (arrowRightImage != null) arrowRightImage.dispose();
-
- createArrowBar();
- ToolItem[] items = arrowBar.getItems();
- ToolItem left = items[0];
- ToolItem right = items[1];
-
- Display display = getDisplay();
- Color foreground = getForeground();
- Color black = display.getSystemColor(SWT.COLOR_BLACK);
- Color background = getBackground();
-
- PaletteData palette = new PaletteData(new RGB[]{foreground.getRGB(), background.getRGB(), black.getRGB()});
- ImageData imageData = new ImageData(7, imageHeight, 4, palette);
- imageData.transparentPixel = 1;
- arrowLeftImage = new Image(display, imageData);
- GC gc = new GC(arrowLeftImage);
- gc.setBackground(background);
- gc.fillRectangle(0, 0, 7, imageHeight);
- gc.setBackground(black);
- //draw a 10x5 '<' centered vertically in image
- int h = (imageHeight / 2 )* 2;
- int midpoint = h / 2 - 1;
- int[] pointArr = new int[] {6, midpoint - 5,
- 1, midpoint,
- 6, midpoint + 5,};
- gc.fillPolygon(pointArr);
- gc.dispose();
-
- palette = new PaletteData(new RGB[]{foreground.getRGB(), background.getRGB(), black.getRGB()});
- imageData = new ImageData(7, imageHeight, 4, palette);
- imageData.transparentPixel = 1;
- arrowRightImage = new Image(display, imageData);
- gc = new GC(arrowRightImage);
- gc.setBackground(background);
- gc.fillRectangle(0, 0, 7, imageHeight);
- gc.setBackground(black);
- //draw a 10x5 '>' centered vertically in image
- pointArr = new int[] {1, midpoint - 5,
- 6, midpoint,
- 1, midpoint + 5,};
- gc.fillPolygon(pointArr);
- gc.dispose();
-
- left.setImage(arrowLeftImage);
- right.setImage(arrowRightImage);
-}
-
-private void onMouseDoubleClick(Event event) {
- Event e = new Event();
- e.item = getItem(new Point(event.x, event.y));
- notifyListeners(SWT.DefaultSelection, e);
-}
-/**
- * A mouse button was pressed down.
- * If a tab was hit select the tab.
- */
-private void onMouseDown(Event event) {
- for (int i=0; i<items.length; i++) {
- if (items[i].getBounds().contains(new Point(event.x, event.y))) {
- if (i == selectedIndex) {
- showSelection();
- return;
- }
- forceFocus();
- setSelection(i, true);
- if (isFocusControl()) setFocus();
- return;
- }
- }
-}
-
-private void onMouseExit(Event event) {
- Rectangle inactiveBounds = inactiveCloseBar.getBounds();
- if (inactiveBounds.contains(event.x, event.y)) return;
- inactiveCloseBar.setVisible(false);
- inactiveItem = null;
-
- showToolTip = false;
- toolTipItem = null;
- if (tip != null && !tip.isDisposed() && tip.isVisible()) tip.setVisible(false);
-}
-
-private void onMouseHover(Event event) {
- if (tip == null || tip.isDisposed()) return;
- showToolTip = true;
- showToolTip(event.x, event.y);
-}
-private void showToolTip (int x, int y) {
- CTabItem item = getItem(new Point (x, y));
- if (item != null) {
- if (item == toolTipItem) return;
- toolTipItem = item;
- String tooltip = item.getToolTipText();
- if (tooltip != null) {
- Display display = tip.getDisplay();
- label.setForeground (display.getSystemColor (SWT.COLOR_INFO_FOREGROUND));
- label.setBackground (display.getSystemColor (SWT.COLOR_INFO_BACKGROUND));
- label.setText(tooltip);
- Point labelSize = label.computeSize(SWT.DEFAULT, SWT.DEFAULT);
- labelSize.x += 2; labelSize.y += 2;
- label.setSize(labelSize);
- tip.pack();
- /*
- * On some platforms, there is a minimum size for a shell
- * which may be greater than the label size.
- * To avoid having the background of the tip shell showing
- * around the label, force the label to fill the entire client area.
- */
- Rectangle area = tip.getClientArea();
- label.setSize(area.width, area.height);
- /*
- * Position the tooltip and ensure that it is not located off
- * the screen.
- */
- Point pt = new Point(item.x + item.width / 4, item.y + item.height + 2);
- pt = toDisplay(pt);
- Rectangle rect = display.getBounds();
- Point tipSize = tip.getSize();
- pt.x = Math.max (0, Math.min (pt.x, rect.width - tipSize.x));
- pt.y = Math.max (0, Math.min (pt.y, rect.height - tipSize.y));
- tip.setLocation(pt);
- tip.setVisible(true);
- return;
- }
- }
-
- toolTipItem = null;
- if (tip != null && !tip.isDisposed() && tip.isVisible()) tip.setVisible(false);
-}
-private void onMouseMove(Event event) {
- if (showToolTip) {
- showToolTip(event.x, event.y);
- }
-
- if (!showClose) return;
-
- CTabItem item = null;
- for (int i=0; i<items.length; i++) {
- Rectangle rect = items[i].getBounds();
- if (rect.contains(new Point(event.x, event.y))) {
- item = items[i];
- break;
- }
- }
- if (item == inactiveItem) return;
-
- inactiveCloseBar.setVisible(false);
- inactiveItem = null;
-
- if (item == null || item == getSelection()) return;
-
- int toolbarHeight = tabHeight - CTabItem.TOP_MARGIN - CTabItem.BOTTOM_MARGIN + 2; // +2 to ignore gap between focus rectangle
- Point size = inactiveCloseBar.computeSize(SWT.DEFAULT, toolbarHeight);
- int x = item.x + item.width - size.x - 2; // -2 to not overlap focus rectangle and trim
- int y = item.y + Math.max(0, (item.height - toolbarHeight)/2);
- Rectangle toolspace = getToolSpace();
- Point folderSize = getSize();
- if ((toolspace.width == 0 || x < toolspace.x) && x + size.x < folderSize.x - borderRight) {
- inactiveCloseBar.setBounds(x, y, size.x, toolbarHeight);
- inactiveCloseBar.setVisible(true);
- inactiveItem = item;
- }
-}
-private void onTraverse (Event event) {
- switch (event.detail) {
- case SWT.TRAVERSE_ESCAPE:
-// TEMPORARY CODE See bug report 17372
-// case SWT.TRAVERSE_RETURN:
- case SWT.TRAVERSE_TAB_NEXT:
- case SWT.TRAVERSE_TAB_PREVIOUS:
- event.doit = true;
- break;
- case SWT.TRAVERSE_MNEMONIC:
- event.doit = onMnemonic(event);
- if (event.doit) event.detail = SWT.TRAVERSE_NONE;
- break;
- case SWT.TRAVERSE_PAGE_NEXT:
- case SWT.TRAVERSE_PAGE_PREVIOUS:
- event.doit = onPageTraversal(event);
- if (event.doit) event.detail = SWT.TRAVERSE_NONE;
- break;
- }
-}
-
-private boolean onPageTraversal(Event event) {
- int count = getItemCount ();
- if (count == 0) return false;
- int index = getSelectionIndex ();
- if (index == -1) {
- index = 0;
- } else {
- int offset = (event.detail == SWT.TRAVERSE_PAGE_NEXT) ? 1 : -1;
- index = (index + offset + count) % count;
- }
- setSelection (index, true);
- return true;
-}
-
-/**
- * Answer true if not all tabs can be visible in the receive
- * thus requiring the scroll buttons to be visible.
- */
-private boolean scroll_leftVisible() {
- return topTabIndex > 0;
-}
-
-/**
- * Answer true if not all tabs can be visible in the receive
- * thus requiring the scroll buttons to be visible.
- */
-private boolean scroll_rightVisible() {
- // only show Scroll buttons if there is more than one item
- // and if we are not already at the last item
- if (items.length < 2) return false;
- Rectangle area = getClientArea();
- int rightEdge = area.x + area.width;
- if (rightEdge <= 0) return false;
- if (topTabIndex > 0) {
- rightEdge -= arrowBar.getSize().x;
- }
- if (topRight != null) {
- rightEdge -= topRight.getSize().x;
- }
- CTabItem item = items[items.length-1];
- return (item.x + item.width > rightEdge);
-}
-
-/**
- * Scroll the tab items to the left.
- */
-private void scroll_scrollLeft() {
- if (items.length == 0) return;
- setLastItem(topTabIndex - 1);
-}
-
-/**
- * Scroll the tab items to the right.
- */
-private void scroll_scrollRight() {
- int lastIndex = getLastItem();
- topTabIndex = lastIndex + 1;
- setItemLocation();
- correctLastItem();
- redrawTabArea(-1);
-}
-private boolean correctLastItem() {
- Rectangle area = getClientArea();
- int rightEdge = area.x + area.width;
- if (rightEdge <= 0) return false;
- Rectangle toolspace = getToolSpace();
- if (toolspace.width > 0) {
- rightEdge -= toolspace.width;
- }
- CTabItem item = items[items.length - 1];
- if (item.x + item.width < rightEdge) {
- setLastItem(items.length - 1);
- return true;
- }
- return false;
-}
-/**
- * Specify a fixed height for the tab items. If no height is specified,
- * the default height is the height of the text or the image, whichever
- * is greater. Specifying a height of 0 will revert to the default height.
- *
- * @param height the pixel value of the height or 0
- *
- * @exception SWTException <ul>
- * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
- * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
- * <li>ERROR_INVALID_ARGUMENT - if called with a height of less than 0</li>
- * </ul>
- */
-public void setTabHeight(int height) {
- checkWidget();
- if (height < 0) {
- SWT.error(SWT.ERROR_INVALID_ARGUMENT);
- }
- fixedTabHeight = true;
- if (tabHeight == height) return;
- tabHeight = height;
- oldSize = null;
- notifyListeners(SWT.Resize, new Event());
-}
-void resetTabSize(boolean checkHeight){
- int oldHeight = tabHeight;
- if (!fixedTabHeight && checkHeight) {
- int tempHeight = 0;
- GC gc = new GC(this);
- for (int i=0; i < items.length; i++) {
- tempHeight = Math.max(tempHeight, items[i].preferredHeight(gc));
- }
- gc.dispose();
- if (topRight != null) tempHeight = Math.max(tempHeight, topRight.computeSize(SWT.DEFAULT, SWT.DEFAULT).y);
- tabHeight = tempHeight;
- }
-
- if (tabHeight != oldHeight){
- oldSize = null;
- notifyListeners(SWT.Resize, new Event());
- } else {
- setItemBounds();
- redraw();
- }
-}
-}
+ * http://www.eclipse.org/legal/cpl-v10.html + */ + +import org.eclipse.swt.*; +import org.eclipse.swt.events.*; +import org.eclipse.swt.graphics.*; +import org.eclipse.swt.widgets.*; +import org.eclipse.swt.accessibility.*; + +/** + * Instances of this class implement the notebook user interface + * metaphor. It allows the user to select a notebook page from + * set of pages. + * <p> + * The item children that may be added to instances of this class + * must be of type <code>CTabItem</code>. + * <code>Control</code> children are created and then set into a + * tab item using <code>CTabItem#setControl</code>. + * </p><p> + * Note that although this class is a subclass of <code>Composite</code>, + * it does not make sense to set a layout on it. + * </p><p> + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>TOP, BOTTOM, FLAT</dd> + * <dt><b>Events:</b></dt> + * <dd>Selection</dd> + * <dd>"CTabFolder"</dd> + * </dl> + * <p> + * Note: Only one of the styles TOP and BOTTOM + * may be specified. + * </p><p> + * IMPORTANT: This class is <em>not</em> intended to be subclassed. + * </p> + */ + +public class CTabFolder extends Composite { + + /** + * marginWidth specifies the number of pixels of horizontal margin + * that will be placed along the left and right edges of the form. + * + * The default value is 0. + */ + public int marginWidth = 0; + /** + * marginHeight specifies the number of pixels of vertical margin + * that will be placed along the top and bottom edges of the form. + * + * The default value is 0. + */ + public int marginHeight = 0; + + /** + * Color of innermost line of drop shadow border. + */ + public static RGB borderInsideRGB = new RGB (132, 130, 132); + /** + * Color of middle line of drop shadow border. + */ + public static RGB borderMiddleRGB = new RGB (143, 141, 138); + /** + * Color of outermost line of drop shadow border. + */ + public static RGB borderOutsideRGB = new RGB (171, 168, 165); + + /* + * A multiple of the tab height that specifies the minimum width to which a tab + * will be compressed before scrolling arrows are used to navigate the tabs. + */ + public int MIN_TAB_WIDTH = 3; + + /* sizing, positioning */ + int xClient, yClient; + boolean onBottom = false; + boolean fixedTabHeight; + int tabHeight; + + /* item management */ + private CTabItem items[] = new CTabItem[0]; + private int selectedIndex = -1; + int topTabIndex = -1; // index of the left most visible tab. + + /* External Listener management */ + private CTabFolderListener[] tabListeners = new CTabFolderListener[0]; + + /* Color appearance */ + Image backgroundImage; + Color[] gradientColors; + int[] gradientPercents; + Color selectionForeground; + Color background; + + // internal constants + private static final int DEFAULT_WIDTH = 64; + private static final int DEFAULT_HEIGHT = 64; + + // scrolling arrows + private ToolBar arrowBar; + private Image arrowLeftImage; + private Image arrowRightImage; + + private Control topRight; + + // close button + boolean showClose = false; + private Image closeImage; + ToolBar closeBar; + private ToolBar inactiveCloseBar; + private CTabItem inactiveItem; + + // borders + boolean showBorders = false; + private int borderBottom = 0; + private int borderLeft = 0; + private int borderRight = 0; + private int borderTop = 0; + private Color borderColor1; + private Color borderColor2; + private Color borderColor3; + + // when disposing CTabFolder, don't try to layout the items or + // change the selection as each child is destroyed. + private boolean inDispose = false; + + // keep track of size changes in order to redraw only affected area + // on Resize + private Point oldSize; + private Font oldFont; + + // insertion marker + int insertionIndex = -2; // Index of insert marker. Marker always shown after index. + // -2 means no insert marker + + // tool tip + private Shell tip; + private Label label; + private boolean showToolTip = false; + private CTabItem toolTipItem; + +/** + * Constructs a new instance of this class given its parent + * and a style value describing its behavior and appearance. + * <p> + * The style value is either one of the style constants defined in + * class <code>SWT</code> which is applicable to instances of this + * class, or must be built by <em>bitwise OR</em>'ing together + * (that is, using the <code>int</code> "|" operator) two or more + * of those <code>SWT</code> style constants. The class description + * lists the style constants that are applicable to the class. + * Style bits are also inherited from superclasses. + * </p> + * + * @param parent a widget which will be the parent of the new instance (cannot be null) + * @param style the style of widget to construct + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li> + * </ul> + * + * @see SWT#TOP + * @see SWT#BOTTOM + * @see SWT#FLAT + * @see #getStyle + */ +public CTabFolder(Composite parent, int style) { + super(parent, checkStyle (style)); + + onBottom = (getStyle() & SWT.BOTTOM) != 0; + + borderColor1 = new Color(getDisplay(), borderInsideRGB); + borderColor2 = new Color(getDisplay(), borderMiddleRGB); + borderColor3 = new Color(getDisplay(), borderOutsideRGB); + + // tool tip support + tip = new Shell (getShell(), SWT.ON_TOP); + label = new Label (tip, SWT.CENTER); + + // Add all listeners + Listener listener = new Listener() { + public void handleEvent(Event event) { + switch (event.type) { + case SWT.Dispose: onDispose(); break; + case SWT.Paint: onPaint(event); break; + case SWT.Resize: onResize(); break; + case SWT.MouseDoubleClick: onMouseDoubleClick(event); break; + case SWT.MouseDown: onMouseDown(event); break; + case SWT.MouseExit: onMouseExit(event); break; + case SWT.MouseHover: onMouseHover(event); break; + case SWT.MouseMove: onMouseMove(event); break; + case SWT.FocusIn: onFocus(event); break; + case SWT.FocusOut: onFocus(event); break; + case SWT.KeyDown: onKeyDown(event); break; + case SWT.Traverse: onTraverse(event); break; + } + } + }; + + int[] folderEvents = new int[]{ + SWT.Dispose, + SWT.Paint, + SWT.Resize, + SWT.MouseDoubleClick, + SWT.MouseDown, + SWT.MouseExit, + SWT.MouseHover, + SWT.MouseMove, + SWT.FocusIn, + SWT.FocusOut, + SWT.KeyDown, + SWT.Traverse, + }; + for (int i = 0; i < folderEvents.length; i++) { + addListener(folderEvents[i], listener); + } + + createArrowBar(); + createCloseBar(); + + setBorderVisible((style & SWT.BORDER) != 0); + + initAccessible(); + +} +private static int checkStyle (int style) { + int mask = SWT.TOP | SWT.BOTTOM | SWT.FLAT; + style = style & mask; + // TOP and BOTTOM are mutually exlusive. + // TOP is the default + if ((style & SWT.TOP) != 0) + style = style & ~(SWT.TOP | SWT.BOTTOM) | SWT.TOP; + // reduce the flash by not redrawing the entire area on a Resize event + style |= SWT.NO_REDRAW_RESIZE; + return style; +} +/** +* Adds the listener to receive events. +* <p> +* +* @param listener the listener +* +* @exception SWTError <ul> +* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li> +* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li> +* <li>ERROR_NULL_ARGUMENT when listener is null</li> +* </ul> +*/ +public void addSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + TypedListener typedListener = new TypedListener(listener); + addListener(SWT.Selection, typedListener); + addListener(SWT.DefaultSelection, typedListener); +} +/** + * Adds the listener to the collection of listeners who will + * be notified when a tab item is closed. + * + * @param listener the listener which should be notified + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li> + * <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * + * @see CTabFolderListener + * @see #removeCTabFolderListener + */ +public void addCTabFolderListener(CTabFolderListener listener) { + checkWidget(); + if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT); + // add to array + CTabFolderListener[] newTabListeners = new CTabFolderListener[tabListeners.length + 1]; + System.arraycopy(tabListeners, 0, newTabListeners, 0, tabListeners.length); + tabListeners = newTabListeners; + tabListeners[tabListeners.length - 1] = listener; + showClose = true; + setButtonBounds(); +} +private void closeNotify(CTabItem item, int time) { + if (item == null) return; + + CTabFolderEvent event = new CTabFolderEvent(this); + event.widget = this; + event.time = time; + event.item = item; + event.doit = true; + if (tabListeners != null) { + for (int i = 0; i < tabListeners.length; i++) { + tabListeners[i].itemClosed(event); + } + } + if (event.doit) { + item.dispose(); + } +} +public Point computeSize (int wHint, int hHint, boolean changed) { + checkWidget(); + int minWidth = 0; + int minHeight = 0; + + // preferred width of tab area to show all tabs + GC gc = new GC(this); + for (int i = 0; i < items.length; i++) { + minWidth += items[i].preferredWidth(gc); + } + gc.dispose(); + + // preferred size of controls in tab items + for (int i = 0; i < items.length; i++) { + Control control = items[i].getControl(); + if (control != null && !control.isDisposed()){ + Point size = control.computeSize (wHint, hHint); + minWidth = Math.max (minWidth, size.x); + minHeight = Math.max (minHeight, size.y); + } + } + if (minWidth == 0) minWidth = DEFAULT_WIDTH; + if (minHeight == 0) minHeight = DEFAULT_HEIGHT; + + if (wHint != SWT.DEFAULT) minWidth = wHint; + if (hHint != SWT.DEFAULT) minHeight = hHint; + + Rectangle trim = computeTrim(0, 0, minWidth, minHeight); + return new Point (trim.width, trim.height); +} +public Rectangle computeTrim (int x, int y, int width, int height) { + checkWidget(); + if (items.length == 0) { + if (!showBorders) return new Rectangle(x, y, width, height); + int trimX = x - borderRight - 1; + int trimY = y - borderBottom - 1; + int trimWidth = width + borderRight + 2; + int trimHeight = height + borderBottom + 2; + return new Rectangle (trimX, trimY, trimWidth, trimHeight); + } else { + int trimX = x - marginWidth - borderLeft; + int trimY = y - marginHeight - tabHeight - borderTop - 1; + // -1 is for the line at the bottom of the tabs + if (onBottom) { + trimY = y - marginHeight - borderTop; + } + int trimWidth = width + borderLeft + borderRight + 2*marginWidth; + int trimHeight = height + borderTop + borderBottom + 2*marginHeight + tabHeight + 1; + return new Rectangle (trimX, trimY, trimWidth, trimHeight); + } +} +/** + * Create the specified item at 'index'. + */ +void createItem (CTabItem item, int index) { + if (0 > index || index > getItemCount ()){ + SWT.error (SWT.ERROR_INVALID_RANGE); + } + // grow by one and rearrange the array. + CTabItem[] newItems = new CTabItem [items.length + 1]; + System.arraycopy(items, 0, newItems, 0, index); + newItems[index] = item; + System.arraycopy(items, index, newItems, index + 1, items.length - index); + items = newItems; + + item.parent = this; + + if (selectedIndex >= index) { + selectedIndex ++; + } + if (items.length == 1) { + topTabIndex = 0; + resetTabSize(true); + } else { + setItemBounds(); + showItem(item); + } + + if (items.length == 1) { + redraw(); + } else { + redrawTabArea(-1); + } +} + +private void createArrowBar() { + // create arrow buttons for scrolling + arrowBar = new ToolBar(this, SWT.FLAT); + arrowBar.setVisible(false); + arrowBar.setBackground(background); + ToolItem scrollLeft = new ToolItem(arrowBar, SWT.PUSH); + scrollLeft.setEnabled(false); + ToolItem scrollRight = new ToolItem(arrowBar, SWT.PUSH); + scrollRight.setEnabled(false); + + scrollLeft.addListener(SWT.Selection, new Listener() { + public void handleEvent(Event event) { + scroll_scrollLeft(); + } + }); + scrollRight.addListener(SWT.Selection, new Listener() { + public void handleEvent(Event event) { + scroll_scrollRight(); + } + }); + +} +private void createCloseBar() { + closeBar = new ToolBar(this, SWT.FLAT); + closeBar.setVisible(false); + if (gradientColors != null && gradientColors.length > 0) { + closeBar.setBackground(gradientColors[gradientColors.length - 1]); + } else { + closeBar.setBackground(background); + } + ToolItem closeItem = new ToolItem(closeBar, SWT.PUSH); + + inactiveCloseBar = new ToolBar(this, SWT.FLAT); + inactiveCloseBar.setVisible(false); + inactiveCloseBar.setBackground(background); + ToolItem inactiveCloseItem = new ToolItem(inactiveCloseBar, SWT.PUSH); + + closeItem.addListener(SWT.Selection, new Listener() { + public void handleEvent(Event event) { + closeNotify(getSelection(), event.time); + } + }); + inactiveCloseItem.addListener(SWT.Selection, new Listener() { + public void handleEvent(Event event) { + closeNotify(inactiveItem, event.time); + inactiveCloseBar.setVisible(false); + inactiveItem = null; + } + }); + inactiveCloseBar.addListener (SWT.MouseExit, new Listener() { + public void handleEvent(Event event) { + if (inactiveItem != null) { + Rectangle itemBounds = inactiveItem.getBounds(); + if (itemBounds.contains(event.x, event.y)) return; + } + inactiveCloseBar.setVisible(false); + inactiveItem = null; + } + }); + +} +/** + * Destroy the specified item. + */ +void destroyItem (CTabItem item) { + if (inDispose) return; + + int index = indexOf(item); + if (index == -1) return; // should this trigger an error? + + insertionIndex = -2; + + if (items.length == 1) { + items = new CTabItem[0]; + selectedIndex = -1; + topTabIndex = 0; + + Control control = item.getControl(); + if (control != null && !control.isDisposed()) { + control.setVisible(false); + } + closeBar.setVisible(false); + if (!fixedTabHeight) tabHeight = 0; + redraw(); + return; + } + + // shrink by one and rearrange the array. + CTabItem[] newItems = new CTabItem [items.length - 1]; + System.arraycopy(items, 0, newItems, 0, index); + System.arraycopy(items, index + 1, newItems, index, items.length - index - 1); + items = newItems; + + if (topTabIndex == items.length) { + --topTabIndex; + } + + // move the selection if this item is selected + if (selectedIndex == index) { + Control control = item.getControl(); + if (control != null && !control.isDisposed()) { + control.setVisible(false); + } + selectedIndex = -1; + setSelection(Math.max(0, index - 1), true); + } else if (selectedIndex > index) { + selectedIndex --; + } + + setItemBounds(); + redrawTabArea(-1); +} +private void onKeyDown(Event e) { + if (e.keyCode == SWT.ARROW_LEFT) { + if (selectedIndex > 0) { + setSelection(selectedIndex - 1, true); + } + } + if (e.keyCode == SWT.ARROW_RIGHT) { + if (selectedIndex < items.length - 1) { + setSelection(selectedIndex + 1, true); + } + } +} +/** + * Dispose the items of the receiver + */ +private void onDispose() { + /* + * Usually when an item is disposed, destroyItem will change the size of the items array, + * reset the bounds of all the tabs and manage the widget associated with the tab. + * Since the whole folder is being disposed, this is not necessary. For speed + * the inDispose flag is used to skip over this part of the item dispose. + */ + inDispose = true; + + int length = items.length; + for (int i = 0; i < length; i++) { + if (items[i] != null) { + items[i].dispose(); + } + } + + // clean up resources + if (tip != null && !tip.isDisposed()) { + tip.dispose(); + tip = null; + label = null; + } + + if (arrowLeftImage != null) arrowLeftImage.dispose(); + arrowLeftImage = null; + if (arrowRightImage != null) arrowRightImage.dispose(); + arrowRightImage = null; + if (closeImage != null) closeImage.dispose(); + closeImage = null; + + gradientColors = null; + gradientPercents = null; + backgroundImage = null; + + if (borderColor1 != null) borderColor1.dispose(); + borderColor1 = null; + + if (borderColor2 != null) borderColor2.dispose(); + borderColor2 = null; + + if (borderColor3 != null) borderColor3.dispose(); + borderColor3 = null; +} +private void onFocus(Event e) { + checkWidget(); + if (selectedIndex >= 0) { + redrawTabArea(selectedIndex); + } else { + setSelection(0, true); + } +} +/** + * Draw a border around the receiver. + */ +private void drawBorder(GC gc) { + + Rectangle d = super.getClientArea(); + + if (showBorders) { + if ((getStyle() & SWT.FLAT) != 0) { + gc.setForeground(borderColor1); + gc.drawRectangle(d.x, d.y, d.x + d.width - 1, d.y + d.height - 1); + } else { + gc.setForeground(borderColor1); + gc.drawRectangle(d.x, d.y, d.x + d.width - 3, d.y + d.height - 3); + + gc.setForeground(borderColor2); + gc.drawLine(d.x + 1, d.y + d.height - 2, d.x + d.width - 1, d.y + d.height - 2); + gc.drawLine(d.x + d.width - 2, d.y + 1, d.x + d.width - 2, d.y + d.height - 1); + + gc.setForeground(borderColor3); + gc.drawLine(d.x + 2, d.y + d.height - 1, d.x + d.width - 2, d.y + d.height - 1); + gc.drawLine(d.x + d.width - 1, d.y + 2, d.x + d.width - 1, d.y + d.height - 2); + + // fill in corners with parent's background + gc.setForeground(getParent().getBackground()); + gc.drawLine(d.x + d.width - 2, d.y, d.x + d.width - 1, d.y); + gc.drawLine(d.x + d.width - 1, d.y + 1, d.x + d.width - 1, d.y + 1); + + gc.drawLine(d.x, d.y + d.height - 2, d.x, d.y + d.height - 2); + gc.drawLine(d.x, d.y + d.height - 1, d.x + 1, d.y + d.height - 1); + + gc.drawLine(d.x + d.width - 1, d.y + d.height - 1, d.x + d.width - 1, d.y + d.height - 1); + } + + } + + // draw a separator line + if (items.length > 0) { + int lineY = d.y + borderTop + tabHeight; + if (onBottom) { + lineY = d.y + d.height - borderBottom - tabHeight - 1; + } + gc.setForeground(borderColor1); + gc.drawLine(d.x + borderLeft, lineY, d.x + d.width - borderRight, lineY); + } + + gc.setForeground(getForeground()); +} +public Rectangle getClientArea() { + checkWidget(); + Point size = getSize(); + if (items.length == 0) { + if (!showBorders) return super.getClientArea(); + int width = size.x - borderRight - 2; + int height = size.y - borderBottom - 2; + return new Rectangle(borderRight + 1, borderBottom + 1, width, height); + } else { + int width = size.x - 2*marginWidth - borderLeft - borderRight; + int height = size.y - 2*marginHeight - borderTop - borderBottom - tabHeight - 1; + return new Rectangle(xClient, yClient, width, height); + } +} +/** + * Returns the height of the tab + * + * @return the height of the tab + * + * @exception SWTError <ul> + * <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li> + * <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li> + * </ul> + */ +public int getTabHeight(){ + checkWidget(); + return tabHeight; +} + +/** + * Return the tab that is located at the specified index. + * + * @return the item at the specified index + */ +public CTabItem getItem (int index) { + //checkWidget(); + if (index < 0 || index >= items.length) + SWT.error(SWT.ERROR_INVALID_RANGE); + return items [index]; +} +/** +* Gets the item at a point in the widget. +* <p> +* +* @return the item at a point +*/ +public CTabItem getItem (Point pt) { + //checkWidget(); + if (items.length == 0) return null; + int lastItem = getLastItem(); + lastItem = Math.min(items.length - 1, lastItem + 1); + for (int i = topTabIndex; i <= lastItem; i++) { + Rectangle bounds = items[i].getBounds(); + if (bounds.contains(pt)) return items[i]; + } + return null; +} +/** + * Return the number of tabs in the folder. + * + * @return the number of tabs in the folder + */ +public int getItemCount(){ + //checkWidget(); + return items.length; +} +/** + * Return the tab items. + * + * @return the tab items + */ +public CTabItem [] getItems() { + //checkWidget(); + CTabItem[] tabItems = new CTabItem [items.length]; + System.arraycopy(items, 0, tabItems, 0, items.length); + return tabItems; +} + +private int getLastItem(){ + if (items.length == 0) return -1; + Rectangle area = getClientArea(); + if (area.width <= 0) return 0; + Rectangle toolspace = getToolSpace(); + if (toolspace.width == 0) return items.length -1; + int width = area.width - toolspace.width; + int index = topTabIndex; + int tabWidth = items[index].width; + while (index < items.length - 1) { + tabWidth += items[index + 1].width; + if (tabWidth > width) break; + index++; + } + return index; +} +/** + * Return the selected tab item, or an empty array if there + * is no selection. + * + * @return the selected tab item + */ +public CTabItem getSelection() { + //checkWidget(); + if (selectedIndex == -1) return null; + return items[selectedIndex]; +} +/** + * Return the index of the selected tab item, or -1 if there + * is no selection. + * + * @return the index of the selected tab item or -1 + */ +public int getSelectionIndex() { + //checkWidget(); + return selectedIndex; +} +private Rectangle getToolSpace() { + boolean showArrows = scroll_leftVisible() || scroll_rightVisible(); + if (!showArrows && topRight == null) return new Rectangle(0, 0, 0, 0); + Rectangle toolspace; + if (showArrows) { + toolspace = arrowBar.getBounds(); + toolspace.width += borderRight; + if (topRight != null) toolspace.width += topRight.getSize().x; + } else { + toolspace = topRight.getBounds(); + toolspace.width += borderRight; + } + return toolspace; +} +/** + * Returns the control in the top right corner of the tab folder. + * Typically this is a close button or a composite with a menu and close button. + * + * @since 2.1 + * + * @return the control in the top right corner of the tab folder or null + * + * @exception SWTError <ul> + * <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li> + * <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li> + * </ul> + */ +public Control getTopRight() { + checkWidget(); + return topRight; +} + +/** + * Return the index of the specified tab or -1 if the tab is not + * in the receiver. + * + * @return the index of the specified tab item or -1 + * + * @exception SWTError <ul> + * <li>ERROR_NULL_ARGUMENT when the item is null</li> + * </ul> + */ +public int indexOf(CTabItem item) { + //checkWidget(); + if (item == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + for (int i = 0; i < items.length; i++) { + if (items[i] == item) return i; + } + return -1; +} + +private void initAccessible() { + final Accessible accessible = getAccessible(); + accessible.addAccessibleListener(new AccessibleAdapter() { + public void getName(AccessibleEvent e) { + String name = null; + int childID = e.childID; + if (childID >= 0 && childID < items.length) { + name = items[childID].getText(); + int index = name.indexOf('&'); + if (index > 0) { + name = name.substring(0, index) + name.substring(index + 1); + } + } + e.result = name; + } + + public void getHelp(AccessibleEvent e) { + String help = null; + int childID = e.childID; + if (childID == ACC.CHILDID_SELF) { + help = getToolTipText(); + } else if (childID >= 0 && childID < items.length) { + help = items[childID].getToolTipText(); + } + e.result = help; + } + + public void getKeyboardShortcut(AccessibleEvent e) { + String shortcut = null; + int childID = e.childID; + if (childID >= 0 && childID < items.length) { + String text = items[childID].getText(); + if (text != null) { + char mnemonic = getMnemonic(text); + if (mnemonic != '\0') { + shortcut = "Alt+"+mnemonic; //$NON-NLS-1$ + } + } + } + e.result = shortcut; + } + }); + + accessible.addAccessibleControlListener(new AccessibleControlAdapter() { + public void getChildAtPoint(AccessibleControlEvent e) { + Point testPoint = toControl(new Point(e.x, e.y)); + int childID = ACC.CHILDID_NONE; + for (int i = 0; i < items.length; i++) { + if (items[i].getBounds().contains(testPoint)) { + childID = i; + break; + } + } + if (childID == ACC.CHILDID_NONE) { + Rectangle location = getBounds(); + location.height = location.height - getClientArea().height; + if (location.contains(testPoint)) { + childID = ACC.CHILDID_SELF; + } + } + e.childID = childID; + } + + + public void getLocation(AccessibleControlEvent e) { + Rectangle location = null; + int childID = e.childID; + if (childID == ACC.CHILDID_SELF) { + location = getBounds(); + } + if (childID >= 0 && childID < items.length) { + location = items[childID].getBounds(); + } + if (location != null) { + 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 = items.length; + } + + public void getDefaultAction(AccessibleControlEvent e) { + String action = null; + int childID = e.childID; + if (childID >= 0 && childID < items.length) { + action = "Switch"; //$NON-NLS-1$ + } + e.result = action; + } + + public void getFocus(AccessibleControlEvent e) { + int childID = ACC.CHILDID_NONE; + if (isFocusControl()) { + if (selectedIndex == -1) { + childID = ACC.CHILDID_SELF; + } else { + childID = selectedIndex; + } + } + e.childID = childID; + } + + public void getRole(AccessibleControlEvent e) { + int role = 0; + int childID = e.childID; + if (childID == ACC.CHILDID_SELF) { + role = ACC.ROLE_TABFOLDER; + } else if (childID >= 0 && childID < items.length) { + role = ACC.ROLE_TABITEM; + } + e.detail = role; + } + + public void getSelection(AccessibleControlEvent e) { + e.childID = (selectedIndex == -1) ? ACC.CHILDID_NONE : selectedIndex; + } + + public void getState(AccessibleControlEvent e) { + int state = 0; + int childID = e.childID; + if (childID == ACC.CHILDID_SELF) { + state = ACC.STATE_NORMAL; + } else if (childID >= 0 && childID < items.length) { + state = ACC.STATE_SELECTABLE; + if (isFocusControl()) { + state |= ACC.STATE_FOCUSABLE; + } + if (selectedIndex == childID) { + state |= ACC.STATE_SELECTED; + if (isFocusControl()) { + state |= ACC.STATE_FOCUSED; + } + } + } + e.detail = state; + } + + public void getChildren(AccessibleControlEvent e) { + Object[] children = new Object[items.length]; + for (int i = 0; i < items.length; i++) { + children[i] = new Integer(i); + } + e.children = children; + } + }); + + addListener(SWT.Selection, new Listener() { + public void handleEvent(Event event) { + if (isFocusControl()) { + if (selectedIndex == -1) { + accessible.setFocus(ACC.CHILDID_SELF); + } else { + accessible.setFocus(selectedIndex); + } + } + } + }); + + addListener(SWT.FocusIn, new Listener() { + public void handleEvent(Event event) { + if (selectedIndex == -1) { + accessible.setFocus(ACC.CHILDID_SELF); + } else { + accessible.setFocus(selectedIndex); + } + } + }); +} + +private void setButtonBounds() { + + updateArrowBar(); + updateCloseBar(); + + Rectangle area = super.getClientArea(); + + int offset = 0; + if (topRight != null) { + Point size = topRight.computeSize(SWT.DEFAULT, tabHeight); + int x = area.x + area.width - borderRight - size.x; + int y = onBottom ? area.y + area.height - borderBottom - size.y : area.y + borderTop; + topRight.setBounds(x, y, size.x, size.y); + offset = size.x; + } + boolean leftVisible = scroll_leftVisible(); + boolean rightVisible = scroll_rightVisible(); + if (leftVisible || rightVisible) { + Point size = arrowBar.computeSize(SWT.DEFAULT, tabHeight); + int x = area.x + area.width - borderRight - size.x - offset; + int y = (onBottom) ? area.y + area.height - borderBottom - size.y : area.y + borderTop; + + arrowBar.setBounds(x, y, size.x, size.y); + ToolItem[] items = arrowBar.getItems(); + items[0].setEnabled(leftVisible); + items[1].setEnabled(rightVisible); + arrowBar.setVisible(true); + } else { + arrowBar.setVisible(false); + } + + // When the close button is right at the edge of the Tab folder, hide it because + // otherwise it may block off a part of the border on the right + if (showClose) { + inactiveCloseBar.setVisible(false); + CTabItem item = getSelection(); + if (item == null) { + closeBar.setVisible(false); + } else { + int toolbarHeight = tabHeight - CTabItem.TOP_MARGIN - CTabItem.BOTTOM_MARGIN + 2; // +2 to ignore gap between focus rectangle + Point size = closeBar.computeSize(SWT.DEFAULT, toolbarHeight); + int x = item.x + item.width - size.x - 2; // -2 to not overlap focus rectangle and trim + int y = item.y + Math.max(0, (item.height - toolbarHeight)/2); + closeBar.setBounds(x, y, size.x, toolbarHeight); + Rectangle toolspace = getToolSpace(); + Point folderSize = getSize(); + boolean visible = (toolspace.width == 0 || x < toolspace.x) && x + size.x < folderSize.x - borderRight; + closeBar.setVisible(visible); + } + } +} +private boolean setItemLocation() { + if (items.length == 0) return false; + Rectangle area = super.getClientArea(); + int x = area.x; + int y = area.y + borderTop; + if (onBottom) y = Math.max(0, area.y + area.height - borderBottom - tabHeight); + + boolean changed = false; + for (int i = topTabIndex - 1; i>=0; i--) { + // if the first visible tab is not the first tab + CTabItem tab = items[i]; + x -= tab.width; + if (!changed && (tab.x != x || tab.y != y) ) changed = true; + // layout tab items from right to left thus making them invisible + tab.x = x; + tab.y = y; + } + + x = area.x + borderLeft; + for (int i = topTabIndex; i < items.length; i++) { + // continue laying out remaining, visible items left to right + CTabItem tab = items[i]; + tab.x = x; + tab.y = y; + x = x + tab.width; + } + setButtonBounds(); + return changed; +} +private void setLastItem(int index) { + if (index < 0 || index > items.length - 1) return; + Rectangle area = getClientArea(); + if (area.width <= 0) return; + int maxWidth = area.width; + Rectangle toolspace = getToolSpace(); + if (toolspace.width > 0){ + maxWidth -= toolspace.width; + } + int tabWidth = items[index].width; + while (index > 0) { + tabWidth += items[index - 1].width; + if (tabWidth > maxWidth) break; + index--; + } + topTabIndex = index; + setItemLocation(); + redrawTabArea(-1); +} +/** + * Layout the items and store the client area size. + */ +boolean setItemBounds() { + boolean changed = false; + if (isDisposed()) return changed; + Rectangle area = super.getClientArea(); + + xClient = area.x + borderLeft + marginWidth; + if (onBottom) { + yClient = area.y + borderTop + marginHeight; + } else { + yClient = area.y + borderTop + tabHeight + 1 + marginHeight; + // +1 is for the line at the bottom of the tabs + } + + if (area.width <= 0 || area.height <= 0 || items.length == 0) return changed; + + int[] widths = new int[items.length]; + GC gc = new GC(this); + for (int i = 0; i < items.length; i++) { + widths[i] = items[i].preferredWidth(gc); + } + gc.dispose(); + + int oldAverageWidth = 0; + int averageWidth = (area.width - borderLeft - borderRight) / items.length; + while (averageWidth > oldAverageWidth) { + int width = area.width - borderLeft - borderRight; + int count = items.length; + for (int i = 0; i < items.length; i++) { + if (widths[i] < averageWidth) { + width -= widths[i]; + count--; + } + } + oldAverageWidth = averageWidth; + if (count > 0) { + averageWidth = width / count; + } + } + averageWidth = Math.max(averageWidth, MIN_TAB_WIDTH * tabHeight); + for (int i = 0; i < items.length; i++) { + if (widths[i] > averageWidth) { + widths[i] = averageWidth; + } + } + + int totalWidth = 0; + for (int i = 0; i < items.length; i++) { + CTabItem tab = items[i]; + if (tab.height != tabHeight || tab.width != widths[i]) changed = true; + tab.height = tabHeight; + tab.width = widths[i]; + totalWidth += widths[i]; + } + + int areaWidth = area.x + area.width - borderRight; + if (totalWidth <= areaWidth) { + topTabIndex = 0; + } + if (setItemLocation()) changed = true; + + // Is there a gap after last item showing + if (correctLastItem()) changed = true; + return changed; +} +private boolean onMnemonic (Event event) { + char key = event.character; + for (int i = 0; i < items.length; i++) { + if (items[i] != null) { + char mnemonic = getMnemonic (items[i].getText ()); + if (mnemonic != '\0') { + if (Character.toUpperCase (key) == Character.toUpperCase (mnemonic)) { + setSelection(i, true); + return true; + } + } + } + } + return false; +} +/** + * Paint the receiver. + */ +private void onPaint(Event event) { + Font font = getFont(); + if (oldFont == null || !oldFont.equals(font)) { + oldFont = font; + resetTabSize(true); + } + GC gc = event.gc; + Rectangle rect = super.getClientArea(); + if (items.length == 0) { + if (showBorders) { + if ((getStyle() & SWT.FLAT) != 0) { + gc.setForeground(borderColor1); + gc.drawRectangle(rect.x, rect.y, rect.x + rect.width - 1, rect.y + rect.height - 1); + } else { + gc.setForeground(borderColor1); + gc.drawRectangle(rect.x, rect.y, rect.x + rect.width - 3, rect.y + rect.height - 3); + + // fill in right and bottom edges with parent's background + gc.setBackground(getParent().getBackground()); + gc.fillRectangle(rect.x + rect.width - 2, rect.y, 2, rect.height); + gc.fillRectangle(rect.x, rect.y + rect.height - 2, rect.width, 2); + } + gc.setForeground(getForeground()); + } + return; + } + + // redraw the Border + drawBorder(gc); + + rect.x += borderLeft; + rect.y += borderTop; + rect.width -= borderLeft + borderRight; + rect.height -= borderTop + borderBottom; + Rectangle clip = gc.getClipping (); + gc.setClipping(clip.intersection(rect)); + + // Draw the unselected tabs first. + for (int i=0; i < items.length; i++) { + if (i != selectedIndex && event.getBounds().intersects(items[i].getBounds())) { + items[i].onPaint(gc, false); + } + } + // Selected tab comes last + if (selectedIndex != -1) { + items[selectedIndex].onPaint(gc, true); + } + + // draw insertion mark + if (insertionIndex > -2) { + gc.setForeground(getDisplay().getSystemColor(SWT.COLOR_LIST_SELECTION)); + if (insertionIndex == -1) { + Rectangle bounds = items[0].getBounds(); + gc.drawLine(bounds.x, bounds.y, bounds.x, bounds.y + bounds.height - 1); + gc.drawLine(bounds.x - 2, bounds.y, bounds.x + 2, bounds.y); + gc.drawLine(bounds.x - 1, bounds.y + 1, bounds.x + 1, bounds.y + 1); + gc.drawLine(bounds.x - 1, bounds.y + bounds.height - 2, bounds.x + 1, bounds.y + bounds.height - 2); + gc.drawLine(bounds.x - 2, bounds.y + bounds.height - 1, bounds.x + 2, bounds.y + bounds.height - 1); + + } else { + Rectangle bounds = items[insertionIndex].getBounds(); + gc.drawLine(bounds.x + bounds.width, bounds.y, bounds.x + bounds.width, bounds.y + bounds.height - 1); + gc.drawLine(bounds.x + bounds.width - 2, bounds.y, bounds.x + bounds.width + 2, bounds.y); + gc.drawLine(bounds.x + bounds.width - 1, bounds.y + 1, bounds.x + bounds.width + 1, bounds.y + 1); + gc.drawLine(bounds.x + bounds.width - 1, bounds.y + bounds.height - 2, bounds.x + bounds.width + 1, bounds.y + bounds.height - 2); + gc.drawLine(bounds.x + bounds.width - 2, bounds.y + bounds.height - 1, bounds.x + bounds.width + 2, bounds.y + bounds.height - 1); + } + } + + gc.setForeground(getForeground()); + gc.setBackground(getBackground()); +} +private void redrawTabArea(int index) { + int x = 0, y = 0, width = 0, height = 0; + if (index == -1) { + Rectangle area = super.getClientArea(); + if (area.width == 0 || area.height == 0) return; + width = area.x + area.width - borderLeft - borderRight; + height = tabHeight + 1; // +1 causes top line between content and tabs to be redrawn + x = area.x + borderLeft; + y = area.y + borderTop; + if (onBottom) { + y = Math.max(0, area.y + area.height - borderBottom - height); + } + } else { + CTabItem item = items[index]; + x = item.x; + y = item.y; + Rectangle area = super.getClientArea(); + width = area.x + area.width - x; + height = item.height; + } + redraw(x, y, width, height, false); +} + +/** + * Removes the listener. + * + * @param listener the listener + * + * @exception SWTError + * <ul><li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li> + * <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li> + * <li>ERROR_NULL_ARGUMENT when listener is null</li></ul> + */ +public void removeSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + removeListener(SWT.Selection, listener); + removeListener(SWT.DefaultSelection, listener); +} +/** + * Removes the listener. + * + * @param listener the listener + * + * @exception SWTError + * <ul><li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li> + * <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li> + * <li>ERROR_NULL_ARGUMENT when listener is null</li></ul> + */ +public void removeCTabFolderListener(CTabFolderListener listener) { + checkWidget(); + if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT); + if (tabListeners.length == 0) return; + int index = -1; + for (int i = 0; i < tabListeners.length; i++) { + if (listener == tabListeners[i]){ + index = i; + break; + } + } + if (index == -1) return; + if (tabListeners.length == 1) { + tabListeners = new CTabFolderListener[0]; + showClose = false; + setButtonBounds(); + return; + } + CTabFolderListener[] newTabListeners = new CTabFolderListener[tabListeners.length - 1]; + System.arraycopy(tabListeners, 0, newTabListeners, 0, index); + System.arraycopy(tabListeners, index + 1, newTabListeners, index, tabListeners.length - index - 1); + tabListeners = newTabListeners; +} + +/** + * The widget was resized. Adjust the size of the currently selected page. + */ +private void onResize() { + + if (items.length == 0) { + redraw(); + return; + } + + if (setItemBounds()) { + redrawTabArea(-1); + } + + Point size = getSize(); + if (oldSize == null) { + redraw(); + } else { + if (onBottom && size.y != oldSize.y) { + redraw(); + } else { + int x1 = Math.min(size.x, oldSize.x); + if (size.x != oldSize.x) x1 -= 10; + int y1 = Math.min(size.y, oldSize.y); + if (size.y != oldSize.y) y1 -= 10; + int x2 = Math.max(size.x, oldSize.x); + int y2 = Math.max(size.y, oldSize.y); + redraw(0, y1, x2 + 10, y2 - y1, false); + redraw(x1, 0, x2 - x1, y2, false); + } + } + oldSize = size; + + // resize content + if (selectedIndex != -1) { + Control control = items[selectedIndex].getControl(); + if (control != null && !control.isDisposed()) { + control.setBounds(getClientArea()); + } + } +} + +public void setBackground (Color color) { + super.setBackground(color); + background = color; + // init inactive close button + inactiveCloseBar.setBackground(color); + + // init scroll buttons + arrowBar.setBackground(color); + + //init topRight control + if (topRight != null) + topRight.setBackground(color); + + // init close button + if (gradientColors == null) { + closeBar.setBackground(color); + } +} +/** + * Specify a gradient of colours to be draw in the background of the selected tab. + * For example to draw a gradient that varies from dark blue to blue and then to + * white, use the following call to setBackground: + * <pre> + * cfolder.setBackground(new Color[]{display.getSystemColor(SWT.COLOR_DARK_BLUE), + * display.getSystemColor(SWT.COLOR_BLUE), + * display.getSystemColor(SWT.COLOR_WHITE), + * display.getSystemColor(SWT.COLOR_WHITE)}, + * new int[] {25, 50, 100}); + * </pre> + * + * @param colors an array of Color that specifies the colors to appear in the gradient + * in order of appearance left to right. The value <code>null</code> clears the + * background gradient. The value <code>null</code> can be used inside the array of + * Color to specify the background color. + * @param percents an array of integers between 0 and 100 specifying the percent of the width + * of the widget at which the color should change. The size of the percents array must be one + * less than the size of the colors array. + * + * @exception SWTError <ul> + * <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li> + * <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li> + * </ul> + */ + +public void setSelectionBackground(Color[] colors, int[] percents) { + checkWidget(); + if (colors != null) { + if (percents == null || percents.length != colors.length - 1) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + if (getDisplay().getDepth() < 15) { + // Don't use gradients on low color displays + colors = new Color[] { colors[0] }; + percents = new int[] { }; + } + for (int i = 0; i < percents.length; i++) { + if (percents[i] < 0 || percents[i] > 100) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + if (i > 0 && percents[i] < percents[i-1]) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + } + } + + // Are these settings the same as before? + if (backgroundImage == null) { + if ((gradientColors != null) && (colors != null) && + (gradientColors.length == colors.length)) { + boolean same = false; + for (int i = 0; i < gradientColors.length; i++) { + if (gradientColors[i] == null) { + same = colors[i] == null; + } else { + same = gradientColors[i].equals(colors[i]); + } + if (!same) break; + } + if (same) { + for (int i = 0; i < gradientPercents.length; i++) { + same = gradientPercents[i] == percents[i]; + if (!same) break; + } + } + if (same) return; + } + } else { + backgroundImage = null; + } + // Store the new settings + if (colors == null) { + gradientColors = null; + gradientPercents = null; + closeBar.setBackground(background); + } else { + gradientColors = new Color[colors.length]; + for (int i = 0; i < colors.length; ++i) + gradientColors[i] = colors[i]; + gradientPercents = new int[percents.length]; + for (int i = 0; i < percents.length; ++i) + gradientPercents[i] = percents[i]; + if (getDisplay().getDepth() < 15) closeBar.setBackground(background); + else closeBar.setBackground(gradientColors[gradientColors.length - 1]); + } + + // Refresh with the new settings + if (selectedIndex > -1) redrawTabArea(selectedIndex); +} + +/** + * Set the image to be drawn in the background of the selected tab. + * + * @param image the image to be drawn in the background + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void setSelectionBackground(Image image) { + checkWidget(); + if (image == backgroundImage) return; + if (image != null) { + gradientColors = null; + gradientPercents = null; + } + backgroundImage = image; + redrawTabArea(selectedIndex); +} +/** + * Toggle the visibility of the border + * + * @param show true if the border should be displayed + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void setBorderVisible(boolean show) { + checkWidget(); + if (showBorders == show) return; + + showBorders = show; + if (showBorders) { + if ((getStyle() & SWT.FLAT) != 0) { + borderBottom = borderTop = borderLeft = borderRight = 1; + } else { + borderLeft = borderTop = 1; + borderRight = borderBottom = 3; + } + } else { + borderBottom = borderTop = borderLeft = borderRight = 0; + } + oldSize = null; + notifyListeners(SWT.Resize, new Event()); +} +public void setFont(Font font) { + checkWidget(); + if (font != null && font.equals(getFont())) return; + super.setFont(font); + oldFont = getFont(); + resetTabSize(true); +} +/** + * Set the foreground color of the selected tab. + * + * @param color the color of the text displayed in the selected tab + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void setSelectionForeground (Color color) { + checkWidget(); + if (selectionForeground == color) return; + if (color == null) color = getForeground(); + selectionForeground = color; + if (selectedIndex > -1) { + redrawTabArea(selectedIndex); + } +} +/** + * Display an insert marker before or after the specified tab item. + * Null will clear the mark. + * + * @param item the item with which the mark is associated or null + * + * @param after true if the mark should be displayed after the specified item + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void setInsertMark(CTabItem item, boolean after) { + checkWidget(); + int index = -1; + if (item != null) { + index = indexOf(item); + } + setInsertMark(index, after); +} +/** + * Display an insert marker before or after the specified tab item. + * -1 will clear the mark. + * + * @param item the index of the item with which the mark is associated or null + * + * @param after true if the mark should be displayed after the specified item + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void setInsertMark(int index, boolean after) { + checkWidget(); + if (index < -1 || index >= getItemCount()) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + + if (index == -1) { + index = -2; + } else { + index = after ? index : --index; + } + + if (insertionIndex == index) return; + int oldIndex = insertionIndex; + insertionIndex = index; + if (index > -1) redrawTabArea(index); + if (oldIndex > 1) redrawTabArea(oldIndex); +} + +/** + * Set the selection to the tab at the specified index. + * + * @param index the index of the tab item to be selected + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void setSelection(int index) { + checkWidget(); + if (index < 0 || index >= items.length) return; + if (selectedIndex == index) return; + + int oldIndex = selectedIndex; + selectedIndex = index; + + Control control = items[index].control; + if (control != null && !control.isDisposed()) { + control.setBounds(getClientArea()); + control.setVisible(true); + } + + if (oldIndex != -1) { + control = items[oldIndex].control; + if (control != null && !control.isDisposed()) { + control.setVisible(false); + } + } + showItem(items[selectedIndex]); + setButtonBounds(); + redrawTabArea(-1); +} +/** + * Set the control that appears in the top right corner of the tab folder. + * Typically this is a close button or a composite with a Menu and close button. + * The topRight control is optional. Setting the top right control to null will remove it from the tab folder. + * + * @since 2.1 + * + * @param control the control to be displayed in the top right corner or null + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * <li>ERROR_INVALID_ARGUMENT - if the control is not a child of this CTabFolder</li> + * </ul> + */ +public void setTopRight(Control control) { + checkWidget(); + if (control != null && control.getParent() != this) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + topRight = control; + resetTabSize(true); +} + +/** + * Shows the item. If the item is already showing in the receiver, + * this method simply returns. Otherwise, the items are scrolled until + * the item is visible. + * + * @param item the item to be shown + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the item is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @see CTabFolder#showSelection() + * + * @since 2.0 + */ +public void showItem (CTabItem item) { + checkWidget(); + if (item == null) SWT.error (SWT.ERROR_NULL_ARGUMENT); + if (item.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + + int index = indexOf(item); + if (index < topTabIndex) { + topTabIndex = index; + setItemLocation(); + redrawTabArea(-1); + return; + } + Rectangle area = getClientArea(); + if (area.width <= 0) { + topTabIndex = index; + return; + } + int rightEdge = area.x + area.width; + Rectangle rect = getToolSpace(); + if (rect.width > 0) { + rightEdge -= rect.width; + } + if (item.x + item.width < rightEdge) return; + setLastItem(index); +} +/** + * Shows the selection. If the selection is already showing in the receiver, + * this method simply returns. Otherwise, the items are scrolled until + * the selection is visible. + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @see CTabFolder#showItem(CTabItem) + * + * @since 2.0 + * + */ +public void showSelection () { + checkWidget (); + if (selectedIndex != -1) { + showItem(getSelection()); + } +} + +char getMnemonic (String string) { + int index = 0; + int length = string.length (); + do { + while ((index < length) && (string.charAt (index) != '&')) index++; + if (++index >= length) return '\0'; + if (string.charAt (index) != '&') return string.charAt (index); + index++; + } while (index < length); + return '\0'; +} +/** + * Set the selection to the tab at the specified item. + * + * @param index the tab item to be selected + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * <li>ERROR_NULL_ARGUMENT - if argument is null</li> + * </ul> + */ +public void setSelection(CTabItem item) { + checkWidget(); + if (item == null) + SWT.error(SWT.ERROR_NULL_ARGUMENT); + int index = indexOf(item); + setSelection(index); +} +/** + * Set the selection to the tab at the specified index. + */ +private void setSelection(int index, boolean notify) { + int oldSelectedIndex = selectedIndex; + setSelection(index); + if (notify && selectedIndex != oldSelectedIndex && selectedIndex != -1) { + Event event = new Event(); + event.item = getItem(selectedIndex); + notifyListeners(SWT.Selection, event); + } +} + +private void updateCloseBar() { + int imageHeight = tabHeight - CTabItem.TOP_MARGIN - CTabItem.BOTTOM_MARGIN - 4; + if (imageHeight < 8) return; + + if (closeImage != null && closeImage.getBounds().height == imageHeight) return; + + if (closeBar != null) closeBar.dispose(); + closeBar = null; + if (inactiveCloseBar != null) inactiveCloseBar.dispose(); + inactiveCloseBar = null; + createCloseBar(); + + ToolItem closeItem = closeBar.getItems()[0]; + ToolItem inactiveCloseItem = inactiveCloseBar.getItems()[0]; + + if (closeImage != null) closeImage.dispose(); + + Display display = getDisplay(); + Color foreground = getForeground(); + Color black = display.getSystemColor(SWT.COLOR_BLACK); + Color background = getBackground(); + + PaletteData palette = new PaletteData(new RGB[]{foreground.getRGB(), background.getRGB(), black.getRGB()}); + ImageData imageData = new ImageData(imageHeight, imageHeight, 4, palette); + imageData.transparentPixel = 1; + closeImage = new Image(display, imageData); + GC gc = new GC(closeImage); + gc.setBackground(background); + gc.fillRectangle(0, 0, imageHeight, imageHeight); + gc.setForeground(black); + + //draw an 8x7 'x' centered in image + int h = (imageHeight / 2 )* 2; + int inset = (h - 8) / 2; + gc.drawLine( inset, inset, h - inset - 1, h - inset - 1); + gc.drawLine( inset + 1, inset, h - inset, h - inset - 1); + gc.drawLine( inset, h - inset - 1, h - inset - 1, inset); + gc.drawLine( inset + 1, h - inset - 1, h - inset, inset); + + gc.dispose(); + + closeItem.setImage(closeImage); + inactiveCloseItem.setImage(closeImage); +} +private void updateArrowBar() { + + int imageHeight = tabHeight - 6; + if (imageHeight < 10) return; + + if (arrowLeftImage != null && arrowLeftImage.getBounds().height == imageHeight) return; + + if (arrowBar != null) arrowBar.dispose(); + arrowBar = null; + if (arrowLeftImage != null) arrowLeftImage.dispose(); + if (arrowRightImage != null) arrowRightImage.dispose(); + + createArrowBar(); + ToolItem[] items = arrowBar.getItems(); + ToolItem left = items[0]; + ToolItem right = items[1]; + + Display display = getDisplay(); + Color foreground = getForeground(); + Color black = display.getSystemColor(SWT.COLOR_BLACK); + Color background = getBackground(); + + PaletteData palette = new PaletteData(new RGB[]{foreground.getRGB(), background.getRGB(), black.getRGB()}); + ImageData imageData = new ImageData(7, imageHeight, 4, palette); + imageData.transparentPixel = 1; + arrowLeftImage = new Image(display, imageData); + GC gc = new GC(arrowLeftImage); + gc.setBackground(background); + gc.fillRectangle(0, 0, 7, imageHeight); + gc.setBackground(black); + //draw a 10x5 '<' centered vertically in image + int h = (imageHeight / 2 )* 2; + int midpoint = h / 2 - 1; + int[] pointArr = new int[] {6, midpoint - 5, + 1, midpoint, + 6, midpoint + 5,}; + gc.fillPolygon(pointArr); + gc.dispose(); + + palette = new PaletteData(new RGB[]{foreground.getRGB(), background.getRGB(), black.getRGB()}); + imageData = new ImageData(7, imageHeight, 4, palette); + imageData.transparentPixel = 1; + arrowRightImage = new Image(display, imageData); + gc = new GC(arrowRightImage); + gc.setBackground(background); + gc.fillRectangle(0, 0, 7, imageHeight); + gc.setBackground(black); + //draw a 10x5 '>' centered vertically in image + pointArr = new int[] {1, midpoint - 5, + 6, midpoint, + 1, midpoint + 5,}; + gc.fillPolygon(pointArr); + gc.dispose(); + + left.setImage(arrowLeftImage); + right.setImage(arrowRightImage); +} + +private void onMouseDoubleClick(Event event) { + Event e = new Event(); + e.item = getItem(new Point(event.x, event.y)); + notifyListeners(SWT.DefaultSelection, e); +} +/** + * A mouse button was pressed down. + * If a tab was hit select the tab. + */ +private void onMouseDown(Event event) { + for (int i=0; i<items.length; i++) { + if (items[i].getBounds().contains(new Point(event.x, event.y))) { + if (i == selectedIndex) { + showSelection(); + return; + } + forceFocus(); + setSelection(i, true); + if (isFocusControl()) setFocus(); + return; + } + } +} + +private void onMouseExit(Event event) { + Rectangle inactiveBounds = inactiveCloseBar.getBounds(); + if (inactiveBounds.contains(event.x, event.y)) return; + inactiveCloseBar.setVisible(false); + inactiveItem = null; + + showToolTip = false; + toolTipItem = null; + if (tip != null && !tip.isDisposed() && tip.isVisible()) tip.setVisible(false); +} + +private void onMouseHover(Event event) { + if (tip == null || tip.isDisposed()) return; + showToolTip = true; + showToolTip(event.x, event.y); +} +private void showToolTip (int x, int y) { + CTabItem item = getItem(new Point (x, y)); + if (item != null) { + if (item == toolTipItem) return; + toolTipItem = item; + String tooltip = item.getToolTipText(); + if (tooltip != null) { + Display display = tip.getDisplay(); + label.setForeground (display.getSystemColor (SWT.COLOR_INFO_FOREGROUND)); + label.setBackground (display.getSystemColor (SWT.COLOR_INFO_BACKGROUND)); + label.setText(tooltip); + Point labelSize = label.computeSize(SWT.DEFAULT, SWT.DEFAULT); + labelSize.x += 2; labelSize.y += 2; + label.setSize(labelSize); + tip.pack(); + /* + * On some platforms, there is a minimum size for a shell + * which may be greater than the label size. + * To avoid having the background of the tip shell showing + * around the label, force the label to fill the entire client area. + */ + Rectangle area = tip.getClientArea(); + label.setSize(area.width, area.height); + /* + * Position the tooltip and ensure that it is not located off + * the screen. + */ + Point pt = new Point(item.x + item.width / 4, item.y + item.height + 2); + pt = toDisplay(pt); + Rectangle rect = display.getBounds(); + Point tipSize = tip.getSize(); + pt.x = Math.max (0, Math.min (pt.x, rect.width - tipSize.x)); + pt.y = Math.max (0, Math.min (pt.y, rect.height - tipSize.y)); + tip.setLocation(pt); + tip.setVisible(true); + return; + } + } + + toolTipItem = null; + if (tip != null && !tip.isDisposed() && tip.isVisible()) tip.setVisible(false); +} +private void onMouseMove(Event event) { + if (showToolTip) { + showToolTip(event.x, event.y); + } + + if (!showClose) return; + + CTabItem item = null; + for (int i=0; i<items.length; i++) { + Rectangle rect = items[i].getBounds(); + if (rect.contains(new Point(event.x, event.y))) { + item = items[i]; + break; + } + } + if (item == inactiveItem) return; + + inactiveCloseBar.setVisible(false); + inactiveItem = null; + + if (item == null || item == getSelection()) return; + + int toolbarHeight = tabHeight - CTabItem.TOP_MARGIN - CTabItem.BOTTOM_MARGIN + 2; // +2 to ignore gap between focus rectangle + Point size = inactiveCloseBar.computeSize(SWT.DEFAULT, toolbarHeight); + int x = item.x + item.width - size.x - 2; // -2 to not overlap focus rectangle and trim + int y = item.y + Math.max(0, (item.height - toolbarHeight)/2); + Rectangle toolspace = getToolSpace(); + Point folderSize = getSize(); + if ((toolspace.width == 0 || x < toolspace.x) && x + size.x < folderSize.x - borderRight) { + inactiveCloseBar.setBounds(x, y, size.x, toolbarHeight); + inactiveCloseBar.setVisible(true); + inactiveItem = item; + } +} +private void onTraverse (Event event) { + switch (event.detail) { + case SWT.TRAVERSE_ESCAPE: +// TEMPORARY CODE See bug report 17372 +// case SWT.TRAVERSE_RETURN: + case SWT.TRAVERSE_TAB_NEXT: + case SWT.TRAVERSE_TAB_PREVIOUS: + event.doit = true; + break; + case SWT.TRAVERSE_MNEMONIC: + event.doit = onMnemonic(event); + if (event.doit) event.detail = SWT.TRAVERSE_NONE; + break; + case SWT.TRAVERSE_PAGE_NEXT: + case SWT.TRAVERSE_PAGE_PREVIOUS: + event.doit = onPageTraversal(event); + if (event.doit) event.detail = SWT.TRAVERSE_NONE; + break; + } +} + +private boolean onPageTraversal(Event event) { + int count = getItemCount (); + if (count == 0) return false; + int index = getSelectionIndex (); + if (index == -1) { + index = 0; + } else { + int offset = (event.detail == SWT.TRAVERSE_PAGE_NEXT) ? 1 : -1; + index = (index + offset + count) % count; + } + setSelection (index, true); + return true; +} + +/** + * Answer true if not all tabs can be visible in the receive + * thus requiring the scroll buttons to be visible. + */ +private boolean scroll_leftVisible() { + return topTabIndex > 0; +} + +/** + * Answer true if not all tabs can be visible in the receive + * thus requiring the scroll buttons to be visible. + */ +private boolean scroll_rightVisible() { + // only show Scroll buttons if there is more than one item + // and if we are not already at the last item + if (items.length < 2) return false; + Rectangle area = getClientArea(); + int rightEdge = area.x + area.width; + if (rightEdge <= 0) return false; + if (topTabIndex > 0) { + rightEdge -= arrowBar.getSize().x; + } + if (topRight != null) { + rightEdge -= topRight.getSize().x; + } + CTabItem item = items[items.length-1]; + return (item.x + item.width > rightEdge); +} + +/** + * Scroll the tab items to the left. + */ +private void scroll_scrollLeft() { + if (items.length == 0) return; + setLastItem(topTabIndex - 1); +} + +/** + * Scroll the tab items to the right. + */ +private void scroll_scrollRight() { + int lastIndex = getLastItem(); + topTabIndex = lastIndex + 1; + setItemLocation(); + correctLastItem(); + redrawTabArea(-1); +} +private boolean correctLastItem() { + Rectangle area = getClientArea(); + int rightEdge = area.x + area.width; + if (rightEdge <= 0) return false; + Rectangle toolspace = getToolSpace(); + if (toolspace.width > 0) { + rightEdge -= toolspace.width; + } + CTabItem item = items[items.length - 1]; + if (item.x + item.width < rightEdge) { + setLastItem(items.length - 1); + return true; + } + return false; +} +/** + * Specify a fixed height for the tab items. If no height is specified, + * the default height is the height of the text or the image, whichever + * is greater. Specifying a height of 0 will revert to the default height. + * + * @param height the pixel value of the height or 0 + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * <li>ERROR_INVALID_ARGUMENT - if called with a height of less than 0</li> + * </ul> + */ +public void setTabHeight(int height) { + checkWidget(); + if (height < 0) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + fixedTabHeight = true; + if (tabHeight == height) return; + tabHeight = height; + oldSize = null; + notifyListeners(SWT.Resize, new Event()); +} +void resetTabSize(boolean checkHeight){ + int oldHeight = tabHeight; + if (!fixedTabHeight && checkHeight) { + int tempHeight = 0; + GC gc = new GC(this); + for (int i=0; i < items.length; i++) { + tempHeight = Math.max(tempHeight, items[i].preferredHeight(gc)); + } + gc.dispose(); + if (topRight != null) tempHeight = Math.max(tempHeight, topRight.computeSize(SWT.DEFAULT, SWT.DEFAULT).y); + tabHeight = tempHeight; + } + + if (tabHeight != oldHeight){ + oldSize = null; + notifyListeners(SWT.Resize, new Event()); + } else { + setItemBounds(); + redraw(); + } +} +} |