blob: 54d21e8f00d349608d68fb589deda27d28981640 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package com.sun.java.swing.plaf.windows;
27
28import java.awt.*;
29
30import javax.swing.plaf.basic.*;
31import javax.swing.plaf.*;
32import javax.swing.*;
33import java.util.Set;
34import java.util.HashSet;
35import java.awt.event.*;
36
37import static com.sun.java.swing.plaf.windows.TMSchema.*;
38import static com.sun.java.swing.plaf.windows.XPStyle.Skin;
39
40
41/**
42 * Windows rendition of the component.
43 * <p>
44 * <strong>Warning:</strong>
45 * Serialized objects of this class will not be compatible with
46 * future Swing releases. The current serialization support is appropriate
47 * for short term storage or RMI between applications running the same
48 * version of Swing. A future release of Swing will provide support for
49 * long term persistence.
50 */
51public class WindowsTabbedPaneUI extends BasicTabbedPaneUI {
52 /**
53 * Keys to use for forward focus traversal when the JComponent is
54 * managing focus.
55 */
56 private static Set managingFocusForwardTraversalKeys;
57
58 /**
59 * Keys to use for backward focus traversal when the JComponent is
60 * managing focus.
61 */
62 private static Set managingFocusBackwardTraversalKeys;
63
64 private boolean contentOpaque = true;
65
66 protected void installDefaults() {
67 super.installDefaults();
68 contentOpaque = UIManager.getBoolean("TabbedPane.contentOpaque");
69
70 // focus forward traversal key
71 if (managingFocusForwardTraversalKeys==null) {
72 managingFocusForwardTraversalKeys = new HashSet();
73 managingFocusForwardTraversalKeys.add(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0));
74 }
75 tabPane.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, managingFocusForwardTraversalKeys);
76 // focus backward traversal key
77 if (managingFocusBackwardTraversalKeys==null) {
78 managingFocusBackwardTraversalKeys = new HashSet();
79 managingFocusBackwardTraversalKeys.add( KeyStroke.getKeyStroke(KeyEvent.VK_TAB, InputEvent.SHIFT_MASK));
80 }
81 tabPane.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, managingFocusBackwardTraversalKeys);
82 }
83
84 protected void uninstallDefaults() {
85 // sets the focus forward and backward traversal keys to null
86 // to restore the defaults
87 tabPane.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, null);
88 tabPane.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, null);
89 super.uninstallDefaults();
90 }
91
92 public static ComponentUI createUI(JComponent c) {
93 return new WindowsTabbedPaneUI();
94 }
95
96 protected void setRolloverTab(int index) {
97 // Rollover is only supported on XP
98 if (XPStyle.getXP() != null) {
99 int oldRolloverTab = getRolloverTab();
100 super.setRolloverTab(index);
101 Rectangle r1 = null;
102 Rectangle r2 = null;
103 if ( (oldRolloverTab >= 0) && (oldRolloverTab < tabPane.getTabCount()) ) {
104 r1 = getTabBounds(tabPane, oldRolloverTab);
105 }
106 if (index >= 0) {
107 r2 = getTabBounds(tabPane, index);
108 }
109 if (r1 != null) {
110 if (r2 != null) {
111 tabPane.repaint(r1.union(r2));
112 } else {
113 tabPane.repaint(r1);
114 }
115 } else if (r2 != null) {
116 tabPane.repaint(r2);
117 }
118 }
119 }
120
121 protected void paintContentBorder(Graphics g, int tabPlacement, int selectedIndex) {
122 XPStyle xp = XPStyle.getXP();
123 if (xp != null && (contentOpaque || tabPane.isOpaque())) {
124 Skin skin = xp.getSkin(tabPane, Part.TABP_PANE);
125 if (skin != null) {
126 Insets insets = tabPane.getInsets();
127 // Note: don't call getTabAreaInsets(), because it causes rotation.
128 // Make sure "TabbedPane.tabsOverlapBorder" is set to true in WindowsLookAndFeel
129 Insets tabAreaInsets = UIManager.getInsets("TabbedPane.tabAreaInsets");
130 int x = insets.left;
131 int y = insets.top;
132 int w = tabPane.getWidth() - insets.right - insets.left;
133 int h = tabPane.getHeight() - insets.top - insets.bottom;
134
135 // Expand area by tabAreaInsets.bottom to allow tabs to overlap onto the border.
136 if (tabPlacement == LEFT || tabPlacement == RIGHT) {
137 int tabWidth = calculateTabAreaWidth(tabPlacement, runCount, maxTabWidth);
138 if (tabPlacement == LEFT) {
139 x += (tabWidth - tabAreaInsets.bottom);
140 }
141 w -= (tabWidth - tabAreaInsets.bottom);
142 } else {
143 int tabHeight = calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight);
144 if (tabPlacement == TOP) {
145 y += (tabHeight - tabAreaInsets.bottom);
146 }
147 h -= (tabHeight - tabAreaInsets.bottom);
148 }
149
150 paintRotatedSkin(g, skin, tabPlacement, x, y, w, h, null);
151 return;
152 }
153 }
154 super.paintContentBorder(g, tabPlacement, selectedIndex);
155 }
156
157 protected void paintTabBackground(Graphics g, int tabPlacement, int tabIndex,
158 int x, int y, int w, int h, boolean isSelected ) {
159 if (XPStyle.getXP() == null) {
160 super.paintTabBackground(g, tabPlacement, tabIndex, x, y, w, h, isSelected);
161 }
162 }
163
164 protected void paintTabBorder(Graphics g, int tabPlacement, int tabIndex,
165 int x, int y, int w, int h, boolean isSelected ) {
166 XPStyle xp = XPStyle.getXP();
167 if (xp != null) {
168 Part part;
169
170 int tabCount = tabPane.getTabCount();
171 int tabRun = getRunForTab(tabCount, tabIndex);
172 if (tabRuns[tabRun] == tabIndex) {
173 part = Part.TABP_TABITEMLEFTEDGE;
174 } else if (tabCount > 1 && lastTabInRun(tabCount, tabRun) == tabIndex) {
175 part = Part.TABP_TABITEMRIGHTEDGE;
176 if (isSelected) {
177 // Align with right edge
178 if (tabPlacement == TOP || tabPlacement == BOTTOM) {
179 w++;
180 } else {
181 h++;
182 }
183 }
184 } else {
185 part = Part.TABP_TABITEM;
186 }
187
188 State state = State.NORMAL;
189 if (isSelected) {
190 state = State.SELECTED;
191 } else if (tabIndex == getRolloverTab()) {
192 state = State.HOT;
193 }
194
195 paintRotatedSkin(g, xp.getSkin(tabPane, part), tabPlacement, x, y, w, h, state);
196 } else {
197 super.paintTabBorder(g, tabPlacement, tabIndex, x, y, w, h, isSelected);
198 }
199 }
200
201 private void paintRotatedSkin(Graphics g, Skin skin, int tabPlacement,
202 int x, int y, int w, int h, State state) {
203 Graphics2D g2d = (Graphics2D)g.create();
204 g2d.translate(x, y);
205 switch (tabPlacement) {
206 case RIGHT: g2d.translate(w, 0);
207 g2d.rotate(Math.toRadians(90.0));
208 skin.paintSkin(g2d, 0, 0, h, w, state);
209 break;
210
211 case LEFT: g2d.scale(-1.0, 1.0);
212 g2d.rotate(Math.toRadians(90.0));
213 skin.paintSkin(g2d, 0, 0, h, w, state);
214 break;
215
216 case BOTTOM: g2d.translate(0, h);
217 g2d.scale(-1.0, 1.0);
218 g2d.rotate(Math.toRadians(180.0));
219 skin.paintSkin(g2d, 0, 0, w, h, state);
220 break;
221
222 case TOP:
223 default: skin.paintSkin(g2d, 0, 0, w, h, state);
224 }
225 g2d.dispose();
226 }
227}