KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > swing > plaf > synth > SynthTabbedPaneUI


1 /*
2  * @(#)SynthTabbedPaneUI.java 1.32 04/04/02
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package javax.swing.plaf.synth;
9
10 import javax.swing.*;
11 import javax.swing.event.*;
12 import javax.swing.plaf.*;
13 import javax.swing.plaf.basic.*;
14 import javax.swing.text.View JavaDoc;
15
16 import java.awt.*;
17 import java.awt.event.*;
18 import java.beans.PropertyChangeListener JavaDoc;
19 import java.beans.PropertyChangeEvent JavaDoc;
20 import java.util.Vector JavaDoc;
21 import java.util.Hashtable JavaDoc;
22 import sun.swing.plaf.synth.SynthUI;
23 import com.sun.java.swing.SwingUtilities2;
24
25 /**
26  * A Synth L&F implementation of TabbedPaneUI.
27  *
28  * @version 1.32, 04/02/04
29  * @author Scott Violet
30  */

31 /**
32  * Looks up 'selectedTabPadInsets' from the Style, which will be additional
33  * insets for the selected tab.
34  */

35 class SynthTabbedPaneUI extends BasicTabbedPaneUI implements SynthUI, PropertyChangeListener JavaDoc {
36     private SynthContext JavaDoc tabAreaContext;
37     private SynthContext JavaDoc tabContext;
38     private SynthContext JavaDoc tabContentContext;
39
40     private SynthStyle JavaDoc style;
41     private SynthStyle JavaDoc tabStyle;
42     private SynthStyle JavaDoc tabAreaStyle;
43     private SynthStyle JavaDoc tabContentStyle;
44     
45     private Rectangle tabAreaBounds = new Rectangle();
46
47     public static ComponentUI createUI(JComponent c) {
48         return new SynthTabbedPaneUI JavaDoc();
49     }
50
51     private boolean scrollableTabLayoutEnabled() {
52     return (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT);
53     }
54
55     protected void installDefaults() {
56         updateStyle(tabPane);
57     }
58
59     private void updateStyle(JTabbedPane c) {
60         SynthContext JavaDoc context = getContext(c, ENABLED);
61         SynthStyle JavaDoc oldStyle = style;
62         style = SynthLookAndFeel.updateStyle(context, this);
63         // Add properties other than JComponent colors, Borders and
64
// opacity settings here:
65
if (style != oldStyle) {
66             tabRunOverlay =
67                 style.getInt(context, "TabbedPane.tabRunOverlay", 0);
68             textIconGap = style.getInt(context, "TabbedPane.textIconGap", 0);
69             selectedTabPadInsets = (Insets)style.get(context,
70                 "TabbedPane.selectedTabPadInsets");
71             if (selectedTabPadInsets == null) {
72                 selectedTabPadInsets = new Insets(0, 0, 0, 0);
73             }
74             if (oldStyle != null) {
75                 uninstallKeyboardActions();
76                 installKeyboardActions();
77             }
78         }
79         context.dispose();
80
81         if (tabContext != null) {
82             tabContext.dispose();
83         }
84         tabContext = getContext(c, Region.TABBED_PANE_TAB, ENABLED);
85         this.tabStyle = SynthLookAndFeel.updateStyle(tabContext, this);
86         tabInsets = tabStyle.getInsets(tabContext, null);
87
88
89         if (tabAreaContext != null) {
90             tabAreaContext.dispose();
91         }
92         tabAreaContext = getContext(c, Region.TABBED_PANE_TAB_AREA, ENABLED);
93         this.tabAreaStyle = SynthLookAndFeel.updateStyle(tabAreaContext, this);
94         tabAreaInsets = tabAreaStyle.getInsets(tabAreaContext, null);
95
96
97         if (tabContentContext != null) {
98             tabContentContext.dispose();
99         }
100         tabContentContext = getContext(c, Region.TABBED_PANE_CONTENT, ENABLED);
101         this.tabContentStyle = SynthLookAndFeel.updateStyle(tabContentContext,
102                                                             this);
103         contentBorderInsets =
104             tabContentStyle.getInsets(tabContentContext, null);
105     }
106
107     protected void installListeners() {
108         super.installListeners();
109         tabPane.addPropertyChangeListener(this);
110     }
111     
112     protected void uninstallListeners() {
113         super.uninstallListeners();
114         tabPane.removePropertyChangeListener(this);
115     }
116
117     protected void uninstallDefaults() {
118         SynthContext JavaDoc context = getContext(tabPane, ENABLED);
119         style.uninstallDefaults(context);
120         context.dispose();
121         style = null;
122
123         tabStyle.uninstallDefaults(tabContext);
124         tabContext.dispose();
125         tabContext = null;
126         tabStyle = null;
127
128         tabAreaStyle.uninstallDefaults(tabAreaContext);
129         tabAreaContext.dispose();
130         tabAreaContext = null;
131         tabAreaStyle = null;
132
133         tabContentStyle.uninstallDefaults(tabContentContext);
134         tabContentContext.dispose();
135         tabContentContext = null;
136         tabContentStyle = null;
137     }
138
139     public SynthContext JavaDoc getContext(JComponent c) {
140         return getContext(c, getComponentState(c));
141     }
142
143     public SynthContext JavaDoc getContext(JComponent c, int state) {
144         return SynthContext.getContext(SynthContext JavaDoc.class, c,
145                     SynthLookAndFeel.getRegion(c),style, state);
146     }
147
148     public SynthContext JavaDoc getContext(JComponent c, Region JavaDoc subregion) {
149         return getContext(c, subregion, getComponentState(c));
150     }
151
152     private SynthContext JavaDoc getContext(JComponent c, Region JavaDoc subregion, int state){
153         SynthStyle JavaDoc style = null;
154         Class JavaDoc klass = SynthContext JavaDoc.class;
155
156         if (subregion == Region.TABBED_PANE_TAB) {
157             style = tabStyle;
158         }
159         else if (subregion == Region.TABBED_PANE_TAB_AREA) {
160             style = tabAreaStyle;
161         }
162         else if (subregion == Region.TABBED_PANE_CONTENT) {
163             style = tabContentStyle;
164         }
165         return SynthContext.getContext(klass, c, subregion, style, state);
166     }
167
168     private Region JavaDoc getRegion(JComponent c) {
169         return SynthLookAndFeel.getRegion(c);
170     }
171
172     private int getComponentState(JComponent c) {
173         return SynthLookAndFeel.getComponentState(c);
174     }
175
176     protected JButton createScrollButton(int direction) {
177         return new SynthScrollableTabButton(direction);
178     }
179
180     public void propertyChange(PropertyChangeEvent JavaDoc e) {
181         if (SynthLookAndFeel.shouldUpdateStyle(e)) {
182             updateStyle(tabPane);
183         }
184     }
185
186     public void update(Graphics g, JComponent c) {
187         SynthContext JavaDoc context = getContext(c);
188
189         SynthLookAndFeel.update(context, g);
190         context.getPainter().paintTabbedPaneBackground(context,
191                           g, 0, 0, c.getWidth(), c.getHeight());
192         paint(context, g);
193         context.dispose();
194     }
195
196     public void paintBorder(SynthContext JavaDoc context, Graphics g, int x,
197                             int y, int w, int h) {
198         context.getPainter().paintTabbedPaneBorder(context, g, x, y, w, h);
199     }
200
201     public void paint(Graphics g, JComponent c) {
202         SynthContext JavaDoc context = getContext(c);
203
204         paint(context, g);
205         context.dispose();
206     }
207
208     protected void paint(SynthContext JavaDoc context, Graphics g) {
209         int selectedIndex = tabPane.getSelectedIndex();
210         int tabPlacement = tabPane.getTabPlacement();
211
212         ensureCurrentLayout();
213
214     // Paint tab area
215
// If scrollable tabs are enabled, the tab area will be
216
// painted by the scrollable tab panel instead.
217
//
218
if (!scrollableTabLayoutEnabled()) { // WRAP_TAB_LAYOUT
219
Insets insets = tabPane.getInsets();
220             int x = insets.left;
221             int y = insets.top;
222             int width = tabPane.getWidth() - insets.left - insets.right;
223             int height = tabPane.getHeight() - insets.top - insets.bottom;
224             int size;
225             switch(tabPlacement) {
226             case LEFT:
227                 width = calculateTabAreaWidth(tabPlacement, runCount,
228                                               maxTabWidth);
229                 break;
230             case RIGHT:
231                 size = calculateTabAreaWidth(tabPlacement, runCount,
232                                              maxTabWidth);
233                 x = x + width - size;
234                 width = size;
235                 break;
236             case BOTTOM:
237                 size = calculateTabAreaHeight(tabPlacement, runCount,
238                                               maxTabHeight);
239                 y = y + height - size;
240                 height = size;
241                 break;
242             case TOP:
243             default:
244                 height = calculateTabAreaHeight(tabPlacement, runCount,
245                                                 maxTabHeight);
246             }
247             
248             tabAreaBounds.setBounds(x, y, width, height);
249             
250             if (g.getClipBounds().intersects(tabAreaBounds)) {
251                 paintTabArea(tabAreaContext, g, tabPlacement,
252                          selectedIndex, tabAreaBounds);
253             }
254     }
255     
256         // Paint content border
257
paintContentBorder(tabContentContext, g, tabPlacement, selectedIndex);
258     }
259
260
261     protected void paintTabArea(Graphics g, int tabPlacement,
262                                 int selectedIndex) {
263         // This can be invoked from ScrollabeTabPanel
264
Insets insets = tabPane.getInsets();
265         int x = insets.left;
266         int y = insets.top;
267         int width = tabPane.getWidth() - insets.left - insets.right;
268         int height = tabPane.getHeight() - insets.top - insets.bottom;
269
270         paintTabArea(tabAreaContext, g, tabPlacement, selectedIndex,
271                      new Rectangle(x, y, width, height));
272     }
273
274     protected void paintTabArea(SynthContext JavaDoc ss, Graphics g,
275                                 int tabPlacement, int selectedIndex,
276                                 Rectangle tabAreaBounds) {
277         Rectangle clipRect = g.getClipBounds();
278
279         // Paint the tab area.
280
SynthLookAndFeel.updateSubregion(ss, g, tabAreaBounds);
281         ss.getPainter().paintTabbedPaneTabAreaBackground(ss, g,
282              tabAreaBounds.x, tabAreaBounds.y, tabAreaBounds.width,
283              tabAreaBounds.height);
284         ss.getPainter().paintTabbedPaneTabAreaBorder(ss, g, tabAreaBounds.x,
285              tabAreaBounds.y, tabAreaBounds.width, tabAreaBounds.height);
286
287         int tabCount = tabPane.getTabCount();
288
289         Rectangle iconRect = new Rectangle(),
290                   textRect = new Rectangle();
291
292         // Paint tabRuns of tabs from back to front
293
for (int i = runCount - 1; i >= 0; i--) {
294             int start = tabRuns[i];
295             int next = tabRuns[(i == runCount - 1)? 0 : i + 1];
296             int end = (next != 0? next - 1: tabCount - 1);
297             for (int j = start; j <= end; j++) {
298                 if (rects[j].intersects(clipRect) && selectedIndex != j) {
299                     paintTab(tabContext, g, tabPlacement, rects, j, iconRect,
300                              textRect);
301                 }
302             }
303         }
304
305         if (selectedIndex >= 0) {
306             if (rects[selectedIndex].intersects(clipRect)) {
307                 paintTab(tabContext, g, tabPlacement, rects, selectedIndex,
308                          iconRect, textRect);
309             }
310         }
311     }
312
313     protected void paintTab(SynthContext JavaDoc ss, Graphics g,
314                             int tabPlacement, Rectangle[] rects, int tabIndex,
315                             Rectangle iconRect, Rectangle textRect) {
316         Rectangle tabRect = rects[tabIndex];
317         int selectedIndex = tabPane.getSelectedIndex();
318         boolean isSelected = selectedIndex == tabIndex;
319         updateTabContext(tabIndex, isSelected, false,
320                           (getFocusIndex() == tabIndex));
321
322         SynthLookAndFeel.updateSubregion(ss, g, tabRect);
323         tabContext.getPainter().paintTabbedPaneTabBackground(tabContext,
324                                 g, tabRect.x, tabRect.y, tabRect.width,
325                                 tabRect.height, tabIndex);
326         tabContext.getPainter().paintTabbedPaneTabBorder(tabContext, g,
327                    tabRect.x, tabRect.y, tabRect.width, tabRect.height,
328                    tabIndex);
329         
330         String JavaDoc title = tabPane.getTitleAt(tabIndex);
331         Font font = ss.getStyle().getFont(ss);
332         FontMetrics metrics = SwingUtilities2.getFontMetrics(tabPane, g, font);
333         Icon icon = getIconForTab(tabIndex);
334
335         layoutLabel(ss, tabPlacement, metrics, tabIndex, title, icon,
336                     tabRect, iconRect, textRect, isSelected);
337
338         paintText(ss, g, tabPlacement, font, metrics,
339                   tabIndex, title, textRect, isSelected);
340
341         paintIcon(g, tabPlacement, tabIndex, icon, iconRect, isSelected);
342     }
343
344     protected void layoutLabel(SynthContext JavaDoc ss, int tabPlacement,
345                                FontMetrics metrics, int tabIndex,
346                                String JavaDoc title, Icon icon,
347                                Rectangle tabRect, Rectangle iconRect,
348                                Rectangle textRect, boolean isSelected ) {
349     View JavaDoc v = getTextViewForTab(tabIndex);
350     if (v != null) {
351         tabPane.putClientProperty("html", v);
352     }
353
354         textRect.x = textRect.y = iconRect.x = iconRect.y = 0;
355
356         ss.getStyle().getGraphicsUtils(ss).layoutText(ss, metrics, title,
357                          icon, SwingUtilities.CENTER, SwingUtilities.CENTER,
358                          SwingUtilities.LEADING, SwingUtilities.TRAILING,
359                          tabRect, iconRect, textRect, textIconGap);
360
361     tabPane.putClientProperty("html", null);
362
363         int xNudge = getTabLabelShiftX(tabPlacement, tabIndex, isSelected);
364         int yNudge = getTabLabelShiftY(tabPlacement, tabIndex, isSelected);
365         iconRect.x += xNudge;
366         iconRect.y += yNudge;
367         textRect.x += xNudge;
368         textRect.y += yNudge;
369     }
370
371     protected void paintText(SynthContext JavaDoc ss,
372                              Graphics g, int tabPlacement,
373                              Font font, FontMetrics metrics, int tabIndex,
374                              String JavaDoc title, Rectangle textRect,
375                              boolean isSelected) {
376         g.setFont(font);
377
378     View JavaDoc v = getTextViewForTab(tabIndex);
379     if (v != null) {
380         // html
381
v.paint(g, textRect);
382     } else {
383         // plain text
384
int mnemIndex = tabPane.getDisplayedMnemonicIndexAt(tabIndex);
385
386             g.setColor(ss.getStyle().getColor(ss, ColorType.TEXT_FOREGROUND));
387             ss.getStyle().getGraphicsUtils(ss).paintText(ss, g, title,
388                                   textRect, mnemIndex);
389     }
390     }
391
392
393     protected void paintContentBorder(SynthContext JavaDoc ss, Graphics g,
394                                       int tabPlacement, int selectedIndex) {
395         int width = tabPane.getWidth();
396         int height = tabPane.getHeight();
397         Insets insets = tabPane.getInsets();
398
399         int x = insets.left;
400         int y = insets.top;
401         int w = width - insets.right - insets.left;
402         int h = height - insets.top - insets.bottom;
403
404         switch(tabPlacement) {
405           case LEFT:
406               x += calculateTabAreaWidth(tabPlacement, runCount, maxTabWidth);
407               w -= (x - insets.left);
408               break;
409           case RIGHT:
410               w -= calculateTabAreaWidth(tabPlacement, runCount, maxTabWidth);
411               break;
412           case BOTTOM:
413               h -= calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight);
414               break;
415           case TOP:
416           default:
417               y += calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight);
418               h -= (y - insets.top);
419         }
420         SynthLookAndFeel.updateSubregion(ss, g, new Rectangle(x, y, w, h));
421         ss.getPainter().paintTabbedPaneContentBackground(ss, g, x, y,
422                                                            w, h);
423         ss.getPainter().paintTabbedPaneContentBorder(ss, g, x, y, w, h);
424     }
425          
426     private void ensureCurrentLayout() {
427         if (!tabPane.isValid()) {
428             tabPane.validate();
429         }
430     /* If tabPane doesn't have a peer yet, the validate() call will
431      * silently fail. We handle that by forcing a layout if tabPane
432      * is still invalid. See bug 4237677.
433      */

434         if (!tabPane.isValid()) {
435             TabbedPaneLayout layout = (TabbedPaneLayout)tabPane.getLayout();
436             layout.calculateLayoutInfo();
437         }
438     }
439     
440
441     protected int calculateMaxTabHeight(int tabPlacement) {
442         FontMetrics metrics = getFontMetrics(tabContext.getStyle().getFont(
443                                              tabContext));
444         int tabCount = tabPane.getTabCount();
445         int result = 0;
446         int fontHeight = metrics.getHeight();
447         for(int i = 0; i < tabCount; i++) {
448             result = Math.max(calculateTabHeight(tabPlacement, i, fontHeight), result);
449         }
450         return result;
451     }
452
453     protected int calculateTabWidth(int tabPlacement, int tabIndex,
454                                     FontMetrics metrics) {
455         Icon icon = getIconForTab(tabIndex);
456         Insets tabInsets = getTabInsets(tabPlacement, tabIndex);
457         int width = tabInsets.left + tabInsets.right + 3;
458
459         if (icon != null) {
460             width += icon.getIconWidth() + textIconGap;
461         }
462     View JavaDoc v = getTextViewForTab(tabIndex);
463     if (v != null) {
464         // html
465
width += (int)v.getPreferredSpan(View.X_AXIS);
466     } else {
467         // plain text
468
String JavaDoc title = tabPane.getTitleAt(tabIndex);
469             width += tabContext.getStyle().getGraphicsUtils(tabContext).
470                         computeStringWidth(tabContext, metrics.getFont(),
471                         metrics, title);
472     }
473     
474         return width;
475     }
476
477     protected int calculateMaxTabWidth(int tabPlacement) {
478         FontMetrics metrics = getFontMetrics(tabContext.getStyle().getFont(
479                                      tabContext));
480         int tabCount = tabPane.getTabCount();
481         int result = 0;
482         for(int i = 0; i < tabCount; i++) {
483             result = Math.max(calculateTabWidth(tabPlacement, i, metrics),
484                               result);
485         }
486         return result;
487     }
488
489     protected Insets getTabInsets(int tabPlacement, int tabIndex) {
490         updateTabContext(tabIndex, false, false,
491                           (getFocusIndex() == tabIndex));
492         return tabInsets;
493     }
494
495     protected FontMetrics getFontMetrics() {
496         return getFontMetrics(tabContext.getStyle().getFont(tabContext));
497     }
498
499     protected FontMetrics getFontMetrics(Font font) {
500         return tabPane.getFontMetrics(font);
501     }
502
503     private void updateTabContext(int index, boolean selected,
504                                   boolean isMouseOver, boolean hasFocus) {
505         int state = 0;
506         if (!tabPane.isEnabledAt(index)) {
507         state |= SynthConstants.DISABLED;
508         }
509         else if (selected) {
510             state |= (SynthConstants.ENABLED | SynthConstants.SELECTED);
511         }
512         else if (isMouseOver) {
513             state |= (SynthConstants.ENABLED | SynthConstants.MOUSE_OVER);
514         }
515         else {
516             state = SynthLookAndFeel.getComponentState(tabPane);
517         state &= ~SynthConstants.FOCUSED; // don't use tabbedpane focus state
518
}
519     if (hasFocus && tabPane.hasFocus()) {
520         state |= SynthConstants.FOCUSED; // individual tab has focus
521
}
522     tabContext.setComponentState(state);
523     }
524
525     private class SynthScrollableTabButton extends SynthArrowButton JavaDoc implements
526             UIResource {
527         public SynthScrollableTabButton(int direction) {
528             super(direction);
529         }
530     }
531 }
532
Popular Tags