/* * 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(); } }