blob: 4921755534a65ea2cc2556e6f381726363fc8961 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2004 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;
}
}