blob: 30f348d97707c6fbf2c074a15ed8cee695478e11 [file] [log] [blame]
/*
* Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.java.swing.plaf.windows;
import java.awt.*;
import javax.swing.plaf.basic.*;
import javax.swing.plaf.*;
import javax.swing.*;
import java.util.Set;
import java.util.HashSet;
import java.awt.event.*;
import static com.sun.java.swing.plaf.windows.TMSchema.*;
import static com.sun.java.swing.plaf.windows.XPStyle.Skin;
/**
* Windows rendition of the component.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is appropriate
* for short term storage or RMI between applications running the same
* version of Swing. A future release of Swing will provide support for
* long term persistence.
*/
public class WindowsTabbedPaneUI extends BasicTabbedPaneUI {
/**
* Keys to use for forward focus traversal when the JComponent is
* managing focus.
*/
private static Set<KeyStroke> managingFocusForwardTraversalKeys;
/**
* Keys to use for backward focus traversal when the JComponent is
* managing focus.
*/
private static Set<KeyStroke> managingFocusBackwardTraversalKeys;
private boolean contentOpaque = true;
protected void installDefaults() {
super.installDefaults();
contentOpaque = UIManager.getBoolean("TabbedPane.contentOpaque");
// focus forward traversal key
if (managingFocusForwardTraversalKeys==null) {
managingFocusForwardTraversalKeys = new HashSet<KeyStroke>();
managingFocusForwardTraversalKeys.add(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0));
}
tabPane.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, managingFocusForwardTraversalKeys);
// focus backward traversal key
if (managingFocusBackwardTraversalKeys==null) {
managingFocusBackwardTraversalKeys = new HashSet<KeyStroke>();
managingFocusBackwardTraversalKeys.add( KeyStroke.getKeyStroke(KeyEvent.VK_TAB, InputEvent.SHIFT_MASK));
}
tabPane.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, managingFocusBackwardTraversalKeys);
}
protected void uninstallDefaults() {
// sets the focus forward and backward traversal keys to null
// to restore the defaults
tabPane.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, null);
tabPane.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, null);
super.uninstallDefaults();
}
public static ComponentUI createUI(JComponent c) {
return new WindowsTabbedPaneUI();
}
protected void setRolloverTab(int index) {
// Rollover is only supported on XP
if (XPStyle.getXP() != null) {
int oldRolloverTab = getRolloverTab();
super.setRolloverTab(index);
Rectangle r1 = null;
Rectangle r2 = null;
if ( (oldRolloverTab >= 0) && (oldRolloverTab < tabPane.getTabCount()) ) {
r1 = getTabBounds(tabPane, oldRolloverTab);
}
if (index >= 0) {
r2 = getTabBounds(tabPane, index);
}
if (r1 != null) {
if (r2 != null) {
tabPane.repaint(r1.union(r2));
} else {
tabPane.repaint(r1);
}
} else if (r2 != null) {
tabPane.repaint(r2);
}
}
}
protected void paintContentBorder(Graphics g, int tabPlacement, int selectedIndex) {
XPStyle xp = XPStyle.getXP();
if (xp != null && (contentOpaque || tabPane.isOpaque())) {
Skin skin = xp.getSkin(tabPane, Part.TABP_PANE);
if (skin != null) {
Insets insets = tabPane.getInsets();
// Note: don't call getTabAreaInsets(), because it causes rotation.
// Make sure "TabbedPane.tabsOverlapBorder" is set to true in WindowsLookAndFeel
Insets tabAreaInsets = UIManager.getInsets("TabbedPane.tabAreaInsets");
int x = insets.left;
int y = insets.top;
int w = tabPane.getWidth() - insets.right - insets.left;
int h = tabPane.getHeight() - insets.top - insets.bottom;
// Expand area by tabAreaInsets.bottom to allow tabs to overlap onto the border.
if (tabPlacement == LEFT || tabPlacement == RIGHT) {
int tabWidth = calculateTabAreaWidth(tabPlacement, runCount, maxTabWidth);
if (tabPlacement == LEFT) {
x += (tabWidth - tabAreaInsets.bottom);
}
w -= (tabWidth - tabAreaInsets.bottom);
} else {
int tabHeight = calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight);
if (tabPlacement == TOP) {
y += (tabHeight - tabAreaInsets.bottom);
}
h -= (tabHeight - tabAreaInsets.bottom);
}
paintRotatedSkin(g, skin, tabPlacement, x, y, w, h, null);
return;
}
}
super.paintContentBorder(g, tabPlacement, selectedIndex);
}
protected void paintTabBackground(Graphics g, int tabPlacement, int tabIndex,
int x, int y, int w, int h, boolean isSelected ) {
if (XPStyle.getXP() == null) {
super.paintTabBackground(g, tabPlacement, tabIndex, x, y, w, h, isSelected);
}
}
protected void paintTabBorder(Graphics g, int tabPlacement, int tabIndex,
int x, int y, int w, int h, boolean isSelected ) {
XPStyle xp = XPStyle.getXP();
if (xp != null) {
Part part;
int tabCount = tabPane.getTabCount();
int tabRun = getRunForTab(tabCount, tabIndex);
if (tabRuns[tabRun] == tabIndex) {
part = Part.TABP_TABITEMLEFTEDGE;
} else if (tabCount > 1 && lastTabInRun(tabCount, tabRun) == tabIndex) {
part = Part.TABP_TABITEMRIGHTEDGE;
if (isSelected) {
// Align with right edge
if (tabPlacement == TOP || tabPlacement == BOTTOM) {
w++;
} else {
h++;
}
}
} else {
part = Part.TABP_TABITEM;
}
State state = State.NORMAL;
if (isSelected) {
state = State.SELECTED;
} else if (tabIndex == getRolloverTab()) {
state = State.HOT;
}
paintRotatedSkin(g, xp.getSkin(tabPane, part), tabPlacement, x, y, w, h, state);
} else {
super.paintTabBorder(g, tabPlacement, tabIndex, x, y, w, h, isSelected);
}
}
private void paintRotatedSkin(Graphics g, Skin skin, int tabPlacement,
int x, int y, int w, int h, State state) {
Graphics2D g2d = (Graphics2D)g.create();
g2d.translate(x, y);
switch (tabPlacement) {
case RIGHT: g2d.translate(w, 0);
g2d.rotate(Math.toRadians(90.0));
skin.paintSkin(g2d, 0, 0, h, w, state);
break;
case LEFT: g2d.scale(-1.0, 1.0);
g2d.rotate(Math.toRadians(90.0));
skin.paintSkin(g2d, 0, 0, h, w, state);
break;
case BOTTOM: g2d.translate(0, h);
g2d.scale(-1.0, 1.0);
g2d.rotate(Math.toRadians(180.0));
skin.paintSkin(g2d, 0, 0, w, h, state);
break;
case TOP:
default: skin.paintSkin(g2d, 0, 0, w, h, state);
}
g2d.dispose();
}
}