KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > swt > custom > CTabItem


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.swt.custom;
12
13
14 import org.eclipse.swt.*;
15 import org.eclipse.swt.graphics.*;
16 import org.eclipse.swt.widgets.*;
17
18 /**
19  * Instances of this class represent a selectable user interface object
20  * that represent a page in a notebook widget.
21  *
22  * <dl>
23  * <dt><b>Styles:</b></dt>
24  * <dd>SWT.CLOSE</dd>
25  * <dt><b>Events:</b></dt>
26  * <dd>(none)</dd>
27  * </dl>
28  * <p>
29  * IMPORTANT: This class is <em>not</em> intended to be subclassed.
30  * </p>
31  */

32 public class CTabItem extends Item {
33     CTabFolder parent;
34     int x,y,width,height = 0;
35     Control control; // the tab page
36

37     String JavaDoc toolTipText;
38     String JavaDoc shortenedText;
39     int shortenedTextWidth;
40     
41     // Appearance
42
Font font;
43     Image disabledImage;
44     
45     Rectangle closeRect = new Rectangle(0, 0, 0, 0);
46     int closeImageState = CTabFolder.NONE;
47     boolean showClose = false;
48     boolean showing = false;
49
50     // internal constants
51
static final int TOP_MARGIN = 2;
52     static final int BOTTOM_MARGIN = 2;
53     static final int LEFT_MARGIN = 4;
54     static final int RIGHT_MARGIN = 4;
55     static final int INTERNAL_SPACING = 4;
56     static final int FLAGS = SWT.DRAW_TRANSPARENT | SWT.DRAW_MNEMONIC;
57     static final String JavaDoc ELLIPSIS = "..."; //$NON-NLS-1$ // could use the ellipsis glyph on some platforms "\u2026"
58

59 /**
60  * Constructs a new instance of this class given its parent
61  * (which must be a <code>CTabFolder</code>) and a style value
62  * describing its behavior and appearance. The item is added
63  * to the end of the items maintained by its parent.
64  * <p>
65  * The style value is either one of the style constants defined in
66  * class <code>SWT</code> which is applicable to instances of this
67  * class, or must be built by <em>bitwise OR</em>'ing together
68  * (that is, using the <code>int</code> "|" operator) two or more
69  * of those <code>SWT</code> style constants. The class description
70  * lists the style constants that are applicable to the class.
71  * Style bits are also inherited from superclasses.
72  * </p>
73  *
74  * @param parent a CTabFolder which will be the parent of the new instance (cannot be null)
75  * @param style the style of control to construct
76  *
77  * @exception IllegalArgumentException <ul>
78  * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
79  * </ul>
80  * @exception SWTException <ul>
81  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
82  * </ul>
83  *
84  * @see SWT
85  * @see Widget#getStyle()
86  */

87 public CTabItem (CTabFolder parent, int style) {
88     this(parent, style, parent.getItemCount());
89 }
90 /**
91  * Constructs a new instance of this class given its parent
92  * (which must be a <code>CTabFolder</code>), a style value
93  * describing its behavior and appearance, and the index
94  * at which to place it in the items maintained by its parent.
95  * <p>
96  * The style value is either one of the style constants defined in
97  * class <code>SWT</code> which is applicable to instances of this
98  * class, or must be built by <em>bitwise OR</em>'ing together
99  * (that is, using the <code>int</code> "|" operator) two or more
100  * of those <code>SWT</code> style constants. The class description
101  * lists the style constants that are applicable to the class.
102  * Style bits are also inherited from superclasses.
103  * </p>
104  *
105  * @param parent a CTabFolder which will be the parent of the new instance (cannot be null)
106  * @param style the style of control to construct
107  * @param index the zero-relative index to store the receiver in its parent
108  *
109  * @exception IllegalArgumentException <ul>
110  * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
111  * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the parent (inclusive)</li>
112  * </ul>
113  * @exception SWTException <ul>
114  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
115  * </ul>
116  *
117  * @see SWT
118  * @see Widget#getStyle()
119  */

120 public CTabItem (CTabFolder parent, int style, int index) {
121     super (parent, checkStyle(style));
122     showClose = (style & SWT.CLOSE) != 0;
123     parent.createItem (this, index);
124 }
125 static int checkStyle(int style) {
126     return SWT.NONE;
127 }
128
129 /*
130  * Return whether to use ellipses or just truncate labels
131  */

132 boolean useEllipses() {
133     return parent.simple;
134 }
135
136 String JavaDoc shortenText(GC gc, String JavaDoc text, int width) {
137     return useEllipses()
138         ? shortenText(gc, text, width, ELLIPSIS)
139         : shortenText(gc, text, width, ""); //$NON-NLS-1$
140
}
141
142 String JavaDoc shortenText(GC gc, String JavaDoc text, int width, String JavaDoc ellipses) {
143     if (gc.textExtent(text, FLAGS).x <= width) return text;
144     int ellipseWidth = gc.textExtent(ellipses, FLAGS).x;
145     int length = text.length();
146     int end = length - 1;
147     while (end > 0) {
148         text = text.substring(0, end);
149         int l = gc.textExtent(text, FLAGS).x;
150         if (l + ellipseWidth <= width) {
151             return text + ellipses;
152         }
153         end--;
154     }
155     return text.substring(0,1);
156 }
157
158 public void dispose() {
159     if (isDisposed ()) return;
160     //if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS);
161
parent.destroyItem(this);
162     super.dispose();
163     parent = null;
164     control = null;
165     toolTipText = null;
166     shortenedText = null;
167     font = null;
168 }
169 void drawClose(GC gc) {
170     if (closeRect.width == 0 || closeRect.height == 0) return;
171     Display display = getDisplay();
172
173     // draw X 9x9
174
int indent = Math.max(1, (CTabFolder.BUTTON_SIZE-9)/2);
175     int x = closeRect.x + indent;
176     int y = closeRect.y + indent;
177     y += parent.onBottom ? -1 : 1;
178     
179     Color closeBorder = display.getSystemColor(CTabFolder.BUTTON_BORDER);
180     switch (closeImageState) {
181         case CTabFolder.NORMAL: {
182             int[] shape = new int[] {x,y, x+2,y, x+4,y+2, x+5,y+2, x+7,y, x+9,y,
183                                      x+9,y+2, x+7,y+4, x+7,y+5, x+9,y+7, x+9,y+9,
184                                      x+7,y+9, x+5,y+7, x+4,y+7, x+2,y+9, x,y+9,
185                                      x,y+7, x+2,y+5, x+2,y+4, x,y+2};
186             gc.setBackground(display.getSystemColor(CTabFolder.BUTTON_FILL));
187             gc.fillPolygon(shape);
188             gc.setForeground(closeBorder);
189             gc.drawPolygon(shape);
190             break;
191         }
192         case CTabFolder.HOT: {
193             int[] shape = new int[] {x,y, x+2,y, x+4,y+2, x+5,y+2, x+7,y, x+9,y,
194                                      x+9,y+2, x+7,y+4, x+7,y+5, x+9,y+7, x+9,y+9,
195                                      x+7,y+9, x+5,y+7, x+4,y+7, x+2,y+9, x,y+9,
196                                      x,y+7, x+2,y+5, x+2,y+4, x,y+2};
197             Color fill = new Color(display, CTabFolder.CLOSE_FILL);
198             gc.setBackground(fill);
199             gc.fillPolygon(shape);
200             fill.dispose();
201             gc.setForeground(closeBorder);
202             gc.drawPolygon(shape);
203             break;
204         }
205         case CTabFolder.SELECTED: {
206             int[] shape = new int[] {x+1,y+1, x+3,y+1, x+5,y+3, x+6,y+3, x+8,y+1, x+10,y+1,
207                                      x+10,y+3, x+8,y+5, x+8,y+6, x+10,y+8, x+10,y+10,
208                                      x+8,y+10, x+6,y+8, x+5,y+8, x+3,y+10, x+1,y+10,
209                                      x+1,y+8, x+3,y+6, x+3,y+5, x+1,y+3};
210             Color fill = new Color(display, CTabFolder.CLOSE_FILL);
211             gc.setBackground(fill);
212             gc.fillPolygon(shape);
213             fill.dispose();
214             gc.setForeground(closeBorder);
215             gc.drawPolygon(shape);
216             break;
217         }
218         case CTabFolder.NONE: {
219             int[] shape = new int[] {x,y, x+10,y, x+10,y+10, x,y+10};
220             if (parent.gradientColors != null && !parent.gradientVertical) {
221                 parent.drawBackground(gc, shape, false);
222             } else {
223                 Color defaultBackground = parent.getBackground();
224                 Image image = parent.bgImage;
225                 Color[] colors = parent.gradientColors;
226                 int[] percents = parent.gradientPercents;
227                 boolean vertical = parent.gradientVertical;
228                 parent.drawBackground(gc, shape, x, y, 10, 10, defaultBackground, image, colors, percents, vertical);
229             }
230             break;
231         }
232     }
233 }
234 void drawSelected(GC gc ) {
235     Point size = parent.getSize();
236     int rightEdge = Math.min (x + width, parent.getRightItemEdge());
237     
238     // Draw selection border across all tabs
239
int xx = parent.borderLeft;
240     int yy = parent.onBottom ? size.y - parent.borderBottom - parent.tabHeight - parent.highlight_header : parent.borderTop + parent.tabHeight + 1;
241     int ww = size.x - parent.borderLeft - parent.borderRight;
242     int hh = parent.highlight_header - 1;
243     int[] shape = new int[] {xx,yy, xx+ww,yy, xx+ww,yy+hh, xx,yy+hh};
244     if (parent.selectionGradientColors != null && !parent.selectionGradientVertical) {
245         parent.drawBackground(gc, shape, true);
246     } else {
247         gc.setBackground(parent.selectionBackground);
248         gc.fillRectangle(xx, yy, ww, hh);
249     }
250     
251     if (parent.single) {
252         if (!showing) return;
253     } else {
254         // if selected tab scrolled out of view or partially out of view
255
// just draw bottom line
256
if (!showing){
257             int x1 = Math.max(0, parent.borderLeft - 1);
258             int y1 = (parent.onBottom) ? y - 1 : y + height;
259             int x2 = size.x - parent.borderRight;
260             gc.setForeground(CTabFolder.borderColor);
261             gc.drawLine(x1, y1, x2, y1);
262             return;
263         }
264             
265         // draw selected tab background and outline
266
shape = null;
267         if (this.parent.onBottom) {
268             int[] left = parent.simple ? CTabFolder.SIMPLE_BOTTOM_LEFT_CORNER : CTabFolder.BOTTOM_LEFT_CORNER;
269             int[] right = parent.simple ? CTabFolder.SIMPLE_BOTTOM_RIGHT_CORNER : parent.curve;
270             if (parent.borderLeft == 0 && parent.indexOf(this) == parent.firstIndex) {
271                 left = new int[]{x, y+height};
272             }
273             shape = new int[left.length+right.length+8];
274             int index = 0;
275             shape[index++] = x; // first point repeated here because below we reuse shape to draw outline
276
shape[index++] = y - 1;
277             shape[index++] = x;
278             shape[index++] = y - 1;
279             for (int i = 0; i < left.length/2; i++) {
280                 shape[index++] = x + left[2*i];
281                 shape[index++] = y + height + left[2*i+1] - 1;
282             }
283             for (int i = 0; i < right.length/2; i++) {
284                 shape[index++] = parent.simple ? rightEdge - 1 + right[2*i] : rightEdge - parent.curveIndent + right[2*i];
285                 shape[index++] = parent.simple ? y + height + right[2*i+1] - 1 : y + right[2*i+1] - 2;
286             }
287             shape[index++] = parent.simple ? rightEdge - 1 : rightEdge + parent.curveWidth - parent.curveIndent;
288             shape[index++] = y - 1;
289             shape[index++] = parent.simple ? rightEdge - 1 : rightEdge + parent.curveWidth - parent.curveIndent;
290             shape[index++] = y - 1;
291         } else {
292             int[] left = parent.simple ? CTabFolder.SIMPLE_TOP_LEFT_CORNER : CTabFolder.TOP_LEFT_CORNER;
293             int[] right = parent.simple ? CTabFolder.SIMPLE_TOP_RIGHT_CORNER : parent.curve;
294             if (parent.borderLeft == 0 && parent.indexOf(this) == parent.firstIndex) {
295                 left = new int[]{x, y};
296             }
297             shape = new int[left.length+right.length+8];
298             int index = 0;
299             shape[index++] = x; // first point repeated here because below we reuse shape to draw outline
300
shape[index++] = y + height + 1;
301             shape[index++] = x;
302             shape[index++] = y + height + 1;
303             for (int i = 0; i < left.length/2; i++) {
304                 shape[index++] = x + left[2*i];
305                 shape[index++] = y + left[2*i+1];
306             }
307             for (int i = 0; i < right.length/2; i++) {
308                 shape[index++] = parent.simple ? rightEdge - 1 + right[2*i] : rightEdge - parent.curveIndent + right[2*i];
309                 shape[index++] = y + right[2*i+1];
310             }
311             shape[index++] = parent.simple ? rightEdge - 1 : rightEdge + parent.curveWidth - parent.curveIndent;
312             shape[index++] = y + height + 1;
313             shape[index++] = parent.simple ? rightEdge - 1 : rightEdge + parent.curveWidth - parent.curveIndent;
314             shape[index++] = y + height + 1;
315         }
316         
317         Rectangle clipping = gc.getClipping();
318         Rectangle bounds = getBounds();
319         bounds.height += 1;
320         if (parent.onBottom) bounds.y -= 1;
321         boolean tabInPaint = clipping.intersects(bounds);
322         
323         if (tabInPaint) {
324             // fill in tab background
325
if (parent.selectionGradientColors != null && !parent.selectionGradientVertical) {
326                 parent.drawBackground(gc, shape, true);
327             } else {
328                 Color defaultBackground = parent.selectionBackground;
329                 Image image = parent.selectionBgImage;
330                 Color[] colors = parent.selectionGradientColors;
331                 int[] percents = parent.selectionGradientPercents;
332                 boolean vertical = parent.selectionGradientVertical;
333                 xx = x;
334                 yy = parent.onBottom ? y -1 : y + 1;
335                 ww = width;
336                 hh = height;
337                 if (!parent.single && !parent.simple) ww += parent.curveWidth - parent.curveIndent;
338                 parent.drawBackground(gc, shape, xx, yy, ww, hh, defaultBackground, image, colors, percents, vertical);
339             }
340         }
341         
342         //Highlight MUST be drawn before the outline so that outline can cover it in the right spots (start of swoop)
343
//otherwise the curve looks jagged
344
drawHighlight(gc, rightEdge);
345
346         // draw outline
347
shape[0] = Math.max(0, parent.borderLeft - 1);
348         if (parent.borderLeft == 0 && parent.indexOf(this) == parent.firstIndex) {
349             shape[1] = parent.onBottom ? y + height - 1 : y;
350             shape[5] = shape[3] = shape[1];
351         }
352         shape[shape.length - 2] = size.x - parent.borderRight + 1;
353         for (int i = 0; i < shape.length/2; i++) {
354             if (shape[2*i + 1] == y + height + 1) shape[2*i + 1] -= 1;
355         }
356         RGB inside = parent.selectionBackground.getRGB();
357         if (parent.selectionBgImage != null ||
358             (parent.selectionGradientColors != null && parent.selectionGradientColors.length > 1)) {
359             inside = null;
360         }
361         RGB outside = parent.getBackground().getRGB();
362         if (parent.bgImage != null ||
363             (parent.gradientColors != null && parent.gradientColors.length > 1)) {
364             outside = null;
365         }
366         parent.antialias(shape, CTabFolder.borderColor.getRGB(), inside, outside, gc);
367         gc.setForeground(CTabFolder.borderColor);
368         gc.drawPolyline(shape);
369         
370         if (!tabInPaint) return;
371     }
372     
373     // draw Image
374
int xDraw = x + LEFT_MARGIN;
375     if (parent.single && (parent.showClose || showClose)) xDraw += CTabFolder.BUTTON_SIZE;
376     Image image = getImage();
377     if (image != null) {
378         Rectangle imageBounds = image.getBounds();
379         // only draw image if it won't overlap with close button
380
int maxImageWidth = rightEdge - xDraw - RIGHT_MARGIN;
381         if (!parent.single && closeRect.width > 0) maxImageWidth -= closeRect.width + INTERNAL_SPACING;
382         if (imageBounds.width < maxImageWidth) {
383             int imageX = xDraw;
384             int imageY = y + (height - imageBounds.height) / 2;
385             imageY += parent.onBottom ? -1 : 1;
386             gc.drawImage(image, imageX, imageY);
387             xDraw += imageBounds.width + INTERNAL_SPACING;
388         }
389     }
390     
391     // draw Text
392
int textWidth = rightEdge - xDraw - RIGHT_MARGIN;
393     if (!parent.single && closeRect.width > 0) textWidth -= closeRect.width + INTERNAL_SPACING;
394     if (textWidth > 0) {
395         Font gcFont = gc.getFont();
396         gc.setFont(font == null ? parent.getFont() : font);
397         
398         if (shortenedText == null || shortenedTextWidth != textWidth) {
399             shortenedText = shortenText(gc, getText(), textWidth);
400             shortenedTextWidth = textWidth;
401         }
402         Point extent = gc.textExtent(shortenedText, FLAGS);
403         int textY = y + (height - extent.y) / 2;
404         textY += parent.onBottom ? -1 : 1;
405         
406         gc.setForeground(parent.selectionForeground);
407         gc.drawText(shortenedText, xDraw, textY, FLAGS);
408         gc.setFont(gcFont);
409         
410         // draw a Focus rectangle
411
if (parent.isFocusControl()) {
412             Display display = getDisplay();
413             if (parent.simple || parent.single) {
414                 gc.setBackground(display.getSystemColor(SWT.COLOR_BLACK));
415                 gc.setForeground(display.getSystemColor(SWT.COLOR_WHITE));
416                 gc.drawFocus(xDraw-1, textY-1, extent.x+2, extent.y+2);
417             } else {
418                 gc.setForeground(display.getSystemColor(CTabFolder.BUTTON_BORDER));
419                 gc.drawLine(xDraw, textY+extent.y+1, xDraw+extent.x+1, textY+extent.y+1);
420             }
421         }
422     }
423     if (parent.showClose || showClose) drawClose(gc);
424 }
425
426 /*
427  * Draw a highlight effect along the left, top, and right edges of the tab.
428  * Only for curved tabs, on top.
429  * Do not draw if insufficient colors.
430  */

431 void drawHighlight(GC gc, int rightEdge) {
432     //only draw for curvy tabs and only draw for top tabs
433
if(parent.simple || this.parent.onBottom)
434         return;
435     
436     if(parent.selectionHighlightGradientBegin == null)
437         return;
438     
439     Color[] gradients = parent.selectionHighlightGradientColorsCache;
440     if(gradients == null)
441         return;
442     int gradientsSize = gradients.length;
443     if(gradientsSize == 0)
444         return; //shouldn't happen but just to be tidy
445

446     gc.setForeground(gradients[0]);
447     
448     //draw top horizontal line
449
gc.drawLine(
450             CTabFolder.TOP_LEFT_CORNER_HILITE[0] + x + 1, //rely on fact that first pair is top/right of curve
451
1 + y,
452             rightEdge - parent.curveIndent,
453             1 + y);
454     
455     int[] leftHighlightCurve = CTabFolder.TOP_LEFT_CORNER_HILITE;
456
457     int d = parent.tabHeight - parent.topCurveHighlightEnd.length /2;
458
459     int lastX = 0;
460     int lastY = 0;
461     int lastColorIndex = 0;
462     
463     //draw upper left curve highlight
464
for (int i = 0; i < leftHighlightCurve.length /2; i++) {
465         int rawX = leftHighlightCurve[i * 2];
466         int rawY = leftHighlightCurve[i * 2 + 1];
467         lastX = rawX + x;
468         lastY = rawY + y;
469         lastColorIndex = rawY - 1;
470         gc.setForeground(gradients[lastColorIndex]);
471         gc.drawPoint(lastX, lastY);
472     }
473     //draw left vertical line highlight
474
for(int i = lastColorIndex; i < gradientsSize; i++) {
475         gc.setForeground(gradients[i]);
476         gc.drawPoint(lastX, 1 + lastY++);
477     }
478     
479     int rightEdgeOffset = rightEdge - parent.curveIndent;
480     
481     //draw right swoop highlight up to diagonal portion
482
for (int i = 0; i < parent.topCurveHighlightStart.length /2; i++) {
483         int rawX = parent.topCurveHighlightStart[i * 2];
484         int rawY = parent.topCurveHighlightStart[i * 2 + 1];
485         lastX = rawX + rightEdgeOffset;
486         lastY = rawY + y;
487         lastColorIndex = rawY - 1;
488         if(lastColorIndex >= gradientsSize)
489             break; //can happen if tabs are unusually short and cut off the curve
490
gc.setForeground(gradients[lastColorIndex]);
491         gc.drawPoint(lastX, lastY);
492     }
493     //draw right diagonal line highlight
494
for(int i = lastColorIndex; i < lastColorIndex + d; i++) {
495         if(i >= gradientsSize)
496             break; //can happen if tabs are unusually short and cut off the curve
497
gc.setForeground(gradients[i]);
498         gc.drawPoint(1 + lastX++, 1 + lastY++);
499     }
500
501     //draw right swoop highlight from diagonal portion to end
502
for (int i = 0; i < parent.topCurveHighlightEnd.length /2; i++) {
503         int rawX = parent.topCurveHighlightEnd[i * 2]; //d is already encoded in this value
504
int rawY = parent.topCurveHighlightEnd[i * 2 + 1]; //d already encoded
505
lastX = rawX + rightEdgeOffset;
506         lastY = rawY + y;
507         lastColorIndex = rawY - 1;
508         if(lastColorIndex >= gradientsSize)
509             break; //can happen if tabs are unusually short and cut off the curve
510
gc.setForeground(gradients[lastColorIndex]);
511         gc.drawPoint(lastX, lastY);
512     }
513 }
514
515 /*
516  * Draw the unselected border for the receiver on the right.
517  *
518  * @param gc
519  */

520 void drawRightUnselectedBorder(GC gc) {
521
522     int[] shape = null;
523     int startX = x + width - 1;
524
525     if (this.parent.onBottom) {
526         int[] right = parent.simple
527             ? CTabFolder.SIMPLE_UNSELECTED_INNER_CORNER
528             : CTabFolder.BOTTOM_RIGHT_CORNER;
529         
530         shape = new int[right.length + 2];
531         int index = 0;
532         
533         for (int i = 0; i < right.length / 2; i++) {
534             shape[index++] = startX + right[2 * i];
535             shape[index++] = y + height + right[2 * i + 1] - 1;
536         }
537         shape[index++] = startX;
538         shape[index++] = y - 1;
539     } else {
540         int[] right = parent.simple
541             ? CTabFolder.SIMPLE_UNSELECTED_INNER_CORNER
542             : CTabFolder.TOP_RIGHT_CORNER;
543         
544         shape = new int[right.length + 2];
545         int index = 0;
546
547         for (int i = 0; i < right.length / 2; i++) {
548             shape[index++] = startX + right[2 * i];
549             shape[index++] = y + right[2 * i + 1];
550         }
551
552         shape[index++] = startX;
553         shape[index++] = y + height;
554
555     }
556
557     drawBorder(gc, shape);
558
559 }
560
561 /*
562  * Draw the border of the tab
563  *
564  * @param gc
565  * @param shape
566  */

567 void drawBorder(GC gc, int[] shape) {
568
569     gc.setForeground(CTabFolder.borderColor);
570     gc.drawPolyline(shape);
571 }
572
573 /*
574  * Draw the unselected border for the receiver on the left.
575  *
576  * @param gc
577  */

578 void drawLeftUnselectedBorder(GC gc) {
579
580     int[] shape = null;
581     if (this.parent.onBottom) {
582         int[] left = parent.simple
583             ? CTabFolder.SIMPLE_UNSELECTED_INNER_CORNER
584             : CTabFolder.BOTTOM_LEFT_CORNER;
585         
586         shape = new int[left.length + 2];
587         int index = 0;
588         shape[index++] = x;
589         shape[index++] = y - 1;
590         for (int i = 0; i < left.length / 2; i++) {
591             shape[index++] = x + left[2 * i];
592             shape[index++] = y + height + left[2 * i + 1] - 1;
593         }
594     } else {
595         int[] left = parent.simple
596             ? CTabFolder.SIMPLE_UNSELECTED_INNER_CORNER
597             : CTabFolder.TOP_LEFT_CORNER;
598
599         shape = new int[left.length + 2];
600         int index = 0;
601         shape[index++] = x;
602         shape[index++] = y + height;
603         for (int i = 0; i < left.length / 2; i++) {
604             shape[index++] = x + left[2 * i];
605             shape[index++] = y + left[2 * i + 1];
606         }
607
608     }
609
610     drawBorder(gc, shape);
611 }
612
613 void drawUnselected(GC gc) {
614     // Do not draw partial items
615
if (!showing) return;
616     
617     Rectangle clipping = gc.getClipping();
618     Rectangle bounds = getBounds();
619     if (!clipping.intersects(bounds)) return;
620     
621     // draw border
622
int index = parent.indexOf(this);
623
624     if (index > 0 && index < parent.selectedIndex)
625         drawLeftUnselectedBorder(gc);
626     // If it is the last one then draw a line
627
if (index > parent.selectedIndex)
628         drawRightUnselectedBorder(gc);
629
630     // draw Image
631
int xDraw = x + LEFT_MARGIN;
632     Image image = getImage();
633     if (image != null && parent.showUnselectedImage) {
634         Rectangle imageBounds = image.getBounds();
635         // only draw image if it won't overlap with close button
636
int maxImageWidth = x + width - xDraw - RIGHT_MARGIN;
637         if (parent.showUnselectedClose && (parent.showClose || showClose)) {
638             maxImageWidth -= closeRect.width + INTERNAL_SPACING;
639         }
640         if (imageBounds.width < maxImageWidth) {
641             int imageX = xDraw;
642             int imageHeight = imageBounds.height;
643             int imageY = y + (height - imageHeight) / 2;
644             imageY += parent.onBottom ? -1 : 1;
645             int imageWidth = imageBounds.width * imageHeight / imageBounds.height;
646             gc.drawImage(image,
647                          imageBounds.x, imageBounds.y, imageBounds.width, imageBounds.height,
648                          imageX, imageY, imageWidth, imageHeight);
649             xDraw += imageWidth + INTERNAL_SPACING;
650         }
651     }
652     // draw Text
653
int textWidth = x + width - xDraw - RIGHT_MARGIN;
654     if (parent.showUnselectedClose && (parent.showClose || showClose)) {
655         textWidth -= closeRect.width + INTERNAL_SPACING;
656     }
657     if (textWidth > 0) {
658         Font gcFont = gc.getFont();
659         gc.setFont(font == null ? parent.getFont() : font);
660         if (shortenedText == null || shortenedTextWidth != textWidth) {
661             shortenedText = shortenText(gc, getText(), textWidth);
662             shortenedTextWidth = textWidth;
663         }
664         Point extent = gc.textExtent(shortenedText, FLAGS);
665         int textY = y + (height - extent.y) / 2;
666         textY += parent.onBottom ? -1 : 1;
667         gc.setForeground(parent.getForeground());
668         gc.drawText(shortenedText, xDraw, textY, FLAGS);
669         gc.setFont(gcFont);
670     }
671     // draw close
672
if (parent.showUnselectedClose && (parent.showClose || showClose)) drawClose(gc);
673 }
674 /**
675  * Returns a rectangle describing the receiver's size and location
676  * relative to its parent.
677  *
678  * @return the receiver's bounding column rectangle
679  *
680  * @exception SWTException <ul>
681  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
682  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
683  * </ul>
684  */

685 public Rectangle getBounds () {
686     //checkWidget();
687
int w = width;
688     if (!parent.simple && !parent.single && parent.indexOf(this) == parent.selectedIndex) w += parent.curveWidth - parent.curveIndent;
689     return new Rectangle(x, y, w, height);
690 }
691 /**
692 * Gets the control that is displayed in the content area of the tab item.
693 *
694 * @return the control
695 *
696 * @exception SWTException <ul>
697 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
698 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
699 * </ul>
700 */

701 public Control getControl () {
702     checkWidget();
703     return control;
704 }
705 /**
706  * Get the image displayed in the tab if the tab is disabled.
707  *
708  * @return the disabled image or null
709  *
710  * @exception SWTException <ul>
711  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
712  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
713  * </ul>
714  *
715  * @deprecated the disabled image is not used
716  */

717 public Image getDisabledImage(){
718     checkWidget();
719     return disabledImage;
720 }
721 /**
722  * Returns the font that the receiver will use to paint textual information.
723  *
724  * @return the receiver's font
725  *
726  * @exception SWTException <ul>
727  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
728  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
729  * </ul>
730  *
731  * @since 3.0
732  */

733 public Font getFont() {
734     checkWidget();
735     if (font != null) return font;
736     return parent.getFont();
737 }
738 /**
739  * Returns the receiver's parent, which must be a <code>CTabFolder</code>.
740  *
741  * @return the receiver's parent
742  *
743  * @exception SWTException <ul>
744  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
745  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
746  * </ul>
747  */

748 public CTabFolder getParent () {
749     //checkWidget();
750
return parent;
751 }
752 /**
753  * Returns the receiver's tool tip text, or null if it has
754  * not been set.
755  *
756  * @return the receiver's tool tip text
757  *
758  * @exception SWTException <ul>
759  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
760  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
761  * </ul>
762  */

763 public String JavaDoc getToolTipText () {
764     checkWidget();
765     if (toolTipText == null && shortenedText != null) {
766         String JavaDoc text = getText();
767         if (!shortenedText.equals(text)) return text;
768     }
769     return toolTipText;
770 }
771 /**
772 * Returns <code>true</code> if the item will be rendered in the visible area of the CTabFolder. Returns false otherwise.
773 *
774 * @return <code>true</code> if the item will be rendered in the visible area of the CTabFolder. Returns false otherwise.
775 *
776 * @exception SWTException <ul>
777  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
778  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
779  * </ul>
780  *
781 * @since 3.0
782 */

783 public boolean isShowing () {
784     checkWidget();
785     return showing;
786 }
787 void onPaint(GC gc, boolean isSelected) {
788     if (width == 0 || height == 0) return;
789     if (isSelected) {
790         drawSelected(gc);
791     } else {
792         drawUnselected(gc);
793     }
794 }
795 int preferredHeight(GC gc) {
796     Image image = getImage();
797     int h = (image == null) ? 0 : image.getBounds().height;
798     String JavaDoc text = getText();
799     if (font == null) {
800         h = Math.max(h, gc.textExtent(text, FLAGS).y);
801     } else {
802         Font gcFont = gc.getFont();
803         gc.setFont(font);
804         h = Math.max(h, gc.textExtent(text, FLAGS).y);
805         gc.setFont(gcFont);
806     }
807     return h + TOP_MARGIN + BOTTOM_MARGIN;
808 }
809 int preferredWidth(GC gc, boolean isSelected, boolean minimum) {
810     // NOTE: preferred width does not include the "dead space" caused
811
// by the curve.
812
if (isDisposed()) return 0;
813     int w = 0;
814     Image image = getImage();
815     if (image != null && (isSelected || parent.showUnselectedImage)) {
816         w += image.getBounds().width;
817     }
818     String JavaDoc text = null;
819     if (minimum) {
820         int minChars = parent.minChars;
821         text = minChars == 0 ? null : getText();
822         if (text != null && text.length() > minChars) {
823             if (useEllipses()) {
824                 int end = minChars < ELLIPSIS.length() + 1 ? minChars : minChars - ELLIPSIS.length();
825                 text = text.substring(0, end);
826                 if (minChars > ELLIPSIS.length() + 1) text += ELLIPSIS;
827             } else {
828                 int end = minChars;
829                 text = text.substring(0, end);
830             }
831         }
832     } else {
833         text = getText();
834     }
835     if (text != null) {
836         if (w > 0) w += INTERNAL_SPACING;
837         if (font == null) {
838             w += gc.textExtent(text, FLAGS).x;
839         } else {
840             Font gcFont = gc.getFont();
841             gc.setFont(font);
842             w += gc.textExtent(text, FLAGS).x;
843             gc.setFont(gcFont);
844         }
845     }
846     if (parent.showClose || showClose) {
847         if (isSelected || parent.showUnselectedClose) {
848             if (w > 0) w += INTERNAL_SPACING;
849             w += CTabFolder.BUTTON_SIZE;
850         }
851     }
852     return w + LEFT_MARGIN + RIGHT_MARGIN;
853 }
854 /**
855  * Sets the control that is used to fill the client area of
856  * the tab folder when the user selects the tab item.
857  *
858  * @param control the new control (or null)
859  *
860  * @exception IllegalArgumentException <ul>
861  * <li>ERROR_INVALID_ARGUMENT - if the control has been disposed</li>
862  * <li>ERROR_INVALID_PARENT - if the control is not in the same widget tree</li>
863  * </ul>
864  * @exception SWTException <ul>
865  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
866  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
867  * </ul>
868  */

869 public void setControl (Control control) {
870     checkWidget();
871     if (control != null) {
872         if (control.isDisposed()) SWT.error (SWT.ERROR_INVALID_ARGUMENT);
873         if (control.getParent() != parent) SWT.error (SWT.ERROR_INVALID_PARENT);
874     }
875     if (this.control != null && !this.control.isDisposed()) {
876         this.control.setVisible(false);
877     }
878     this.control = control;
879     if (this.control != null) {
880         int index = parent.indexOf (this);
881         if (index == parent.getSelectionIndex ()){
882             this.control.setBounds(parent.getClientArea ());
883             this.control.setVisible(true);
884         } else {
885             this.control.setVisible(false);
886         }
887     }
888 }
889 /**
890  * Sets the image that is displayed if the tab item is disabled.
891  * Null will clear the image.
892  *
893  * @param image the image to be displayed when the item is disabled or null
894  *
895  * @exception SWTException <ul>
896  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
897  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
898  * </ul>
899  *
900  * @deprecated This image is not used
901  */

902 public void setDisabledImage (Image image) {
903     checkWidget();
904     if (image != null && image.isDisposed ()) {
905         SWT.error(SWT.ERROR_INVALID_ARGUMENT);
906     }
907     this.disabledImage = image;
908 }
909 /**
910  * Sets the font that the receiver will use to paint textual information
911  * for this item to the font specified by the argument, or to the default font
912  * for that kind of control if the argument is null.
913  *
914  * @param font the new font (or null)
915  *
916  * @exception IllegalArgumentException <ul>
917  * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
918  * </ul>
919  * @exception SWTException <ul>
920  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
921  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
922  * </ul>
923  *
924  * @since 3.0
925  */

926 public void setFont (Font font){
927     checkWidget();
928     if (font != null && font.isDisposed ()) {
929         SWT.error(SWT.ERROR_INVALID_ARGUMENT);
930     }
931     if (font == null && this.font == null) return;
932     if (font != null && font.equals(this.font)) return;
933     this.font = font;
934     if (!parent.updateTabHeight(false)) {
935         parent.updateItems();
936         parent.redrawTabs();
937     }
938 }
939 public void setImage (Image image) {
940     checkWidget();
941     if (image != null && image.isDisposed ()) {
942         SWT.error(SWT.ERROR_INVALID_ARGUMENT);
943     }
944     Image oldImage = getImage();
945     if (image == null && oldImage == null) return;
946     if (image != null && image.equals(oldImage)) return;
947     super.setImage(image);
948     if (!parent.updateTabHeight(false)) {
949         // If image is the same size as before,
950
// redraw only the image
951
if (oldImage != null && image != null) {
952             Rectangle oldBounds = oldImage.getBounds();
953             Rectangle bounds = image.getBounds();
954             if (bounds.width == oldBounds.width && bounds.height == oldBounds.height) {
955                 if (showing) {
956                     boolean selected = parent.indexOf(this) == parent.selectedIndex;
957                     if (selected || parent.showUnselectedImage) {
958                         int imageX = x + LEFT_MARGIN, maxImageWidth;
959                         if (selected) {
960                             if (parent.single && (parent.showClose || showClose)) imageX += CTabFolder.BUTTON_SIZE;
961                             int rightEdge = Math.min (x + width, parent.getRightItemEdge());
962                             maxImageWidth = rightEdge - imageX - RIGHT_MARGIN;
963                             if (!parent.single && closeRect.width > 0) maxImageWidth -= closeRect.width + INTERNAL_SPACING;
964                         } else {
965                             maxImageWidth = x + width - imageX - RIGHT_MARGIN;
966                             if (parent.showUnselectedClose && (parent.showClose || showClose)) {
967                                 maxImageWidth -= closeRect.width + INTERNAL_SPACING;
968                             }
969                         }
970                         if (bounds.width < maxImageWidth) {
971                             int imageY = y + (height - bounds.height) / 2 + (parent.onBottom ? -1 : 1);
972                             parent.redraw(imageX, imageY, bounds.width, bounds.height, false);
973                         }
974                     }
975                 }
976                 return;
977             }
978         }
979         parent.updateItems();
980         parent.redrawTabs();
981     }
982 }
983 public void setText (String JavaDoc string) {
984     checkWidget();
985     if (string == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
986     if (string.equals(getText())) return;
987     super.setText(string);
988     shortenedText = null;
989     shortenedTextWidth = 0;
990     if (!parent.updateTabHeight(false)) {
991         parent.updateItems();
992         parent.redrawTabs();
993     }
994 }
995 /**
996  * Sets the receiver's tool tip text to the argument, which
997  * may be null indicating that no tool tip text should be shown.
998  *
999  * @param string the new tool tip text (or null)
1000 *
1001 * @exception SWTException <ul>
1002 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1003 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1004 * </ul>
1005 */

1006public void setToolTipText (String JavaDoc string) {
1007    checkWidget();
1008    toolTipText = string;
1009}
1010}
1011
Popular Tags