/******************************************************************************* * Copyright (c) 2000, 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.swt.widgets; import org.eclipse.swt.*; import org.eclipse.swt.events.*; import org.eclipse.swt.graphics.*; /** * Instances of this class implement the notebook user interface * metaphor. It allows the user to select a notebook page from * set of pages. *

* The item children that may be added to instances of this class * must be of type TabItem. * Control children are created and then set into a * tab item using TabItem#setControl. *

* Note that although this class is a subclass of Composite, * it does not make sense to set a layout on it. *

*

*
Styles:
*
TOP, BOTTOM
*
Events:
*
Selection
*
*

* Note: Only one of the styles TOP and BOTTOM may be specified. *

* IMPORTANT: This class is not intended to be subclassed. *

* * @see TabFolder, TabItem snippets * @see SWT Example: ControlExample * @see Sample code and further information */ public class TabFolder extends Composite { TabItem items[] = new TabItem [0]; int selectedIndex = -1; int xClient, yClient; int imageHeight = -1; // all images have the height of the first image ever set int topTabIndex = 0; // index of the first visible tab. Used for tab scrolling boolean scrollButtonDown = false; // true=one of the scroll buttons is being pushed boolean inDispose = false; String toolTipText; // internal constants static final int SCROLL_BUTTON_SIZE = 20; // width/height of the scroll button used for scrolling tab items static final int CLIENT_MARGIN_WIDTH = 2; // distance between widget border and client rect static final int SELECTED_TAB_TOP_EXPANSION = 2; // amount we expand the selected tab on top static final int SELECTED_TAB_HORIZONTAL_EXPANSION = 2; // amount we expand so it overlays to left and right /** * Constructs a new instance of this class given its parent * and a style value describing its behavior and appearance. *

* The style value is either one of the style constants defined in * class SWT which is applicable to instances of this * class, or must be built by bitwise OR'ing together * (that is, using the int "|" operator) two or more * of those SWT style constants. The class description * lists the style constants that are applicable to the class. * Style bits are also inherited from superclasses. *

* * @param parent a composite control which will be the parent of the new instance (cannot be null) * @param style the style of control to construct * * @exception IllegalArgumentException * @exception SWTException * * @see SWT * @see Widget#checkSubclass * @see Widget#getStyle */ public TabFolder(Composite parent, int style) { super(parent, checkStyle (style)); Listener listener = new Listener() { public void handleEvent(Event event) {handleEvents(event);} }; addListener (SWT.Dispose, listener); addListener (SWT.MouseDown, listener); addListener (SWT.MouseUp, listener); addListener (SWT.MouseHover, listener); addListener (SWT.Paint, listener); // addListener (SWT.Resize, listener); addListener (SWT.Traverse, listener); addListener (SWT.KeyDown, listener); addListener (SWT.FocusIn, listener); addListener (SWT.FocusOut, listener); } /** * Adds the listener to the collection of listeners who will * be notified when the user changes the receiver's selection, by sending * it one of the messages defined in the SelectionListener * interface. *

* When widgetSelected is called, the item field of the event object is valid. * widgetDefaultSelected is not called. *

* * @param listener the listener which should be notified when the user changes the receiver's selection * * @exception IllegalArgumentException * @exception SWTException * * @see SelectionListener * @see #removeSelectionListener * @see SelectionEvent */ public void addSelectionListener(SelectionListener listener) { checkWidget(); if (listener == null) error (SWT.ERROR_NULL_ARGUMENT); TypedListener typedListener = new TypedListener(listener); addListener(SWT.Selection,typedListener); addListener(SWT.DefaultSelection,typedListener); } static int checkStyle (int style) { style = checkBits (style, SWT.TOP, SWT.BOTTOM, 0, 0, 0, 0); /* * Even though it is legal to create this widget * with scroll bars, they serve no useful purpose * because they do not automatically scroll the * widget's client area. The fix is to clear * the SWT style. */ return style & ~(SWT.H_SCROLL | SWT.V_SCROLL); } protected void checkSubclass () { if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS); } public Point computeSize (int wHint, int hHint, boolean changed) { Point size = super.computeSize (wHint, hHint, changed); if (items.length > 0) { TabItem lastItem = items[items.length-1]; int border = getBorderWidth (); int width = lastItem.x + lastItem.width + border * 2 + CLIENT_MARGIN_WIDTH * 2 + TabItem.SHADOW_WIDTH * 2; size.x = Math.max (width, size.x); } return size; } public Rectangle computeTrim (int x, int y, int width, int height) { checkWidget(); int border = getBorderWidth (); int trimX = x - border - CLIENT_MARGIN_WIDTH - TabItem.SHADOW_WIDTH; int trimY = y - border - CLIENT_MARGIN_WIDTH - TabItem.SHADOW_WIDTH; int tabHeight = 0; if (items.length > 0) { TabItem item = items [0]; tabHeight = item.y + item.height; // only use height of the first item because all items should be the same height } int trimWidth = width + border * 2 + CLIENT_MARGIN_WIDTH * 2 + TabItem.SHADOW_WIDTH * 2; int trimHeight = height + tabHeight + border * 2 + CLIENT_MARGIN_WIDTH * 2 + TabItem.SHADOW_WIDTH * 2; return new Rectangle (trimX, trimY - tabHeight, trimWidth, trimHeight); } /** * Create the specified item at 'index'. */ void createChild (TabItem item, int index) { boolean isTabScrolling = isTabScrolling(); if (!(0 <= index && index <= getItemCount ())) error (SWT.ERROR_INVALID_RANGE); item.parent = this; // grow by one and rearrange the array. TabItem[] newItems = new TabItem [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; if (selectedIndex >= index) selectedIndex ++; layoutItems(); redrawTabs(); // redraw scroll buttons if they just became visible // fixes 1G5X1QL if (isTabScrolling() != isTabScrolling && isTabScrolling == false) { redrawScrollButtons(); } if (getItemCount() == 1) { // select the first added item and send a selection event. // fixes 1GAP79N setSelection(0, true); } } /** * Destroy the specified item. */ void destroyChild (TabItem item) { int index = indexOf(item); if (index == -1) return; // should trigger an error? if (items.length == 1) { items = new TabItem [0]; selectedIndex = -1; topTabIndex = 0; if (!inDispose){ Control control = item.control; if (control != null && !control.isDisposed()) { control.setVisible(false); } redraw(); } } else { // shrink by one and rearrange the array. TabItem[] newItems = new TabItem [items.length - 1]; System.arraycopy(items, 0, newItems, 0, index); System.arraycopy(items, index + 1, newItems, index, items.length - index - 1); items = newItems; // move the selection if this item is selected if (selectedIndex == index) { if (!inDispose) { Control control = item.control; if (control != null && !control.isDisposed()) { control.setVisible(false); } selectedIndex = -1; setSelection(Math.max(0, index - 1), true); } } else if (selectedIndex > index) { selectedIndex--; } if (topTabIndex == items.length) { --topTabIndex; } } // Make sure that the first tab is visible if scroll buttons are no longer drawn. // Fixes 1FXW5DV if (topTabIndex > 0 && !isTabScrolling()) { topTabIndex = 0; } if (!inDispose) { layoutItems(); redrawTabs(); } } /** * Dispose the items of the receiver */ void doDispose(Event event) { if (inDispose) return; inDispose = true; notifyListeners(SWT.Dispose, event); event.type = SWT.None; // items array is resized during TabItem.dispose // it is length 0 if the last item is removed while (items.length > 0) { if (items[items.length-1] != null) { items[items.length-1].dispose(); } } } /** * Draw an arrow like that used in Button with SWT.ARROW style. * @param gc - GC to draw on * @param xPos - x position the underlying button is drawn at * @param yPos - y position the underlying button is drawn at * @param size - size of the underlying button * @param left - true=arrow is facing left. false=arrow is facing right */ void drawArrow(GC gc, int xPos, int yPos, int size, boolean left) { int arrowWidth = size / 4; int arrow[] = new int[6]; if (!left) arrowWidth *= -1; // start polygon lines with vertical line which is always the same arrow[0] = xPos + (size + arrowWidth) / 2; arrow[1] = yPos + size / 4; arrow[2] = arrow[0]; arrow[3] = arrow[1] + size / 2; arrow[4] = arrow[0] - arrowWidth; arrow[5] = yPos + size / 2; gc.setBackground(getForeground()); gc.fillPolygon(arrow); gc.setBackground(getBackground()); } /** * Draw a border around the receiver. */ void drawBorder(Event event) { GC gc = event.gc; Rectangle clientArea = getClientArea(); int wClient = clientArea.width; int hClient = clientArea.height; int x, y, x1, y1; final Color HighlightShadow = display.getSystemColor(SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW); final Color LightShadow = display.getSystemColor(SWT.COLOR_WIDGET_LIGHT_SHADOW); // Draw the left line gc.setForeground(HighlightShadow); gc.drawLine((x = xClient - CLIENT_MARGIN_WIDTH), yClient + hClient + CLIENT_MARGIN_WIDTH, x, (y = yClient - CLIENT_MARGIN_WIDTH) + 1); // Second, darker, line right of the previous line. // Necessary to workaround color constant differences on Windows/Motif gc.setForeground(LightShadow); gc.drawLine(x + 1, yClient + hClient + CLIENT_MARGIN_WIDTH, x + 1, y + 1); gc.setForeground(HighlightShadow); // Draw the upper line in two chunks so we don't overwrite the selected tab if (selectedIndex == -1) { gc.setForeground(LightShadow); gc.drawLine(x + 1, y + 1, xClient + wClient + CLIENT_MARGIN_WIDTH, y + 1); } else { TabItem item = items[selectedIndex]; gc.setForeground(LightShadow); if (selectedIndex > 0) { gc.drawLine(x + 1, y + 1, item.x - 1 + CLIENT_MARGIN_WIDTH, y + 1); } gc.drawLine(item.x + item.width, y + 1, xClient + wClient + CLIENT_MARGIN_WIDTH, y + 1); } // Draw the right and bottom black lines gc.setForeground(display.getSystemColor(SWT.COLOR_WIDGET_FOREGROUND)); gc.drawLine((x = xClient - CLIENT_MARGIN_WIDTH), (y = yClient + hClient + CLIENT_MARGIN_WIDTH), (x1 = xClient + wClient + CLIENT_MARGIN_WIDTH), y); gc.drawLine(x1, y, x1, (y1 = yClient - CLIENT_MARGIN_WIDTH + 1)); x1--; x++; y--; y1++; // There is a dark gray line above the bottom back line gc.setForeground(display.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW)); gc.drawLine(x, y, x1, y); // On the right there is a dark gray line, left of the black one gc.drawLine(x1, y-1, x1, y1); // restore the foreground color. gc.setForeground(getForeground()); } /** * Draw a plain push button * @param gc - GC to draw on * @param xPos - x position the button is drawn at * @param yPos - y position the button is drawn at * @param size - size of the button */ void drawPlainButton(GC gc, int xPos, int yPos, int size) { Color rightBottomColor = getForeground(); Color leftTopColor = display.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW); Color rightBottomInnerColor = display.getSystemColor(SWT.COLOR_WIDGET_DARK_SHADOW); Color leftTopInnerColor = display.getSystemColor(SWT.COLOR_WIDGET_LIGHT_SHADOW); int upper = yPos; int left = xPos; int lower = yPos + size - 1; int right = xPos + size - 1; if (scrollButtonDown) { // draw the button in the pressed down state? rightBottomColor = display.getSystemColor(SWT.COLOR_WIDGET_LIGHT_SHADOW); leftTopColor = display.getSystemColor(SWT.COLOR_WIDGET_DARK_SHADOW); rightBottomInnerColor = display.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW); leftTopInnerColor = getForeground(); } gc.fillRectangle(left, upper, right - left, lower - upper); // draw right, bottom line in foreground color gc.setForeground(rightBottomColor); gc.drawLine(right, upper, right, lower); gc.drawLine(left, lower, right, lower); // draw left, top line in normal shadow (default light gray) gc.setForeground(leftTopColor); gc.drawLine(left, upper, left, lower - 1); gc.drawLine(left, upper, right - 1, upper); upper++; left++; lower--; right--; // draw right, bottom line in dark shadow (default dark gray) gc.setForeground(rightBottomInnerColor); gc.drawLine(right, upper, right, lower); gc.drawLine(left, lower, right, lower); // draw left, top line in high light shadow (default off white) gc.setForeground(leftTopInnerColor); gc.drawLine(left, upper, left, lower - 1); gc.drawLine(left, upper, right - 1, upper); gc.setForeground(getForeground()); } /** * Draw the buttons used to scroll tab items */ void drawScrollButtons(Event event) { Rectangle buttonArea = getScrollButtonArea(); int buttonSize = buttonArea.width / 2; drawPlainButton(event.gc, buttonArea.x, buttonArea.y, buttonSize); drawPlainButton(event.gc, buttonArea.x + buttonSize, buttonArea.y, buttonSize); if (scrollButtonDown) { drawArrow(event.gc, buttonArea.x, buttonArea.y, buttonSize, true); drawArrow(event.gc, buttonArea.x + buttonSize + 1, buttonArea.y, buttonSize + 1, false); } else { drawArrow(event.gc, buttonArea.x - 1, buttonArea.y - 1, buttonSize, true); drawArrow(event.gc, buttonArea.x + buttonSize, buttonArea.y - 1, buttonSize, false); } } /** * Make sure that the first tab is visible if scroll buttons are no * longer drawn. */ void ensureRightFreeSpaceUsed() { if (topTabIndex > 0 && !isTabScrolling()) { topTabIndex = 0; layoutItems(); redrawTabs(); } } /** * If the tab at 'tabIndex' is not visible or partially covered by the tab * scroll buttons and there is enough space to completely show the tab, * the tab is scrolled to the left to make it fully visible. */ void ensureVisible(int tabIndex) { if (tabIndex < 0 || tabIndex >= items.length) return; if (!isTabScrolling()) return; if (tabIndex < topTabIndex) { topTabIndex = tabIndex; layoutItems(); redrawTabs(); return; } int rightEdge = getScrollButtonArea().x; TabItem tabItem = items[tabIndex]; while (tabItem.x + tabItem.width > rightEdge && tabIndex != topTabIndex) { topTabIndex++; layoutItems(); redrawTabs(); } } void focus (Event e) { if (selectedIndex == -1) return; TabItem tab = items[selectedIndex]; redraw(tab.x, tab.y, tab.width, tab.height); } public Rectangle getClientArea() { checkWidget(); Rectangle clientArea = super.getClientArea(); if (yClient == 0) { // position not calculated yet layoutItems(); // calculate tab folder bounds as soon as there is tab data to use. } clientArea.x = xClient; clientArea.y = yClient; clientArea.width = Math.max (0, clientArea.width - (xClient + CLIENT_MARGIN_WIDTH + 1)); clientArea.height = Math.max (0, clientArea.height - (yClient + CLIENT_MARGIN_WIDTH + 1)); return clientArea; } /** * Return the height of item images. All images are scaled to * the height of the first image. */ int getImageHeight() { return imageHeight; } /** * Returns the item at the given, zero-relative index in the * receiver. Throws an exception if the index is out of range. * * @param index the index of the item to return * @return the item at the given index * * @exception IllegalArgumentException * @exception SWTException */ public TabItem getItem (int index) { checkWidget(); if (!(0 <= index && index < getItemCount())) error(SWT.ERROR_INVALID_RANGE); return items [index]; } /** * Returns the tab item at the given point in the receiver * or null if no such item exists. The point is in the * coordinate system of the receiver. * * @param point the point used to locate the item * @return the tab item at the given point, or null if the point is not in a tab item * * @exception IllegalArgumentException * @exception SWTException * * @since 3.4 */ public TabItem getItem (Point point) { checkWidget(); if (point == null) error (SWT.ERROR_NULL_ARGUMENT); int count = items.length; for (int index = 0; index < count; index++) { TabItem item = items[index]; Rectangle bounds = item.getBounds(); if (bounds.contains(point)) return item; } return null; } /** * Returns the number of items contained in the receiver. * * @return the number of items * * @exception SWTException */ public int getItemCount(){ checkWidget(); return items.length; } /** * Returns an array of TabItems which are the items * in the receiver. *

* Note: This is not the actual structure used by the receiver * to maintain its list of items, so modifying the array will * not affect the receiver. *

* * @return the items in the receiver * * @exception SWTException */ public TabItem [] getItems() { checkWidget(); TabItem[] tabItems = new TabItem [items.length]; System.arraycopy(items, 0, tabItems, 0, items.length); return tabItems; } 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'; } /** * Returns the area where the two scroll buttons are drawn. */ Rectangle getScrollButtonArea() { return new Rectangle( super.getClientArea().width - SCROLL_BUTTON_SIZE * 2, SELECTED_TAB_TOP_EXPANSION, SCROLL_BUTTON_SIZE * 2, SCROLL_BUTTON_SIZE); } /** * Returns an array of TabItems that are currently * selected in the receiver. An empty array indicates that no * items are selected. *

* Note: This is not the actual structure used by the receiver * to maintain its selection, so modifying the array will * not affect the receiver. *

* @return an array representing the selection * * @exception SWTException */ public TabItem [] getSelection() { checkWidget(); if (selectedIndex == -1) return new TabItem [0]; return new TabItem [] {items[selectedIndex]}; } /** * Returns the zero-relative index of the item which is currently * selected in the receiver, or -1 if no item is selected. * * @return the index of the selected item * * @exception SWTException */ public int getSelectionIndex() { checkWidget(); return selectedIndex; } public String getToolTipText () { checkWidget(); return toolTipText; } /** * Handle the events that I have hooked on the canvas. */ void handleEvents (Event event){ switch (event.type) { case SWT.Dispose: doDispose(event); break; case SWT.Paint: paint(event); break; // case SWT.Resize: // resize(); // break; case SWT.MouseDown: mouseDown(event); break; case SWT.MouseUp: mouseUp(event); break; case SWT.MouseHover: mouseHover(event); break; case SWT.Traverse: traversal(event); break; case SWT.FocusIn: case SWT.FocusOut: focus(event); break; case SWT.KeyDown: // this callback is always needed so that widget is included in tab order keyDown(event); break; default: break; } } /** * Searches the receiver's list starting at the first item * (index 0) until an item is found that is equal to the * argument, and returns the index of that item. If no item * is found, returns -1. * * @param item the search item * @return the index of the item * * @exception IllegalArgumentException * @exception SWTException */ public int indexOf(TabItem item) { checkWidget(); if (item == null) { error(SWT.ERROR_NULL_ARGUMENT); } for (int i = 0; i < items.length; i++) { if (items[i] == item) return i; } return -1; } /** * Answer true when the left scroll button was clicked with mouse button 1. */ boolean isLeftButtonHit(Event event) { Rectangle buttonArea = getScrollButtonArea(); buttonArea.width /= 2; return isTabScrolling() && event.button == 1 && buttonArea.contains(event.x, event.y); } /** * Answer true when the right scroll button was clicked with mouse button 1. */ boolean isRightButtonHit(Event event) { Rectangle buttonArea = getScrollButtonArea(); int buttonSize = buttonArea.width / 2; buttonArea.x += buttonSize; buttonArea.width = buttonSize; return isTabScrolling() && event.button == 1 && buttonArea.contains(event.x, event.y); } /** * Answer true if not all tabs can be visible in the receive * thus requiring the scroll buttons to be visible. */ boolean isTabScrolling() { boolean isVisible = false; if (items.length > 0) { TabItem tabItem = items[items.length-1]; int tabStopX = tabItem.x + tabItem.width; tabItem = items[0]; if (tabStopX - tabItem.x > super.getClientArea().width) { isVisible = true; // not all tabs fit in the client area } } return isVisible; } /** * 'item' has changed. Store the image size if this is the * first item with an image. */ void itemChanged(TabItem item) { Image itemImage = item.getImage(); boolean isTabScrolling = isTabScrolling(); if (imageHeight == -1 && itemImage != null) { imageHeight = itemImage.getBounds().height; } layoutItems(); redrawTabs(); // redraw scroll buttons if they just became visible // fixes 1G5X1QL if (isTabScrolling() != isTabScrolling && isTabScrolling == false) { redrawScrollButtons(); } } /** * A key was pressed. If one of the tab-selection keys that is not a traversal * was pressed then change tabs accordingly. */ void keyDown(Event event) { int count = items.length; if (count <= 1) return; switch (event.keyCode) { case SWT.ARROW_RIGHT: if (selectedIndex < items.length - 1) { setSelection(selectedIndex + 1, true); } break; case SWT.ARROW_LEFT: if (selectedIndex > 0) { setSelection(selectedIndex - 1, true); } break; case SWT.HOME: if (selectedIndex > 0) { setSelection(0, true); } break; case SWT.END: if (selectedIndex < count - 1) { setSelection(count - 1, true); } break; } } /** * Layout the items and store the client area size. */ void layoutItems() { int x = SELECTED_TAB_HORIZONTAL_EXPANSION; int y = SELECTED_TAB_TOP_EXPANSION; int tabHeight = 0; GC gc = new GC(this); for (int i=topTabIndex - 1; i>=0; i--) { // if the first visible tab is not the first tab TabItem tab = items[i]; tab.width = tab.preferredWidth(gc); tab.height = tab.preferredHeight(gc); x -= tab.width; // layout tab items from right to left thus making them invisible tab.x = x; tab.y = y; if (tab.height > tabHeight) tabHeight = tab.height; } x = SELECTED_TAB_HORIZONTAL_EXPANSION; for (int i=topTabIndex; i tabHeight) tabHeight = tab.height; } gc.dispose(); xClient = CLIENT_MARGIN_WIDTH; yClient = CLIENT_MARGIN_WIDTH + tabHeight; TabItem selection[] = getSelection(); if (selection.length > 0) selection[0].expand(SELECTED_TAB_HORIZONTAL_EXPANSION, SELECTED_TAB_TOP_EXPANSION, SELECTED_TAB_HORIZONTAL_EXPANSION, 0); } Point minimumSize (int wHint, int hHint, boolean flushCache) { Control [] children = _getChildren (); int width = 0, height = 0; for (int i=0; i buttonArea.x) { x = buttonArea.x; fixScrollButtons = true; } if (x + width > buttonArea.x) { width = buttonArea.x - x; fixScrollButtons = true; } } redraw(x, y, width, height, false); if (fixScrollButtons) { redraw(buttonArea.x, 0, buttonArea.width, buttonArea.y, false); // redraw space above scroll buttons if (buttonArea.height < getClientArea().y) { int redrawY = buttonArea.y + buttonArea.height; redraw( buttonArea.x, redrawY, buttonArea.width, getClientArea().y - redrawY, false); // redraw space below scroll buttons } } } /** * Redraw the scroll button that was pressed down */ void redrawHitButton(Event event) { Rectangle scrollButtonArea = getScrollButtonArea(); int scrollButtonWidth = scrollButtonArea.width / 2; if (isLeftButtonHit(event)) { redraw( scrollButtonArea.x, scrollButtonArea.y, scrollButtonWidth, scrollButtonArea.height, false); } else if (isRightButtonHit(event)) { redraw( scrollButtonArea.x + scrollButtonWidth, scrollButtonArea.y, scrollButtonWidth, scrollButtonArea.height, false); } } /** * Redraw both scroll buttons */ void redrawScrollButtons() { Rectangle scrollButtonArea = getScrollButtonArea(); redraw( scrollButtonArea.x, scrollButtonArea.y, scrollButtonArea.width, scrollButtonArea.height, false); } /** * Redraw the tabs at the specified indexes. */ void redrawSelectionChange(int oldSelection, int newSelection) { if (oldSelection != -1) { TabItem tab = items[oldSelection]; // since the tab used to be selected, we need to clear its old expanded size redraw(tab.x - SELECTED_TAB_HORIZONTAL_EXPANSION, tab.y - SELECTED_TAB_TOP_EXPANSION, tab.width + 2 * SELECTED_TAB_HORIZONTAL_EXPANSION, tab.height + SELECTED_TAB_TOP_EXPANSION); } if (newSelection != -1) { TabItem tab = items[newSelection]; // this tab is already at the expanded size redraw(tab.x, tab.y, tab.width, tab.height); } // make sure the tab is repainted before the new page is made visible. // The latter could take a long time and delay the screen update. update(); } /** * Redraw the whole tab area */ void redrawTabs() { redraw(0, 0, super.getClientArea().width, getClientArea().y); } void removeControl (Control control) { super.removeControl (control); for (int i=0; i *
  • ERROR_NULL_ARGUMENT - if the listener is null
  • * * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    * * @see SelectionListener * @see #addSelectionListener */ public void removeSelectionListener(SelectionListener listener) { checkWidget(); if (listener == null) { error(SWT.ERROR_NULL_ARGUMENT); } removeListener(SWT.Selection, listener); removeListener(SWT.DefaultSelection, listener); } /** * The widget was resized. Adjust the size of the currently selected page. */ void resize() { if (selectedIndex != -1) { Control control = items[selectedIndex].getControl(); if (control != null && !control.isDisposed()) { control.setBounds(getClientArea()); } } ensureRightFreeSpaceUsed(); } /** * Scroll the tab items to the left. */ void scrollLeft() { if (topTabIndex > 0) { --topTabIndex; layoutItems(); redrawTabs(); } } /** * Scroll the tab items to the right. */ void scrollRight() { if (items.length > 0 && topTabIndex < items.length - 1) { TabItem lastTabItem = items[items.length-1]; int tabStopX = lastTabItem.x + lastTabItem.width; if (tabStopX > super.getClientArea().width - SCROLL_BUTTON_SIZE * 2) { topTabIndex++; layoutItems(); redrawTabs(); } } } boolean setBounds (int x, int y, int width, int height, boolean move, boolean resize) { boolean changed = super.setBounds (x, y, width, height, move, resize); if (changed && resize) resize (); return changed; } public void setFont(Font font) { checkWidget(); if (font != null && font.equals(getFont())) return; super.setFont(font); layoutItems(); redrawTabs(); } /** * Selects the item at the given zero-relative index in the receiver. * If the item at the index was already selected, it remains selected. * The current selection is first cleared, then the new items are * selected. Indices that are out of range are ignored. * * @param index the index of the item to select * * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    */ public void setSelection(int index) { checkWidget(); if (!(0 <= index && index < items.length)) return; setSelection(index, false); } /** * Sets the receiver's selection to the given item. * The current selected is first cleared, then the new item is * selected. * * @param item the item to select * * @exception IllegalArgumentException
      *
    • ERROR_NULL_ARGUMENT - if the item is null
    • *
    * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    * * @since 3.2 */ public void setSelection(TabItem item) { checkWidget(); if (item == null) error(SWT.ERROR_NULL_ARGUMENT); setSelection(new TabItem[]{item}); } /** * Sets the receiver's selection to be the given array of items. * The current selected is first cleared, then the new items are * selected. * * @param items the array of items * * @exception IllegalArgumentException
      *
    • ERROR_NULL_ARGUMENT - if the items array is null
    • *
    * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    */ public void setSelection(TabItem selectedItems[]) { checkWidget(); if (selectedItems == null) error(SWT.ERROR_NULL_ARGUMENT); int index = -1; if (selectedItems.length > 0) { index = indexOf(selectedItems[0]); } setSelection(index, false); } /** * Set the selection to the tab at the specified index. */ void setSelection(int index, boolean notify) { if (selectedIndex == index) return; int oldIndex = selectedIndex; if (selectedIndex == index || index >= getItemCount()) return; if (selectedIndex != -1) { Control control = items[selectedIndex].control; if (control != null && !control.isDisposed()) { control.setVisible(false); } } if (index < 0) { index = -1; // make sure the index is always -1 if it's negative } selectedIndex = index; layoutItems(); ensureVisible(index); redrawSelectionChange(oldIndex, index); if (index >= 0) { Control control = items[index].control; if (control != null && !control.isDisposed()) { control.setBounds(getClientArea()); control.setVisible(true); } } if (notify) { if (selectedIndex != oldIndex && selectedIndex != -1) { Event event = new Event(); event.item = getSelection()[0]; notifyListeners(SWT.Selection, event); } } } public void setToolTipText (String string) { checkWidget(); super.setToolTipText (string); toolTipText = string; } void traversal(Event event) { switch (event.detail) { case SWT.TRAVERSE_ESCAPE: case SWT.TRAVERSE_RETURN: case SWT.TRAVERSE_TAB_NEXT: case SWT.TRAVERSE_TAB_PREVIOUS: case SWT.TRAVERSE_MNEMONIC: case SWT.TRAVERSE_PAGE_NEXT: case SWT.TRAVERSE_PAGE_PREVIOUS: event.doit = true; } } boolean traverseItem (boolean next) { return false; } boolean traversePage (boolean next) { int count = items.length; if (count == 0) return false; int index = selectedIndex; if (index == -1) { index = 0; } else { int offset = next ? 1 : -1; index = (index + offset + count) % count; } setSelection (index, true); return true; } }