KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > ui > internal > views > properties > tabbed > view > TabbedPropertyList


1 /*******************************************************************************
2  * Copyright (c) 2001, 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.ui.internal.views.properties.tabbed.view;
12
13 import org.eclipse.jface.resource.JFaceResources;
14 import org.eclipse.swt.SWT;
15 import org.eclipse.swt.accessibility.ACC;
16 import org.eclipse.swt.accessibility.Accessible;
17 import org.eclipse.swt.accessibility.AccessibleAdapter;
18 import org.eclipse.swt.accessibility.AccessibleControlAdapter;
19 import org.eclipse.swt.accessibility.AccessibleControlEvent;
20 import org.eclipse.swt.accessibility.AccessibleEvent;
21 import org.eclipse.swt.events.ControlAdapter;
22 import org.eclipse.swt.events.ControlEvent;
23 import org.eclipse.swt.events.FocusEvent;
24 import org.eclipse.swt.events.FocusListener;
25 import org.eclipse.swt.events.MouseAdapter;
26 import org.eclipse.swt.events.MouseEvent;
27 import org.eclipse.swt.events.MouseMoveListener;
28 import org.eclipse.swt.events.MouseTrackAdapter;
29 import org.eclipse.swt.events.PaintEvent;
30 import org.eclipse.swt.events.PaintListener;
31 import org.eclipse.swt.events.TraverseEvent;
32 import org.eclipse.swt.events.TraverseListener;
33 import org.eclipse.swt.graphics.Color;
34 import org.eclipse.swt.graphics.FontMetrics;
35 import org.eclipse.swt.graphics.GC;
36 import org.eclipse.swt.graphics.Point;
37 import org.eclipse.swt.graphics.RGB;
38 import org.eclipse.swt.graphics.Rectangle;
39 import org.eclipse.swt.layout.FormAttachment;
40 import org.eclipse.swt.layout.FormData;
41 import org.eclipse.swt.layout.FormLayout;
42 import org.eclipse.swt.widgets.Canvas;
43 import org.eclipse.swt.widgets.Composite;
44 import org.eclipse.swt.widgets.Display;
45 import org.eclipse.swt.widgets.Event;
46 import org.eclipse.swt.widgets.Listener;
47 import org.eclipse.swt.widgets.Shell;
48 import org.eclipse.ui.forms.FormColors;
49 import org.eclipse.ui.internal.views.properties.tabbed.l10n.TabbedPropertyMessages;
50 import org.eclipse.ui.views.properties.tabbed.ITabItem;
51 import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetWidgetFactory;
52
53
54 /**
55  * Shows the list of tabs in the tabbed property sheet page.
56  *
57  * @author Anthony Hunter
58  */

59 public class TabbedPropertyList
60     extends Composite {
61
62     private static final ListElement[] ELEMENTS_EMPTY = new ListElement[0];
63
64     protected static final int NONE = -1;
65
66     protected static final int INDENT = 7;
67
68     private ListElement[] elements;
69
70     private int selectedElementIndex = NONE;
71
72     private int topVisibleIndex = NONE;
73
74     private int bottomVisibleIndex = NONE;
75
76     private TopNavigationElement topNavigationElement;
77
78     private BottomNavigationElement bottomNavigationElement;
79
80     private int widestLabelIndex = NONE;
81
82     private int tabsThatFitInComposite = NONE;
83
84     private Color widgetForeground;
85
86     private Color widgetBackground;
87
88     private Color widgetNormalShadow;
89
90     private Color widgetDarkShadow;
91
92     private Color listBackground;
93
94     private Color hoverGradientStart;
95
96     private Color hoverGradientEnd;
97
98     private Color defaultGradientStart;
99
100     private Color defaultGradientEnd;
101
102     private Color indentedDefaultBackground;
103
104     private Color indentedHoverBackground;
105
106     private Color navigationElementShadowStroke;
107
108     private Color bottomNavigationElementShadowStroke1;
109
110     private Color bottomNavigationElementShadowStroke2;
111
112     private TabbedPropertySheetWidgetFactory factory;
113
114     /**
115      * One of the tabs in the tabbed property list.
116      */

117     public class ListElement extends Canvas {
118
119         private ITabItem tab;
120
121         private int index;
122
123         private boolean selected;
124
125         private boolean hover;
126
127         /**
128          * Constructor for ListElement.
129          *
130          * @param parent
131          * the parent Composite.
132          * @param tab
133          * the tab item for the element.
134          * @param index
135          * the index in the list.
136          */

137         public ListElement(Composite parent, final ITabItem tab, int index) {
138             super(parent, SWT.NO_FOCUS);
139             this.tab = tab;
140             hover = false;
141             selected = false;
142             this.index = index;
143
144             addPaintListener(new PaintListener() {
145
146                 public void paintControl(PaintEvent e) {
147                     paint(e);
148                 }
149             });
150             addMouseListener(new MouseAdapter() {
151
152                 public void mouseUp(MouseEvent e) {
153                     if (!selected) {
154                         select(getIndex(ListElement.this));
155                         /*
156                          * We set focus to the tabbed property composite so that
157                          * focus is moved to the appropriate widget in the
158                          * section.
159                          */

160                         Composite tabbedPropertyComposite = getParent();
161                         while (!(tabbedPropertyComposite instanceof TabbedPropertyComposite)) {
162                             tabbedPropertyComposite = tabbedPropertyComposite
163                                 .getParent();
164                         }
165                         tabbedPropertyComposite.setFocus();
166                     }
167                 }
168             });
169             addMouseMoveListener(new MouseMoveListener() {
170
171                 public void mouseMove(MouseEvent e) {
172                     if (!hover) {
173                         hover = true;
174                         redraw();
175                     }
176                 }
177             });
178             addMouseTrackListener(new MouseTrackAdapter() {
179
180                 public void mouseExit(MouseEvent e) {
181                     hover = false;
182                     redraw();
183                 }
184             });
185         }
186
187         /**
188          * Set selected value for this element.
189          *
190          * @param selected
191          * the selected value.
192          */

193         public void setSelected(boolean selected) {
194             this.selected = selected;
195             redraw();
196         }
197
198         /**
199          * Paint the element.
200          *
201          * @param e
202          * the paint event.
203          */

204         private void paint(PaintEvent e) {
205             /*
206              * draw the top two lines of the tab, same for selected, hover and
207              * default
208              */

209             Rectangle bounds = getBounds();
210             e.gc.setForeground(widgetNormalShadow);
211             e.gc.drawLine(0, 0, bounds.width - 1, 0);
212             e.gc.setForeground(listBackground);
213             e.gc.drawLine(0, 1, bounds.width - 1, 1);
214
215             /* draw the fill in the tab */
216             if (selected) {
217                 e.gc.setBackground(listBackground);
218                 e.gc.fillRectangle(0, 2, bounds.width, bounds.height - 1);
219             } else if (hover && tab.isIndented()) {
220                 e.gc.setBackground(indentedHoverBackground);
221                 e.gc.fillRectangle(0, 2, bounds.width - 1, bounds.height - 1);
222             } else if (hover) {
223                 e.gc.setForeground(hoverGradientStart);
224                 e.gc.setBackground(hoverGradientEnd);
225                 e.gc.fillGradientRectangle(0, 2, bounds.width - 1,
226                         bounds.height - 1, true);
227             } else if (tab.isIndented()) {
228                 e.gc.setBackground(indentedDefaultBackground);
229                 e.gc.fillRectangle(0, 2, bounds.width - 1, bounds.height - 1);
230             } else {
231                 e.gc.setForeground(defaultGradientStart);
232                 e.gc.setBackground(defaultGradientEnd);
233                 e.gc.fillGradientRectangle(0, 2, bounds.width - 1,
234                         bounds.height - 1, true);
235             }
236
237             if (!selected) {
238                 e.gc.setForeground(widgetNormalShadow);
239                 e.gc.drawLine(bounds.width - 1, 1, bounds.width - 1,
240                         bounds.height + 1);
241             }
242
243             int textIndent = INDENT;
244             FontMetrics fm = e.gc.getFontMetrics();
245             int height = fm.getHeight();
246             int textMiddle = (bounds.height - height) / 2;
247
248             if (selected && tab.getImage() != null
249                 && !tab.getImage().isDisposed()) {
250                 /* draw the icon for the selected tab */
251                 if (tab.isIndented()) {
252                     textIndent = textIndent + INDENT;
253                 } else {
254                     textIndent = textIndent - 3;
255                 }
256                 e.gc.drawImage(tab.getImage(), textIndent, textMiddle - 1);
257                 textIndent = textIndent + 16 + 5;
258             } else if (tab.isIndented()) {
259                 textIndent = textIndent + INDENT;
260             }
261
262             /* draw the text */
263             e.gc.setForeground(widgetForeground);
264             if (selected) {
265                 /* selected tab is bold font */
266                 e.gc.setFont(JFaceResources.getFontRegistry().getBold(
267                         JFaceResources.DEFAULT_FONT));
268             }
269             e.gc.drawText(tab.getText(), textIndent, textMiddle, true);
270
271             /* draw the bottom line on the tab for selected and default */
272             if (!hover) {
273                 e.gc.setForeground(listBackground);
274                 e.gc.drawLine(0, bounds.height - 1, bounds.width - 2,
275                         bounds.height - 1);
276             }
277         }
278
279         /**
280          * Get the tab item.
281          *
282          * @return the tab item.
283          */

284         public ITabItem getTabItem() {
285             return tab;
286         }
287
288         public String JavaDoc toString() {
289             return tab.getText();
290         }
291     }
292
293     /**
294      * The top navigation element in the tabbed property list. It looks like a
295      * scroll button when scrolling is needed or is just a spacer when no
296      * scrolling is required.
297      */

298     public class TopNavigationElement extends Canvas {
299
300         /**
301          * Constructor for TopNavigationElement.
302          *
303          * @param parent
304          * the parent Composite.
305          */

306         public TopNavigationElement(Composite parent) {
307             super(parent, SWT.NO_FOCUS);
308             addPaintListener(new PaintListener() {
309
310                 public void paintControl(PaintEvent e) {
311                     paint(e);
312                 }
313             });
314             addMouseListener(new MouseAdapter() {
315
316                 public void mouseUp(MouseEvent e) {
317                     if (isUpScrollRequired()) {
318                         bottomVisibleIndex--;
319                         if (topVisibleIndex != 0) {
320                             topVisibleIndex--;
321                         }
322                         layoutTabs();
323                         topNavigationElement.redraw();
324                         bottomNavigationElement.redraw();
325                     }
326                 }
327             });
328         }
329
330         /**
331          * Paint the element.
332          *
333          * @param e
334          * the paint event.
335          */

336         private void paint(PaintEvent e) {
337             e.gc.setBackground(widgetBackground);
338             e.gc.setForeground(widgetForeground);
339             Rectangle bounds = getBounds();
340
341             if (elements.length != 0) {
342                 e.gc.fillRectangle(0, 0, bounds.width, bounds.height);
343                 e.gc.setForeground(widgetNormalShadow);
344                 e.gc.drawLine(bounds.width - 1, 0, bounds.width - 1,
345                     bounds.height - 1);
346             } else {
347                 e.gc.setBackground(listBackground);
348                 e.gc.fillRectangle(0, 0, bounds.width, bounds.height);
349                 int textIndent = INDENT;
350                 FontMetrics fm = e.gc.getFontMetrics();
351                 int height = fm.getHeight();
352                 int textMiddle = (bounds.height - height) / 2;
353                 e.gc.setForeground(widgetForeground);
354                 String JavaDoc properties_not_available = TabbedPropertyMessages.TabbedPropertyList_properties_not_available;
355                 e.gc.drawText(properties_not_available, textIndent, textMiddle);
356             }
357
358             if (isUpScrollRequired()) {
359                 e.gc.setForeground(widgetDarkShadow);
360                 int middle = bounds.width / 2;
361                 e.gc.drawLine(middle + 1, 3, middle + 5, 7);
362                 e.gc.drawLine(middle, 3, middle - 4, 7);
363                 e.gc.drawLine(middle - 3, 7, middle + 4, 7);
364
365                 e.gc.setForeground(listBackground);
366                 e.gc.drawLine(middle, 4, middle + 1, 4);
367                 e.gc.drawLine(middle - 1, 5, middle + 2, 5);
368                 e.gc.drawLine(middle - 2, 6, middle + 3, 6);
369
370                 e.gc.setForeground(widgetNormalShadow);
371                 e.gc.drawLine(0, 0, bounds.width - 2, 0);
372                 e.gc.setForeground(navigationElementShadowStroke);
373                 e.gc.drawLine(0, 1, bounds.width - 2, 1);
374                 e.gc.drawLine(0, bounds.height - 1, bounds.width - 2,
375                         bounds.height - 1);
376             }
377         }
378     }
379
380     /**
381      * The top navigation element in the tabbed property list. It looks like a
382      * scroll button when scrolling is needed or is just a spacer when no
383      * scrolling is required.
384      */

385     public class BottomNavigationElement extends Canvas {
386
387         /**
388          * Constructor for BottomNavigationElement.
389          *
390          * @param parent
391          * the parent Composite.
392          */

393         public BottomNavigationElement(Composite parent) {
394             super(parent, SWT.NO_FOCUS);
395             addPaintListener(new PaintListener() {
396
397                 public void paintControl(PaintEvent e) {
398                     paint(e);
399                 }
400             });
401             addMouseListener(new MouseAdapter() {
402
403                 public void mouseUp(MouseEvent e) {
404                     if (isDownScrollRequired()) {
405                         topVisibleIndex++;
406                         if (bottomVisibleIndex != elements.length - 1) {
407                             bottomVisibleIndex++;
408                         }
409                         layoutTabs();
410                         topNavigationElement.redraw();
411                         bottomNavigationElement.redraw();
412                     }
413                 }
414             });
415         }
416
417         /**
418          * Paint the element.
419          *
420          * @param e
421          * the paint event.
422          */

423         private void paint(PaintEvent e) {
424             e.gc.setBackground(widgetBackground);
425             e.gc.setForeground(widgetForeground);
426             Rectangle bounds = getBounds();
427
428             if (elements.length != 0) {
429                 e.gc.fillRectangle(0, 0, bounds.width, bounds.height);
430                 e.gc.setForeground(widgetNormalShadow);
431                 e.gc.drawLine(bounds.width - 1, 0, bounds.width - 1,
432                         bounds.height - 1);
433                 e.gc.drawLine(0, 0, bounds.width - 1, 0);
434
435                 e.gc.setForeground(bottomNavigationElementShadowStroke1);
436                 e.gc.drawLine(0, 1, bounds.width - 2, 1);
437                 e.gc.setForeground(bottomNavigationElementShadowStroke2);
438                 e.gc.drawLine(0, 2, bounds.width - 2, 2);
439             } else {
440                 e.gc.setBackground(listBackground);
441                 e.gc.fillRectangle(0, 0, bounds.width, bounds.height);
442             }
443
444             if (isDownScrollRequired()) {
445                 e.gc.setForeground(widgetDarkShadow);
446                 int middle = bounds.width / 2;
447                 int bottom = bounds.height - 3;
448                 e.gc.drawLine(middle + 1, bottom, middle + 5, bottom - 4);
449                 e.gc.drawLine(middle, bottom, middle - 4, bottom - 4);
450                 e.gc.drawLine(middle - 3, bottom - 4, middle + 4, bottom - 4);
451
452                 e.gc.setForeground(listBackground);
453                 e.gc.drawLine(middle, bottom - 1, middle + 1, bottom - 1);
454                 e.gc.drawLine(middle - 1, bottom - 2, middle + 2, bottom - 2);
455                 e.gc.drawLine(middle - 2, bottom - 3, middle + 3, bottom - 3);
456
457                 e.gc.setForeground(widgetNormalShadow);
458                 e.gc.drawLine(0, bottom - 7, bounds.width - 2, bottom - 7);
459                 e.gc.setForeground(navigationElementShadowStroke);
460                 e.gc.drawLine(0, bottom + 2, bounds.width - 2, bottom + 2);
461                 e.gc.drawLine(0, bottom - 6, bounds.width - 2, bottom - 6);
462             }
463         }
464     }
465
466     /**
467      * Constructor for TabbedPropertyList.
468      *
469      * @param parent
470      * the parent widget.
471      * @param factory
472      * the widget factory.
473      */

474     public TabbedPropertyList(Composite parent,
475             TabbedPropertySheetWidgetFactory factory) {
476         super(parent, SWT.NO_FOCUS);
477         this.factory = factory;
478         removeAll();
479         setLayout(new FormLayout());
480         initColours();
481         initAccessible();
482         topNavigationElement = new TopNavigationElement(this);
483         bottomNavigationElement = new BottomNavigationElement(this);
484
485         this.addFocusListener(new FocusListener() {
486
487             public void focusGained(FocusEvent e) {
488                 int i = getSelectionIndex();
489                 if (i >= 0) {
490                     elements[i].redraw();
491                 }
492             }
493
494             public void focusLost(FocusEvent e) {
495                 int i = getSelectionIndex();
496                 if (i >= 0) {
497                     elements[i].redraw();
498                 }
499             }
500         });
501         this.addControlListener(new ControlAdapter() {
502
503             public void controlResized(ControlEvent e) {
504                 computeTopAndBottomTab();
505             }
506         });
507         this.addTraverseListener(new TraverseListener() {
508
509             public void keyTraversed(TraverseEvent e) {
510                 if (e.detail == SWT.TRAVERSE_ARROW_PREVIOUS
511                     || e.detail == SWT.TRAVERSE_ARROW_NEXT) {
512                     int nMax = elements.length - 1;
513                     int nCurrent = getSelectionIndex();
514                     if (e.detail == SWT.TRAVERSE_ARROW_PREVIOUS) {
515                         nCurrent -= 1;
516                         nCurrent = Math.max(0, nCurrent);
517                     } else if (e.detail == SWT.TRAVERSE_ARROW_NEXT) {
518                         nCurrent += 1;
519                         nCurrent = Math.min(nCurrent, nMax);
520                     }
521                     select(nCurrent);
522                     redraw();
523                 } else {
524                     e.doit = true;
525                 }
526             }
527         });
528     }
529
530     /**
531      * Calculate the number of tabs that will fit in the tab list composite.
532      */

533     protected void computeTabsThatFitInComposite() {
534         tabsThatFitInComposite = Math
535             .round((getSize().y - 22) / getTabHeight());
536         if (tabsThatFitInComposite <= 0) {
537             tabsThatFitInComposite = 1;
538         }
539     }
540
541     /**
542      * Returns the element with the given index from this list viewer. Returns
543      * <code>null</code> if the index is out of range.
544      *
545      * @param index
546      * the zero-based index
547      * @return the element at the given index, or <code>null</code> if the
548      * index is out of range
549      */

550     public Object JavaDoc getElementAt(int index) {
551         if (index >= 0 && index < elements.length) {
552             return elements[index];
553         }
554         return null;
555     }
556
557     /**
558      * Returns the zero-relative index of the item which is currently selected
559      * in the receiver, or -1 if no item is selected.
560      *
561      * @return the index of the selected item
562      */

563     public int getSelectionIndex() {
564         return selectedElementIndex;
565     }
566
567     /**
568      * Removes all elements from this list.
569      */

570     public void removeAll() {
571         if (elements != null) {
572             for (int i = 0; i < elements.length; i++) {
573                 elements[i].dispose();
574             }
575         }
576         elements = ELEMENTS_EMPTY;
577         selectedElementIndex = NONE;
578         widestLabelIndex = NONE;
579         topVisibleIndex = NONE;
580         bottomVisibleIndex = NONE;
581     }
582
583     /**
584      * Sets the new list elements.
585      *
586      * @param children
587      */

588     public void setElements(Object JavaDoc[] children) {
589         if (elements != ELEMENTS_EMPTY) {
590             removeAll();
591         }
592         elements = new ListElement[children.length];
593         if (children.length == 0) {
594             widestLabelIndex = NONE;
595         } else {
596             widestLabelIndex = 0;
597             for (int i = 0; i < children.length; i++) {
598                 elements[i] = new ListElement(this, (ITabItem) children[i], i);
599                 elements[i].setVisible(false);
600                 elements[i].setLayoutData(null);
601
602                 if (i != widestLabelIndex) {
603                     String JavaDoc label = ((ITabItem) children[i]).getText();
604                     int width = getTextDimension(label).x;
605                     if (((ITabItem) children[i]).getImage() != null) {
606                         width = width + 16 + 5;
607                     }
608                     if (((ITabItem) children[i]).isIndented()) {
609                         width = width + INDENT;
610                     }
611                     if (width > getTextDimension(((ITabItem) children[widestLabelIndex])
612                             .getText()).x) {
613                         widestLabelIndex = i;
614                     }
615                 }
616             }
617         }
618
619         computeTopAndBottomTab();
620     }
621
622     /**
623      * Selects one of the elements in the list.
624      *
625      * @param index
626      * the index of the element to select.
627      */

628     protected void select(int index) {
629         if (getSelectionIndex() == index) {
630             /*
631              * this index is already selected.
632              */

633             return;
634         }
635         if (index >= 0 && index < elements.length) {
636             int lastSelected = getSelectionIndex();
637             elements[index].setSelected(true);
638             selectedElementIndex = index;
639             if (lastSelected != NONE) {
640                 elements[lastSelected].setSelected(false);
641                 if (getSelectionIndex() != elements.length - 1) {
642                     /*
643                      * redraw the next tab to fix the border by calling
644                      * setSelected()
645                      */

646                     elements[getSelectionIndex() + 1].setSelected(false);
647                 }
648             }
649             topNavigationElement.redraw();
650             bottomNavigationElement.redraw();
651
652             if (selectedElementIndex < topVisibleIndex
653                 || selectedElementIndex > bottomVisibleIndex) {
654                 computeTopAndBottomTab();
655             }
656         }
657         notifyListeners(SWT.Selection, new Event());
658     }
659
660     /**
661      * Deselects all the elements in the list.
662      */

663     public void deselectAll() {
664         if (getSelectionIndex() != NONE) {
665             elements[getSelectionIndex()].setSelected(false);
666             selectedElementIndex = NONE;
667         }
668     }
669
670     private int getIndex(ListElement element) {
671         return element.index;
672     }
673
674     public Point computeSize(int wHint, int hHint, boolean changed) {
675         Point result = super.computeSize(hHint, wHint, changed);
676         if (widestLabelIndex == -1) {
677             String JavaDoc properties_not_available = TabbedPropertyMessages.TabbedPropertyList_properties_not_available;
678             result.x = getTextDimension(properties_not_available).x + INDENT;
679         } else {
680             ITabItem widestTab = elements[widestLabelIndex].getTabItem();
681             int width = getTextDimension(widestTab.getText()).x + INDENT;
682             /*
683              * To anticipate for the icon placement we should always keep the
684              * space available after the label. So when the active tab includes
685              * an icon the width of the tab doesn't change.
686              */

687             if (widestTab.getImage() != null) {
688                 width = width + 16 + 4;
689             }
690             if (widestTab.isIndented()) {
691                 width = width + 10;
692             }
693             /*
694              * Add 10 pixels to the right of the longest string as a margin.
695              */

696             result.x = width + 10;
697         }
698         return result;
699     }
700
701     /**
702      * Get the dimensions of the provided string.
703      *
704      * @param text
705      * the string.
706      * @return the dimensions of the provided string.
707      */

708     private Point getTextDimension(String JavaDoc text) {
709         Shell shell = new Shell();
710         GC gc = new GC(shell);
711         gc.setFont(JFaceResources.getFontRegistry().getBold(
712                 JFaceResources.DEFAULT_FONT));
713         Point point = gc.textExtent(text);
714         point.x++;
715         gc.dispose();
716         shell.dispose();
717         return point;
718     }
719
720     /**
721      * Initialize the colours used in the list.
722      */

723     private void initColours() {
724         /*
725          * Colour 3 COLOR_LIST_BACKGROUND
726          */

727         listBackground = Display.getCurrent().getSystemColor(
728                 SWT.COLOR_LIST_BACKGROUND);
729
730         /*
731          * Colour 13 COLOR_WIDGET_BACKGROUND
732          */

733         widgetBackground = Display.getCurrent().getSystemColor(
734                 SWT.COLOR_WIDGET_BACKGROUND);
735
736         /*
737          * Colour 15 COLOR_WIDGET_DARK_SHADOW
738          */

739         widgetDarkShadow = Display.getCurrent().getSystemColor(
740                 SWT.COLOR_WIDGET_DARK_SHADOW);
741
742         /*
743          * Colour 16 COLOR_WIDGET_FOREGROUND
744          */

745         widgetForeground = Display.getCurrent().getSystemColor(
746                 SWT.COLOR_WIDGET_FOREGROUND);
747
748         /*
749          * Colour 19 COLOR_WIDGET_NORMAL_SHADOW
750          */

751         widgetNormalShadow = Display.getCurrent().getSystemColor(
752                 SWT.COLOR_WIDGET_NORMAL_SHADOW);
753
754         RGB infoBackground = Display.getCurrent().getSystemColor(
755                 SWT.COLOR_INFO_BACKGROUND).getRGB();
756         RGB white = Display.getCurrent().getSystemColor(SWT.COLOR_WHITE)
757                 .getRGB();
758         RGB black = Display.getCurrent().getSystemColor(SWT.COLOR_BLACK)
759                 .getRGB();
760
761         /*
762          * gradient in the default tab: start colour WIDGET_NORMAL_SHADOW 100% +
763          * white 20% + INFO_BACKGROUND 60% end colour WIDGET_NORMAL_SHADOW 100% +
764          * INFO_BACKGROUND 40%
765          */

766         defaultGradientStart = factory.getColors().createColor(
767                 "TabbedPropertyList.defaultTabGradientStart", //$NON-NLS-1$
768
FormColors.blend(infoBackground, FormColors.blend(white,
769                         widgetNormalShadow.getRGB(), 20), 60));
770         defaultGradientEnd = factory.getColors().createColor(
771                 "TabbedPropertyList.defaultTabGradientEnd", //$NON-NLS-1$
772
FormColors.blend(infoBackground, widgetNormalShadow.getRGB(),
773                         40));
774
775         navigationElementShadowStroke = factory.getColors().createColor(
776                 "TabbedPropertyList.shadowStroke", //$NON-NLS-1$
777
FormColors.blend(white, widgetNormalShadow.getRGB(), 55));
778         bottomNavigationElementShadowStroke1 = factory.getColors().createColor(
779                 "TabbedPropertyList.tabShadowStroke1", //$NON-NLS-1$
780
FormColors.blend(black, widgetBackground.getRGB(), 10));
781         bottomNavigationElementShadowStroke2 = factory.getColors().createColor(
782                 "TabbedPropertyList.tabShadowStroke2", //$NON-NLS-1$
783
FormColors.blend(black, widgetBackground.getRGB(), 5));
784
785         /*
786          * gradient in the hover tab: start colour WIDGET_BACKGROUND 100% +
787          * white 20% end colour WIDGET_BACKGROUND 100% + WIDGET_NORMAL_SHADOW
788          * 10%
789          */

790         hoverGradientStart = factory.getColors().createColor(
791                 "TabbedPropertyList.hoverBackgroundGradientStart", //$NON-NLS-1$
792
FormColors.blend(white, widgetBackground.getRGB(), 20));
793         hoverGradientEnd = factory.getColors().createColor(
794                 "TabbedPropertyList.hoverBackgroundGradientEnd", //$NON-NLS-1$
795
FormColors.blend(widgetNormalShadow.getRGB(), widgetBackground
796                         .getRGB(), 10));
797
798         indentedDefaultBackground = factory.getColors().createColor(
799                 "TabbedPropertyList.indentedDefaultBackground", //$NON-NLS-1$
800
FormColors.blend(white, widgetBackground.getRGB(), 10));
801         indentedHoverBackground = factory.getColors().createColor(
802                 "TabbedPropertyList.indentedHoverBackground", //$NON-NLS-1$
803
FormColors.blend(white, widgetBackground.getRGB(), 75));
804     }
805
806     public void dispose() {
807         hoverGradientStart.dispose();
808         hoverGradientEnd.dispose();
809         defaultGradientStart.dispose();
810         defaultGradientEnd.dispose();
811         indentedDefaultBackground.dispose();
812         indentedHoverBackground.dispose();
813         navigationElementShadowStroke.dispose();
814         bottomNavigationElementShadowStroke1.dispose();
815         bottomNavigationElementShadowStroke2.dispose();
816         super.dispose();
817     }
818
819     /**
820      * Get the height of a tab. The height of the tab is the height of the text
821      * plus buffer.
822      *
823      * @return the height of a tab.
824      */

825     private int getTabHeight() {
826         int tabHeight = getTextDimension("").y + INDENT; //$NON-NLS-1$
827
if (tabsThatFitInComposite == 1) {
828             /*
829              * if only one tab will fix, reduce the size of the tab height so
830              * that the navigation elements fit.
831              */

832             int ret = getBounds().height - 20;
833             return (ret > tabHeight) ? tabHeight
834                 : (ret < 5) ? 5
835                     : ret;
836         }
837         return tabHeight;
838     }
839
840     /**
841      * Determine if a downward scrolling is required.
842      *
843      * @return true if downward scrolling is required.
844      */

845     private boolean isDownScrollRequired() {
846         return elements.length > tabsThatFitInComposite
847             && bottomVisibleIndex != elements.length - 1;
848     }
849
850     /**
851      * Determine if an upward scrolling is required.
852      *
853      * @return true if upward scrolling is required.
854      */

855     private boolean isUpScrollRequired() {
856         return elements.length > tabsThatFitInComposite && topVisibleIndex != 0;
857     }
858
859     /**
860      * Based on available space, figure out the top and bottom tabs in the list.
861      */

862     private void computeTopAndBottomTab() {
863         computeTabsThatFitInComposite();
864         if (elements.length == 0) {
865             /*
866              * no tabs to display.
867              */

868             topVisibleIndex = 0;
869             bottomVisibleIndex = 0;
870         } else if (tabsThatFitInComposite >= elements.length) {
871             /*
872              * all the tabs fit.
873              */

874             topVisibleIndex = 0;
875             bottomVisibleIndex = elements.length - 1;
876         } else if (getSelectionIndex() == NONE) {
877             /*
878              * there is no selected tab yet, assume that tab one would
879              * be selected for now.
880              */

881             topVisibleIndex = 0;
882             bottomVisibleIndex = tabsThatFitInComposite - 1;
883         } else if (getSelectionIndex() + tabsThatFitInComposite > elements.length) {
884             /*
885              * the selected tab is near the bottom.
886              */

887             bottomVisibleIndex = elements.length - 1;
888             topVisibleIndex = bottomVisibleIndex - tabsThatFitInComposite + 1;
889         } else {
890             /*
891              * the selected tab is near the top.
892              */

893             topVisibleIndex = selectedElementIndex;
894             bottomVisibleIndex = selectedElementIndex + tabsThatFitInComposite
895                 - 1;
896         }
897         layoutTabs();
898     }
899
900     /**
901      * Layout the tabs.
902      *
903      * @param up
904      * if <code>true</code>, then we are laying out as a result of
905      * an scroll up request.
906      */

907     private void layoutTabs() {
908         //System.out.println("TabFit " + tabsThatFitInComposite + " length "
909
// + elements.length + " top " + topVisibleIndex + " bottom "
910
// + bottomVisibleIndex);
911
if (tabsThatFitInComposite == NONE || elements.length == 0) {
912             FormData formData = new FormData();
913             formData.left = new FormAttachment(0, 0);
914             formData.right = new FormAttachment(100, 0);
915             formData.top = new FormAttachment(0, 0);
916             formData.height = getTabHeight();
917             topNavigationElement.setLayoutData(formData);
918
919             formData = new FormData();
920             formData.left = new FormAttachment(0, 0);
921             formData.right = new FormAttachment(100, 0);
922             formData.top = new FormAttachment(topNavigationElement, 0);
923             formData.bottom = new FormAttachment(100, 0);
924             bottomNavigationElement.setLayoutData(formData);
925         } else {
926
927             FormData formData = new FormData();
928             formData.left = new FormAttachment(0, 0);
929             formData.right = new FormAttachment(100, 0);
930             formData.top = new FormAttachment(0, 0);
931             formData.height = 10;
932             topNavigationElement.setLayoutData(formData);
933
934             /*
935              * use nextElement to attach the layout to the previous canvas
936              * widget in the list.
937              */

938             Canvas nextElement = topNavigationElement;
939
940             for (int i = 0; i < elements.length; i++) {
941                 //System.out.print(i + " [" + elements[i].getText() + "]");
942
if (i < topVisibleIndex || i > bottomVisibleIndex) {
943                     /*
944                      * this tab is not visible
945                      */

946                     elements[i].setLayoutData(null);
947                     elements[i].setVisible(false);
948                 } else {
949                     /*
950                      * this tab is visible.
951                      */

952                     //System.out.print(" visible");
953
formData = new FormData();
954                     formData.height = getTabHeight();
955                     formData.left = new FormAttachment(0, 0);
956                     formData.right = new FormAttachment(100, 0);
957                     formData.top = new FormAttachment(nextElement, 0);
958                     nextElement = elements[i];
959                     elements[i].setLayoutData(formData);
960                     elements[i].setVisible(true);
961                 }
962
963                 //if (i == selectedElementIndex) {
964
// System.out.print(" selected");
965
//}
966
//System.out.println("");
967
}
968             formData = new FormData();
969             formData.left = new FormAttachment(0, 0);
970             formData.right = new FormAttachment(100, 0);
971             formData.top = new FormAttachment(nextElement, 0);
972             formData.bottom = new FormAttachment(100, 0);
973             formData.height = 10;
974             bottomNavigationElement.setLayoutData(formData);
975         }
976         //System.out.println("");
977

978         // layout so that we have enough space for the new labels
979
Composite grandparent = getParent().getParent();
980         grandparent.layout(true);
981         layout(true);
982     }
983
984     /**
985      * Initialize the accessibility adapter.
986      */

987     private void initAccessible() {
988         final Accessible accessible = getAccessible();
989         accessible.addAccessibleListener(new AccessibleAdapter() {
990
991             public void getName(AccessibleEvent e) {
992                 if (getSelectionIndex() != NONE) {
993                     e.result = elements[getSelectionIndex()].getTabItem()
994                             .getText();
995                 }
996             }
997
998             public void getHelp(AccessibleEvent e) {
999                 if (getSelectionIndex() != NONE) {
1000                    e.result = elements[getSelectionIndex()].getTabItem()
1001                            .getText();
1002                }
1003            }
1004        });
1005
1006        accessible.addAccessibleControlListener(new AccessibleControlAdapter() {
1007
1008            public void getChildAtPoint(AccessibleControlEvent e) {
1009                Point pt = toControl(new Point(e.x, e.y));
1010                e.childID = (getBounds().contains(pt)) ? ACC.CHILDID_SELF
1011                    : ACC.CHILDID_NONE;
1012            }
1013
1014            public void getLocation(AccessibleControlEvent e) {
1015                if (getSelectionIndex() != NONE) {
1016                    Rectangle location = elements[getSelectionIndex()]
1017                        .getBounds();
1018                    Point pt = toDisplay(new Point(location.x, location.y));
1019                    e.x = pt.x;
1020                    e.y = pt.y;
1021                    e.width = location.width;
1022                    e.height = location.height;
1023                }
1024            }
1025
1026            public void getChildCount(AccessibleControlEvent e) {
1027                e.detail = 0;
1028            }
1029
1030            public void getRole(AccessibleControlEvent e) {
1031                e.detail = ACC.ROLE_TABITEM;
1032            }
1033
1034            public void getState(AccessibleControlEvent e) {
1035                e.detail = ACC.STATE_NORMAL | ACC.STATE_SELECTABLE
1036                    | ACC.STATE_SELECTED | ACC.STATE_FOCUSED
1037                    | ACC.STATE_FOCUSABLE;
1038            }
1039        });
1040
1041        addListener(SWT.Selection, new Listener() {
1042
1043            public void handleEvent(Event event) {
1044                if (isFocusControl()) {
1045                    accessible.setFocus(ACC.CHILDID_SELF);
1046                }
1047            }
1048        });
1049
1050        addListener(SWT.FocusIn, new Listener() {
1051
1052            public void handleEvent(Event event) {
1053                accessible.setFocus(ACC.CHILDID_SELF);
1054            }
1055        });
1056    }
1057}
1058
Popular Tags