| /******************************************************************************* |
| * Copyright (c) 2000, 2012 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.custom; |
| |
| import org.eclipse.swt.*; |
| import org.eclipse.swt.accessibility.*; |
| import org.eclipse.swt.events.*; |
| import org.eclipse.swt.graphics.*; |
| import org.eclipse.swt.widgets.*; |
| |
| /** |
| * |
| * 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>CLOSE, TOP, BOTTOM, FLAT, BORDER, SINGLE, MULTI</dd> |
| * <dt><b>Events:</b></dt> |
| * <dd>Selection</dd> |
| * <dd>"CTabFolder2"</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> |
| * |
| * @see <a href="http://www.eclipse.org/swt/snippets/#ctabfolder">CTabFolder, CTabItem snippets</a> |
| * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: CustomControlExample</a> |
| * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a> |
| * @noextend This class is not intended to be subclassed by clients. |
| */ |
| |
| 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; |
| |
| /** |
| * 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. |
| * |
| * NOTE This field is badly named and can not be fixed for backwards compatibility. |
| * It should not be capitalized. |
| * |
| * @deprecated This field is no longer used. See setMinimumCharacters(int) |
| */ |
| public int MIN_TAB_WIDTH = 4; |
| |
| /** |
| * Color of innermost line of drop shadow border. |
| * |
| * NOTE This field is badly named and can not be fixed for backwards compatibility. |
| * It should be capitalized. |
| * |
| * @deprecated drop shadow border is no longer drawn in 3.0 |
| */ |
| public static RGB borderInsideRGB = new RGB (132, 130, 132); |
| /** |
| * Color of middle line of drop shadow border. |
| * |
| * NOTE This field is badly named and can not be fixed for backwards compatibility. |
| * It should be capitalized. |
| * |
| * @deprecated drop shadow border is no longer drawn in 3.0 |
| */ |
| public static RGB borderMiddleRGB = new RGB (143, 141, 138); |
| /** |
| * Color of outermost line of drop shadow border. |
| * |
| * NOTE This field is badly named and can not be fixed for backwards compatibility. |
| * It should be capitalized. |
| * |
| * @deprecated drop shadow border is no longer drawn in 3.0 |
| */ |
| public static RGB borderOutsideRGB = new RGB (171, 168, 165); |
| |
| /* sizing, positioning */ |
| boolean onBottom = false; |
| boolean single = false; |
| boolean simple = true; |
| int fixedTabHeight = SWT.DEFAULT; |
| int tabHeight; |
| int minChars = 20; |
| boolean borderVisible = false; |
| |
| /* item management */ |
| CTabFolderRenderer renderer; |
| CTabItem items[] = new CTabItem[0]; |
| int firstIndex = -1; // index of the left most visible tab. |
| int selectedIndex = -1; |
| int[] priority = new int[0]; |
| boolean mru = false; |
| Listener listener; |
| boolean ignoreTraverse; |
| |
| /* External Listener management */ |
| CTabFolder2Listener[] folderListeners = new CTabFolder2Listener[0]; |
| // support for deprecated listener mechanism |
| CTabFolderListener[] tabListeners = new CTabFolderListener[0]; |
| |
| /* Selected item appearance */ |
| Image selectionBgImage; |
| Color[] selectionGradientColors; |
| int[] selectionGradientPercents; |
| boolean selectionGradientVertical; |
| Color selectionForeground; |
| Color selectionBackground; |
| |
| /* Unselected item appearance */ |
| Color[] gradientColors; |
| int[] gradientPercents; |
| boolean gradientVertical; |
| boolean showUnselectedImage = true; |
| |
| // close, min/max and chevron buttons |
| boolean showClose = false; |
| boolean showUnselectedClose = true; |
| |
| boolean showMin = false; |
| boolean minimized = false; |
| boolean showMax = false; |
| boolean maximized = false; |
| ToolBar minMaxTb; |
| ToolItem maxItem; |
| ToolItem minItem; |
| Image maxImage; |
| Image minImage; |
| boolean hoverTb; |
| Rectangle hoverRect = new Rectangle(0,0,0,0); |
| boolean hovering; |
| boolean hoverTimerRunning; |
| |
| boolean showChevron = false; |
| Menu showMenu; |
| ToolBar chevronTb; |
| ToolItem chevronItem; |
| Image chevronImage; |
| int chevronCount; |
| boolean chevronVisible = true; |
| |
| Control topRight; |
| int topRightAlignment = SWT.RIGHT; |
| boolean ignoreResize; |
| Control[] controls; |
| int[] controlAlignments; |
| Rectangle[] controlRects; |
| Image[] controlBkImages; |
| |
| int updateFlags; |
| final static int REDRAW = 1 << 1; |
| final static int REDRAW_TABS = 1 << 2; |
| final static int UPDATE_TAB_HEIGHT = 1 << 3; |
| Runnable updateRun; |
| |
| // when disposing CTabFolder, don't try to layout the items or |
| // change the selection as each child is destroyed. |
| boolean inDispose = false; |
| |
| // keep track of size changes in order to redraw only affected area |
| // on Resize |
| Point oldSize; |
| Font oldFont; |
| |
| // internal constants |
| static final int DEFAULT_WIDTH = 64; |
| static final int DEFAULT_HEIGHT = 64; |
| |
| static final int SELECTION_FOREGROUND = SWT.COLOR_LIST_FOREGROUND; |
| static final int SELECTION_BACKGROUND = SWT.COLOR_LIST_BACKGROUND; |
| |
| static final int FOREGROUND = SWT.COLOR_WIDGET_FOREGROUND; |
| static final int BACKGROUND = SWT.COLOR_WIDGET_BACKGROUND; |
| |
| //TODO: add setter for spacing? |
| static final int SPACING = 3; |
| |
| /** |
| * 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 SWT#BORDER |
| * @see SWT#SINGLE |
| * @see SWT#MULTI |
| * @see #getStyle() |
| */ |
| public CTabFolder(Composite parent, int style) { |
| super(parent, checkStyle (parent, style)); |
| init(style); |
| } |
| |
| void init(int style) { |
| super.setLayout(new CTabFolderLayout()); |
| int style2 = super.getStyle(); |
| oldFont = getFont(); |
| onBottom = (style2 & SWT.BOTTOM) != 0; |
| showClose = (style2 & SWT.CLOSE) != 0; |
| // showMin = (style2 & SWT.MIN) != 0; - conflicts with SWT.TOP |
| // showMax = (style2 & SWT.MAX) != 0; - conflicts with SWT.BOTTOM |
| single = (style2 & SWT.SINGLE) != 0; |
| borderVisible = (style & SWT.BORDER) != 0; |
| //set up default colors |
| Display display = getDisplay(); |
| selectionForeground = display.getSystemColor(SELECTION_FOREGROUND); |
| selectionBackground = display.getSystemColor(SELECTION_BACKGROUND); |
| renderer = new CTabFolderRenderer(this); |
| controls = new Control[0]; |
| controlAlignments = new int[0]; |
| controlRects = new Rectangle[0]; |
| controlBkImages = new Image[0]; |
| updateTabHeight(false); |
| |
| // Add all listeners |
| listener = new Listener() { |
| public void handleEvent(Event event) { |
| switch (event.type) { |
| case SWT.Dispose: onDispose(event); break; |
| case SWT.DragDetect: onDragDetect(event); break; |
| case SWT.FocusIn: onFocus(event); break; |
| case SWT.FocusOut: onFocus(event); break; |
| case SWT.KeyDown: onKeyDown(event); break; |
| case SWT.MouseDoubleClick: onMouseDoubleClick(event); break; |
| case SWT.MouseDown: onMouse(event); break; |
| case SWT.MouseEnter: onMouse(event); break; |
| case SWT.MouseExit: onMouse(event); break; |
| case SWT.MouseHover: onMouse(event); break; |
| case SWT.MouseMove: onMouse(event); break; |
| case SWT.MouseUp: onMouse(event); break; |
| case SWT.Paint: onPaint(event); break; |
| case SWT.Resize: onResize(event); break; |
| case SWT.Traverse: onTraverse(event); break; |
| case SWT.Selection: onSelection(event); break; |
| } |
| } |
| }; |
| |
| int[] folderEvents = new int[]{ |
| SWT.Dispose, |
| SWT.DragDetect, |
| SWT.FocusIn, |
| SWT.FocusOut, |
| SWT.KeyDown, |
| SWT.MouseDoubleClick, |
| SWT.MouseDown, |
| SWT.MouseEnter, |
| SWT.MouseExit, |
| SWT.MouseHover, |
| SWT.MouseMove, |
| SWT.MouseUp, |
| SWT.Paint, |
| SWT.Resize, |
| SWT.Traverse, |
| }; |
| for (int i = 0; i < folderEvents.length; i++) { |
| addListener(folderEvents[i], listener); |
| } |
| |
| initAccessible(); |
| } |
| static int checkStyle (Composite parent, int style) { |
| int mask = SWT.CLOSE | SWT.TOP | SWT.BOTTOM | SWT.FLAT | SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT | SWT.SINGLE | SWT.MULTI; |
| style = style & mask; |
| // TOP and BOTTOM are mutually exclusive. |
| // TOP is the default |
| if ((style & SWT.TOP) != 0) style = style & ~SWT.BOTTOM; |
| // SINGLE and MULTI are mutually exclusive. |
| // MULTI is the default |
| if ((style & SWT.MULTI) != 0) style = style & ~SWT.SINGLE; |
| // reduce the flash by not redrawing the entire area on a Resize event |
| style |= SWT.NO_REDRAW_RESIZE; |
| |
| //TEMPORARY CODE |
| /* |
| * In Right To Left orientation on Windows, all GC calls that use a brush are drawing |
| * offset by one pixel. This results in some parts of the CTabFolder not drawing correctly. |
| * To alleviate some of the appearance problems, allow the OS to draw the background. |
| * This does not draw correctly but the result is less obviously wrong. |
| */ |
| if ((style & SWT.RIGHT_TO_LEFT) != 0) return style; |
| if ((parent.getStyle() & SWT.MIRRORED) != 0 && (style & SWT.LEFT_TO_RIGHT) == 0) return style; |
| |
| return style | SWT.DOUBLE_BUFFERED; |
| } |
| |
| /** |
| * |
| * Adds the listener to the collection of listeners who will |
| * be notified when a tab item is closed, minimized, maximized, |
| * restored, or to show the list of items that are not |
| * currently visible. |
| * |
| * @param listener the listener which should be notified |
| * |
| * @exception IllegalArgumentException <ul> |
| * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> |
| * </ul> |
| * |
| * @exception SWTException <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> |
| * |
| * @see CTabFolder2Listener |
| * @see #removeCTabFolder2Listener(CTabFolder2Listener) |
| * |
| * @since 3.0 |
| */ |
| public void addCTabFolder2Listener(CTabFolder2Listener listener) { |
| checkWidget(); |
| if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT); |
| // add to array |
| CTabFolder2Listener[] newListeners = new CTabFolder2Listener[folderListeners.length + 1]; |
| System.arraycopy(folderListeners, 0, newListeners, 0, folderListeners.length); |
| folderListeners = newListeners; |
| folderListeners[folderListeners.length - 1] = listener; |
| } |
| /** |
| * 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_NULL_ARGUMENT - if the listener is null</li> |
| * </ul> |
| * @exception SWTException <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> |
| * |
| * @see CTabFolderListener |
| * @see #removeCTabFolderListener(CTabFolderListener) |
| * |
| * @deprecated use addCTabFolder2Listener(CTabFolder2Listener) |
| */ |
| 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; |
| // display close button to be backwards compatible |
| if (!showClose) { |
| showClose = true; |
| updateFolder(REDRAW); |
| } |
| } |
| /** |
| * 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 <code>SelectionListener</code> |
| * interface. |
| * <p> |
| * <code>widgetSelected</code> is called when the user changes the selected tab. |
| * <code>widgetDefaultSelected</code> is not called. |
| * </p> |
| * |
| * @param listener the listener which should be notified when the user changes the receiver's selection |
| * |
| * @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 SelectionListener |
| * @see #removeSelectionListener |
| * @see SelectionEvent |
| */ |
| 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); |
| } |
| |
| Rectangle[] computeControlBounds (Point size, boolean[][] position) { |
| if (controls == null || controls.length == 0) return new Rectangle[0]; |
| Rectangle[] rects = new Rectangle[controls.length]; |
| for (int i = 0; i < rects.length; i++) { |
| rects[i] = new Rectangle(0, 0, 0, 0); |
| } |
| Rectangle trim = renderer.computeTrim(CTabFolderRenderer.PART_BORDER, SWT.NONE, 0, 0, 0, 0); |
| int borderRight = trim.width + trim.x; |
| int borderLeft = -trim.x; |
| int borderBottom = trim.height + trim.y; |
| int borderTop = -trim.y; |
| |
| Point[] tabControlSize = new Point[controls.length]; |
| boolean[] overflow = new boolean [controls.length]; |
| //Left Control |
| int leftWidth = 0; |
| int x = borderLeft + SPACING; |
| int rightWidth = 0; |
| int allWidth = 0; |
| for (int i = 0; i < controls.length; i++) { |
| Point ctrlSize = tabControlSize[i] = !controls[i].isDisposed() && controls[i].getVisible() ? controls[i].computeSize(SWT.DEFAULT, SWT.DEFAULT) : new Point(0,0); |
| int alignment = controlAlignments[i]; |
| if ((alignment & SWT.LEAD) != 0) { |
| rects[i].width = ctrlSize.x; |
| rects[i].height = getControlHeight(ctrlSize); |
| rects[i].x = x; |
| rects[i].y = getControlY(size, rects, borderBottom, borderTop, i); |
| x += ctrlSize.x; |
| leftWidth += ctrlSize.x; |
| } else { |
| if ((alignment & (SWT.FILL | SWT.WRAP)) == 0) { |
| rightWidth += ctrlSize.x; |
| } |
| allWidth += ctrlSize.x; |
| } |
| } |
| if (leftWidth > 0) leftWidth += SPACING * 2; |
| |
| int itemWidth = 0; |
| for (int i = 0; i < items.length; i++) { |
| if (items[i].showing) itemWidth += items[i].width; |
| } |
| |
| int maxWidth = size.x - borderLeft - leftWidth - borderRight; |
| int availableWidth = Math.max(0, maxWidth - itemWidth - rightWidth); |
| if (rightWidth > 0) availableWidth -= SPACING * 2; |
| x = size.x - borderRight - SPACING; |
| if (itemWidth + allWidth <= maxWidth) { |
| //Everything fits |
| for (int i = 0; i < controls.length; i++) { |
| int alignment = controlAlignments[i]; |
| if ((alignment & SWT.TRAIL) != 0) { |
| Point ctrlSize = tabControlSize[i]; |
| x -= ctrlSize.x; |
| rects[i].width = ctrlSize.x; |
| rects[i].height = getControlHeight(ctrlSize); |
| rects[i].x = x; |
| rects[i].y = getControlY(size, rects, borderBottom, borderTop, i); |
| if ((alignment & (SWT.FILL | SWT.WRAP)) != 0) availableWidth -= ctrlSize.x; |
| } |
| } |
| } else { |
| for (int i = 0; i < controls.length; i++) { |
| int alignment = controlAlignments[i]; |
| Point ctrlSize = tabControlSize[i]; |
| if ((alignment & SWT.TRAIL) != 0) { |
| if ((alignment & (SWT.FILL | SWT.WRAP)) == 0) { |
| x -= ctrlSize.x; |
| rects[i].width = ctrlSize.x; |
| rects[i].height = getControlHeight(ctrlSize); |
| rects[i].x = x; |
| rects[i].y = getControlY(size, rects, borderBottom, borderTop, i); |
| } else if (((alignment & (SWT.WRAP)) != 0 && ctrlSize.x < availableWidth)) { |
| x -= ctrlSize.x; |
| rects[i].width = ctrlSize.x; |
| rects[i].height = getControlHeight(ctrlSize); |
| rects[i].x = x; |
| rects[i].y = getControlY(size, rects, borderBottom, borderTop, i); |
| availableWidth -= ctrlSize.x; |
| } else if ((alignment & (SWT.FILL)) != 0 && (alignment & (SWT.WRAP)) == 0) { |
| rects[i].width = 0; |
| rects[i].height = getControlHeight(ctrlSize); |
| rects[i].x = x; |
| rects[i].y = getControlY(size, rects, borderBottom, borderTop, i); |
| } else { |
| if ((alignment & (SWT.WRAP)) != 0) { |
| overflow[i] = true; |
| } |
| } |
| } |
| } |
| } |
| |
| //Any space, distribute amongst FILL |
| if (availableWidth > 0) { |
| int fillCount = 0; |
| for (int i = 0; i < controls.length; i++) { |
| int alignment = controlAlignments[i]; |
| if ((alignment & SWT.TRAIL) != 0 && (alignment & SWT.FILL) != 0 && !overflow[i]) { |
| fillCount++; |
| } |
| } |
| if (fillCount != 0) { |
| int extraSpace = availableWidth/fillCount; |
| int addedSpace = 0; |
| for (int i = 0; i < controls.length; i++) { |
| int alignment = controlAlignments[i]; |
| if ((alignment & SWT.TRAIL) != 0) { |
| if ((alignment & SWT.FILL) != 0 && !overflow[i]) { |
| rects[i].width += extraSpace; |
| addedSpace += extraSpace; |
| } |
| if (!overflow[i]) { |
| rects[i].x -= addedSpace; |
| } |
| } |
| } |
| } |
| } |
| |
| //Go through overflow laying out all wrapped controls |
| Rectangle bodyTrim = renderer.computeTrim(CTabFolderRenderer.PART_BODY, SWT.NONE, 0, 0, 0, 0); |
| int bodyRight = bodyTrim.width + bodyTrim.x; |
| int bodyLeft = -bodyTrim.x; |
| int bodyWidth = size.x - bodyLeft - bodyRight; |
| x = size.x - bodyRight; |
| int y = -bodyTrim.y; |
| availableWidth = bodyWidth; |
| int maxHeight = 0; |
| for (int i = 0; i < controls.length; i++) { |
| Point ctrlSize = tabControlSize[i]; |
| if (overflow[i]) { |
| if (availableWidth > ctrlSize.x) { |
| x -= ctrlSize.x; |
| rects[i].width = ctrlSize.x; |
| rects[i].y = y; |
| rects[i].height = ctrlSize.y; |
| rects[i].x = x; |
| availableWidth -= ctrlSize.x; |
| maxHeight = Math.max(maxHeight, ctrlSize.y); |
| } else { |
| x = size.x - bodyRight; |
| y += maxHeight; |
| maxHeight = 0; |
| availableWidth = bodyWidth; |
| if (availableWidth > ctrlSize.x) { |
| //Relayout this control in the next line |
| i--; |
| } else { |
| ctrlSize = controls[i].isDisposed() ? new Point(0,0) : controls[i].computeSize(bodyWidth, SWT.DEFAULT); |
| rects[i].width = bodyWidth; |
| rects[i].y = y; |
| rects[i].height = ctrlSize.y; |
| rects[i].x = size.x - ctrlSize.x - bodyRight; |
| y += ctrlSize.y; |
| } |
| } |
| } |
| } |
| |
| if (showChevron) { |
| int i = 0, lastIndex = -1; |
| while (i < priority.length && items[priority[i]].showing) { |
| lastIndex = Math.max(lastIndex, priority[i++]); |
| } |
| if (lastIndex == -1) lastIndex = selectedIndex; |
| if (lastIndex != -1) { |
| CTabItem lastItem = items[lastIndex]; |
| int w = lastItem.x + lastItem.width + SPACING; |
| if (!simple && lastIndex == selectedIndex) w -= (renderer.curveIndent - 7); |
| rects[controls.length - 1].x = w; |
| } |
| } |
| |
| if (position != null) position[0] = overflow; |
| return rects; |
| } |
| |
| int getControlHeight(Point ctrlSize) { |
| return fixedTabHeight == SWT.DEFAULT ? Math.max(tabHeight - 1, ctrlSize.y) : ctrlSize.y; |
| } |
| /* |
| * This class was not intended to be subclassed but this restriction |
| * cannot be enforced without breaking backward compatibility. |
| */ |
| //protected void checkSubclass () { |
| // String name = getClass ().getName (); |
| // int index = name.lastIndexOf ('.'); |
| // if (!name.substring (0, index + 1).equals ("org.eclipse.swt.custom.")) { |
| // SWT.error (SWT.ERROR_INVALID_SUBCLASS); |
| // } |
| //} |
| public Rectangle computeTrim (int x, int y, int width, int height) { |
| checkWidget(); |
| Rectangle trim = renderer.computeTrim(CTabFolderRenderer.PART_BODY, SWT.NONE, x, y, width, height); |
| Point size = new Point(width, height); |
| int wrapHeight = getWrappedHeight(size); |
| if (onBottom) { |
| trim.height += wrapHeight; |
| } else { |
| trim.y -= wrapHeight; |
| trim.height += wrapHeight; |
| } |
| return trim; |
| } |
| Image createButtonImage(Display display, int button) { |
| GC tempGC = new GC (this); |
| Point size = renderer.computeSize(button, SWT.NONE, tempGC, SWT.DEFAULT, SWT.DEFAULT); |
| tempGC.dispose(); |
| Rectangle trim = renderer.computeTrim(button, SWT.NONE, 0, 0, 0, 0); |
| Image image = new Image (display, size.x - trim.width, size.y - trim.height); |
| GC gc = new GC (image); |
| RGB transparent; |
| if (button == CTabFolderRenderer.PART_CHEVRON_BUTTON) { |
| transparent = new RGB(0xFF, 0xFF, 0xFF); |
| } else { |
| transparent = new RGB(0xFD, 0, 0); |
| } |
| Color transColor = new Color(display, transparent); |
| gc.setBackground(transColor); |
| gc.fillRectangle(image.getBounds()); |
| renderer.draw(button, SWT.NONE, new Rectangle(trim.x, trim.y, size.x, size.y), gc); |
| gc.dispose (); |
| transColor.dispose(); |
| ImageData imageData = image.getImageData(); |
| imageData.transparentPixel = imageData.palette.getPixel(transparent); |
| image.dispose(); |
| image = new Image(display, imageData); |
| return image; |
| } |
| void createItem (CTabItem item, int index) { |
| if (0 > index || index > getItemCount ())SWT.error (SWT.ERROR_INVALID_RANGE); |
| item.parent = this; |
| 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; |
| if (selectedIndex >= index) selectedIndex ++; |
| int[] newPriority = new int[priority.length + 1]; |
| int next = 0, priorityIndex = priority.length; |
| for (int i = 0; i < priority.length; i++) { |
| if (!mru && (priority[i] == index || (priority[i] == 0 && index+1 == items.length))) { |
| priorityIndex = next++; |
| } |
| newPriority[next++] = priority[i] >= index ? priority[i] + 1 : priority[i]; |
| } |
| newPriority[priorityIndex] = index; |
| priority = newPriority; |
| |
| if (items.length == 1) { |
| updateFolder(UPDATE_TAB_HEIGHT | REDRAW); |
| } else { |
| updateFolder(REDRAW_TABS); |
| } |
| } |
| void destroyItem (CTabItem item) { |
| if (inDispose) return; |
| int index = indexOf(item); |
| if (index == -1) return; |
| |
| if (items.length == 1) { |
| items = new CTabItem[0]; |
| priority = new int[0]; |
| firstIndex = -1; |
| selectedIndex = -1; |
| |
| Control control = item.getControl(); |
| if (control != null && !control.isDisposed()) { |
| control.setVisible(false); |
| } |
| setToolTipText(null); |
| GC gc = new GC(this); |
| setButtonBounds(gc); |
| gc.dispose(); |
| redraw(); |
| return; |
| } |
| |
| 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; |
| |
| int[] newPriority = new int[priority.length - 1]; |
| int next = 0; |
| for (int i = 0; i < priority.length; i++) { |
| if (priority [i] == index) continue; |
| newPriority[next++] = priority[i] > index ? priority[i] - 1 : priority [i]; |
| } |
| priority = newPriority; |
| |
| // move the selection if this item is selected |
| if (selectedIndex == index) { |
| Control control = item.getControl(); |
| selectedIndex = -1; |
| int nextSelection = mru ? priority[0] : Math.max(0, index - 1); |
| setSelection(nextSelection, true); |
| if (control != null && !control.isDisposed()) { |
| control.setVisible(false); |
| } |
| } else if (selectedIndex > index) { |
| selectedIndex --; |
| } |
| |
| updateFolder(UPDATE_TAB_HEIGHT | REDRAW_TABS); |
| } |
| |
| /** |
| * Returns <code>true</code> if the receiver's border is visible. |
| * |
| * @return the receiver's border visibility state |
| * |
| * @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> |
| * |
| * @since 3.0 |
| */ |
| public boolean getBorderVisible() { |
| checkWidget(); |
| return borderVisible; |
| } |
| ToolBar getChevron() { |
| if (chevronTb == null) { |
| chevronTb = new ToolBar(this, SWT.FLAT); |
| initAccessibleChevronTb(); |
| addTabControl(chevronTb, SWT.TRAIL, -1, false); |
| } |
| if (chevronItem == null) { |
| chevronItem = new ToolItem(chevronTb, SWT.PUSH); |
| chevronItem.setToolTipText(SWT.getMessage("SWT_ShowList")); |
| chevronItem.addListener(SWT.Selection, listener); |
| } |
| return chevronTb; |
| } |
| /** |
| * Returns <code>true</code> if the chevron button |
| * is visible when necessary. |
| * |
| * @return the visibility of the chevron button |
| * |
| * @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*/ boolean getChevronVisible() { |
| checkWidget(); |
| return chevronVisible; |
| } |
| public Rectangle getClientArea() { |
| checkWidget(); |
| //TODO: HACK - find a better way to get padding |
| Rectangle trim = renderer.computeTrim(CTabFolderRenderer.PART_BODY, SWT.FILL, 0, 0, 0, 0); |
| Point size = getSize(); |
| int wrapHeight = getWrappedHeight(size); |
| if (onBottom) { |
| trim.height += wrapHeight; |
| } else { |
| trim.y -= wrapHeight; |
| trim.height += wrapHeight; |
| } |
| if (minimized) return new Rectangle(-trim.x, -trim.y, 0, 0); |
| int width = size.x - trim.width; |
| int height = size.y - trim.height; |
| return new Rectangle(-trim.x, -trim.y, width, height); |
| } |
| |
| /** |
| * Return the tab that is located at the specified index. |
| * |
| * @param index the index of the tab item |
| * @return the item at the specified index |
| * |
| * @exception IllegalArgumentException <ul> |
| * <li>ERROR_INVALID_RANGE - if the index is out of range</li> |
| * </ul> |
| * @exception SWTException <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 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. |
| * |
| * @param pt the point in coordinates relative to the CTabFolder |
| * @return the item at a point or null |
| * |
| * @exception SWTException <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 CTabItem getItem (Point pt) { |
| //checkWidget(); |
| if (items.length == 0) return null; |
| runUpdate(); |
| Point size = getSize(); |
| Rectangle trim = renderer.computeTrim(CTabFolderRenderer.PART_BORDER, SWT.NONE, 0, 0, 0, 0); |
| if (size.x <= trim.width) return null; |
| for (int i = 0; i < priority.length; i++) { |
| CTabItem item = items[priority[i]]; |
| Rectangle rect = item.getBounds(); |
| if (rect.contains(pt)) return item; |
| } |
| return null; |
| } |
| /** |
| * Return the number of tabs in the folder. |
| * |
| * @return the number of tabs in the folder |
| * |
| * @exception SWTException <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 getItemCount(){ |
| //checkWidget(); |
| return items.length; |
| } |
| /** |
| * Return the tab items. |
| * |
| * @return the tab items |
| * |
| * @exception SWTException <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 CTabItem [] getItems() { |
| //checkWidget(); |
| CTabItem[] tabItems = new CTabItem [items.length]; |
| System.arraycopy(items, 0, tabItems, 0, items.length); |
| return tabItems; |
| } |
| int getLeftItemEdge (GC gc, int part){ |
| Rectangle trim = renderer.computeTrim(part, SWT.NONE, 0, 0, 0, 0); |
| int x = -trim.x; |
| int width = 0; |
| for (int i = 0; i < controls.length; i++) { |
| if ((controlAlignments[i] & SWT.LEAD) != 0 && !controls[i].isDisposed() && controls[i].getVisible()) { |
| width += controls[i].computeSize(SWT.DEFAULT, SWT.DEFAULT).x; |
| } |
| } |
| if (width != 0) width += SPACING * 2; |
| x += width; |
| return Math.max(0, x); |
| } |
| /* |
| * Return the lowercase of the first non-'&' character following |
| * an '&' character in the given string. If there are no '&' |
| * characters in the given string, return '\0'. |
| */ |
| char _findMnemonic (String string) { |
| if (string == null) return '\0'; |
| 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 Character.toLowerCase (string.charAt (index)); |
| index++; |
| } while (index < length); |
| return '\0'; |
| } |
| String stripMnemonic (String string) { |
| int index = 0; |
| int length = string.length (); |
| do { |
| while ((index < length) && (string.charAt (index) != '&')) index++; |
| if (++index >= length) return string; |
| if (string.charAt (index) != '&') { |
| return string.substring(0, index-1) + string.substring(index, length); |
| } |
| index++; |
| } while (index < length); |
| return string; |
| } |
| /** |
| * Returns <code>true</code> if the receiver is minimized. |
| * |
| * @return the receiver's minimized state |
| * |
| * @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> |
| * |
| * @since 3.0 |
| */ |
| public boolean getMinimized() { |
| checkWidget(); |
| return minimized; |
| } |
| /** |
| * Returns <code>true</code> if the minimize button |
| * is visible. |
| * |
| * @return the visibility of the minimized button |
| * |
| * @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> |
| * |
| * @since 3.0 |
| */ |
| public boolean getMinimizeVisible() { |
| checkWidget(); |
| return showMin; |
| } |
| /** |
| * Returns the number of characters that will |
| * appear in a fully compressed tab. |
| * |
| * @return number of characters that will appear in a fully compressed tab |
| * |
| * @since 3.0 |
| */ |
| public int getMinimumCharacters() { |
| checkWidget(); |
| return minChars; |
| } |
| |
| /** |
| * Returns <code>true</code> if the receiver is maximized. |
| * <p> |
| * |
| * @return the receiver's maximized state |
| * |
| * @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> |
| * |
| * @since 3.0 |
| */ |
| public boolean getMaximized() { |
| checkWidget(); |
| return maximized; |
| } |
| /** |
| * Returns <code>true</code> if the maximize button |
| * is visible. |
| * |
| * @return the visibility of the maximized button |
| * |
| * @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> |
| * |
| * @since 3.0 |
| */ |
| public boolean getMaximizeVisible() { |
| checkWidget(); |
| return showMax; |
| } |
| /** |
| * Returns <code>true</code> if the receiver displays most |
| * recently used tabs and <code>false</code> otherwise. |
| * <p> |
| * When there is not enough horizontal space to show all the tabs, |
| * by default, tabs are shown sequentially from left to right in |
| * order of their index. When the MRU visibility is turned on, |
| * the tabs that are visible will be the tabs most recently selected. |
| * Tabs will still maintain their left to right order based on index |
| * but only the most recently selected tabs are visible. |
| * <p> |
| * For example, consider a CTabFolder that contains "Tab 1", "Tab 2", |
| * "Tab 3" and "Tab 4" (in order by index). The user selects |
| * "Tab 1" and then "Tab 3". If the CTabFolder is now |
| * compressed so that only two tabs are visible, by default, |
| * "Tab 2" and "Tab 3" will be shown ("Tab 3" since it is currently |
| * selected and "Tab 2" because it is the previous item in index order). |
| * If MRU visibility is enabled, the two visible tabs will be "Tab 1" |
| * and "Tab 3" (in that order from left to right).</p> |
| * |
| * @return the receiver's header's visibility state |
| * |
| * @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> |
| * |
| * @since 3.1 |
| */ |
| public boolean getMRUVisible() { |
| checkWidget(); |
| return mru; |
| } |
| /** |
| * Returns the receiver's renderer. |
| * |
| * @return the receiver's renderer |
| * |
| * @exception SWTException <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> |
| * |
| * @see #setRenderer(CTabFolderRenderer) |
| * @see CTabFolderRenderer |
| * |
| * @since 3.6 |
| */ |
| public CTabFolderRenderer getRenderer() { |
| checkWidget(); |
| return renderer; |
| } |
| int getRightItemEdge (GC gc){ |
| Rectangle trim = renderer.computeTrim(CTabFolderRenderer.PART_BORDER, SWT.NONE, 0, 0, 0, 0); |
| int x = getSize().x - (trim.width + trim.x); |
| int width = 0; |
| for (int i = 0; i < controls.length; i++) { |
| int align = controlAlignments[i]; |
| if ((align & SWT.WRAP) == 0 && (align & SWT.LEAD) == 0 && !controls[i].isDisposed() && controls[i].getVisible()) { |
| Point rightSize = controls[i].computeSize(SWT.DEFAULT, SWT.DEFAULT); |
| width += rightSize.x; |
| } |
| } |
| if (width != 0) width += SPACING * 2; |
| x -= width; |
| return Math.max(0, x); |
| } |
| /** |
| * Return the selected tab item, or null if there is no selection. |
| * |
| * @return the selected tab item, or null if none has been selected |
| * |
| * @exception SWTException <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 CTabItem getSelection() { |
| //checkWidget(); |
| if (selectedIndex == -1) return null; |
| return items[selectedIndex]; |
| } |
| /** |
| * Returns the receiver's selection background color. |
| * |
| * @return the selection background color of the receiver |
| * |
| * @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> |
| * |
| * @since 3.0 |
| */ |
| public Color getSelectionBackground() { |
| checkWidget(); |
| return selectionBackground; |
| } |
| /** |
| * Returns the receiver's selection foreground color. |
| * |
| * @return the selection foreground color of the receiver |
| * |
| * @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> |
| * |
| * @since 3.0 |
| */ |
| public Color getSelectionForeground() { |
| checkWidget(); |
| return selectionForeground; |
| } |
| /** |
| * 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 |
| * |
| * @exception SWTException <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 getSelectionIndex() { |
| //checkWidget(); |
| return selectedIndex; |
| } |
| /** |
| * Returns <code>true</code> if the CTabFolder is rendered |
| * with a simple, traditional shape. |
| * |
| * @return <code>true</code> if the CTabFolder is rendered with a simple shape |
| * |
| * @since 3.0 |
| */ |
| public boolean getSimple() { |
| checkWidget(); |
| return simple; |
| } |
| /** |
| * Returns <code>true</code> if the CTabFolder only displays the selected tab |
| * and <code>false</code> if the CTabFolder displays multiple tabs. |
| * |
| * @return <code>true</code> if the CTabFolder only displays the selected tab and <code>false</code> if the CTabFolder displays multiple tabs |
| * |
| * @since 3.0 |
| */ |
| public boolean getSingle() { |
| checkWidget(); |
| return single; |
| } |
| |
| public int getStyle() { |
| int style = super.getStyle(); |
| style &= ~(SWT.TOP | SWT.BOTTOM); |
| style |= onBottom ? SWT.BOTTOM : SWT.TOP; |
| style &= ~(SWT.SINGLE | SWT.MULTI); |
| style |= single ? SWT.SINGLE : SWT.MULTI; |
| if (borderVisible) style |= SWT.BORDER; |
| style &= ~SWT.CLOSE; |
| if (showClose) style |= SWT.CLOSE; |
| return style; |
| } |
| /** |
| * Returns the height of the tab |
| * |
| * @return the height of the tab |
| * |
| * @exception SWTException <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(); |
| if (fixedTabHeight != SWT.DEFAULT) return fixedTabHeight; |
| return tabHeight - 1; // -1 for line drawn across top of tab //TODO: replace w/ computeTrim of tab area? |
| } |
| /** |
| * Returns the position of the tab. Possible values are SWT.TOP or SWT.BOTTOM. |
| * |
| * @return the position of the tab |
| * |
| * @exception SWTException <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 getTabPosition(){ |
| checkWidget(); |
| return onBottom ? SWT.BOTTOM : SWT.TOP; |
| } |
| /** |
| * 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. |
| * |
| * @return the control in the top right corner of the tab folder or null |
| * |
| * @exception SWTException <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> |
| * |
| * @since 2.1 |
| */ |
| public Control getTopRight() { |
| checkWidget(); |
| return topRight; |
| } |
| /** |
| * Returns the alignment of the top right control. |
| * |
| * @return the alignment of the top right control which is either |
| * <code>SWT.RIGHT</code> or <code>SWT.FILL</code> |
| * |
| * @exception SWTException <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> |
| * |
| * @since 3.6 |
| */ |
| public int getTopRightAlignment() { |
| checkWidget(); |
| return topRightAlignment; |
| } |
| /** |
| * Returns <code>true</code> if the close button appears |
| * when the user hovers over an unselected tabs. |
| * |
| * @return <code>true</code> if the close button appears on unselected tabs |
| * |
| * @since 3.0 |
| */ |
| public boolean getUnselectedCloseVisible() { |
| checkWidget(); |
| return showUnselectedClose; |
| } |
| /** |
| * Returns <code>true</code> if an image appears |
| * in unselected tabs. |
| * |
| * @return <code>true</code> if an image appears in unselected tabs |
| * |
| * @since 3.0 |
| */ |
| public boolean getUnselectedImageVisible() { |
| checkWidget(); |
| return showUnselectedImage; |
| } |
| /** |
| * Return the index of the specified tab or -1 if the tab is not |
| * in the receiver. |
| * |
| * @param item the tab item for which the index is required |
| * |
| * @return the index of the specified tab item or -1 |
| * |
| * @exception IllegalArgumentException <ul> |
| * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> |
| * </ul> |
| * |
| * @exception SWTException <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 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; |
| } |
| 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 = stripMnemonic(items[childID].getText()); |
| } |
| 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 = _findMnemonic(text); |
| if (mnemonic != '\0') { |
| shortcut = SWT.getMessage ("SWT_Page_Mnemonic", new Object[] {new Character(mnemonic)}); //$NON-NLS-1$ |
| } |
| } |
| } |
| if (childID == ACC.CHILDID_SELF) { |
| shortcut = SWT.getMessage ("SWT_SwitchPage_Shortcut"); //$NON-NLS-1$ |
| } |
| e.result = shortcut; |
| } |
| }); |
| |
| accessible.addAccessibleControlListener(new AccessibleControlAdapter() { |
| public void getChildAtPoint(AccessibleControlEvent e) { |
| Point testPoint = toControl(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.x = location.y = 0; |
| 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; |
| Point pt = null; |
| int childID = e.childID; |
| if (childID == ACC.CHILDID_SELF) { |
| location = getBounds(); |
| pt = getParent().toDisplay(location.x, location.y); |
| } else { |
| if (childID >= 0 && childID < items.length && items[childID].isShowing()) { |
| location = items[childID].getBounds(); |
| } |
| if (location != null) { |
| pt = toDisplay(location.x, location.y); |
| } |
| } |
| if (location != null && pt != null) { |
| 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 = SWT.getMessage ("SWT_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) { |
| int childIdCount = items.length; |
| Object[] children = new Object[childIdCount]; |
| for (int i = 0; i < childIdCount; 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); |
| } |
| } |
| }); |
| } |
| void initAccessibleMinMaxTb() { |
| minMaxTb.getAccessible().addAccessibleListener(new AccessibleAdapter() { |
| public void getName(AccessibleEvent e) { |
| if (e.childID != ACC.CHILDID_SELF) { |
| if (minItem != null && e.childID == minMaxTb.indexOf(minItem)) { |
| e.result = minItem.getToolTipText(); |
| } else if (maxItem != null && e.childID == minMaxTb.indexOf(maxItem)) { |
| e.result = maxItem.getToolTipText(); |
| } |
| } |
| } |
| }); |
| } |
| void initAccessibleChevronTb() { |
| chevronTb.getAccessible().addAccessibleListener(new AccessibleAdapter() { |
| public void getName(AccessibleEvent e) { |
| if (e.childID != ACC.CHILDID_SELF) { |
| if (chevronItem != null && e.childID == chevronTb.indexOf(chevronItem)) { |
| e.result = chevronItem.getToolTipText(); |
| } |
| } |
| } |
| }); |
| } |
| void onKeyDown (Event event) { |
| switch (event.keyCode) { |
| case SWT.ARROW_LEFT: |
| case SWT.ARROW_RIGHT: |
| int count = items.length; |
| if (count == 0) return; |
| if (selectedIndex == -1) return; |
| int leadKey = (getStyle() & SWT.RIGHT_TO_LEFT) != 0 ? SWT.ARROW_RIGHT : SWT.ARROW_LEFT; |
| int offset = event.keyCode == leadKey ? -1 : 1; |
| int index; |
| if (!mru) { |
| index = selectedIndex + offset; |
| } else { |
| int[] visible = new int[items.length]; |
| int idx = 0; |
| int current = -1; |
| for (int i = 0; i < items.length; i++) { |
| if (items[i].showing) { |
| if (i == selectedIndex) current = idx; |
| visible [idx++] = i; |
| } |
| } |
| if (current + offset >= 0 && current + offset < idx){ |
| index = visible [current + offset]; |
| } else { |
| if (showChevron) { |
| Rectangle chevronRect = chevronItem.getBounds(); |
| chevronRect = event.display.map(chevronTb, this, chevronRect); |
| CTabFolderEvent e = new CTabFolderEvent(this); |
| e.widget = this; |
| e.time = event.time; |
| e.x = chevronRect.x; |
| e.y = chevronRect.y; |
| e.width = chevronRect.width; |
| e.height = chevronRect.height; |
| e.doit = true; |
| for (int i = 0; i < folderListeners.length; i++) { |
| folderListeners[i].showList(e); |
| } |
| if (e.doit && !isDisposed()) { |
| showList(chevronRect); |
| } |
| } |
| return; |
| } |
| } |
| if (index < 0 || index >= count) return; |
| setSelection (index, true); |
| forceFocus(); |
| } |
| } |
| void onDispose(Event event) { |
| removeListener(SWT.Dispose, listener); |
| notifyListeners(SWT.Dispose, event); |
| event.type = SWT.None; |
| /* |
| * 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; |
| |
| if (showMenu != null && !showMenu.isDisposed()) { |
| showMenu.dispose(); |
| showMenu = null; |
| } |
| int length = items.length; |
| for (int i = 0; i < length; i++) { |
| if (items[i] != null) { |
| items[i].dispose(); |
| } |
| } |
| |
| gradientColors = null; |
| |
| selectionGradientColors = null; |
| selectionGradientPercents = null; |
| selectionBgImage = null; |
| |
| selectionBackground = null; |
| selectionForeground = null; |
| |
| if (controlBkImages != null) { |
| for (int i = 0; i < controlBkImages.length; i++) { |
| if (controlBkImages[i] != null) { |
| controlBkImages[i].dispose(); |
| controlBkImages[i] = null; |
| } |
| } |
| controlBkImages = null; |
| } |
| controls = null; |
| controlAlignments = null; |
| controlRects = null; |
| |
| if (maxImage != null) maxImage.dispose(); |
| maxImage = null; |
| |
| if (minImage != null) minImage.dispose(); |
| minImage = null; |
| |
| if (chevronImage != null) chevronImage.dispose(); |
| chevronImage = null; |
| |
| if (renderer != null) renderer.dispose(); |
| renderer = null; |
| |
| minItem = null; |
| maxItem = null; |
| minMaxTb = null; |
| |
| chevronItem = null; |
| chevronTb = null; |
| |
| if (folderListeners.length != 0) folderListeners = new CTabFolder2Listener[0]; |
| if (tabListeners.length != 0) tabListeners = new CTabFolderListener[0]; |
| } |
| void onDragDetect(Event event) { |
| boolean consume = false; |
| for (int i = 0; i < items.length; i++) { |
| if (items[i].closeRect.contains(event.x, event.y)) { |
| consume = true; |
| break; |
| } |
| } |
| if (consume) { |
| event.type = SWT.None; |
| } |
| } |
| void onFocus(Event event) { |
| checkWidget(); |
| if (selectedIndex >= 0) { |
| redraw(); |
| } else { |
| setSelection(0, true); |
| } |
| } |
| boolean onMnemonic (Event event, boolean doit) { |
| char key = event.character; |
| for (int i = 0; i < items.length; i++) { |
| if (items[i] != null) { |
| char mnemonic = _findMnemonic (items[i].getText ()); |
| if (mnemonic != '\0') { |
| if (Character.toLowerCase (key) == mnemonic) { |
| if (doit) { |
| setSelection(i, true); |
| forceFocus(); |
| } |
| return true; |
| } |
| } |
| } |
| } |
| return false; |
| } |
| void onMouseDoubleClick(Event event) { |
| if (event.button != 1 || |
| (event.stateMask & SWT.BUTTON2) != 0 || |
| (event.stateMask & SWT.BUTTON3) != 0) return; |
| Event e = new Event(); |
| e.item = getItem(new Point(event.x, event.y)); |
| if (e.item != null) { |
| notifyListeners(SWT.DefaultSelection, e); |
| } |
| } |
| void onMouse(Event event) { |
| if( isDisposed() ) { |
| return; |
| } |
| int x = event.x, y = event.y; |
| switch (event.type) { |
| case SWT.MouseEnter: { |
| setToolTipText(null); |
| break; |
| } |
| case SWT.MouseExit: { |
| for (int i=0; i<items.length; i++) { |
| CTabItem item = items[i]; |
| if (i != selectedIndex && item.closeImageState != SWT.BACKGROUND) { |
| item.closeImageState = SWT.BACKGROUND; |
| redraw(item.closeRect.x, item.closeRect.y, item.closeRect.width, item.closeRect.height, false); |
| } |
| if ((item.state & SWT.HOT) != 0) { |
| item.state &= ~SWT.HOT; |
| redraw(item.x, item.y, item.width, item.height, false); |
| } |
| if (i == selectedIndex && item.closeImageState != SWT.NONE) { |
| item.closeImageState = SWT.NONE; |
| redraw(item.closeRect.x, item.closeRect.y, item.closeRect.width, item.closeRect.height, false); |
| } |
| } |
| break; |
| } |
| case SWT.MouseHover: |
| case SWT.MouseDown: { |
| if (hoverTb && hoverRect.contains(x, y) && !hovering) { |
| hovering = true; |
| updateItems(); |
| hoverTimerRunning = true; |
| event.display.timerExec(2000, new Runnable() { |
| public void run() { |
| if (isDisposed()) return; |
| if (hovering) { |
| Display display = getDisplay(); |
| Control c = display.getCursorControl(); |
| boolean reschedule = false; |
| if (c != null) { |
| for (int i = 0; i < controls.length; i++) { |
| Control temp = c; |
| do { |
| if (temp.equals(controls[i])) { |
| reschedule = true; |
| } else { |
| temp = temp.getParent(); |
| if (temp == null || temp.equals(CTabFolder.this)) break; |
| } |
| } while (!reschedule); |
| if (reschedule) break; |
| } |
| } |
| if (reschedule && hoverTimerRunning) { |
| display.timerExec(2000, this); |
| } else { |
| hovering = false; |
| updateItems(); |
| } |
| } |
| } |
| }); |
| return; |
| } |
| if (event.button != 1) return; |
| CTabItem item = null; |
| if (single) { |
| if (selectedIndex != -1) { |
| Rectangle bounds = items[selectedIndex].getBounds(); |
| if (bounds.contains(x, y)){ |
| item = items[selectedIndex]; |
| } |
| } |
| } else { |
| for (int i=0; i<items.length; i++) { |
| Rectangle bounds = items[i].getBounds(); |
| if (bounds.contains(x, y)){ |
| item = items[i]; |
| } |
| } |
| } |
| if (item != null) { |
| if (item.closeRect.contains(x,y)){ |
| item.closeImageState = SWT.SELECTED; |
| redraw(item.closeRect.x, item.closeRect.y, item.closeRect.width, item.closeRect.height, false); |
| update(); |
| return; |
| } |
| int index = indexOf(item); |
| if (item.showing){ |
| int oldSelectedIndex = selectedIndex; |
| setSelection(index, true); |
| if (oldSelectedIndex == selectedIndex) { |
| /* If the click is on the selected tabitem, then set focus to the tabfolder */ |
| forceFocus(); |
| } |
| } |
| return; |
| } |
| break; |
| } |
| case SWT.MouseMove: { |
| _setToolTipText(event.x, event.y); |
| boolean close = false; |
| for (int i=0; i<items.length; i++) { |
| CTabItem item = items[i]; |
| close = false; |
| if (item.getBounds().contains(x, y)) { |
| close = true; |
| if (item.closeRect.contains(x, y)) { |
| if (item.closeImageState != SWT.SELECTED && item.closeImageState != SWT.HOT) { |
| item.closeImageState = SWT.HOT; |
| redraw(item.closeRect.x, item.closeRect.y, item.closeRect.width, item.closeRect.height, false); |
| } |
| } else { |
| if (item.closeImageState != SWT.NONE) { |
| item.closeImageState = SWT.NONE; |
| redraw(item.closeRect.x, item.closeRect.y, item.closeRect.width, item.closeRect.height, false); |
| } |
| } |
| if ((item.state & SWT.HOT) == 0) { |
| item.state |= SWT.HOT; |
| redraw(item.x, item.y, item.width, item.height, false); |
| } |
| } |
| if (i != selectedIndex && item.closeImageState != SWT.BACKGROUND && !close) { |
| item.closeImageState = SWT.BACKGROUND; |
| redraw(item.closeRect.x, item.closeRect.y, item.closeRect.width, item.closeRect.height, false); |
| } |
| if ((item.state & SWT.HOT) != 0 && !close) { |
| item.state &= ~SWT.HOT; |
| redraw(item.x, item.y, item.width, item.height, false); |
| } |
| if (i == selectedIndex && item.closeImageState != SWT.NONE && !close) { |
| item.closeImageState = SWT.NONE; |
| redraw(item.closeRect.x, item.closeRect.y, item.closeRect.width, item.closeRect.height, false); |
| } |
| } |
| break; |
| } |
| case SWT.MouseUp: { |
| if (event.button != 1) return; |
| CTabItem item = null; |
| if (single) { |
| if (selectedIndex != -1) { |
| Rectangle bounds = items[selectedIndex].getBounds(); |
| if (bounds.contains(x, y)){ |
| item = items[selectedIndex]; |
| } |
| } |
| } else { |
| for (int i=0; i<items.length; i++) { |
| Rectangle bounds = items[i].getBounds(); |
| if (bounds.contains(x, y)){ |
| item = items[i]; |
| } |
| } |
| } |
| if (item != null) { |
| if (item.closeRect.contains(x,y)) { |
| boolean selected = item.closeImageState == SWT.SELECTED; |
| item.closeImageState = SWT.HOT; |
| redraw(item.closeRect.x, item.closeRect.y, item.closeRect.width, item.closeRect.height, false); |
| if (!selected) return; |
| CTabFolderEvent e = new CTabFolderEvent(this); |
| e.widget = this; |
| e.time = event.time; |
| e.item = item; |
| e.doit = true; |
| for (int j = 0; j < folderListeners.length; j++) { |
| CTabFolder2Listener listener = folderListeners[j]; |
| listener.close(e); |
| } |
| for (int j = 0; j < tabListeners.length; j++) { |
| CTabFolderListener listener = tabListeners[j]; |
| listener.itemClosed(e); |
| } |
| if (e.doit) item.dispose(); |
| if (!isDisposed() && item.isDisposed()) { |
| Display display = getDisplay(); |
| Point pt = display.getCursorLocation(); |
| pt = display.map(null, this, pt.x, pt.y); |
| CTabItem nextItem = getItem(pt); |
| if (nextItem != null) { |
| if (nextItem.closeRect.contains(pt)) { |
| if (nextItem.closeImageState != SWT.SELECTED && nextItem.closeImageState != SWT.HOT) { |
| nextItem.closeImageState = SWT.HOT; |
| redraw(nextItem.closeRect.x, nextItem.closeRect.y, nextItem.closeRect.width, nextItem.closeRect.height, false); |
| } |
| } else { |
| if (nextItem.closeImageState != SWT.NONE) { |
| nextItem.closeImageState = SWT.NONE; |
| redraw(nextItem.closeRect.x, nextItem.closeRect.y, nextItem.closeRect.width, nextItem.closeRect.height, false); |
| } |
| } |
| } |
| } |
| return; |
| } |
| } |
| } |
| } |
| } |
| void onPageTraversal(Event event) { |
| int count = items.length; |
| if (count == 0) return; |
| int index = selectedIndex; |
| if (index == -1) { |
| index = 0; |
| } else { |
| int offset = (event.detail == SWT.TRAVERSE_PAGE_NEXT) ? 1 : -1; |
| if (!mru) { |
| index = (selectedIndex + offset + count) % count; |
| } else { |
| int[] visible = new int[items.length]; |
| int idx = 0; |
| int current = -1; |
| for (int i = 0; i < items.length; i++) { |
| if (items[i].showing) { |
| if (i == selectedIndex) current = idx; |
| visible [idx++] = i; |
| } |
| } |
| if (current + offset >= 0 && current + offset < idx){ |
| index = visible [current + offset]; |
| } else { |
| if (showChevron) { |
| Rectangle chevronRect = chevronItem.getBounds(); |
| chevronRect = event.display.map(chevronTb, this, chevronRect); |
| CTabFolderEvent e = new CTabFolderEvent(this); |
| e.widget = this; |
| e.time = event.time; |
| e.x = chevronRect.x; |
| e.y = chevronRect.y; |
| e.width = chevronRect.width; |
| e.height = chevronRect.height; |
| e.doit = true; |
| for (int i = 0; i < folderListeners.length; i++) { |
| folderListeners[i].showList(e); |
| } |
| if (e.doit && !isDisposed()) { |
| showList(chevronRect); |
| } |
| } |
| } |
| } |
| } |
| setSelection (index, true); |
| } |
| void onPaint(Event event) { |
| if (inDispose) return; |
| Font font = getFont(); |
| if (oldFont == null || !oldFont.equals(font)) { |
| // handle case where default font changes |
| oldFont = font; |
| if (!updateTabHeight(false)) { |
| updateItems(); |
| redraw(); |
| return; |
| } |
| } |
| |
| GC gc = event.gc; |
| Font gcFont = gc.getFont(); |
| Color gcBackground = gc.getBackground(); |
| Color gcForeground = gc.getForeground(); |
| |
| // Useful for debugging paint problems |
| //{ |
| //Point size = getSize(); |
| //gc.setBackground(getDisplay().getSystemColor(SWT.COLOR_GREEN)); |
| //gc.fillRectangle(-10, -10, size.x + 20, size.y+20); |
| //} |
| |
| Point size = getSize(); |
| Rectangle bodyRect = new Rectangle(0, 0, size.x, size.y); |
| renderer.draw(CTabFolderRenderer.PART_BODY, SWT.BACKGROUND | SWT.FOREGROUND, bodyRect, gc); |
| |
| gc.setFont(gcFont); |
| gc.setForeground(gcForeground); |
| gc.setBackground(gcBackground); |
| |
| renderer.draw(CTabFolderRenderer.PART_HEADER, SWT.BACKGROUND | SWT.FOREGROUND, bodyRect, gc); |
| |
| gc.setFont(gcFont); |
| gc.setForeground(gcForeground); |
| gc.setBackground(gcBackground); |
| |
| if (!single) { |
| for (int i=0; i < items.length; i++) { |
| Rectangle itemBounds = items[i].getBounds(); |
| if (i != selectedIndex && event.getBounds().intersects(itemBounds)) { |
| renderer.draw(i, SWT.BACKGROUND | SWT.FOREGROUND | items[i].state , itemBounds, gc); |
| } |
| } |
| } |
| |
| gc.setFont(gcFont); |
| gc.setForeground(gcForeground); |
| gc.setBackground(gcBackground); |
| |
| if (selectedIndex != -1) { |
| renderer.draw(selectedIndex, items[selectedIndex].state | SWT.BACKGROUND | SWT.FOREGROUND, items[selectedIndex].getBounds(), gc); |
| } |
| |
| gc.setFont(gcFont); |
| gc.setForeground(gcForeground); |
| gc.setBackground(gcBackground); |
| |
| if (hoverTb) { |
| Rectangle trim = renderer.computeTrim(CTabFolderRenderer.PART_BORDER, SWT.NONE, 0, 0, 0, 0); |
| int x = getSize().x - (trim.width + trim.x); |
| hoverRect = new Rectangle(x - 16 - SPACING, 2, 16, getTabHeight() - 2); |
| gc.setForeground(gc.getDevice().getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW)); |
| x = hoverRect.x; |
| int y = hoverRect.y; |
| gc.setBackground(gc.getDevice().getSystemColor(SWT.COLOR_WHITE)); |
| gc.fillRectangle(x + hoverRect.width - 6, y, 5, 5); |
| gc.drawRectangle(x + hoverRect.width - 6, y, 5, 5); |
| gc.drawLine(x + hoverRect.width - 6, y+2, x + hoverRect.width - 6 + 5, y + 2); |
| gc.fillRectangle(x, y, 5 , 2); |
| gc.drawRectangle(x, y, 5 , 2); |
| } |
| gc.setFont(gcFont); |
| gc.setForeground(gcForeground); |
| gc.setBackground(gcBackground); |
| } |
| |
| void onResize(Event event) { |
| if (inDispose) return; |
| if (ignoreResize) return; |
| if (updateItems()) { |
| redrawTabs(); |
| } |
| Point size = getSize(); |
| if (oldSize == null) { |
| redraw(); |
| } else { |
| if (onBottom && size.y != oldSize.y) { |
| redraw(); |
| } else { |
| int x1 = Math.min(size.x, oldSize.x); |
| Rectangle trim = renderer.computeTrim(CTabFolderRenderer.PART_BODY, SWT.NONE, 0, 0, 0, 0); |
| if (size.x != oldSize.x) x1 -= trim.width + trim.x - marginWidth + 2; |
| if (!simple) x1 -= 5; // rounded top right corner |
| int y1 = Math.min(size.y, oldSize.y); |
| if (size.y != oldSize.y) y1 -= trim.height + trim.y - marginHeight; |
| int x2 = Math.max(size.x, oldSize.x); |
| int y2 = Math.max(size.y, oldSize.y); |
| redraw(0, y1, x2, y2 - y1, false); |
| redraw(x1, 0, x2 - x1, y2, false); |
| if (hoverTb) { |
| redraw(hoverRect.x, hoverRect.y, hoverRect.width, hoverRect.height, false); |
| } |
| } |
| } |
| oldSize = size; |
| } |
| void onSelection(Event event) { |
| if (hovering) { |
| hovering = false; |
| updateItems(); |
| } |
| if (event.widget == maxItem) { |
| CTabFolderEvent e = new CTabFolderEvent(this); |
| e.widget = CTabFolder.this; |
| e.time = event.time; |
| for (int i = 0; i < folderListeners.length; i++) { |
| if (maximized) { |
| folderListeners[i].restore(e); |
| } else { |
| folderListeners[i].maximize(e); |
| } |
| } |
| } else if (event.widget == minItem) { |
| CTabFolderEvent e = new CTabFolderEvent(this); |
| e.widget = CTabFolder.this; |
| e.time = event.time; |
| for (int i = 0; i < folderListeners.length; i++) { |
| if (minimized) { |
| folderListeners[i].restore(e); |
| } else { |
| folderListeners[i].minimize(e); |
| } |
| } |
| } else if (event.widget == chevronItem) { |
| Rectangle chevronRect = chevronItem.getBounds(); |
| chevronRect = event.display.map(chevronTb, this, chevronRect); |
| CTabFolderEvent e = new CTabFolderEvent(this); |
| e.widget = this; |
| e.time = event.time; |
| e.x = chevronRect.x; |
| e.y = chevronRect.y; |
| e.width = chevronRect.width; |
| e.height = chevronRect.height; |
| e.doit = true; |
| for (int i = 0; i < folderListeners.length; i++) { |
| folderListeners[i].showList(e); |
| } |
| if (e.doit && !isDisposed()) { |
| showList(chevronRect); |
| } |
| } |
| } |
| void onTraverse (Event event) { |
| if (ignoreTraverse) return; |
| switch (event.detail) { |
| case SWT.TRAVERSE_ESCAPE: |
| case SWT.TRAVERSE_RETURN: |
| case SWT.TRAVERSE_TAB_NEXT: |
| case SWT.TRAVERSE_TAB_PREVIOUS: |
| Control focusControl = getDisplay().getFocusControl(); |
| if (focusControl == this) event.doit = true; |
| break; |
| case SWT.TRAVERSE_MNEMONIC: |
| event.doit = onMnemonic(event, false); |
| break; |
| case SWT.TRAVERSE_PAGE_NEXT: |
| case SWT.TRAVERSE_PAGE_PREVIOUS: |
| event.doit = items.length > 0; |
| break; |
| } |
| ignoreTraverse = true; |
| notifyListeners(SWT.Traverse, event); |
| ignoreTraverse = false; |
| event.type = SWT.None; |
| if (isDisposed()) return; |
| if (!event.doit) return; |
| switch (event.detail) { |
| case SWT.TRAVERSE_MNEMONIC: |
| onMnemonic(event, true); |
| event.detail = SWT.TRAVERSE_NONE; |
| break; |
| case SWT.TRAVERSE_PAGE_NEXT: |
| case SWT.TRAVERSE_PAGE_PREVIOUS: |
| onPageTraversal(event); |
| event.detail = SWT.TRAVERSE_NONE; |
| break; |
| } |
| } |
| void redrawTabs() { |
| Point size = getSize(); |
| Rectangle trim = renderer.computeTrim(CTabFolderRenderer.PART_BODY, SWT.NONE, 0, 0, 0, 0); |
| if (onBottom) { |
| int h = trim.height + trim.y - marginHeight; |
| redraw(0, size.y - h - 1, size.x, h + 1, false); |
| } else { |
| redraw(0, 0, size.x, -trim.y - marginHeight + 1, false); |
| } |
| } |
| /** |
| * Removes the listener. |
| * |
| * @param listener the listener which should no longer be notified |
| * |
| * @exception IllegalArgumentException <ul> |
| * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> |
| * </ul> |
| * |
| * @exception SWTException <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> |
| * |
| * @see #addCTabFolder2Listener(CTabFolder2Listener) |
| * |
| * @since 3.0 |
| */ |
| public void removeCTabFolder2Listener(CTabFolder2Listener listener) { |
| checkWidget(); |
| if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT); |
| if (folderListeners.length == 0) return; |
| int index = -1; |
| for (int i = 0; i < folderListeners.length; i++) { |
| if (listener == folderListeners[i]){ |
| index = i; |
| break; |
| } |
| } |
| if (index == -1) return; |
| if (folderListeners.length == 1) { |
| folderListeners = new CTabFolder2Listener[0]; |
| return; |
| } |
| CTabFolder2Listener[] newTabListeners = new CTabFolder2Listener[folderListeners.length - 1]; |
| System.arraycopy(folderListeners, 0, newTabListeners, 0, index); |
| System.arraycopy(folderListeners, index + 1, newTabListeners, index, folderListeners.length - index - 1); |
| folderListeners = newTabListeners; |
| } |
| /** |
| * Removes the listener. |
| * |
| * @param listener the listener which should no longer be notified |
| * |
| * @exception IllegalArgumentException <ul> |
| * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> |
| * </ul> |
| * |
| * @exception SWTException <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> |
| * |
| * @deprecated see removeCTabFolderCloseListener(CTabFolderListener) |
| */ |
| 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]; |
| 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; |
| } |
| /** |
| * Removes the listener from the collection of listeners who will |
| * be notified when the user changes the receiver's selection. |
| * |
| * @param listener the listener which should no longer be notified |
| * |
| * @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 SelectionListener |
| * @see #addSelectionListener |
| */ |
| public void removeSelectionListener(SelectionListener listener) { |
| checkWidget(); |
| if (listener == null) { |
| SWT.error(SWT.ERROR_NULL_ARGUMENT); |
| } |
| removeListener(SWT.Selection, listener); |
| removeListener(SWT.DefaultSelection, listener); |
| } |
| |
| public void reskin(int flags) { |
| super.reskin(flags); |
| for (int i = 0; i < items.length; i++) { |
| items[i].reskin(flags); |
| } |
| } |
| |
| public void setBackground (Color color) { |
| super.setBackground(color); |
| renderer.createAntialiasColors(); //TODO: need better caching strategy |
| updateBkImages(); |
| redraw(); |
| } |
| /** |
| * Specify a gradient of colors to be drawn in the background of the unselected tabs. |
| * 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 <code>percents</code> |
| * array must be one less than the size of the <code>colors</code> array. |
| * |
| * @exception SWTException <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> |
| * |
| * @since 3.6 |
| */ |
| public void setBackground(Color[] colors, int[] percents) { |
| setBackground(colors, percents, false); |
| } |
| /** |
| * Specify a gradient of colors to be drawn in the background of the unselected tab. |
| * For example to draw a vertical 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}, true); |
| * </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 <code>percents</code> |
| * array must be one less than the size of the <code>colors</code> array. |
| * |
| * @param vertical indicate the direction of the gradient. <code>True</code> is vertical and <code>false</code> is horizontal. |
| * |
| * @exception SWTException <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> |
| * |
| * @since 3.6 |
| */ |
| public void setBackground(Color[] colors, int[] percents, boolean vertical) { |
| checkWidget(); |
| if (colors != null) { |
| if (percents == null || percents.length != colors.length - 1) { |
| SWT.error(SWT.ERROR_INVALID_ARGUMENT); |
| } |
| 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); |
| } |
| } |
| if (getDisplay().getDepth() < 15) { |
| // Don't use gradients on low color displays |
| colors = new Color[] {colors[colors.length - 1]}; |
| percents = new int[] {}; |
| } |
| } |
| |
| // Are these settings the same as before? |
| 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 && this.gradientVertical == vertical) return; |
| } |
| // Store the new settings |
| if (colors == null) { |
| gradientColors = null; |
| gradientPercents = null; |
| gradientVertical = false; |
| setBackground((Color)null); |
| } 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]; |
| } |
| gradientVertical = vertical; |
| setBackground(gradientColors[gradientColors.length-1]); |
| } |
| |
| // Refresh with the new settings |
| redraw(); |
| } |
| public void setBackgroundImage(Image image) { |
| super.setBackgroundImage(image); |
| renderer.createAntialiasColors(); //TODO: need better caching strategy |
| redraw(); |
| } |
| /** |
| * 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 (borderVisible == show) return; |
| this.borderVisible = show; |
| updateFolder(REDRAW); |
| } |
| void setButtonBounds(GC gc) { |
| Point size = getSize(); |
| // max button |
| Display display = getDisplay(); |
| if (showMax) { |
| if (minMaxTb == null) { |
| minMaxTb = new ToolBar(this, SWT.FLAT); |
| initAccessibleMinMaxTb(); |
| addTabControl(minMaxTb, SWT.TRAIL, 0, false); |
| } |
| if (maxItem == null) { |
| maxItem = new ToolItem(minMaxTb, SWT.PUSH); |
| if (maxImage == null) { |
| maxImage = createButtonImage(display, CTabFolderRenderer.PART_MAX_BUTTON); |
| } |
| maxItem.setImage(maxImage); |
| maxItem.setToolTipText(maximized ? SWT.getMessage("SWT_Restore") : SWT.getMessage("SWT_Maximize")); //$NON-NLS-1$ //$NON-NLS-2$ |
| maxItem.addListener(SWT.Selection, listener); |
| } |
| } else { |
| //might need to remove it if already there |
| if (maxItem != null) { |
| maxItem.dispose(); |
| maxItem = null; |
| } |
| } |
| // min button |
| if (showMin) { |
| if (minMaxTb == null) { |
| minMaxTb = new ToolBar(this, SWT.FLAT); |
| initAccessibleMinMaxTb(); |
| addTabControl(minMaxTb, SWT.TRAIL, 0, false); |
| } |
| if (minItem == null) { |
| minItem = new ToolItem(minMaxTb, SWT.PUSH, 0); |
| if (minImage == null) { |
| minImage = createButtonImage(display, CTabFolderRenderer.PART_MIN_BUTTON); |
| } |
| minItem.setImage(minImage); |
| minItem.setToolTipText(minimized ? SWT.getMessage("SWT_Restore") : SWT.getMessage("SWT_Minimize")); //$NON-NLS-1$ //$NON-NLS-2$ |
| minItem.addListener(SWT.Selection, listener); |
| } |
| } else { |
| //might need to remove it if already there |
| if (minItem != null) { |
| minItem.dispose(); |
| minItem = null; |
| } |
| } |
| if (minMaxTb != null && minMaxTb.getItemCount() == 0) { |
| removeTabControl(minMaxTb, false); |
| minMaxTb.dispose(); |
| minMaxTb = null; |
| } |
| if (showChevron) { |
| int itemCount = items.length; |
| int count; |
| if (single) { |
| count = selectedIndex == -1 ? itemCount : itemCount - 1; |
| } else { |
| int showCount = 0; |
| while (showCount < priority.length && items[priority[showCount]].showing) { |
| showCount++; |
| } |
| count = itemCount - showCount; |
| } |
| if (count != chevronCount) { |
| chevronCount = count; |
| if (chevronImage != null) chevronImage.dispose(); |
| chevronImage = createButtonImage(display, CTabFolderRenderer.PART_CHEVRON_BUTTON); |
| chevronItem.setImage(chevronImage); |
| } |
| } |
| |
| boolean[][] overflow = new boolean[1][0]; |
| Rectangle[] rects = computeControlBounds(size, overflow); |
| if (fixedTabHeight != SWT.DEFAULT) { |
| int height = fixedTabHeight; |
| if (!hovering) { |
| hoverTb = false; |
| Rectangle tabBounds = this.getBounds(); |
| for (int i = 0; i < rects.length; i++) { |
| if (!(overflow[0][i])) { |
| if (rects[i].height > height) { |
| hoverTb = true; |
| break; |
| } |
| } |
| } |
| if (hoverTb) { |
| for (int i = 0; i < rects.length; i++) { |
| if (!(overflow[0][i])) { |
| if (rects[i].height > height) { |
| rects[i].x = tabBounds.width + 20; |
| } |
| } |
| } |
| } |
| } |
| } |
| int headerHeight = 0; |
| for (int i = 0; i < rects.length; i++) { |
| if (!overflow[0][i]) headerHeight = Math.max(rects[i].height, headerHeight); |
| } |
| boolean changed = false; |
| ignoreResize = true; |
| for (int i = 0; i < controls.length; i++) { |
| if (!controls[i].isDisposed()) { |
| if (overflow[0][i]) { |
| controls[i].setBounds(rects[i]); |
| } else { |
| controls[i].moveAbove(null); |
| controls[i].setBounds(rects[i].x, rects[i].y, rects[i].width, headerHeight); |
| } |
| } |
| if (!changed && !rects[i].equals(controlRects[i])) changed = true; |
| } |
| ignoreResize = false; |
| controlRects = rects; |
| if (changed || hovering) updateBkImages(); |
| } |
| public boolean setFocus () { |
| checkWidget (); |
| |
| /* |
| * Feature in SWT. When a new tab item is selected |
| * and the previous tab item had focus, removing focus |
| * from the previous tab item causes fixFocus() to give |
| * focus to the first child, which is usually one of the |
| * toolbars. This is unexpected. |
| * The fix is to try to set focus on the first tab item |
| * if fixFocus() is called. |
| */ |
| Control focusControl = getDisplay().getFocusControl (); |
| boolean fixFocus = isAncestor (focusControl); |
| if (fixFocus) { |
| CTabItem item = getSelection(); |
| if (item != null) { |
| if (item.setFocus ()) return true; |
| } |
| } |
| return super.setFocus (); |
| } |
| /* Copy of isFocusAncestor from Control. */ |
| boolean isAncestor (Control control) { |
| while (control != null && control != this && !(control instanceof Shell)) { |
| control = control.getParent(); |
| } |
| return control == this; |
| } |
| public void setFont(Font font) { |
| checkWidget(); |
| if (font != null && font.equals(getFont())) return; |
| super.setFont(font); |
| oldFont = getFont(); |
| updateFolder(REDRAW); |
| } |
| public void setForeground (Color color) { |
| super.setForeground(color); |
| redraw(); |
| } |
| /** |
| * Display an insert marker before or after the specified tab item. |
| * |
| * A value of 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(); |
| } |
| /** |
| * Display an insert marker before or after the specified tab item. |
| * |
| * A value of -1 will clear the mark. |
| * |
| * @param index 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 IllegalArgumentException<ul> |
| * </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> |
| */ |
| public void setInsertMark(int index, boolean after) { |
| checkWidget(); |
| if (index < -1 || index >= getItemCount()) { |
| SWT.error(SWT.ERROR_INVALID_ARGUMENT); |
| } |
| } |
| boolean setItemLocation(GC gc) { |
| boolean changed = false; |
| if (items.length == 0) return false; |
| Rectangle trim = renderer.computeTrim(CTabFolderRenderer.PART_BORDER, SWT.NONE, 0, 0, 0, 0); |
| int borderBottom = trim.height + trim.y; |
| int borderTop = -trim.y; |
| Point size = getSize(); |
| int y = onBottom ? Math.max(borderBottom, size.y - borderBottom - tabHeight) : borderTop; |
| Point closeButtonSize = renderer.computeSize(CTabFolderRenderer.PART_CLOSE_BUTTON, 0, gc, SWT.DEFAULT, SWT.DEFAULT); |
| int leftItemEdge = getLeftItemEdge(gc, CTabFolderRenderer.PART_BORDER); |
| if (single) { |
| int defaultX = getDisplay().getBounds().width + 10; // off screen |
| for (int i = 0; i < items.length; i++) { |
| CTabItem item = items[i]; |
| if (i == selectedIndex) { |
| firstIndex = selectedIndex; |
| int oldX = item.x, oldY = item.y; |
| item.x = leftItemEdge; |
| item.y = y; |
| item.showing = true; |
| if (showClose || item.showClose) { |
| item.closeRect.x = leftItemEdge - renderer.computeTrim(i, SWT.NONE, 0, 0, 0, 0).x; |
| item.closeRect.y = onBottom ? size.y - borderBottom - tabHeight + (tabHeight - closeButtonSize.y)/2: borderTop + (tabHeight - closeButtonSize.y)/2; |
| } |
| if (item.x != oldX || item.y != oldY) changed = true; |
| } else { |
| item.x = defaultX; |
| item.showing = false; |
| } |
| } |
| } else { |
| int rightItemEdge = getRightItemEdge(gc); |
| int maxWidth = rightItemEdge - leftItemEdge; |
| int width = 0; |
| for (int i = 0; i < priority.length; i++) { |
| CTabItem item = items[priority[i]]; |
| width += item.width; |
| item.showing = i == 0 ? true : item.width > 0 && width <= maxWidth; |
| } |
| int x = getLeftItemEdge(gc, CTabFolderRenderer.PART_HEADER); |
| int defaultX = getDisplay().getBounds().width + 10; // off screen |
| firstIndex = items.length - 1; |
| for (int i = 0; i < items.length; i++) { |
| CTabItem item = items[i]; |
| if (!item.showing) { |
| if (item.x != defaultX) changed = true; |
| item.x = defaultX; |
| } else { |
| firstIndex = Math.min(firstIndex, i); |
| if (item.x != x || item.y != y) changed = true; |
| item.x = x; |
| item.y = y; |
| int state = SWT.NONE; |
| if (i == selectedIndex) state |= SWT.SELECTED; |
| Rectangle edgeTrim = renderer.computeTrim(i, state, 0, 0, 0, 0); |
| item.closeRect.x = item.x + item.width - (edgeTrim.width + edgeTrim.x) - closeButtonSize.x; |
| item.closeRect.y = onBottom ? size.y - borderBottom - tabHeight + (tabHeight - closeButtonSize.y)/2: borderTop + (tabHeight - closeButtonSize.y)/2; |
| x = x + item.width; |
| if (!simple && i == selectedIndex) x -= renderer.curveIndent; //TODO: fix next item position |
| } |
| } |
| } |
| return changed; |
| } |
| /** |
| * Reorder the items of the receiver. |
| * @param indices an array containing the new indices for all items |
| * |
| * @exception IllegalArgumentException <ul> |
| * <li>ERROR_NULL_ARGUMENT - if the indices array is null</li> |
| * <li>ERROR_INVALID_ARGUMENT - if the indices array is not the same length as the number of items, |
| * if there are duplicate indices or an index is out of range.</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> |
| */ |
| /*public*/ void setItemOrder (int[] indices) { |
| checkWidget(); |
| if (indices == null) SWT.error (SWT.ERROR_NULL_ARGUMENT); |
| if (indices.length != items.length) SWT.error (SWT.ERROR_INVALID_ARGUMENT); |
| int newSelectedIndex = -1; |
| boolean[] seen = new boolean[items.length]; |
| CTabItem[] temp = new CTabItem[items.length]; |
| for (int i=0; i<indices.length; i++) { |
| int index = indices[i]; |
| if (!(0 <= index && index < items.length)) SWT.error (SWT.ERROR_INVALID_ARGUMENT); |
| if (seen[index]) SWT.error (SWT.ERROR_INVALID_ARGUMENT); |
| seen[index] = true; |
| if (index == selectedIndex) newSelectedIndex = i; |
| temp[i] = items[index]; |
| } |
| items = temp; |
| selectedIndex = newSelectedIndex; |
| updateFolder(REDRAW); |
| } |
| boolean setItemSize(GC gc) { |
| boolean changed = false; |
| if (isDisposed()) return changed; |
| Point size = getSize(); |
| if (size.x <= 0 || size.y <= 0) return changed; |
| ToolBar chevron = getChevron(); |
| if (chevron != null) chevron.setVisible(false); |
| showChevron = false; |
| if (single) { |
| showChevron = chevronVisible && items.length > 1; |
| if (showChevron) { |
| chevron.setVisible(true); |
| } |
| if (selectedIndex != -1) { |
| CTabItem tab = items[selectedIndex]; |
| int width = renderer.computeSize(selectedIndex, SWT.SELECTED, gc, SWT.DEFAULT, SWT.DEFAULT).x; |
| width = Math.min(width, getRightItemEdge(gc) - getLeftItemEdge(gc, CTabFolderRenderer.PART_BORDER)); |
| if (tab.height != tabHeight || tab.width != width) { |
| changed = true; |
| tab.shortenedText = null; |
| tab.shortenedTextWidth = 0; |
| tab.height = tabHeight; |
| tab.width = width; |
| tab.closeRect.width = tab.closeRect.height = 0; |
| if (showClose || tab.showClose) { |
| Point closeSize = renderer.computeSize(CTabFolderRenderer.PART_CLOSE_BUTTON, SWT.SELECTED, gc, SWT.DEFAULT, SWT.DEFAULT); |
| tab.closeRect.width = closeSize.x; |
| tab.closeRect.height = closeSize.y; |
| } |
| } |
| } |
| return changed; |
| } |
| |
| if (items.length == 0) return changed; |
| int[] widths; |
| int tabAreaWidth = Math.max(0, getRightItemEdge(gc) - getLeftItemEdge(gc, CTabFolderRenderer.PART_BORDER)); |
| // First, try the minimum tab size at full compression. |
| int minWidth = 0; |
| int[] minWidths = new int[items.length]; |
| for (int i = 0; i < priority.length; i++) { |
| int index = priority[i]; |
| int state = CTabFolderRenderer.MINIMUM_SIZE; |
| if (index == selectedIndex) state |= SWT.SELECTED; |
| minWidths[index] = renderer.computeSize(index, state, gc, SWT.DEFAULT, SWT.DEFAULT).x; |
| minWidth += minWidths[index]; |
| if (minWidth > tabAreaWidth) break; |
| } |
| if (minWidth > tabAreaWidth) { |
| // full compression required and a chevron |
| showChevron = chevronVisible && items.length > 1; |
| if (showChevron) { |
| tabAreaWidth -= chevron.computeSize(SWT.DEFAULT, SWT.DEFAULT).x; |
| chevron.setVisible(true); |
| } |
| widths = minWidths; |
| int index = selectedIndex != -1 ? selectedIndex : 0; |
| if (tabAreaWidth < widths[index]) { |
| widths[index] = Math.max(0, tabAreaWidth); |
| } |
| } else { |
| int maxWidth = 0; |
| int[] maxWidths = new int[items.length]; |
| for (int i = 0; i < items.length; i++) { |
| int state = 0; |
| if (i == selectedIndex) state |= SWT.SELECTED; |
| maxWidths[i] = renderer.computeSize(i, state, gc, SWT.DEFAULT, SWT.DEFAULT).x; |
| maxWidth += maxWidths[i]; |
| } |
| if (maxWidth <= tabAreaWidth) { |
| // no compression required |
| widths = maxWidths; |
| } else { |
| // determine compression for each item |
| int extra = (tabAreaWidth - minWidth) / items.length; |
| while (true) { |
| int large = 0, totalWidth = 0; |
| for (int i = 0 ; i < items.length; i++) { |
| if (maxWidths[i] > minWidths[i] + extra) { |
| totalWidth += minWidths[i] + extra; |
| large++; |
| } else { |
| totalWidth += maxWidths[i]; |
| } |
| } |
| if (totalWidth >= tabAreaWidth) { |
| extra--; |
| break; |
| } |
| if (large == 0 || tabAreaWidth - totalWidth < large) break; |
| extra++; |
| } |
| widths = new int[items.length]; |
| for (int i = 0; i < items.length; i++) { |
| widths[i] = Math.min(maxWidths[i], minWidths[i] + extra); |
| } |
| } |
| } |
| |
| for (int i = 0; i < items.length; i++) { |
| CTabItem tab = items[i]; |
| int width = widths[i]; |
| if (tab.height != tabHeight || tab.width != width) { |
| changed = true; |
| tab.shortenedText = null; |
| tab.shortenedTextWidth = 0; |
| tab.height = tabHeight; |
| tab.width = width; |
| tab.closeRect.width = tab.closeRect.height = 0; |
| if (showClose || tab.showClose) { |
| if (i == selectedIndex || showUnselectedClose) { |
| Point closeSize = renderer.computeSize(CTabFolderRenderer.PART_CLOSE_BUTTON, SWT.NONE, gc, SWT.DEFAULT, SWT.DEFAULT); |
| tab.closeRect.width = closeSize.x; |
| tab.closeRect.height = closeSize.y; |
| } |
| } |
| } |
| } |
| return changed; |
| } |
| /** |
| * Marks the receiver's maximize button as visible if the argument is <code>true</code>, |
| * and marks it invisible otherwise. |
| * |
| * @param visible the new visibility state |
| * |
| * @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> |
| * |
| * @since 3.0 |
| */ |
| public void setMaximizeVisible(boolean visible) { |
| checkWidget(); |
| if (showMax == visible) return; |
| // display maximize button |
| showMax = visible; |
| updateFolder(UPDATE_TAB_HEIGHT | REDRAW); |
| } |
| /** |
| * Sets the layout which is associated with the receiver to be |
| * the argument which may be null. |
| * <p> |
| * Note: No Layout can be set on this Control because it already |
| * manages the size and position of its children. |
| * </p> |
| * |
| * @param layout the receiver's new layout 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> |
| * </ul> |
| */ |
| public void setLayout (Layout layout) { |
| checkWidget(); |
| return; |
| } |
| /** |
| * Sets the maximized state of the receiver. |
| * |
| * @param maximize the new maximized state |
| * |
| * @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> |
| * |
| * @since 3.0 |
| */ |
| public void setMaximized(boolean maximize) { |
| checkWidget (); |
| if (this.maximized == maximize) return; |
| if (maximize && this.minimized) setMinimized(false); |
| this.maximized = maximize; |
| if (minMaxTb != null && maxItem != null) { |
| if (maxImage != null) maxImage.dispose(); |
| maxImage = createButtonImage(getDisplay(), CTabFolderRenderer.PART_MAX_BUTTON); |
| maxItem.setImage(maxImage); |
| maxItem.setToolTipText(maximized ? SWT.getMessage("SWT_Restore") : SWT.getMessage("SWT_Maximize")); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| } |
| /** |
| * Marks the receiver's minimize button as visible if the argument is <code>true</code>, |
| * and marks it invisible otherwise. |
| * |
| * @param visible the new visibility state |
| * |
| * @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> |
| * |
| * @since 3.0 |
| */ |
| public void setMinimizeVisible(boolean visible) { |
| checkWidget(); |
| if (showMin == visible) return; |
| // display minimize button |
| showMin = visible; |
| updateFolder(UPDATE_TAB_HEIGHT | REDRAW); |
| } |
| /** |
| * Sets the minimized state of the receiver. |
| * |
| * @param minimize the new minimized state |
| * |
| * @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> |
| * |
| * @since 3.0 |
| */ |
| public void setMinimized(boolean minimize) { |
| checkWidget (); |
| if (this.minimized == minimize) return; |
| if (minimize && this.maximized) setMaximized(false); |
| this.minimized = minimize; |
| if (minMaxTb != null && minItem != null) { |
| if (minImage != null) minImage.dispose(); |
| minImage = createButtonImage(getDisplay(), CTabFolderRenderer.PART_MIN_BUTTON); |
| minItem.setImage(minImage); |
| minItem.setToolTipText(minimized ? SWT.getMessage("SWT_Restore") : SWT.getMessage("SWT_Minimize")); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| } |
| |
| /** |
| * Sets the minimum number of characters that will |
| * be displayed in a fully compressed tab. |
| * |
| * @param count the minimum number of characters that will be displayed in a fully compressed 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> |
| * <li>ERROR_INVALID_RANGE - if the count is less than zero</li> |
| * </ul> |
| * |
| * @since 3.0 |
| */ |
| public void setMinimumCharacters(int count) { |
| checkWidget (); |
| if (count < 0) SWT.error(SWT.ERROR_INVALID_RANGE); |
| if (minChars == count) return; |
| minChars = count; |
| updateFolder(REDRAW_TABS); |
| } |
| |
| /** |
| * When there is not enough horizontal space to show all the tabs, |
| * by default, tabs are shown sequentially from left to right in |
| * order of their index. When the MRU visibility is turned on, |
| * the tabs that are visible will be the tabs most recently selected. |
| * Tabs will still maintain their left to right order based on index |
| * but only the most recently selected tabs are visible. |
| * <p> |
| * For example, consider a CTabFolder that contains "Tab 1", "Tab 2", |
| * "Tab 3" and "Tab 4" (in order by index). The user selects |
| * "Tab 1" and then "Tab 3". If the CTabFolder is now |
| * compressed so that only two tabs are visible, by default, |
| * "Tab 2" and "Tab 3" will be shown ("Tab 3" since it is currently |
| * selected and "Tab 2" because it is the previous item in index order). |
| * If MRU visibility is enabled, the two visible tabs will be "Tab 1" |
| * and "Tab 3" (in that order from left to right).</p> |
| * |
| * @param show the new visibility state |
| * |
| * @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> |
| * |
| * @since 3.1 |
| */ |
| public void setMRUVisible(boolean show) { |
| checkWidget(); |
| if (mru == show) return; |
| mru = show; |
| if (!mru) { |
| if (firstIndex == -1) return; |
| int idx = firstIndex; |
| int next = 0; |
| for (int i = firstIndex; i < items.length; i++) { |
| priority[next++] = i; |
| } |
| for (int i = 0; i < idx; i++) { |
| priority[next++] = i; |
| } |
| updateFolder(REDRAW_TABS); |
| } |
| } |
| /** |
| * Sets the renderer which is associated with the receiver to be |
| * the argument which may be null. In the case of null, the default |
| * renderer is used. |
| * |
| * @param renderer a new renderer |
| * |
| * @exception SWTException <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> |
| * |
| * @see CTabFolderRenderer |
| * |
| * @since 3.6 |
| */ |
| public void setRenderer(CTabFolderRenderer renderer) { |
| checkWidget(); |
| if (this.renderer == renderer) return; |
| if (this.renderer != null) this.renderer.dispose(); |
| if (renderer == null) renderer = new CTabFolderRenderer(this); |
| this.renderer = renderer; |
| updateFolder(REDRAW); |
| } |
| /** |
| * Set the selection to the tab at the specified item. |
| * |
| * @param item the tab item to be selected |
| * |
| * @exception IllegalArgumentException <ul> |
| * <li>ERROR_NULL_ARGUMENT - if the item is null</li> |
| * </ul> |
| * |
| * @exception SWTException <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 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. |
| * |
| * @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; |
| CTabItem selection = items[index]; |
| if (selectedIndex == index) { |
| showItem(selection); |
| return; |
| } |
| |
| int oldIndex = selectedIndex; |
| selectedIndex = index; |
| if (oldIndex != -1) { |
| items[oldIndex].closeImageState = SWT.BACKGROUND; |
| items[oldIndex].state &= ~SWT.SELECTED; |
| } |
| selection.closeImageState = SWT.NONE; |
| selection.showing = false; |
| selection.state |= SWT.SELECTED; |
| |
| Control newControl = selection.control; |
| Control oldControl = null; |
| if (oldIndex != -1) { |
| oldControl = items[oldIndex].control; |
| } |
| |
| if (newControl != oldControl) { |
| if (newControl != null && !newControl.isDisposed()) { |
| newControl.setBounds(getClientArea()); |
| newControl.setVisible(true); |
| } |
| if (oldControl != null && !oldControl.isDisposed()) { |
| oldControl.setVisible(false); |
| } |
| } |
| showItem(selection); |
| redraw(); |
| } |
| 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); |
| } |
| } |
| /** |
| * Sets the receiver's selection background color to the color specified |
| * by the argument, or to the default system color for the control |
| * if the argument is null. |
| * |
| * @param color the new color (or null) |
| * |
| * @exception IllegalArgumentException <ul> |
| * <li>ERROR_INVALID_ARGUMENT - if the argument 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> |
| * |
| * @since 3.0 |
| */ |
| public void setSelectionBackground (Color color) { |
| if (inDispose) return; |
| checkWidget(); |
| setSelectionHighlightGradientColor(null); |
| if (selectionBackground == color) return; |
| if (color == null) color = getDisplay().getSystemColor(SELECTION_BACKGROUND); |
| selectionBackground = color; |
| renderer.createAntialiasColors(); //TODO: need better caching strategy |
| if (selectedIndex > -1) redraw(); |
| } |
| /** |
| * 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 SWTException <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) { |
| setSelectionBackground(colors, percents, false); |
| } |
| /** |
| * Specify a gradient of colours to be draw in the background of the selected tab. |
| * For example to draw a vertical 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}, true); |
| * </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. |
| * |
| * @param vertical indicate the direction of the gradient. True is vertical and false is horizontal. |
| * |
| * @exception SWTException <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> |
| * |
| * @since 3.0 |
| */ |
| public void setSelectionBackground(Color[] colors, int[] percents, boolean vertical) { |
| checkWidget(); |
| int colorsLength; |
| Color highlightBeginColor = null; //null == no highlight |
| |
| if (colors != null) { |
| //The colors array can optionally have an extra entry which describes the highlight top color |
| //Thus its either one or two larger than the percents array |
| if (percents == null || |
| ! ((percents.length == colors.length - 1) || (percents.length == colors.length - 2))){ |
| SWT.error(SWT.ERROR_INVALID_ARGUMENT); |
| } |
| 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); |
| } |
| } |
| //If the colors is exactly two more than percents then last is highlight |
| //Keep track of *real* colorsLength (minus the highlight) |
| if(percents.length == colors.length - 2) { |
| highlightBeginColor = colors[colors.length - 1]; |
| colorsLength = colors.length - 1; |
| } else { |
| colorsLength = colors.length; |
| } |
| if (getDisplay().getDepth() < 15) { |
| // Don't use gradients on low color displays |
| colors = new Color[] {colors[colorsLength - 1]}; |
| colorsLength = colors.length; |
| percents = new int[] {}; |
| } |
| } else { |
| colorsLength = 0; |
| } |
| |
| // Are these settings the same as before? |
| if (selectionBgImage == null) { |
| if ((selectionGradientColors != null) && (colors != null) && |
| (selectionGradientColors.length == colorsLength)) { |
| boolean same = false; |
| for (int i = 0; i < selectionGradientColors.length; i++) { |
| if (selectionGradientColors[i] == null) { |
| same = colors[i] == null; |
| } else { |
| same = selectionGradientColors[i].equals(colors[i]); |
| } |
| if (!same) break; |
| } |
| if (same) { |
| for (int i = 0; i < selectionGradientPercents.length; i++) { |
| same = selectionGradientPercents[i] == percents[i]; |
| if (!same) break; |
| } |
| } |
| if (same && this.selectionGradientVertical == vertical) return; |
| } |
| } else { |
| selectionBgImage = null; |
| } |
| // Store the new settings |
| if (colors == null) { |
| selectionGradientColors = null; |
| selectionGradientPercents = null; |
| selectionGradientVertical = false; |
| setSelectionBackground((Color)null); |
| setSelectionHighlightGradientColor(null); |
| } else { |
| selectionGradientColors = new Color[colorsLength]; |
| for (int i = 0; i < colorsLength; ++i) { |
| selectionGradientColors[i] = colors[i]; |
| } |
| selectionGradientPercents = new int[percents.length]; |
| for (int i = 0; i < percents.length; ++i) { |
| selectionGradientPercents[i] = percents[i]; |
| } |
| selectionGradientVertical = vertical; |
| setSelectionBackground(selectionGradientColors[selectionGradientColors.length-1]); |
| setSelectionHighlightGradientColor(highlightBeginColor); |
| } |
| |
| // Refresh with the new settings |
| if (selectedIndex > -1) redraw(); |
| } |
| |
| /* |
| * Set the color for the highlight start for selected tabs. |
| * Update the cache of highlight gradient colors if required. |
| */ |
| void setSelectionHighlightGradientColor(Color start) { |
| if (inDispose) return; |
| renderer.setSelectionHighlightGradientColor(start); //TODO: need better caching strategy |
| } |
| |
| /** |
| * Set the image to be drawn in the background of the selected tab. Image |
| * is stretched or compressed to cover entire selection tab area. |
| * |
| * @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(); |
| setSelectionHighlightGradientColor(null); |
| if (image == selectionBgImage) return; |
| if (image != null) { |
| selectionGradientColors = null; |
| selectionGradientPercents = null; |
| renderer.disposeSelectionHighlightGradientColors(); //TODO: need better caching strategy |
| } |
| selectionBgImage = image; |
| renderer.createAntialiasColors(); //TODO: need better caching strategy |
| if (selectedIndex > -1) redraw(); |
| } |
| /** |
| * 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 = getDisplay().getSystemColor(SELECTION_FOREGROUND); |
| selectionForeground = color; |
| if (selectedIndex > -1) redraw(); |
| } |
| |
| /** |
| * Sets the shape that the CTabFolder will use to render itself. |
| * |
| * @param simple <code>true</code> if the CTabFolder should render itself in a simple, traditional style |
| * |
| * @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> |
| * |
| * @since 3.0 |
| */ |
| public void setSimple(boolean simple) { |
| checkWidget(); |
| if (this.simple != simple) { |
| this.simple = simple; |
| updateFolder(UPDATE_TAB_HEIGHT | REDRAW); |
| } |
| } |
| /** |
| * Sets the number of tabs that the CTabFolder should display |
| * |
| * @param single <code>true</code> if only the selected tab should be displayed otherwise, multiple tabs will be shown. |
| * |
| * @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> |
| * |
| * @since 3.0 |
| */ |
| public void setSingle(boolean single) { |
| checkWidget(); |
| if (this.single != single) { |
| this.single = single; |
| if (!single) { |
| for (int i = 0; i < items.length; i++) { |
| if (i != selectedIndex && items[i].closeImageState == SWT.NONE) { |
| items[i].closeImageState = SWT.BACKGROUND; |
| } |
| } |
| } |
| updateFolder(REDRAW); |
| } |
| } |
| |
| int getControlY(Point size, Rectangle[] rects, int borderBottom, int borderTop, int i) { |
| int center = fixedTabHeight != SWT.DEFAULT ? 0 : (tabHeight - rects[i].height)/2; |
| return onBottom ? size.y - 1 - borderBottom - tabHeight + center : 1 + borderTop + center; |
| } |
| |
| /** |
| * 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 -1 will revert to the default height. |
| * |
| * @param height the pixel value of the height or -1 |
| * |
| * @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 < -1) { |
| SWT.error(SWT.ERROR_INVALID_ARGUMENT); |
| } |
| fixedTabHeight = height; |
| updateFolder(UPDATE_TAB_HEIGHT); |
| } |
| /** |
| * Specify whether the tabs should appear along the top of the folder |
| * or along the bottom of the folder. |
| * |
| * @param position <code>SWT.TOP</code> for tabs along the top or <code>SWT.BOTTOM</code> for tabs along the bottom |
| * |
| * @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 position value is not either SWT.TOP or SWT.BOTTOM</li> |
| * </ul> |
| * |
| * @since 3.0 |
| */ |
| public void setTabPosition(int position) { |
| checkWidget(); |
| if (position != SWT.TOP && position != SWT.BOTTOM) { |
| SWT.error(SWT.ERROR_INVALID_ARGUMENT); |
| } |
| if (onBottom != (position == SWT.BOTTOM)) { |
| onBottom = position == SWT.BOTTOM; |
| updateFolder(REDRAW); |
| } |
| } |
| /** |
| * 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. |
| * |
| * @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 disposed, or not a child of this CTabFolder</li> |
| * </ul> |
| * |
| * @since 2.1 |
| */ |
| public void setTopRight(Control control) { |
| setTopRight(control, SWT.RIGHT); |
| } |
| /** |
| * 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. |
| * <p> |
| * The alignment parameter sets the layout of the control in the tab area. |
| * <code>SWT.RIGHT</code> will cause the control to be positioned on the far |
| * right of the folder and it will have its default size. <code>SWT.FILL</code> |
| * will size the control to fill all the available space to the right of the |
| * last tab. If there is no available space, the control will not be visible. |
| * <code>SWT.RIGHT | SWT.WRAP</code> will allow the control to wrap below the |
| * tabs if there is not enough available space to the right of the last tab. |
| * </p> |
| * |
| * @param control the control to be displayed in the top right corner or null |
| * @param alignment <code>SWT.RIGHT</code> or <code>SWT.FILL</code> or <code>SWT.RIGHT | SWT.WRAP</code> |
| * |
| * @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 disposed, or not a child of this CTabFolder</li> |
| * </ul> |
| * |
| * @since 3.0 |
| */ |
| public void setTopRight(Control control, int alignment) { |
| checkWidget(); |
| if (alignment != SWT.RIGHT && alignment != SWT.FILL && alignment != (SWT.RIGHT | SWT.WRAP)) { |
| SWT.error(SWT.ERROR_INVALID_ARGUMENT); |
| } |
| if (control != null && (control.isDisposed() || control.getParent() != this)) { |
| SWT.error(SWT.ERROR_INVALID_ARGUMENT); |
| } |
| if (topRight == control && topRightAlignment == alignment) return; |
| if (topRight != null && !topRight.isDisposed()) removeTabControl(topRight, false); |
| topRight = control; |
| topRightAlignment = alignment; |
| alignment &= ~SWT.RIGHT; |
| if (control != null) addTabControl(control, SWT.TRAIL | alignment, -1, false); |
| updateFolder(UPDATE_TAB_HEIGHT | REDRAW); |
| } |
| |
| |
| /** |
| * Specify whether the close button appears |
| * when the user hovers over an unselected tabs. |
| * |
| * @param visible <code>true</code> makes the close button appear |
| * |
| * @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> |
| * |
| * @since 3.0 |
| */ |
| public void setUnselectedCloseVisible(boolean visible) { |
| checkWidget(); |
| if (showUnselectedClose == visible) return; |
| // display close button when mouse hovers |
| showUnselectedClose = visible; |
| updateFolder(REDRAW); |
| } |
| /** |
| * Specify whether the image appears on unselected tabs. |
| * |
| * @param visible <code>true</code> makes the image appear |
| * |
| * @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> |
| * |
| * @since 3.0 |
| */ |
| public void setUnselectedImageVisible(boolean visible) { |
| checkWidget(); |
| if (showUnselectedImage == visible) return; |
| // display image on unselected items |
| showUnselectedImage = visible; |
| updateFolder(REDRAW); |
| } |
| /** |
| * 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 == -1) SWT.error(SWT.ERROR_INVALID_ARGUMENT); |
| int idx = -1; |
| for (int i = 0; i < priority.length; i++) { |
| if (priority[i] == index) { |
| idx = i; |
| break; |
| } |
| } |
| if (mru) { |
| // move to front of mru order |
| int[] newPriority = new int[priority.length]; |
| System.arraycopy(priority, 0, newPriority, 1, idx); |
| System.arraycopy(priority, idx+1, newPriority, idx+1, priority.length - idx - 1); |
| newPriority[0] = index; |
| priority = newPriority; |
| } |
| if (item.isShowing()) return; |
| updateFolder(REDRAW_TABS); |
| } |
| void showList (Rectangle rect) { |
| if (items.length == 0 || !showChevron) return; |
| if (showMenu == null || showMenu.isDisposed()) { |
| showMenu = new Menu(getShell(), getStyle() & (SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT)); |
| } else { |
| MenuItem[] items = showMenu.getItems(); |
| for (int i = 0; i < items.length; i++) { |
| items[i].dispose(); |
| } |
| } |
| final String id = "CTabFolder_showList_Index"; //$NON-NLS-1$ |
| for (int i = 0; i < items.length; i++) { |
| CTabItem tab = items[i]; |
| if (tab.showing) continue; |
| MenuItem item = new MenuItem(showMenu, SWT.NONE); |
| item.setText(tab.getText()); |
| item.setImage(tab.getImage()); |
| item.setData(id, tab); |
| item.addSelectionListener(new SelectionAdapter() { |
| public void widgetSelected(SelectionEvent e) { |
| MenuItem menuItem = (MenuItem)e.widget; |
| int index = indexOf((CTabItem)menuItem.getData(id)); |
| CTabFolder.this.setSelection(index, true); |
| } |
| }); |
| } |
| int x = rect.x; |
| int y = rect.y + rect.height; |
| Point location = getDisplay().map(this, null, x, y); |
| showMenu.setLocation(location.x, location.y); |
| showMenu.setVisible(true); |
| } |
| /** |
| * 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 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()); |
| } |
| } |
| |
| void _setToolTipText (int x, int y) { |
| String oldTip = getToolTipText(); |
| String newTip = _getToolTip(x, y); |
| if (newTip == null || !newTip.equals(oldTip)) { |
| setToolTipText(newTip); |
| } |
| } |
| |
| boolean updateItems() { |
| return updateItems(selectedIndex); |
| } |
| |
| boolean updateItems (int showIndex) { |
| GC gc = new GC(this); |
| if (!single && !mru && showIndex != -1) { |
| // make sure selected item will be showing |
| int firstIndex = showIndex; |
| if (priority[0] < showIndex) { |
| int maxWidth = getRightItemEdge(gc) - getLeftItemEdge(gc, CTabFolderRenderer.PART_BORDER); |
| int width = 0; |
| int[] widths = new int[items.length]; |
| for (int i = priority[0]; i <= showIndex; i++) { |
| int state = CTabFolderRenderer.MINIMUM_SIZE; |
| if (i == selectedIndex) state |= SWT.SELECTED; |
| widths[i] = renderer.computeSize(i, state, gc, SWT.DEFAULT, SWT.DEFAULT).x; |
| width += widths[i]; |
| if (width > maxWidth) break; |
| } |
| if (width > maxWidth) { |
| width = 0; |
| for (int i = showIndex; i >= 0; i--) { |
| int state = CTabFolderRenderer.MINIMUM_SIZE; |
| if (i == selectedIndex) state |= SWT.SELECTED; |
| if (widths[i] == 0) widths[i] = renderer.computeSize(i, state, gc, SWT.DEFAULT, SWT.DEFAULT).x; |
| width += widths[i]; |
| if (width > maxWidth) break; |
| firstIndex = i; |
| } |
| } else { |
| firstIndex = priority[0]; |
| for (int i = showIndex + 1; i < items.length; i++) { |
| int state = CTabFolderRenderer.MINIMUM_SIZE; |
| if (i == selectedIndex) state |= SWT.SELECTED; |
| widths[i] = renderer.computeSize(i, state, gc, SWT.DEFAULT, SWT.DEFAULT).x; |
| width += widths[i]; |
| if (width >= maxWidth) break; |
| } |
| if (width < maxWidth) { |
| for (int i = priority[0] - 1; i >= 0; i--) { |
| int state = CTabFolderRenderer.MINIMUM_SIZE; |
| if (i == selectedIndex) state |= SWT.SELECTED; |
| if (widths[i] == 0) widths[i] = renderer.computeSize(i, state, gc, SWT.DEFAULT, SWT.DEFAULT).x; |
| width += widths[i]; |
| if (width > maxWidth) break; |
| firstIndex = i; |
| } |
| } |
| } |
| |
| } |
| if (firstIndex != priority[0]) { |
| int index = 0; |
| for (int i = firstIndex; i < items.length; i++) { |
| priority[index++] = i; |
| } |
| for (int i = 0; i < firstIndex; i++) { |
| priority[index++] = i; |
| } |
| } |
| } |
| |
| boolean oldShowChevron = showChevron; |
| boolean changed = setItemSize(gc); |
| changed |= setItemLocation(gc); |
| setButtonBounds(gc); |
| changed |= showChevron != oldShowChevron; |
| if (changed && getToolTipText() != null) { |
| Point pt = getDisplay().getCursorLocation(); |
| pt = toControl(pt); |
| _setToolTipText(pt.x, pt.y); |
| } |
| gc.dispose(); |
| return changed; |
| } |
| boolean updateTabHeight(boolean force){ |
| int oldHeight = tabHeight; |
| GC gc = new GC(this); |
| tabHeight = renderer.computeSize(CTabFolderRenderer.PART_HEADER, SWT.NONE, gc, SWT.DEFAULT, SWT.DEFAULT).y; |
| gc.dispose(); |
| if (fixedTabHeight == SWT.DEFAULT && controls != null && controls.length > 0) { |
| for (int i = 0; i < controls.length; i++) { |
| if ((controlAlignments[i] & SWT.WRAP) == 0 && !controls[i].isDisposed() && (controls[i].getVisible() || controls[i] == chevronTb)) { |
| int topHeight = controls[i].computeSize(SWT.DEFAULT, SWT.DEFAULT).y; |
| topHeight += renderer.computeTrim(CTabFolderRenderer.PART_HEADER, SWT.NONE, 0,0,0,0).height + 1; |
| tabHeight = Math.max(topHeight, tabHeight); |
| } |
| } |
| } |
| if (!force && tabHeight == oldHeight) return false; |
| oldSize = null; |
| return true; |
| } |
| |
| void updateFolder (int flags) { |
| updateFlags |= flags; |
| if (updateRun != null) return; |
| updateRun = new Runnable() { |
| public void run() { |
| updateRun = null; |
| if (isDisposed()) return; |
| runUpdate(); |
| } |
| }; |
| this.getDisplay().asyncExec(updateRun); |
| } |
| |
| void runUpdate() { |
| if (updateFlags == 0) return; |
| int flags = updateFlags; |
| updateFlags = 0; |
| Rectangle rectBefore = getClientArea(); |
| this.updateTabHeight(false); |
| this.updateItems(selectedIndex); |
| if ((flags & REDRAW) != 0) { |
| redraw(); |
| } else if ((flags & REDRAW_TABS) != 0) { |
| redrawTabs(); |
| } |
| Rectangle rectAfter = getClientArea(); |
| if (!rectBefore.equals(rectAfter)) { |
| notifyListeners(SWT.Resize, new Event()); |
| this.layout(); |
| } |
| } |
| |
| void updateBkImages() { |
| if (controls != null && controls.length > 0) { |
| for (int i = 0; i < controls.length; i++) { |
| Control control = controls[i]; |
| if (!control.isDisposed()) { |
| if (hovering) { |
| if (control instanceof Composite) ((Composite) control).setBackgroundMode(SWT.INHERIT_NONE); |
| control.setBackgroundImage(null); |
| control.setBackground(getBackground()); |
| } else { |
| if (control instanceof Composite) ((Composite) control).setBackgroundMode(SWT.INHERIT_DEFAULT); |
| Rectangle bounds = control.getBounds(); |
| if (bounds.y > getTabHeight() || gradientColors == null) { |
| control.setBackgroundImage(null); |
| control.setBackground(getBackground()); |
| } else { |
| bounds.width = 10; |
| bounds.y = -bounds.y; |
| bounds.height -= 2*bounds.y - 1; |
| bounds.x = 0; |
| if (controlBkImages[i] != null) controlBkImages[i].dispose(); |
| controlBkImages[i] = new Image(control.getDisplay(), bounds); |
| GC gc = new GC(controlBkImages[i]); |
| renderer.drawBackground(gc, bounds, 0); |
| gc.dispose(); |
| control.setBackground(null); |
| control.setBackgroundImage(controlBkImages[i]); |
| } |
| } |
| } |
| } |
| |
| } |
| } |
| String _getToolTip(int x, int y) { |
| CTabItem item = getItem(new Point (x, y)); |
| if (item == null) return null; |
| if (!item.showing) return null; |
| if ((showClose || item.showClose) && item.closeRect.contains(x, y)) { |
| return SWT.getMessage("SWT_Close"); //$NON-NLS-1$ |
| } |
| return item.getToolTipText(); |
| } |
| /** |
| * Set a control that can appear to the left or to the right of the folder tabs. |
| * This method can also be used instead of #setTopRight(Control). To remove a tab |
| * control, see#removeTabControl(Control); |
| * <p> |
| * The flags parameter sets the layout of the control in the tab area. |
| * <code>SWT.LEAD</code> will cause the control to be positioned on the left |
| * of the tabs. <code>SWT.TRAIL</code> will cause the control to be positioned on |
| * the far right of the folder and it will have its default size. <code>SWT.TRAIL</code> |
| * can be combined with <code>SWT.FILL</code>to fill all the available space to the |
| * right of the last tab. <code>SWT.WRAP</code> can also be added to <code>SWT.TRAIL</code> |
| * only to cause a control to wrap if there is not enough space to display it in its |
| * entirety. |
| * </p> |
| * @param control the control to be displayed in the top right corner or null |
| * |
| * @param flags valid combinations are: |
| * <ul><li>SWT.LEAD |
| * <li> SWT.TRAIL (| SWT.FILL | SWT.WRAP) |
| * </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> |
| * <li>ERROR_INVALID_ARGUMENT - if the control is not a child of this CTabFolder</li> |
| * </ul> |
| */ |
| /*public*/ void addTabControl(Control control, int flags) { |
| checkWidget(); |
| addTabControl(control, flags, -1, true); |
| } |
| |
| void addTabControl(Control control, int flags, int index, boolean update) { |
| switch (flags) { |
| case SWT.TRAIL: |
| case SWT.TRAIL | SWT.WRAP: |
| case SWT.TRAIL | SWT.FILL: |
| case SWT.TRAIL | SWT.FILL | SWT.WRAP: |
| case SWT.LEAD: |
| break; |
| default: |
| SWT.error(SWT.ERROR_INVALID_ARGUMENT); |
| break; |
| } |
| if (control != null && control.getParent() != this) { |
| SWT.error(SWT.ERROR_INVALID_ARGUMENT); |
| } |
| //check for duplicates |
| for (int i = 0; i < controls.length; i++) { |
| if (controls[i] == control) { |
| SWT.error(SWT.ERROR_INVALID_ARGUMENT); |
| } |
| } |
| int length = controls.length; |
| |
| control.addListener(SWT.Resize, listener); |
| |
| //Grow all 4 arrays |
| Control[] newControls = new Control [length + 1]; |
| System.arraycopy(controls, 0, newControls, 0, length); |
| controls = newControls; |
| int[] newAlignment = new int [length + 1]; |
| System.arraycopy(controlAlignments, 0, newAlignment, 0, length); |
| controlAlignments = newAlignment; |
| Rectangle[] newRect = new Rectangle [length + 1]; |
| System.arraycopy(controlRects, 0, newRect, 0, length); |
| controlRects = newRect; |
| Image[] newImage = new Image [length + 1]; |
| System.arraycopy(controlBkImages, 0, newImage, 0, length); |
| controlBkImages = newImage; |
| if (index == -1) { |
| index = length; |
| if (chevronTb != null && control != chevronTb) index--; |
| } |
| System.arraycopy (controls, index, controls, index + 1, length - index); |
| System.arraycopy (controlAlignments, index, controlAlignments, index + 1, length - index); |
| System.arraycopy (controlRects, index, controlRects, index + 1, length - index); |
| System.arraycopy (controlBkImages, index, controlBkImages, index + 1, length - index); |
| controls[index] = control; |
| controlAlignments[index] = flags; |
| controlRects[index] = new Rectangle(0, 0, 0, 0); |
| if (update) { |
| updateFolder(UPDATE_TAB_HEIGHT | REDRAW); |
| } |
| } |
| |
| /** |
| * Removes the control from the list of tab controls. |
| * |
| * @param control the control to be removed |
| * |
| * @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 removeTabControl (Control control) { |
| checkWidget(); |
| removeTabControl (control, true); |
| } |
| |
| void removeTabControl (Control control, boolean update) { |
| if (control != null && control.getParent() != this) { |
| SWT.error(SWT.ERROR_INVALID_ARGUMENT); |
| } |
| int index = -1; |
| for (int i = 0; i < controls.length; i++) { |
| if (controls[i] == control){ |
| index = i; |
| break; |
| } |
| } |
| if (index == -1) return; |
| |
| if (!control.isDisposed()) { |
| control.removeListener(SWT.Resize, listener); |
| control.setBackground (null); |
| control.setBackgroundImage (null); |
| if (control instanceof Composite) ((Composite) control).setBackgroundMode(SWT.INHERIT_NONE); |
| } |
| |
| if (controlBkImages[index] != null && !controlBkImages[index].isDisposed()) controlBkImages[index].dispose(); |
| if (controls.length == 1) { |
| controls = new Control[0]; |
| controlAlignments = new int[0]; |
| controlRects = new Rectangle[0]; |
| controlBkImages = new Image[0]; |
| } else { |
| Control[] newControls = new Control [controls.length - 1]; |
| System.arraycopy(controls, 0, newControls, 0, index); |
| System.arraycopy(controls, index + 1, newControls, index, controls.length - index - 1); |
| controls = newControls; |
| |
| int[] newAlignments = new int [controls.length]; |
| System.arraycopy(controlAlignments, 0, newAlignments, 0, index); |
| System.arraycopy(controlAlignments, index + 1, newAlignments, index, controls.length - index); |
| controlAlignments = newAlignments; |
| |
| Rectangle[] newRects = new Rectangle [controls.length]; |
| System.arraycopy(controlRects, 0, newRects, 0, index); |
| System.arraycopy(controlRects, index + 1, newRects, index, controls.length - index); |
| controlRects = newRects; |
| |
| Image[] newBkImages = new Image [controls.length]; |
| System.arraycopy(controlBkImages, 0, newBkImages, 0, index); |
| System.arraycopy(controlBkImages, index + 1, newBkImages, index, controls.length - index); |
| controlBkImages = newBkImages; |
| } |
| if (update) { |
| updateFolder(UPDATE_TAB_HEIGHT | REDRAW); |
| } |
| } |
| |
| int getWrappedHeight (Point size) { |
| boolean[][] positions = new boolean[1][]; |
| Rectangle[] rects = computeControlBounds(size, positions); |
| int minY = Integer.MAX_VALUE, maxY = 0, wrapHeight = 0; |
| for (int i = 0; i < rects.length; i++) { |
| if (positions[0][i]) { |
| minY = Math.min(minY, rects[i].y); |
| maxY = Math.max(maxY, rects[i].y + rects[i].height); |
| wrapHeight = maxY - minY; |
| } |
| } |
| return wrapHeight; |
| } |
| |
| /** |
| * Sets whether a chevron is shown when there are more items to be displayed. |
| * |
| * @exception IllegalArgumentException <ul> |
| * <li>ERROR_INVALID_RANGE - if the index is out of range</li> |
| * </ul> |
| * @exception SWTException <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 setChevronVisible(boolean visible) { |
| checkWidget(); |
| if (chevronVisible == visible) return; |
| chevronVisible = visible; |
| updateFolder(UPDATE_TAB_HEIGHT | REDRAW); |
| } |
| } |