| /******************************************************************************* |
| * Copyright (c) 2000, 2006 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.ui.internal.presentations.r21.widgets; |
| |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.SWTError; |
| import org.eclipse.swt.SWTException; |
| import org.eclipse.swt.graphics.Color; |
| import org.eclipse.swt.graphics.GC; |
| import org.eclipse.swt.graphics.Image; |
| import org.eclipse.swt.graphics.Rectangle; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.Item; |
| import org.eclipse.swt.widgets.Widget; |
| |
| public class CTabItem extends Item { |
| CTabFolder parent; |
| |
| int x, y, width, height = 0; |
| |
| String toolTipText; |
| |
| Control control; // the tab page |
| |
| private Image disabledImage; |
| |
| // internal constants |
| static final int LEFT_MARGIN = 4; |
| |
| static final int RIGHT_MARGIN = 4; |
| |
| static final int TOP_MARGIN = 3; |
| |
| static final int BOTTOM_MARGIN = 3; |
| |
| private static final int INTERNAL_SPACING = 2; |
| |
| private static final String ellipsis = "..."; //$NON-NLS-1$ |
| |
| String shortenedText; |
| |
| int shortenedTextWidth; |
| |
| /** |
| * Constructs a new instance of this class given its parent |
| * (which must be a <code>CTabFolder</code>) and a style value |
| * describing its behavior and appearance. The item is added |
| * to the end of the items maintained by its parent. |
| * <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 CTabFolder which will be the parent of the new instance (cannot be null) |
| * @param style the style of control 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 |
| * @see Widget#getStyle |
| */ |
| public CTabItem(CTabFolder parent, int style) { |
| this(parent, style, parent.getItemCount()); |
| } |
| |
| /** |
| * Constructs a new instance of this class given its parent |
| * (which must be a <code>CTabFolder</code>), a style value |
| * describing its behavior and appearance, and the index |
| * at which to place it in the items maintained by its parent. |
| * <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 CTabFolder which will be the parent of the new instance (cannot be null) |
| * @param style the style of control to construct |
| * @param index the index to store the receiver in its parent |
| * |
| * @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 |
| * @see Widget#getStyle |
| */ |
| public CTabItem(CTabFolder parent, int style, int index) { |
| super(parent, checkStyle(style)); |
| parent.createItem(this, index); |
| } |
| |
| private static int checkStyle(int style) { |
| return SWT.NONE; |
| } |
| |
| public void dispose() { |
| if (isDisposed()) { |
| return; |
| } |
| parent.destroyItem(this); |
| super.dispose(); |
| parent = null; |
| control = null; |
| toolTipText = null; |
| } |
| |
| /** |
| * Returns a rectangle describing the receiver's size and location |
| * relative to its parent. |
| * |
| * @return the receiver's bounding column rectangle |
| * |
| * @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 Rectangle getBounds() { |
| //checkWidget(); |
| return new Rectangle(x, y, width, height); |
| } |
| |
| /** |
| * Gets the control that is displayed in the content are of the tab item. |
| * |
| * @return the control |
| * |
| * @exception SWTError(ERROR_THREAD_INVALID_ACCESS) |
| * when called from the wrong thread |
| * @exception SWTError(ERROR_WIDGET_DISPOSED) |
| * when the widget has been disposed |
| */ |
| public Control getControl() { |
| checkWidget(); |
| return control; |
| } |
| |
| public Display getDisplay() { |
| if (parent == null) { |
| SWT.error(SWT.ERROR_WIDGET_DISPOSED); |
| } |
| return parent.getDisplay(); |
| } |
| |
| /** |
| * Get the image displayed in the tab if the tab is disabled. |
| * |
| * @return the disabled image or null |
| */ |
| public Image getDisabledImage() { |
| //checkWidget(); |
| return disabledImage; |
| } |
| |
| /** |
| * Returns the receiver's parent, which must be a <code>CTabFolder</code>. |
| * |
| * @return the receiver's parent |
| */ |
| public CTabFolder getParent() { |
| //checkWidget(); |
| return parent; |
| } |
| |
| /** |
| * Returns the receiver's tool tip text, or null if it has |
| * not been set. |
| * |
| * @return the receiver's tool tip text |
| * |
| * @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 String getToolTipText() { |
| checkWidget(); |
| return toolTipText; |
| } |
| |
| /** |
| * Paint the receiver. |
| */ |
| void onPaint(GC gc, boolean isSelected) { |
| |
| if (width == 0 || height == 0) { |
| return; |
| } |
| |
| Display display = getDisplay(); |
| Color highlightShadow = display |
| .getSystemColor(SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW); |
| Color normalShadow = display |
| .getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW); |
| |
| int index = parent.indexOf(this); |
| |
| if (isSelected) { |
| |
| Rectangle bounds = null; |
| if (!parent.onBottom) { |
| if (index == parent.topTabIndex) { |
| bounds = new Rectangle(x + 1, y + 1, width - 2, height - 1); |
| } else { |
| bounds = new Rectangle(x + 2, y + 1, width - 3, height - 1); |
| } |
| } else { |
| if (index == parent.topTabIndex) { |
| bounds = new Rectangle(x + 1, y + 1, width - 2, height - 2); |
| } else { |
| bounds = new Rectangle(x + 2, y + 1, width - 3, height - 2); |
| } |
| } |
| if (parent.backgroundImage != null) { |
| // draw a background image behind the text |
| Rectangle imageRect = parent.backgroundImage.getBounds(); |
| gc.drawImage(parent.backgroundImage, 0, 0, imageRect.width, |
| imageRect.height, bounds.x, bounds.y, bounds.width, |
| bounds.height); |
| } else if (parent.gradientColors != null) { |
| // draw a gradient behind the text |
| Color oldBackground = gc.getBackground(); |
| if (parent.gradientColors.length == 1) { |
| if (parent.gradientColors[0] != null) { |
| gc.setBackground(parent.gradientColors[0]); |
| } |
| gc.fillRectangle(bounds.x, bounds.y, bounds.width, |
| bounds.height); |
| } else { |
| Color oldForeground = gc.getForeground(); |
| Color lastColor = parent.gradientColors[0]; |
| if (lastColor == null) { |
| lastColor = oldBackground; |
| } |
| for (int i = 0, pos = 0; i < parent.gradientPercents.length; ++i) { |
| gc.setForeground(lastColor); |
| lastColor = parent.gradientColors[i + 1]; |
| if (lastColor == null) { |
| lastColor = oldBackground; |
| } |
| gc.setBackground(lastColor); |
| int gradientWidth = (parent.gradientPercents[i] |
| * bounds.width / 100) |
| - pos; |
| gc.fillGradientRectangle(bounds.x + pos, bounds.y, |
| gradientWidth, bounds.height, false); |
| pos += gradientWidth; |
| } |
| gc.setForeground(oldForeground); |
| } |
| gc.setBackground(oldBackground); |
| } |
| |
| // draw tab lines |
| if (!parent.onBottom) { |
| gc.setForeground(normalShadow); |
| if (index != parent.topTabIndex) { |
| gc.drawLine(x + 1, y, x + 1, y); |
| gc.drawLine(x, y + 1, x, y + height - 2); |
| gc.drawLine(x, y + height - 1, x, y + height - 1); |
| } |
| gc.drawLine(x + width - 1, y, x + width - 1, y); |
| gc.drawLine(x + width, y + 1, x + width, y + height - 2); |
| gc.drawLine(x + width, y + height - 1, x + width, y + height |
| - 1); |
| |
| gc.setForeground(highlightShadow); |
| if (index != parent.topTabIndex) { |
| gc.drawLine(x + 2, y, x + 2, y); |
| gc.drawLine(x + 1, y + 1, x + 1, y + height - 2); |
| gc.drawLine(x + 1, y + height - 1, x + 1, y + height - 1); |
| } else { |
| gc.drawLine(x, y, x, y + height - 1); |
| } |
| |
| gc.drawLine(x + width - 2, y, x + width - 2, y); |
| gc |
| .drawLine(x + width - 1, y + 1, x + width - 1, y |
| + height - 2); |
| gc.drawLine(x + width - 1, y + height - 1, x + width - 1, y |
| + height - 1); |
| |
| // light line across top |
| if (index != parent.topTabIndex) { |
| gc.drawLine(x + 3, y, x + width - 3, y); |
| } else { |
| gc.drawLine(x + 1, y, x + width - 3, y); |
| } |
| } else { |
| gc.setForeground(normalShadow); |
| if (index != parent.topTabIndex) { |
| gc.drawLine(x, y, x, y); |
| gc.drawLine(x, y + 1, x, y + height - 2); |
| gc.drawLine(x + 1, y + height - 1, x + 1, y + height - 1); |
| } |
| gc.drawLine(x + width, y, x + width, y); |
| gc.drawLine(x + width, y + 1, x + width, y + height - 2); |
| gc.drawLine(x + width - 1, y + height - 1, x + width - 1, y |
| + height - 1); |
| |
| gc.setForeground(highlightShadow); |
| if (index != parent.topTabIndex) { |
| gc.drawLine(x + 1, y, x + 1, y); |
| gc.drawLine(x + 1, y + 1, x + 1, y + height - 2); |
| gc.drawLine(x + 2, y + height - 1, x + 2, y + height - 1); |
| } else { |
| gc.drawLine(x, y, x, y + height - 1); |
| } |
| |
| gc.drawLine(x + width - 1, y, x + width - 1, y); |
| gc |
| .drawLine(x + width - 1, y + 1, x + width - 1, y |
| + height - 2); |
| gc.drawLine(x + width - 2, y + height - 1, x + width - 2, y |
| + height - 1); |
| |
| // light line across top and bottom |
| if (index != parent.topTabIndex) { |
| gc.drawLine(x + 1, y, x + width - 2, y); |
| gc.drawLine(x + 2, y + height - 1, x + width - 3, y |
| + height - 1); |
| } else { |
| gc.drawLine(x + 1, y, x + width - 2, y); |
| gc.drawLine(x + 1, y + height - 1, x + width - 3, y |
| + height - 1); |
| } |
| } |
| if (parent.isFocusControl()) { |
| // draw a focus rectangle |
| int x1, y1, width1, height1; |
| if (!parent.onBottom) { |
| if (index == parent.topTabIndex) { |
| x1 = x + 1; |
| y1 = y + 1; |
| width1 = width - 2; |
| height1 = height - 1; |
| } else { |
| x1 = x + 2; |
| y1 = y + 1; |
| width1 = width - 3; |
| height1 = height - 1; |
| } |
| } else { |
| if (index == parent.topTabIndex) { |
| x1 = x + 1; |
| y1 = y + 1; |
| width1 = width - 2; |
| height1 = height - 2; |
| } else { |
| x1 = x + 2; |
| y1 = y + 1; |
| width1 = width - 3; |
| height1 = height - 2; |
| } |
| } |
| gc.setBackground(display.getSystemColor(SWT.COLOR_BLACK)); |
| gc.setForeground(display.getSystemColor(SWT.COLOR_WHITE)); |
| gc.drawFocus(x1, y1, width1, height1); |
| } |
| } else { |
| // draw tab lines for unselected items |
| gc.setForeground(normalShadow); |
| if (!parent.onBottom) { |
| if (index != parent.topTabIndex |
| && index != parent.getSelectionIndex() + 1) { |
| gc.drawLine(x, y, x, y + (height / 2)); |
| } |
| } else { |
| if (index != parent.topTabIndex |
| && index != parent.getSelectionIndex() + 1) { |
| gc.drawLine(x, y + (height / 2), x, y + height - 1); |
| } |
| } |
| |
| } |
| |
| // draw Image |
| int xDraw = x + LEFT_MARGIN; |
| |
| Image image = getImage(); |
| if (!isSelected && image != null) { |
| Image temp = getDisabledImage(); |
| if (temp != null) { |
| image = temp; |
| } |
| } |
| if (image != null) { |
| Rectangle imageBounds = image.getBounds(); |
| int imageX = xDraw; |
| int imageHeight = Math.min(height - BOTTOM_MARGIN - TOP_MARGIN, |
| imageBounds.height); |
| int imageY = y + (height - imageHeight) / 2; |
| int imageWidth = imageBounds.width * imageHeight |
| / imageBounds.height; |
| gc.drawImage(image, imageBounds.x, imageBounds.y, |
| imageBounds.width, imageBounds.height, imageX, imageY, |
| imageWidth, imageHeight); |
| xDraw += imageWidth + INTERNAL_SPACING; |
| } |
| |
| // draw Text |
| int textWidth = x + width - xDraw - RIGHT_MARGIN; |
| if (isSelected && parent.showClose) { |
| textWidth = x + width - xDraw - parent.closeBar.getSize().x |
| - RIGHT_MARGIN; |
| } |
| if (shortenedText == null || shortenedTextWidth != textWidth) { |
| shortenedText = shortenText(gc, getText(), textWidth); |
| shortenedTextWidth = textWidth; |
| } |
| String text = shortenedText; |
| |
| if (isSelected && parent.selectionForeground != null) { |
| gc.setForeground(parent.selectionForeground); |
| } else { |
| gc.setForeground(parent.getForeground()); |
| } |
| int textY = y + (height - gc.textExtent(text, SWT.DRAW_MNEMONIC).y) / 2; |
| gc.drawText(text, xDraw, textY, SWT.DRAW_TRANSPARENT |
| | SWT.DRAW_MNEMONIC); |
| |
| gc.setForeground(parent.getForeground()); |
| } |
| |
| private static String shortenText(GC gc, String text, int width) { |
| if (gc.textExtent(text, SWT.DRAW_MNEMONIC).x <= width) { |
| return text; |
| } |
| |
| int ellipseWidth = gc.textExtent(ellipsis, SWT.DRAW_MNEMONIC).x; |
| int length = text.length(); |
| int end = length - 1; |
| while (end > 0) { |
| text = text.substring(0, end); |
| int l1 = gc.textExtent(text, SWT.DRAW_MNEMONIC).x; |
| if (l1 + ellipseWidth <= width) { |
| return text + ellipsis; |
| } |
| end--; |
| } |
| return text + ellipsis; |
| } |
| |
| /** |
| * Answer the preferred height of the receiver for the GC. |
| */ |
| int preferredHeight(GC gc) { |
| Image image = getImage(); |
| int height = 0; |
| if (image != null) { |
| height = image.getBounds().height; |
| } |
| String text = getText(); |
| height = Math.max(height, gc.textExtent(text, SWT.DRAW_MNEMONIC).y); |
| return height + TOP_MARGIN + BOTTOM_MARGIN; |
| } |
| |
| /** |
| * Answer the preferred width of the receiver for the GC. |
| */ |
| int preferredWidth(GC gc) { |
| int width = 0; |
| Image image = getImage(); |
| if (image != null) { |
| width += image.getBounds().width; |
| } |
| String text = getText(); |
| if (text != null) { |
| if (image != null) { |
| width += INTERNAL_SPACING; |
| } |
| width += gc.textExtent(text, SWT.DRAW_MNEMONIC).x; |
| } |
| if (parent.showClose) { |
| width += INTERNAL_SPACING + preferredHeight(gc); // closebar will be square and will fill preferred height |
| } |
| return width + LEFT_MARGIN + RIGHT_MARGIN; |
| } |
| |
| /** |
| * Sets the control that is used to fill the client area of |
| * the tab folder when the user selects the tab item. |
| * <p> |
| * @param control the new control (or null) |
| * |
| * @exception IllegalArgumentException <ul> |
| * <li>ERROR_INVALID_ARGUMENT - if the control has been disposed</li> |
| * <li>ERROR_INVALID_PARENT - if the control is not in the same widget tree</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 setControl(Control control) { |
| checkWidget(); |
| if (control != null) { |
| if (control.isDisposed()) { |
| SWT.error(SWT.ERROR_INVALID_ARGUMENT); |
| } |
| if (control.getParent() != parent) { |
| SWT.error(SWT.ERROR_INVALID_PARENT); |
| } |
| } |
| if (this.control != null && !this.control.isDisposed()) { |
| this.control.setVisible(false); |
| } |
| this.control = control; |
| if (this.control != null) { |
| int index = parent.indexOf(this); |
| if (index == parent.getSelectionIndex()) { |
| this.control.setBounds(parent.getClientArea()); |
| this.control.setVisible(true); |
| } else { |
| this.control.setVisible(false); |
| } |
| } |
| } |
| |
| public void setImage(Image image) { |
| checkWidget(); |
| if (image != null && image.equals(getImage())) { |
| return; |
| } |
| super.setImage(image); |
| parent.resetTabSize(true); |
| } |
| |
| /** |
| * Sets the image that is displayed if the tab item is disabled. |
| * Null will clear the image. |
| * |
| * @param image the image to be displayed when the item is disabled 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 setDisabledImage(Image image) { |
| checkWidget(); |
| if (image != null && image.equals(getDisabledImage())) { |
| return; |
| } |
| disabledImage = image; |
| parent.redraw(); |
| } |
| |
| /** |
| * Set the widget text. |
| * <p> |
| * This method sets the widget label. The label may include |
| * mnemonic characters but must not contain line delimiters. |
| * |
| * @param string the new label for the widget |
| * |
| * @exception IllegalArgumentException <ul> |
| * <li>ERROR_NULL_ARGUMENT - if the text 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> |
| */ |
| public void setText(String string) { |
| checkWidget(); |
| if (string.equals(getText())) { |
| return; |
| } |
| super.setText(string); |
| shortenedText = null; |
| shortenedTextWidth = 0; |
| parent.resetTabSize(false); |
| } |
| |
| /** |
| * Sets the receiver's tool tip text to the argument, which |
| * may be null indicating that no tool tip text should be shown. |
| * |
| * @param string the new tool tip text (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 setToolTipText(String string) { |
| checkWidget(); |
| toolTipText = string; |
| } |
| } |