4632N/A/*
4632N/A * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
4632N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4632N/A *
4632N/A * This code is free software; you can redistribute it and/or modify it
4632N/A * under the terms of the GNU General Public License version 2 only, as
4632N/A * published by the Free Software Foundation. Oracle designates this
4632N/A * particular file as subject to the "Classpath" exception as provided
4632N/A * by Oracle in the LICENSE file that accompanied this code.
4632N/A *
4632N/A * This code is distributed in the hope that it will be useful, but WITHOUT
4632N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
4632N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
4632N/A * version 2 for more details (a copy is included in the LICENSE file that
4632N/A * accompanied this code).
4632N/A *
4632N/A * You should have received a copy of the GNU General Public License version
4632N/A * 2 along with this work; if not, write to the Free Software Foundation,
4632N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
4632N/A *
4632N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
4632N/A * or visit www.oracle.com if you need additional information or have any
4632N/A * questions.
4632N/A */
4632N/A
4632N/A/*
4632N/A * Copy of javax.swing.plaf.basic.BasicTabbedPaneUI because the original
4632N/A * does not have enough private methods marked as protected.
4632N/A *
4632N/A * This copy is from 1.6.0_04 as of 2008-02-02.
4632N/A */
4632N/A
4632N/Apackage com.apple.laf;
4632N/A
4632N/Aimport java.awt.*;
4632N/Aimport java.awt.event.*;
4632N/Aimport java.beans.*;
4632N/Aimport java.lang.reflect.InvocationTargetException;
4632N/Aimport java.util.*;
4632N/A
4632N/Aimport javax.swing.*;
4632N/Aimport javax.swing.event.*;
4632N/Aimport javax.swing.plaf.*;
4632N/Aimport javax.swing.plaf.basic.*;
4632N/Aimport javax.swing.text.View;
4632N/A
4632N/Aimport sun.swing.*;
4632N/A
4632N/Apublic class AquaTabbedPaneCopyFromBasicUI extends TabbedPaneUI implements SwingConstants {
4632N/A// Instance variables initialized at installation
4632N/A
4632N/A protected JTabbedPane tabPane;
4632N/A
4632N/A protected Color highlight;
4632N/A protected Color lightHighlight;
4632N/A protected Color shadow;
4632N/A protected Color darkShadow;
4632N/A protected Color focus;
4632N/A private Color selectedColor;
4632N/A
4632N/A protected int textIconGap;
4632N/A
4632N/A protected int tabRunOverlay;
4632N/A
4632N/A protected Insets tabInsets;
4632N/A protected Insets selectedTabPadInsets;
4632N/A protected Insets tabAreaInsets;
4632N/A protected Insets contentBorderInsets;
4632N/A private boolean tabsOverlapBorder;
4632N/A private boolean tabsOpaque = true;
4632N/A private boolean contentOpaque = true;
4632N/A
4632N/A /**
4632N/A * As of Java 2 platform v1.3 this previously undocumented field is no
4632N/A * longer used.
4632N/A * Key bindings are now defined by the LookAndFeel, please refer to
4632N/A * the key bindings specification for further details.
4632N/A *
4632N/A * @deprecated As of Java 2 platform v1.3.
4632N/A */
4632N/A @Deprecated
4632N/A protected KeyStroke upKey;
4632N/A /**
4632N/A * As of Java 2 platform v1.3 this previously undocumented field is no
4632N/A * longer used.
4632N/A * Key bindings are now defined by the LookAndFeel, please refer to
4632N/A * the key bindings specification for further details.
4632N/A *
4632N/A * @deprecated As of Java 2 platform v1.3.
4632N/A */
4632N/A @Deprecated
4632N/A protected KeyStroke downKey;
4632N/A /**
4632N/A * As of Java 2 platform v1.3 this previously undocumented field is no
4632N/A * longer used.
4632N/A * Key bindings are now defined by the LookAndFeel, please refer to
4632N/A * the key bindings specification for further details.
4632N/A *
4632N/A * @deprecated As of Java 2 platform v1.3.
4632N/A */
4632N/A @Deprecated
4632N/A protected KeyStroke leftKey;
4632N/A /**
4632N/A * As of Java 2 platform v1.3 this previously undocumented field is no
4632N/A * longer used.
4632N/A * Key bindings are now defined by the LookAndFeel, please refer to
4632N/A * the key bindings specification for further details.
4632N/A *
4632N/A * @deprecated As of Java 2 platform v1.3.
4632N/A */
4632N/A @Deprecated
4632N/A protected KeyStroke rightKey;
4632N/A
4632N/A// Transient variables (recalculated each time TabbedPane is layed out)
4632N/A
4632N/A protected int tabRuns[] = new int[10];
4632N/A protected int runCount = 0;
4632N/A protected int selectedRun = -1;
4632N/A protected Rectangle rects[] = new Rectangle[0];
4632N/A protected int maxTabHeight;
4632N/A protected int maxTabWidth;
4632N/A
4632N/A// Listeners
4632N/A
4632N/A protected ChangeListener tabChangeListener;
4632N/A protected PropertyChangeListener propertyChangeListener;
4632N/A protected MouseListener mouseListener;
4632N/A protected FocusListener focusListener;
4632N/A
4632N/A// Private instance data
4632N/A
4632N/A private final Insets currentPadInsets = new Insets(0, 0, 0, 0);
4632N/A private final Insets currentTabAreaInsets = new Insets(0, 0, 0, 0);
4632N/A
4632N/A private Component visibleComponent;
4632N/A // PENDING(api): See comment for ContainerHandler
4632N/A private Vector<View> htmlViews;
4632N/A
4632N/A private Hashtable<Integer, Integer> mnemonicToIndexMap;
4632N/A
4632N/A /**
4632N/A * InputMap used for mnemonics. Only non-null if the JTabbedPane has
4632N/A * mnemonics associated with it. Lazily created in initMnemonics.
4632N/A */
4632N/A private InputMap mnemonicInputMap;
4632N/A
4632N/A // For use when tabLayoutPolicy = SCROLL_TAB_LAYOUT
4632N/A private ScrollableTabSupport tabScroller;
4632N/A
4632N/A private TabContainer tabContainer;
4632N/A
4632N/A /**
4632N/A * A rectangle used for general layout calculations in order
4632N/A * to avoid constructing many new Rectangles on the fly.
4632N/A */
4632N/A protected transient Rectangle calcRect = new Rectangle(0, 0, 0, 0);
4632N/A
4632N/A /**
4632N/A * Tab that has focus.
4632N/A */
4632N/A private int focusIndex;
4632N/A
4632N/A /**
4632N/A * Combined listeners.
4632N/A */
4632N/A private Handler handler;
4632N/A
4632N/A /**
4632N/A * Index of the tab the mouse is over.
4632N/A */
4632N/A private int rolloverTabIndex;
4632N/A
4632N/A /**
4632N/A * This is set to true when a component is added/removed from the tab
4632N/A * pane and set to false when layout happens. If true it indicates that
4632N/A * tabRuns is not valid and shouldn't be used.
4632N/A */
4632N/A private boolean isRunsDirty;
4632N/A
4632N/A private boolean calculatedBaseline;
4632N/A private int baseline;
4632N/A
4632N/A// UI creation
4632N/A
4632N/A public static ComponentUI createUI(final JComponent c) {
4632N/A return new AquaTabbedPaneCopyFromBasicUI();
4632N/A }
4632N/A
4632N/A // MACOSX adding accessor for superclass
4632N/A protected Component getTabComponentAt(final int i) {
4632N/A return tabPane.getTabComponentAt(i);
4632N/A }
4632N/A // END MACOSX
4632N/A
4632N/A static void loadActionMap(final LazyActionMap map) {
4632N/A map.put(new Actions(Actions.NEXT));
4632N/A map.put(new Actions(Actions.PREVIOUS));
4632N/A map.put(new Actions(Actions.RIGHT));
4632N/A map.put(new Actions(Actions.LEFT));
4632N/A map.put(new Actions(Actions.UP));
4632N/A map.put(new Actions(Actions.DOWN));
4632N/A map.put(new Actions(Actions.PAGE_UP));
4632N/A map.put(new Actions(Actions.PAGE_DOWN));
4632N/A map.put(new Actions(Actions.REQUEST_FOCUS));
4632N/A map.put(new Actions(Actions.REQUEST_FOCUS_FOR_VISIBLE));
4632N/A map.put(new Actions(Actions.SET_SELECTED));
4632N/A map.put(new Actions(Actions.SELECT_FOCUSED));
4632N/A map.put(new Actions(Actions.SCROLL_FORWARD));
4632N/A map.put(new Actions(Actions.SCROLL_BACKWARD));
4632N/A }
4632N/A
4632N/A// UI Installation/De-installation
4632N/A
4632N/A public void installUI(final JComponent c) {
4632N/A this.tabPane = (JTabbedPane)c;
4632N/A
4632N/A calculatedBaseline = false;
4632N/A rolloverTabIndex = -1;
4632N/A focusIndex = -1;
4632N/A c.setLayout(createLayoutManager());
4632N/A installComponents();
4632N/A installDefaults();
4632N/A installListeners();
4632N/A installKeyboardActions();
4632N/A }
4632N/A
4632N/A public void uninstallUI(final JComponent c) {
4632N/A uninstallKeyboardActions();
4632N/A uninstallListeners();
4632N/A uninstallDefaults();
4632N/A uninstallComponents();
4632N/A c.setLayout(null);
4632N/A
4632N/A this.tabPane = null;
4632N/A }
4632N/A
4632N/A /**
4632N/A * Invoked by <code>installUI</code> to create
4632N/A * a layout manager object to manage
4632N/A * the <code>JTabbedPane</code>.
4632N/A *
4632N/A * @return a layout manager object
4632N/A *
4632N/A * @see TabbedPaneLayout
4632N/A * @see javax.swing.JTabbedPane#getTabLayoutPolicy
4632N/A */
4632N/A protected LayoutManager createLayoutManager() {
4632N/A if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT) {
4632N/A return new TabbedPaneScrollLayout();
4632N/A } else { /* WRAP_TAB_LAYOUT */
4632N/A return new TabbedPaneLayout();
4632N/A }
4632N/A }
4632N/A
4632N/A /* In an attempt to preserve backward compatibility for programs
4632N/A * which have extended BasicTabbedPaneUI to do their own layout, the
4632N/A * UI uses the installed layoutManager (and not tabLayoutPolicy) to
4632N/A * determine if scrollTabLayout is enabled.
4632N/A */
4632N/A boolean scrollableTabLayoutEnabled() {
4632N/A return (tabPane.getLayout() instanceof TabbedPaneScrollLayout);
4632N/A }
4632N/A
4632N/A /**
4632N/A * Creates and installs any required subcomponents for the JTabbedPane.
4632N/A * Invoked by installUI.
4632N/A *
4632N/A * @since 1.4
4632N/A */
4632N/A protected void installComponents() {
4632N/A if (scrollableTabLayoutEnabled()) {
4632N/A if (tabScroller == null) {
4632N/A tabScroller = new ScrollableTabSupport(tabPane.getTabPlacement());
4632N/A tabPane.add(tabScroller.viewport);
4632N/A }
4632N/A }
4632N/A installTabContainer();
4632N/A }
4632N/A
4632N/A private void installTabContainer() {
4632N/A for (int i = 0; i < tabPane.getTabCount(); i++) {
4632N/A final Component tabComponent = tabPane.getTabComponentAt(i);
4632N/A if (tabComponent != null) {
4632N/A if (tabContainer == null) {
4632N/A tabContainer = new TabContainer();
4632N/A }
4632N/A tabContainer.add(tabComponent);
4632N/A }
4632N/A }
4632N/A if (tabContainer == null) {
4632N/A return;
4632N/A }
4632N/A if (scrollableTabLayoutEnabled()) {
4632N/A tabScroller.tabPanel.add(tabContainer);
4632N/A } else {
4632N/A tabPane.add(tabContainer);
4632N/A }
4632N/A }
4632N/A
4632N/A /**
4632N/A * Creates and returns a JButton that will provide the user
4632N/A * with a way to scroll the tabs in a particular direction. The
4632N/A * returned JButton must be instance of UIResource.
4632N/A *
4632N/A * @param direction One of the SwingConstants constants:
4632N/A * SOUTH, NORTH, EAST or WEST
4632N/A * @return Widget for user to
4632N/A * @see javax.swing.JTabbedPane#setTabPlacement
4632N/A * @see javax.swing.SwingConstants
4632N/A * @throws IllegalArgumentException if direction is not one of
4632N/A * NORTH, SOUTH, EAST or WEST
4632N/A * @since 1.5
4632N/A */
4632N/A protected JButton createScrollButton(final int direction) {
4632N/A if (direction != SOUTH && direction != NORTH && direction != EAST && direction != WEST) {
4632N/A throw new IllegalArgumentException("Direction must be one of: " + "SOUTH, NORTH, EAST or WEST");
4632N/A }
4632N/A return new ScrollableTabButton(direction);
4632N/A }
4632N/A
4632N/A /**
4632N/A * Removes any installed subcomponents from the JTabbedPane.
4632N/A * Invoked by uninstallUI.
4632N/A *
4632N/A * @since 1.4
4632N/A */
4632N/A protected void uninstallComponents() {
4632N/A uninstallTabContainer();
4632N/A if (scrollableTabLayoutEnabled()) {
4632N/A tabPane.remove(tabScroller.viewport);
4632N/A tabPane.remove(tabScroller.scrollForwardButton);
4632N/A tabPane.remove(tabScroller.scrollBackwardButton);
4632N/A tabScroller = null;
4632N/A }
4632N/A }
4632N/A
4632N/A private void uninstallTabContainer() {
4632N/A if (tabContainer == null) {
4632N/A return;
4632N/A }
4632N/A // Remove all the tabComponents, making sure not to notify
4632N/A // the tabbedpane.
4632N/A tabContainer.notifyTabbedPane = false;
4632N/A tabContainer.removeAll();
4632N/A if (scrollableTabLayoutEnabled()) {
4632N/A tabContainer.remove(tabScroller.croppedEdge);
4632N/A tabScroller.tabPanel.remove(tabContainer);
4632N/A } else {
4632N/A tabPane.remove(tabContainer);
4632N/A }
4632N/A tabContainer = null;
4632N/A }
4632N/A
4632N/A protected void installDefaults() {
4632N/A LookAndFeel.installColorsAndFont(tabPane, "TabbedPane.background", "TabbedPane.foreground", "TabbedPane.font");
4632N/A highlight = UIManager.getColor("TabbedPane.light");
4632N/A lightHighlight = UIManager.getColor("TabbedPane.highlight");
4632N/A shadow = UIManager.getColor("TabbedPane.shadow");
4632N/A darkShadow = UIManager.getColor("TabbedPane.darkShadow");
4632N/A focus = UIManager.getColor("TabbedPane.focus");
4632N/A selectedColor = UIManager.getColor("TabbedPane.selected");
4632N/A
4632N/A textIconGap = UIManager.getInt("TabbedPane.textIconGap");
4632N/A tabInsets = UIManager.getInsets("TabbedPane.tabInsets");
4632N/A selectedTabPadInsets = UIManager.getInsets("TabbedPane.selectedTabPadInsets");
4632N/A tabAreaInsets = UIManager.getInsets("TabbedPane.tabAreaInsets");
4632N/A tabsOverlapBorder = UIManager.getBoolean("TabbedPane.tabsOverlapBorder");
4632N/A contentBorderInsets = UIManager.getInsets("TabbedPane.contentBorderInsets");
4632N/A tabRunOverlay = UIManager.getInt("TabbedPane.tabRunOverlay");
4632N/A tabsOpaque = UIManager.getBoolean("TabbedPane.tabsOpaque");
4632N/A contentOpaque = UIManager.getBoolean("TabbedPane.contentOpaque");
4632N/A Object opaque = UIManager.get("TabbedPane.opaque");
4632N/A if (opaque == null) {
4632N/A opaque = Boolean.FALSE;
4632N/A }
4632N/A LookAndFeel.installProperty(tabPane, "opaque", opaque);
4632N/A }
4632N/A
4632N/A protected void uninstallDefaults() {
4632N/A highlight = null;
4632N/A lightHighlight = null;
4632N/A shadow = null;
4632N/A darkShadow = null;
4632N/A focus = null;
4632N/A tabInsets = null;
4632N/A selectedTabPadInsets = null;
4632N/A tabAreaInsets = null;
4632N/A contentBorderInsets = null;
4632N/A }
4632N/A
4632N/A protected void installListeners() {
4632N/A if ((propertyChangeListener = createPropertyChangeListener()) != null) {
4632N/A tabPane.addPropertyChangeListener(propertyChangeListener);
4632N/A }
4632N/A if ((tabChangeListener = createChangeListener()) != null) {
4632N/A tabPane.addChangeListener(tabChangeListener);
4632N/A }
4632N/A if ((mouseListener = createMouseListener()) != null) {
4632N/A tabPane.addMouseListener(mouseListener);
4632N/A }
4632N/A tabPane.addMouseMotionListener(getHandler());
4632N/A if ((focusListener = createFocusListener()) != null) {
4632N/A tabPane.addFocusListener(focusListener);
4632N/A }
4632N/A tabPane.addContainerListener(getHandler());
4632N/A if (tabPane.getTabCount() > 0) {
4632N/A htmlViews = createHTMLVector();
4632N/A }
4632N/A }
4632N/A
4632N/A protected void uninstallListeners() {
4632N/A if (mouseListener != null) {
4632N/A tabPane.removeMouseListener(mouseListener);
4632N/A mouseListener = null;
4632N/A }
4632N/A tabPane.removeMouseMotionListener(getHandler());
4632N/A if (focusListener != null) {
4632N/A tabPane.removeFocusListener(focusListener);
4632N/A focusListener = null;
4632N/A }
4632N/A
4632N/A tabPane.removeContainerListener(getHandler());
4632N/A if (htmlViews != null) {
4632N/A htmlViews.removeAllElements();
4632N/A htmlViews = null;
4632N/A }
4632N/A if (tabChangeListener != null) {
4632N/A tabPane.removeChangeListener(tabChangeListener);
4632N/A tabChangeListener = null;
4632N/A }
4632N/A if (propertyChangeListener != null) {
4632N/A tabPane.removePropertyChangeListener(propertyChangeListener);
4632N/A propertyChangeListener = null;
4632N/A }
4632N/A handler = null;
4632N/A }
4632N/A
4632N/A protected MouseListener createMouseListener() {
4632N/A return getHandler();
4632N/A }
4632N/A
4632N/A protected FocusListener createFocusListener() {
4632N/A return getHandler();
4632N/A }
4632N/A
4632N/A protected ChangeListener createChangeListener() {
4632N/A return getHandler();
4632N/A }
4632N/A
4632N/A protected PropertyChangeListener createPropertyChangeListener() {
4632N/A return getHandler();
4632N/A }
4632N/A
4632N/A private Handler getHandler() {
4632N/A if (handler == null) {
4632N/A handler = new Handler();
4632N/A }
4632N/A return handler;
4632N/A }
4632N/A
4632N/A protected void installKeyboardActions() {
4632N/A InputMap km = getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
4632N/A
4632N/A SwingUtilities.replaceUIInputMap(tabPane, JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, km);
4632N/A km = getInputMap(JComponent.WHEN_FOCUSED);
4632N/A SwingUtilities.replaceUIInputMap(tabPane, JComponent.WHEN_FOCUSED, km);
4632N/A
4632N/A LazyActionMap.installLazyActionMap(tabPane, AquaTabbedPaneCopyFromBasicUI.class, "TabbedPane.actionMap");
4632N/A updateMnemonics();
4632N/A }
4632N/A
4632N/A InputMap getInputMap(final int condition) {
4632N/A if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) {
4632N/A return (InputMap)DefaultLookup.get(tabPane, this, "TabbedPane.ancestorInputMap");
4632N/A } else if (condition == JComponent.WHEN_FOCUSED) {
4632N/A return (InputMap)DefaultLookup.get(tabPane, this, "TabbedPane.focusInputMap");
4632N/A }
4632N/A return null;
4632N/A }
4632N/A
4632N/A protected void uninstallKeyboardActions() {
4632N/A SwingUtilities.replaceUIActionMap(tabPane, null);
4632N/A SwingUtilities.replaceUIInputMap(tabPane, JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null);
4632N/A SwingUtilities.replaceUIInputMap(tabPane, JComponent.WHEN_FOCUSED, null);
4632N/A SwingUtilities.replaceUIInputMap(tabPane, JComponent.WHEN_IN_FOCUSED_WINDOW, null);
4632N/A mnemonicToIndexMap = null;
4632N/A mnemonicInputMap = null;
4632N/A }
4632N/A
4632N/A /**
4632N/A * Reloads the mnemonics. This should be invoked when a memonic changes,
4632N/A * when the title of a mnemonic changes, or when tabs are added/removed.
4632N/A */
4632N/A private void updateMnemonics() {
4632N/A resetMnemonics();
4632N/A for (int counter = tabPane.getTabCount() - 1; counter >= 0; counter--) {
4632N/A final int mnemonic = tabPane.getMnemonicAt(counter);
4632N/A
4632N/A if (mnemonic > 0) {
4632N/A addMnemonic(counter, mnemonic);
4632N/A }
4632N/A }
4632N/A }
4632N/A
4632N/A /**
4632N/A * Resets the mnemonics bindings to an empty state.
4632N/A */
4632N/A private void resetMnemonics() {
4632N/A if (mnemonicToIndexMap != null) {
4632N/A mnemonicToIndexMap.clear();
4632N/A mnemonicInputMap.clear();
4632N/A }
4632N/A }
4632N/A
4632N/A /**
4632N/A * Adds the specified mnemonic at the specified index.
4632N/A */
4632N/A private void addMnemonic(final int index, final int mnemonic) {
4632N/A if (mnemonicToIndexMap == null) {
4632N/A initMnemonics();
4632N/A }
4632N/A // [2165820] Mac OS X change: mnemonics need to be triggered with ctrl-option, not just option.
4632N/A mnemonicInputMap.put(KeyStroke.getKeyStroke(mnemonic, Event.ALT_MASK | Event.CTRL_MASK), "setSelectedIndex");
4632N/A mnemonicToIndexMap.put(new Integer(mnemonic), new Integer(index));
4632N/A }
4632N/A
4632N/A /**
4632N/A * Installs the state needed for mnemonics.
4632N/A */
4632N/A private void initMnemonics() {
4632N/A mnemonicToIndexMap = new Hashtable<Integer, Integer>();
4632N/A mnemonicInputMap = new ComponentInputMapUIResource(tabPane);
4632N/A mnemonicInputMap.setParent(SwingUtilities.getUIInputMap(tabPane, JComponent.WHEN_IN_FOCUSED_WINDOW));
4632N/A SwingUtilities.replaceUIInputMap(tabPane, JComponent.WHEN_IN_FOCUSED_WINDOW, mnemonicInputMap);
4632N/A }
4632N/A
4632N/A /**
4632N/A * Sets the tab the mouse is over by location. This is a cover method
4632N/A * for <code>setRolloverTab(tabForCoordinate(x, y, false))</code>.
4632N/A */
4632N/A private void setRolloverTab(final int x, final int y) {
4632N/A // NOTE:
4632N/A // This calls in with false otherwise it could trigger a validate,
4632N/A // which should NOT happen if the user is only dragging the
4632N/A // mouse around.
4632N/A setRolloverTab(tabForCoordinate(tabPane, x, y, false));
4632N/A }
4632N/A
4632N/A /**
4632N/A * Sets the tab the mouse is currently over to <code>index</code>.
4632N/A * <code>index</code> will be -1 if the mouse is no longer over any
4632N/A * tab. No checking is done to ensure the passed in index identifies a
4632N/A * valid tab.
4632N/A *
4632N/A * @param index Index of the tab the mouse is over.
4632N/A * @since 1.5
4632N/A */
4632N/A protected void setRolloverTab(final int index) {
4632N/A rolloverTabIndex = index;
4632N/A }
4632N/A
4632N/A /**
4632N/A * Returns the tab the mouse is currently over, or {@code -1} if the mouse is no
4632N/A * longer over any tab.
4632N/A *
4632N/A * @return the tab the mouse is currently over, or {@code -1} if the mouse is no
4632N/A * longer over any tab
4632N/A * @since 1.5
4632N/A */
4632N/A protected int getRolloverTab() {
4632N/A return rolloverTabIndex;
4632N/A }
4632N/A
4632N/A public Dimension getMinimumSize(final JComponent c) {
4632N/A // Default to LayoutManager's minimumLayoutSize
4632N/A return null;
4632N/A }
4632N/A
4632N/A public Dimension getMaximumSize(final JComponent c) {
4632N/A // Default to LayoutManager's maximumLayoutSize
4632N/A return null;
4632N/A }
4632N/A
4632N/A /**
4632N/A * Returns the baseline.
4632N/A *
4632N/A * @throws NullPointerException {@inheritDoc}
4632N/A * @throws IllegalArgumentException {@inheritDoc}
4632N/A * @see javax.swing.JComponent#getBaseline(int, int)
4632N/A * @since 1.6
4632N/A */
4632N/A public int getBaseline(final JComponent c, final int width, final int height) {
4632N/A super.getBaseline(c, width, height);
4632N/A int baseline = calculateBaselineIfNecessary();
4632N/A if (baseline != -1) {
4632N/A final int placement = tabPane.getTabPlacement();
4632N/A final Insets insets = tabPane.getInsets();
4632N/A final Insets tabAreaInsets = getTabAreaInsets(placement);
4632N/A switch (placement) {
4632N/A case SwingConstants.TOP:
4632N/A baseline += insets.top + tabAreaInsets.top;
4632N/A return baseline;
4632N/A case SwingConstants.BOTTOM:
4632N/A baseline = height - insets.bottom - tabAreaInsets.bottom - maxTabHeight + baseline;
4632N/A return baseline;
4632N/A case SwingConstants.LEFT:
4632N/A case SwingConstants.RIGHT:
4632N/A baseline += insets.top + tabAreaInsets.top;
4632N/A return baseline;
4632N/A }
4632N/A }
4632N/A return -1;
4632N/A }
4632N/A
4632N/A /**
4632N/A * Returns an enum indicating how the baseline of the component
4632N/A * changes as the size changes.
4632N/A *
4632N/A * @throws NullPointerException {@inheritDoc}
4632N/A * @see javax.swing.JComponent#getBaseline(int, int)
4632N/A * @since 1.6
4632N/A */
4632N/A public Component.BaselineResizeBehavior getBaselineResizeBehavior(final JComponent c) {
4632N/A super.getBaselineResizeBehavior(c);
4632N/A switch (tabPane.getTabPlacement()) {
4632N/A case SwingConstants.LEFT:
4632N/A case SwingConstants.RIGHT:
4632N/A case SwingConstants.TOP:
4632N/A return Component.BaselineResizeBehavior.CONSTANT_ASCENT;
4632N/A case SwingConstants.BOTTOM:
4632N/A return Component.BaselineResizeBehavior.CONSTANT_DESCENT;
4632N/A }
4632N/A return Component.BaselineResizeBehavior.OTHER;
4632N/A }
4632N/A
4632N/A /**
4632N/A * Returns the baseline for the specified tab.
4632N/A *
4632N/A * @param tab index of tab to get baseline for
4632N/A * @exception IndexOutOfBoundsException if index is out of range
4632N/A * (index < 0 || index >= tab count)
4632N/A * @return baseline or a value &lt; 0 indicating there is no reasonable
4632N/A * baseline
4632N/A * @since 1.6
4632N/A */
4632N/A protected int getBaseline(final int tab) {
4632N/A if (tabPane.getTabComponentAt(tab) != null) {
4632N/A final int offset = getBaselineOffset();
4632N/A if (offset != 0) {
4632N/A // The offset is not applied to the tab component, and so
4632N/A // in general we can't get good alignment like with components
4632N/A // in the tab.
4632N/A return -1;
4632N/A }
4632N/A final Component c = tabPane.getTabComponentAt(tab);
4632N/A final Dimension pref = c.getPreferredSize();
4632N/A final Insets tabInsets = getTabInsets(tabPane.getTabPlacement(), tab);
4632N/A final int cellHeight = maxTabHeight - tabInsets.top - tabInsets.bottom;
4632N/A return c.getBaseline(pref.width, pref.height) + (cellHeight - pref.height) / 2 + tabInsets.top;
4632N/A } else {
4632N/A final View view = getTextViewForTab(tab);
4632N/A if (view != null) {
4632N/A final int viewHeight = (int)view.getPreferredSpan(View.Y_AXIS);
4632N/A final int baseline = BasicHTML.getHTMLBaseline(view, (int)view.getPreferredSpan(View.X_AXIS), viewHeight);
4632N/A if (baseline >= 0) {
4632N/A return maxTabHeight / 2 - viewHeight / 2 + baseline + getBaselineOffset();
4632N/A }
4632N/A return -1;
4632N/A }
4632N/A }
4632N/A final FontMetrics metrics = getFontMetrics();
4632N/A final int fontHeight = metrics.getHeight();
4632N/A final int fontBaseline = metrics.getAscent();
4632N/A return maxTabHeight / 2 - fontHeight / 2 + fontBaseline + getBaselineOffset();
4632N/A }
4632N/A
4632N/A /**
4632N/A * Returns the amount the baseline is offset by. This is typically
4632N/A * the same as <code>getTabLabelShiftY</code>.
4632N/A *
4632N/A * @return amount to offset the baseline by
4632N/A * @since 1.6
4632N/A */
4632N/A protected int getBaselineOffset() {
4632N/A switch (tabPane.getTabPlacement()) {
4632N/A case SwingConstants.TOP:
4632N/A if (tabPane.getTabCount() > 1) {
4632N/A return 1;
4632N/A } else {
4632N/A return -1;
4632N/A }
4632N/A case SwingConstants.BOTTOM:
4632N/A if (tabPane.getTabCount() > 1) {
4632N/A return -1;
4632N/A } else {
4632N/A return 1;
4632N/A }
4632N/A default: // RIGHT|LEFT
4632N/A return (maxTabHeight % 2);
4632N/A }
4632N/A }
4632N/A
4632N/A private int calculateBaselineIfNecessary() {
4632N/A if (!calculatedBaseline) {
4632N/A calculatedBaseline = true;
4632N/A baseline = -1;
4632N/A if (tabPane.getTabCount() > 0) {
4632N/A calculateBaseline();
4632N/A }
4632N/A }
4632N/A return baseline;
4632N/A }
4632N/A
4632N/A private void calculateBaseline() {
4632N/A final int tabCount = tabPane.getTabCount();
4632N/A final int tabPlacement = tabPane.getTabPlacement();
4632N/A maxTabHeight = calculateMaxTabHeight(tabPlacement);
4632N/A baseline = getBaseline(0);
4632N/A if (isHorizontalTabPlacement()) {
4632N/A for (int i = 1; i < tabCount; i++) {
4632N/A if (getBaseline(i) != baseline) {
4632N/A baseline = -1;
4632N/A break;
4632N/A }
4632N/A }
4632N/A } else {
4632N/A // left/right, tabs may be different sizes.
4632N/A final FontMetrics fontMetrics = getFontMetrics();
4632N/A final int fontHeight = fontMetrics.getHeight();
4632N/A final int height = calculateTabHeight(tabPlacement, 0, fontHeight);
4632N/A for (int i = 1; i < tabCount; i++) {
4632N/A final int newHeight = calculateTabHeight(tabPlacement, i, fontHeight);
4632N/A if (height != newHeight) {
4632N/A // assume different baseline
4632N/A baseline = -1;
4632N/A break;
4632N/A }
4632N/A }
4632N/A }
4632N/A }
4632N/A
4632N/A// UI Rendering
4632N/A
4632N/A public void paint(final Graphics g, final JComponent c) {
4632N/A final int selectedIndex = tabPane.getSelectedIndex();
4632N/A final int tabPlacement = tabPane.getTabPlacement();
4632N/A
4632N/A ensureCurrentLayout();
4632N/A
4632N/A // Paint content border and tab area
4632N/A if (tabsOverlapBorder) {
4632N/A paintContentBorder(g, tabPlacement, selectedIndex);
4632N/A }
4632N/A // If scrollable tabs are enabled, the tab area will be
4632N/A // painted by the scrollable tab panel instead.
4632N/A //
4632N/A if (!scrollableTabLayoutEnabled()) { // WRAP_TAB_LAYOUT
4632N/A paintTabArea(g, tabPlacement, selectedIndex);
4632N/A }
4632N/A if (!tabsOverlapBorder) {
4632N/A paintContentBorder(g, tabPlacement, selectedIndex);
4632N/A }
4632N/A }
4632N/A
4632N/A /**
4632N/A * Paints the tabs in the tab area.
4632N/A * Invoked by paint().
4632N/A * The graphics parameter must be a valid <code>Graphics</code>
4632N/A * object. Tab placement may be either:
4632N/A * <code>JTabbedPane.TOP</code>, <code>JTabbedPane.BOTTOM</code>,
4632N/A * <code>JTabbedPane.LEFT</code>, or <code>JTabbedPane.RIGHT</code>.
4632N/A * The selected index must be a valid tabbed pane tab index (0 to
4632N/A * tab count - 1, inclusive) or -1 if no tab is currently selected.
4632N/A * The handling of invalid parameters is unspecified.
4632N/A *
4632N/A * @param g the graphics object to use for rendering
4632N/A * @param tabPlacement the placement for the tabs within the JTabbedPane
4632N/A * @param selectedIndex the tab index of the selected component
4632N/A *
4632N/A * @since 1.4
4632N/A */
4632N/A protected void paintTabArea(final Graphics g, final int tabPlacement, final int selectedIndex) {
4632N/A final int tabCount = tabPane.getTabCount();
4632N/A
4632N/A final Rectangle iconRect = new Rectangle(), textRect = new Rectangle();
4632N/A final Rectangle clipRect = g.getClipBounds();
4632N/A
4632N/A // Paint tabRuns of tabs from back to front
4632N/A for (int i = runCount - 1; i >= 0; i--) {
4632N/A final int start = tabRuns[i];
4632N/A final int next = tabRuns[(i == runCount - 1) ? 0 : i + 1];
4632N/A final int end = (next != 0 ? next - 1 : tabCount - 1);
4632N/A for (int j = start; j <= end; j++) {
4632N/A if (j != selectedIndex && rects[j].intersects(clipRect)) {
4632N/A paintTab(g, tabPlacement, rects, j, iconRect, textRect);
4632N/A }
4632N/A }
4632N/A }
4632N/A
4632N/A // Paint selected tab if its in the front run
4632N/A // since it may overlap other tabs
4632N/A if (selectedIndex >= 0 && rects[selectedIndex].intersects(clipRect)) {
4632N/A paintTab(g, tabPlacement, rects, selectedIndex, iconRect, textRect);
4632N/A }
4632N/A }
4632N/A
4632N/A protected void paintTab(final Graphics g, final int tabPlacement, final Rectangle[] rects, final int tabIndex, final Rectangle iconRect, final Rectangle textRect) {
4632N/A final Rectangle tabRect = rects[tabIndex];
4632N/A final int selectedIndex = tabPane.getSelectedIndex();
4632N/A final boolean isSelected = selectedIndex == tabIndex;
4632N/A
4632N/A if (tabsOpaque || tabPane.isOpaque()) {
4632N/A paintTabBackground(g, tabPlacement, tabIndex, tabRect.x, tabRect.y, tabRect.width, tabRect.height, isSelected);
4632N/A }
4632N/A
4632N/A paintTabBorder(g, tabPlacement, tabIndex, tabRect.x, tabRect.y, tabRect.width, tabRect.height, isSelected);
4632N/A
4632N/A final String title = tabPane.getTitleAt(tabIndex);
4632N/A final Font font = tabPane.getFont();
4632N/A final FontMetrics metrics = SwingUtilities2.getFontMetrics(tabPane, g, font);
4632N/A final Icon icon = getIconForTab(tabIndex);
4632N/A
4632N/A layoutLabel(tabPlacement, metrics, tabIndex, title, icon, tabRect, iconRect, textRect, isSelected);
4632N/A
4632N/A if (tabPane.getTabComponentAt(tabIndex) == null) {
4632N/A String clippedTitle = title;
4632N/A
4632N/A if (scrollableTabLayoutEnabled() && tabScroller.croppedEdge.isParamsSet() && tabScroller.croppedEdge.getTabIndex() == tabIndex && isHorizontalTabPlacement()) {
4632N/A final int availTextWidth = tabScroller.croppedEdge.getCropline() - (textRect.x - tabRect.x) - tabScroller.croppedEdge.getCroppedSideWidth();
4632N/A clippedTitle = SwingUtilities2.clipStringIfNecessary(null, metrics, title, availTextWidth);
4632N/A }
4632N/A
4632N/A paintText(g, tabPlacement, font, metrics, tabIndex, clippedTitle, textRect, isSelected);
4632N/A
4632N/A paintIcon(g, tabPlacement, tabIndex, icon, iconRect, isSelected);
4632N/A }
4632N/A paintFocusIndicator(g, tabPlacement, rects, tabIndex, iconRect, textRect, isSelected);
4632N/A }
4632N/A
4632N/A private boolean isHorizontalTabPlacement() {
4632N/A return tabPane.getTabPlacement() == TOP || tabPane.getTabPlacement() == BOTTOM;
4632N/A }
4632N/A
4632N/A /* This method will create and return a polygon shape for the given tab rectangle
4632N/A * which has been cropped at the specified cropline with a torn edge visual.
4632N/A * e.g. A "File" tab which has cropped been cropped just after the "i":
4632N/A * -------------
4632N/A * | ..... |
4632N/A * | . |
4632N/A * | ... . |
4632N/A * | . . |
4632N/A * | . . |
4632N/A * | . . |
4632N/A * --------------
4632N/A *
4632N/A * The x, y arrays below define the pattern used to create a "torn" edge
4632N/A * segment which is repeated to fill the edge of the tab.
4632N/A * For tabs placed on TOP and BOTTOM, this righthand torn edge is created by
4632N/A * line segments which are defined by coordinates obtained by
4632N/A * subtracting xCropLen[i] from (tab.x + tab.width) and adding yCroplen[i]
4632N/A * to (tab.y).
4632N/A * For tabs placed on LEFT or RIGHT, the bottom torn edge is created by
4632N/A * subtracting xCropLen[i] from (tab.y + tab.height) and adding yCropLen[i]
4632N/A * to (tab.x).
4632N/A */
4632N/A private static int xCropLen[] = { 1, 1, 0, 0, 1, 1, 2, 2 };
4632N/A private static int yCropLen[] = { 0, 3, 3, 6, 6, 9, 9, 12 };
4632N/A private static final int CROP_SEGMENT = 12;
4632N/A
4632N/A private static Polygon createCroppedTabShape(final int tabPlacement, final Rectangle tabRect, final int cropline) {
4632N/A int rlen = 0;
4632N/A int start = 0;
4632N/A int end = 0;
4632N/A int ostart = 0;
4632N/A
4632N/A switch (tabPlacement) {
4632N/A case LEFT:
4632N/A case RIGHT:
4632N/A rlen = tabRect.width;
4632N/A start = tabRect.x;
4632N/A end = tabRect.x + tabRect.width;
4632N/A ostart = tabRect.y + tabRect.height;
4632N/A break;
4632N/A case TOP:
4632N/A case BOTTOM:
4632N/A default:
4632N/A rlen = tabRect.height;
4632N/A start = tabRect.y;
4632N/A end = tabRect.y + tabRect.height;
4632N/A ostart = tabRect.x + tabRect.width;
4632N/A }
4632N/A int rcnt = rlen / CROP_SEGMENT;
4632N/A if (rlen % CROP_SEGMENT > 0) {
4632N/A rcnt++;
4632N/A }
4632N/A final int npts = 2 + (rcnt * 8);
4632N/A final int xp[] = new int[npts];
4632N/A final int yp[] = new int[npts];
4632N/A int pcnt = 0;
4632N/A
4632N/A xp[pcnt] = ostart;
4632N/A yp[pcnt++] = end;
4632N/A xp[pcnt] = ostart;
4632N/A yp[pcnt++] = start;
4632N/A for (int i = 0; i < rcnt; i++) {
4632N/A for (int j = 0; j < xCropLen.length; j++) {
4632N/A xp[pcnt] = cropline - xCropLen[j];
4632N/A yp[pcnt] = start + (i * CROP_SEGMENT) + yCropLen[j];
4632N/A if (yp[pcnt] >= end) {
4632N/A yp[pcnt] = end;
4632N/A pcnt++;
4632N/A break;
4632N/A }
4632N/A pcnt++;
4632N/A }
4632N/A }
4632N/A if (tabPlacement == SwingConstants.TOP || tabPlacement == SwingConstants.BOTTOM) {
4632N/A return new Polygon(xp, yp, pcnt);
4632N/A
4632N/A } else { // LEFT or RIGHT
4632N/A return new Polygon(yp, xp, pcnt);
4632N/A }
4632N/A }
4632N/A
4632N/A /* If tabLayoutPolicy == SCROLL_TAB_LAYOUT, this method will paint an edge
4632N/A * indicating the tab is cropped in the viewport display
4632N/A */
4632N/A private void paintCroppedTabEdge(final Graphics g) {
4632N/A final int tabIndex = tabScroller.croppedEdge.getTabIndex();
4632N/A final int cropline = tabScroller.croppedEdge.getCropline();
4632N/A int x, y;
4632N/A switch (tabPane.getTabPlacement()) {
4632N/A case LEFT:
4632N/A case RIGHT:
4632N/A x = rects[tabIndex].x;
4632N/A y = cropline;
4632N/A int xx = x;
4632N/A g.setColor(shadow);
4632N/A while (xx <= x + rects[tabIndex].width) {
4632N/A for (int i = 0; i < xCropLen.length; i += 2) {
4632N/A g.drawLine(xx + yCropLen[i], y - xCropLen[i], xx + yCropLen[i + 1] - 1, y - xCropLen[i + 1]);
4632N/A }
4632N/A xx += CROP_SEGMENT;
4632N/A }
4632N/A break;
4632N/A case TOP:
4632N/A case BOTTOM:
4632N/A default:
4632N/A x = cropline;
4632N/A y = rects[tabIndex].y;
4632N/A int yy = y;
4632N/A g.setColor(shadow);
4632N/A while (yy <= y + rects[tabIndex].height) {
4632N/A for (int i = 0; i < xCropLen.length; i += 2) {
4632N/A g.drawLine(x - xCropLen[i], yy + yCropLen[i], x - xCropLen[i + 1], yy + yCropLen[i + 1] - 1);
4632N/A }
4632N/A yy += CROP_SEGMENT;
4632N/A }
4632N/A }
4632N/A }
4632N/A
4632N/A protected void layoutLabel(final int tabPlacement, final FontMetrics metrics, final int tabIndex, final String title, final Icon icon, final Rectangle tabRect, final Rectangle iconRect, final Rectangle textRect, final boolean isSelected) {
4632N/A textRect.x = textRect.y = iconRect.x = iconRect.y = 0;
4632N/A
4632N/A final View v = getTextViewForTab(tabIndex);
4632N/A if (v != null) {
4632N/A tabPane.putClientProperty("html", v);
4632N/A }
4632N/A
4632N/A SwingUtilities.layoutCompoundLabel(tabPane, metrics, title, icon, SwingConstants.CENTER, SwingConstants.CENTER, SwingConstants.CENTER, SwingConstants.TRAILING, tabRect, iconRect, textRect, textIconGap);
4632N/A
4632N/A tabPane.putClientProperty("html", null);
4632N/A
4632N/A final int xNudge = getTabLabelShiftX(tabPlacement, tabIndex, isSelected);
4632N/A final int yNudge = getTabLabelShiftY(tabPlacement, tabIndex, isSelected);
4632N/A iconRect.x += xNudge;
4632N/A iconRect.y += yNudge;
4632N/A textRect.x += xNudge;
4632N/A textRect.y += yNudge;
4632N/A }
4632N/A
4632N/A protected void paintIcon(final Graphics g, final int tabPlacement, final int tabIndex, final Icon icon, final Rectangle iconRect, final boolean isSelected) {
4632N/A if (icon != null) {
4632N/A icon.paintIcon(tabPane, g, iconRect.x, iconRect.y);
4632N/A }
4632N/A }
4632N/A
4632N/A protected void paintText(final Graphics g, final int tabPlacement, final Font font, final FontMetrics metrics, final int tabIndex, final String title, final Rectangle textRect, final boolean isSelected) {
4632N/A
4632N/A g.setFont(font);
4632N/A
4632N/A final View v = getTextViewForTab(tabIndex);
4632N/A if (v != null) {
4632N/A // html
4632N/A v.paint(g, textRect);
4632N/A } else {
4632N/A // plain text
4632N/A final int mnemIndex = tabPane.getDisplayedMnemonicIndexAt(tabIndex);
4632N/A
4632N/A if (tabPane.isEnabled() && tabPane.isEnabledAt(tabIndex)) {
4632N/A Color fg = tabPane.getForegroundAt(tabIndex);
4632N/A if (isSelected && (fg instanceof UIResource)) {
4632N/A final Color selectedFG = UIManager.getColor("TabbedPane.selectedForeground");
4632N/A if (selectedFG != null) {
4632N/A fg = selectedFG;
4632N/A }
4632N/A }
4632N/A g.setColor(fg);
4632N/A SwingUtilities2.drawStringUnderlineCharAt(tabPane, g, title, mnemIndex, textRect.x, textRect.y + metrics.getAscent());
4632N/A
4632N/A } else { // tab disabled
4632N/A g.setColor(tabPane.getBackgroundAt(tabIndex).brighter());
4632N/A SwingUtilities2.drawStringUnderlineCharAt(tabPane, g, title, mnemIndex, textRect.x, textRect.y + metrics.getAscent());
4632N/A g.setColor(tabPane.getBackgroundAt(tabIndex).darker());
4632N/A SwingUtilities2.drawStringUnderlineCharAt(tabPane, g, title, mnemIndex, textRect.x - 1, textRect.y + metrics.getAscent() - 1);
4632N/A
4632N/A }
4632N/A }
4632N/A }
4632N/A
4632N/A protected int getTabLabelShiftX(final int tabPlacement, final int tabIndex, final boolean isSelected) {
4632N/A final Rectangle tabRect = rects[tabIndex];
4632N/A int nudge = 0;
4632N/A switch (tabPlacement) {
4632N/A case LEFT:
4632N/A nudge = isSelected ? -1 : 1;
4632N/A break;
4632N/A case RIGHT:
4632N/A nudge = isSelected ? 1 : -1;
4632N/A break;
4632N/A case BOTTOM:
4632N/A case TOP:
4632N/A default:
4632N/A nudge = tabRect.width % 2;
4632N/A }
4632N/A return nudge;
4632N/A }
4632N/A
4632N/A protected int getTabLabelShiftY(final int tabPlacement, final int tabIndex, final boolean isSelected) {
4632N/A final Rectangle tabRect = rects[tabIndex];
4632N/A int nudge = 0;
4632N/A switch (tabPlacement) {
4632N/A case BOTTOM:
4632N/A nudge = isSelected ? 1 : -1;
4632N/A break;
4632N/A case LEFT:
4632N/A case RIGHT:
4632N/A nudge = tabRect.height % 2;
4632N/A break;
4632N/A case TOP:
4632N/A default:
4632N/A nudge = isSelected ? -1 : 1;
4632N/A ;
4632N/A }
4632N/A return nudge;
4632N/A }
4632N/A
4632N/A protected void paintFocusIndicator(final Graphics g, final int tabPlacement, final Rectangle[] rects, final int tabIndex, final Rectangle iconRect, final Rectangle textRect, final boolean isSelected) {
4632N/A final Rectangle tabRect = rects[tabIndex];
4632N/A if (tabPane.hasFocus() && isSelected) {
4632N/A int x, y, w, h;
4632N/A g.setColor(focus);
4632N/A switch (tabPlacement) {
4632N/A case LEFT:
4632N/A x = tabRect.x + 3;
4632N/A y = tabRect.y + 3;
4632N/A w = tabRect.width - 5;
4632N/A h = tabRect.height - 6;
4632N/A break;
4632N/A case RIGHT:
4632N/A x = tabRect.x + 2;
4632N/A y = tabRect.y + 3;
4632N/A w = tabRect.width - 5;
4632N/A h = tabRect.height - 6;
4632N/A break;
4632N/A case BOTTOM:
4632N/A x = tabRect.x + 3;
4632N/A y = tabRect.y + 2;
4632N/A w = tabRect.width - 6;
4632N/A h = tabRect.height - 5;
4632N/A break;
4632N/A case TOP:
4632N/A default:
4632N/A x = tabRect.x + 3;
4632N/A y = tabRect.y + 3;
4632N/A w = tabRect.width - 6;
4632N/A h = tabRect.height - 5;
4632N/A }
4632N/A BasicGraphicsUtils.drawDashedRect(g, x, y, w, h);
4632N/A }
4632N/A }
4632N/A
4632N/A /**
4632N/A * this function draws the border around each tab
4632N/A * note that this function does now draw the background of the tab.
4632N/A * that is done elsewhere
4632N/A */
4632N/A protected void paintTabBorder(final Graphics g, final int tabPlacement, final int tabIndex, final int x, final int y, final int w, final int h, final boolean isSelected) {
4632N/A g.setColor(lightHighlight);
4632N/A
4632N/A switch (tabPlacement) {
4632N/A case LEFT:
4632N/A g.drawLine(x + 1, y + h - 2, x + 1, y + h - 2); // bottom-left highlight
4632N/A g.drawLine(x, y + 2, x, y + h - 3); // left highlight
4632N/A g.drawLine(x + 1, y + 1, x + 1, y + 1); // top-left highlight
4632N/A g.drawLine(x + 2, y, x + w - 1, y); // top highlight
4632N/A
4632N/A g.setColor(shadow);
4632N/A g.drawLine(x + 2, y + h - 2, x + w - 1, y + h - 2); // bottom shadow
4632N/A
4632N/A g.setColor(darkShadow);
4632N/A g.drawLine(x + 2, y + h - 1, x + w - 1, y + h - 1); // bottom dark shadow
4632N/A break;
4632N/A case RIGHT:
4632N/A g.drawLine(x, y, x + w - 3, y); // top highlight
4632N/A
4632N/A g.setColor(shadow);
4632N/A g.drawLine(x, y + h - 2, x + w - 3, y + h - 2); // bottom shadow
4632N/A g.drawLine(x + w - 2, y + 2, x + w - 2, y + h - 3); // right shadow
4632N/A
4632N/A g.setColor(darkShadow);
4632N/A g.drawLine(x + w - 2, y + 1, x + w - 2, y + 1); // top-right dark shadow
4632N/A g.drawLine(x + w - 2, y + h - 2, x + w - 2, y + h - 2); // bottom-right dark shadow
4632N/A g.drawLine(x + w - 1, y + 2, x + w - 1, y + h - 3); // right dark shadow
4632N/A g.drawLine(x, y + h - 1, x + w - 3, y + h - 1); // bottom dark shadow
4632N/A break;
4632N/A case BOTTOM:
4632N/A g.drawLine(x, y, x, y + h - 3); // left highlight
4632N/A g.drawLine(x + 1, y + h - 2, x + 1, y + h - 2); // bottom-left highlight
4632N/A
4632N/A g.setColor(shadow);
4632N/A g.drawLine(x + 2, y + h - 2, x + w - 3, y + h - 2); // bottom shadow
4632N/A g.drawLine(x + w - 2, y, x + w - 2, y + h - 3); // right shadow
4632N/A
4632N/A g.setColor(darkShadow);
4632N/A g.drawLine(x + 2, y + h - 1, x + w - 3, y + h - 1); // bottom dark shadow
4632N/A g.drawLine(x + w - 2, y + h - 2, x + w - 2, y + h - 2); // bottom-right dark shadow
4632N/A g.drawLine(x + w - 1, y, x + w - 1, y + h - 3); // right dark shadow
4632N/A break;
4632N/A case TOP:
4632N/A default:
4632N/A g.drawLine(x, y + 2, x, y + h - 1); // left highlight
4632N/A g.drawLine(x + 1, y + 1, x + 1, y + 1); // top-left highlight
4632N/A g.drawLine(x + 2, y, x + w - 3, y); // top highlight
4632N/A
4632N/A g.setColor(shadow);
4632N/A g.drawLine(x + w - 2, y + 2, x + w - 2, y + h - 1); // right shadow
4632N/A
4632N/A g.setColor(darkShadow);
4632N/A g.drawLine(x + w - 1, y + 2, x + w - 1, y + h - 1); // right dark-shadow
4632N/A g.drawLine(x + w - 2, y + 1, x + w - 2, y + 1); // top-right shadow
4632N/A }
4632N/A }
4632N/A
4632N/A protected void paintTabBackground(final Graphics g, final int tabPlacement, final int tabIndex, final int x, final int y, final int w, final int h, boolean isSelected) {
4632N/A g.setColor(!isSelected || selectedColor == null ? tabPane.getBackgroundAt(tabIndex) : selectedColor);
4632N/A switch (tabPlacement) {
4632N/A case LEFT:
4632N/A g.fillRect(x + 1, y + 1, w - 1, h - 3);
4632N/A break;
4632N/A case RIGHT:
4632N/A g.fillRect(x, y + 1, w - 2, h - 3);
4632N/A break;
4632N/A case BOTTOM:
4632N/A g.fillRect(x + 1, y, w - 3, h - 1);
4632N/A break;
4632N/A case TOP:
4632N/A default:
4632N/A g.fillRect(x + 1, y + 1, w - 3, h - 1);
4632N/A }
4632N/A }
4632N/A
4632N/A protected void paintContentBorder(final Graphics g, final int tabPlacement, final int selectedIndex) {
4632N/A final int width = tabPane.getWidth();
4632N/A final int height = tabPane.getHeight();
4632N/A final Insets insets = tabPane.getInsets();
4632N/A final Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
4632N/A
4632N/A int x = insets.left;
4632N/A int y = insets.top;
4632N/A int w = width - insets.right - insets.left;
4632N/A int h = height - insets.top - insets.bottom;
4632N/A
4632N/A switch (tabPlacement) {
4632N/A case LEFT:
4632N/A x += calculateTabAreaWidth(tabPlacement, runCount, maxTabWidth);
4632N/A if (tabsOverlapBorder) {
4632N/A x -= tabAreaInsets.right;
4632N/A }
4632N/A w -= (x - insets.left);
4632N/A break;
4632N/A case RIGHT:
4632N/A w -= calculateTabAreaWidth(tabPlacement, runCount, maxTabWidth);
4632N/A if (tabsOverlapBorder) {
4632N/A w += tabAreaInsets.left;
4632N/A }
4632N/A break;
4632N/A case BOTTOM:
4632N/A h -= calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight);
4632N/A if (tabsOverlapBorder) {
4632N/A h += tabAreaInsets.top;
4632N/A }
4632N/A break;
4632N/A case TOP:
4632N/A default:
4632N/A y += calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight);
4632N/A if (tabsOverlapBorder) {
4632N/A y -= tabAreaInsets.bottom;
4632N/A }
4632N/A h -= (y - insets.top);
4632N/A }
4632N/A
4632N/A if (tabPane.getTabCount() > 0 && (contentOpaque || tabPane.isOpaque())) {
4632N/A // Fill region behind content area
4632N/A final Color color = UIManager.getColor("TabbedPane.contentAreaColor");
4632N/A if (color != null) {
4632N/A g.setColor(color);
4632N/A } else if (selectedColor == null || selectedIndex == -1) {
4632N/A g.setColor(tabPane.getBackground());
4632N/A } else {
4632N/A g.setColor(selectedColor);
4632N/A }
4632N/A g.fillRect(x, y, w, h);
4632N/A }
4632N/A
4632N/A paintContentBorderTopEdge(g, tabPlacement, selectedIndex, x, y, w, h);
4632N/A paintContentBorderLeftEdge(g, tabPlacement, selectedIndex, x, y, w, h);
4632N/A paintContentBorderBottomEdge(g, tabPlacement, selectedIndex, x, y, w, h);
4632N/A paintContentBorderRightEdge(g, tabPlacement, selectedIndex, x, y, w, h);
4632N/A
4632N/A }
4632N/A
4632N/A protected void paintContentBorderTopEdge(final Graphics g, final int tabPlacement, final int selectedIndex, final int x, final int y, final int w, final int h) {
4632N/A final Rectangle selRect = selectedIndex < 0 ? null : getTabBounds(selectedIndex, calcRect);
4632N/A
4632N/A g.setColor(lightHighlight);
4632N/A
4632N/A // Draw unbroken line if tabs are not on TOP, OR
4632N/A // selected tab is not in run adjacent to content, OR
4632N/A // selected tab is not visible (SCROLL_TAB_LAYOUT)
4632N/A //
4632N/A if (tabPlacement != TOP || selectedIndex < 0 || (selRect.y + selRect.height + 1 < y) || (selRect.x < x || selRect.x > x + w)) {
4632N/A g.drawLine(x, y, x + w - 2, y);
4632N/A } else {
4632N/A // Break line to show visual connection to selected tab
4632N/A g.drawLine(x, y, selRect.x - 1, y);
4632N/A if (selRect.x + selRect.width < x + w - 2) {
4632N/A g.drawLine(selRect.x + selRect.width, y, x + w - 2, y);
4632N/A } else {
4632N/A g.setColor(shadow);
4632N/A g.drawLine(x + w - 2, y, x + w - 2, y);
4632N/A }
4632N/A }
4632N/A }
4632N/A
4632N/A protected void paintContentBorderLeftEdge(final Graphics g, final int tabPlacement, final int selectedIndex, final int x, final int y, final int w, final int h) {
4632N/A final Rectangle selRect = selectedIndex < 0 ? null : getTabBounds(selectedIndex, calcRect);
4632N/A
4632N/A g.setColor(lightHighlight);
4632N/A
4632N/A // Draw unbroken line if tabs are not on LEFT, OR
4632N/A // selected tab is not in run adjacent to content, OR
4632N/A // selected tab is not visible (SCROLL_TAB_LAYOUT)
4632N/A //
4632N/A if (tabPlacement != LEFT || selectedIndex < 0 || (selRect.x + selRect.width + 1 < x) || (selRect.y < y || selRect.y > y + h)) {
4632N/A g.drawLine(x, y, x, y + h - 2);
4632N/A } else {
4632N/A // Break line to show visual connection to selected tab
4632N/A g.drawLine(x, y, x, selRect.y - 1);
4632N/A if (selRect.y + selRect.height < y + h - 2) {
4632N/A g.drawLine(x, selRect.y + selRect.height, x, y + h - 2);
4632N/A }
4632N/A }
4632N/A }
4632N/A
4632N/A protected void paintContentBorderBottomEdge(final Graphics g, final int tabPlacement, final int selectedIndex, final int x, final int y, final int w, final int h) {
4632N/A final Rectangle selRect = selectedIndex < 0 ? null : getTabBounds(selectedIndex, calcRect);
4632N/A
4632N/A g.setColor(shadow);
4632N/A
4632N/A // Draw unbroken line if tabs are not on BOTTOM, OR
4632N/A // selected tab is not in run adjacent to content, OR
4632N/A // selected tab is not visible (SCROLL_TAB_LAYOUT)
4632N/A //
4632N/A if (tabPlacement != BOTTOM || selectedIndex < 0 || (selRect.y - 1 > h) || (selRect.x < x || selRect.x > x + w)) {
4632N/A g.drawLine(x + 1, y + h - 2, x + w - 2, y + h - 2);
4632N/A g.setColor(darkShadow);
4632N/A g.drawLine(x, y + h - 1, x + w - 1, y + h - 1);
4632N/A } else {
4632N/A // Break line to show visual connection to selected tab
4632N/A g.drawLine(x + 1, y + h - 2, selRect.x - 1, y + h - 2);
4632N/A g.setColor(darkShadow);
4632N/A g.drawLine(x, y + h - 1, selRect.x - 1, y + h - 1);
4632N/A if (selRect.x + selRect.width < x + w - 2) {
4632N/A g.setColor(shadow);
4632N/A g.drawLine(selRect.x + selRect.width, y + h - 2, x + w - 2, y + h - 2);
4632N/A g.setColor(darkShadow);
4632N/A g.drawLine(selRect.x + selRect.width, y + h - 1, x + w - 1, y + h - 1);
4632N/A }
4632N/A }
4632N/A
4632N/A }
4632N/A
4632N/A protected void paintContentBorderRightEdge(final Graphics g, final int tabPlacement, final int selectedIndex, final int x, final int y, final int w, final int h) {
4632N/A final Rectangle selRect = selectedIndex < 0 ? null : getTabBounds(selectedIndex, calcRect);
4632N/A
4632N/A g.setColor(shadow);
4632N/A
4632N/A // Draw unbroken line if tabs are not on RIGHT, OR
4632N/A // selected tab is not in run adjacent to content, OR
4632N/A // selected tab is not visible (SCROLL_TAB_LAYOUT)
4632N/A //
4632N/A if (tabPlacement != RIGHT || selectedIndex < 0 || (selRect.x - 1 > w) || (selRect.y < y || selRect.y > y + h)) {
4632N/A g.drawLine(x + w - 2, y + 1, x + w - 2, y + h - 3);
4632N/A g.setColor(darkShadow);
4632N/A g.drawLine(x + w - 1, y, x + w - 1, y + h - 1);
4632N/A } else {
4632N/A // Break line to show visual connection to selected tab
4632N/A g.drawLine(x + w - 2, y + 1, x + w - 2, selRect.y - 1);
4632N/A g.setColor(darkShadow);
4632N/A g.drawLine(x + w - 1, y, x + w - 1, selRect.y - 1);
4632N/A
4632N/A if (selRect.y + selRect.height < y + h - 2) {
4632N/A g.setColor(shadow);
4632N/A g.drawLine(x + w - 2, selRect.y + selRect.height, x + w - 2, y + h - 2);
4632N/A g.setColor(darkShadow);
4632N/A g.drawLine(x + w - 1, selRect.y + selRect.height, x + w - 1, y + h - 2);
4632N/A }
4632N/A }
4632N/A }
4632N/A
4632N/A protected void ensureCurrentLayout() {
4632N/A if (!tabPane.isValid()) {
4632N/A tabPane.validate();
4632N/A }
4632N/A /* If tabPane doesn't have a peer yet, the validate() call will
4632N/A * silently fail. We handle that by forcing a layout if tabPane
4632N/A * is still invalid. See bug 4237677.
4632N/A */
4632N/A if (!tabPane.isValid()) {
4632N/A final TabbedPaneLayout layout = (TabbedPaneLayout)tabPane.getLayout();
4632N/A layout.calculateLayoutInfo();
4632N/A }
4632N/A }
4632N/A
4632N/A// TabbedPaneUI methods
4632N/A
4632N/A /**
4632N/A * Returns the bounds of the specified tab index. The bounds are
4632N/A * with respect to the JTabbedPane's coordinate space.
4632N/A */
4632N/A public Rectangle getTabBounds(final JTabbedPane pane, final int i) {
4632N/A ensureCurrentLayout();
4632N/A final Rectangle tabRect = new Rectangle();
4632N/A return getTabBounds(i, tabRect);
4632N/A }
4632N/A
4632N/A public int getTabRunCount(final JTabbedPane pane) {
4632N/A ensureCurrentLayout();
4632N/A return runCount;
4632N/A }
4632N/A
4632N/A /**
4632N/A * Returns the tab index which intersects the specified point
4632N/A * in the JTabbedPane's coordinate space.
4632N/A */
4632N/A public int tabForCoordinate(final JTabbedPane pane, final int x, final int y) {
4632N/A return tabForCoordinate(pane, x, y, true);
4632N/A }
4632N/A
4632N/A private int tabForCoordinate(final JTabbedPane pane, final int x, final int y, final boolean validateIfNecessary) {
4632N/A if (validateIfNecessary) {
4632N/A ensureCurrentLayout();
4632N/A }
4632N/A if (isRunsDirty) {
4632N/A // We didn't recalculate the layout, runs and tabCount may not
4632N/A // line up, bail.
4632N/A return -1;
4632N/A }
4632N/A final Point p = new Point(x, y);
4632N/A
4632N/A if (scrollableTabLayoutEnabled()) {
4632N/A translatePointToTabPanel(x, y, p);
4632N/A final Rectangle viewRect = tabScroller.viewport.getViewRect();
4632N/A if (!viewRect.contains(p)) {
4632N/A return -1;
4632N/A }
4632N/A }
4632N/A final int tabCount = tabPane.getTabCount();
4632N/A for (int i = 0; i < tabCount; i++) {
4632N/A if (rects[i].contains(p.x, p.y)) {
4632N/A return i;
4632N/A }
4632N/A }
4632N/A return -1;
4632N/A }
4632N/A
4632N/A /**
4632N/A * Returns the bounds of the specified tab in the coordinate space
4632N/A * of the JTabbedPane component. This is required because the tab rects
4632N/A * are by default defined in the coordinate space of the component where
4632N/A * they are rendered, which could be the JTabbedPane
4632N/A * (for WRAP_TAB_LAYOUT) or a ScrollableTabPanel (SCROLL_TAB_LAYOUT).
4632N/A * This method should be used whenever the tab rectangle must be relative
4632N/A * to the JTabbedPane itself and the result should be placed in a
4632N/A * designated Rectangle object (rather than instantiating and returning
4632N/A * a new Rectangle each time). The tab index parameter must be a valid
4632N/A * tabbed pane tab index (0 to tab count - 1, inclusive). The destination
4632N/A * rectangle parameter must be a valid <code>Rectangle</code> instance.
4632N/A * The handling of invalid parameters is unspecified.
4632N/A *
4632N/A * @param tabIndex the index of the tab
4632N/A * @param dest the rectangle where the result should be placed
4632N/A * @return the resulting rectangle
4632N/A *
4632N/A * @since 1.4
4632N/A */
4632N/A protected Rectangle getTabBounds(final int tabIndex, final Rectangle dest) {
4632N/A dest.width = rects[tabIndex].width;
4632N/A dest.height = rects[tabIndex].height;
4632N/A
4632N/A if (scrollableTabLayoutEnabled()) { // SCROLL_TAB_LAYOUT
4632N/A // Need to translate coordinates based on viewport location &
4632N/A // view position
4632N/A final Point vpp = tabScroller.viewport.getLocation();
4632N/A final Point viewp = tabScroller.viewport.getViewPosition();
4632N/A dest.x = rects[tabIndex].x + vpp.x - viewp.x;
4632N/A dest.y = rects[tabIndex].y + vpp.y - viewp.y;
4632N/A
4632N/A } else { // WRAP_TAB_LAYOUT
4632N/A dest.x = rects[tabIndex].x;
4632N/A dest.y = rects[tabIndex].y;
4632N/A }
4632N/A return dest;
4632N/A }
4632N/A
4632N/A /**
4632N/A * Returns the index of the tab closest to the passed in location, note
4632N/A * that the returned tab may not contain the location x,y.
4632N/A */
4632N/A private int getClosestTab(final int x, final int y) {
4632N/A int min = 0;
4632N/A final int tabCount = Math.min(rects.length, tabPane.getTabCount());
4632N/A int max = tabCount;
4632N/A final int tabPlacement = tabPane.getTabPlacement();
4632N/A final boolean useX = (tabPlacement == TOP || tabPlacement == BOTTOM);
4632N/A final int want = (useX) ? x : y;
4632N/A
4632N/A while (min != max) {
4632N/A final int current = (max + min) / 2;
4632N/A int minLoc;
4632N/A int maxLoc;
4632N/A
4632N/A if (useX) {
4632N/A minLoc = rects[current].x;
4632N/A maxLoc = minLoc + rects[current].width;
4632N/A } else {
4632N/A minLoc = rects[current].y;
4632N/A maxLoc = minLoc + rects[current].height;
4632N/A }
4632N/A if (want < minLoc) {
4632N/A max = current;
4632N/A if (min == max) {
4632N/A return Math.max(0, current - 1);
4632N/A }
4632N/A } else if (want >= maxLoc) {
4632N/A min = current;
4632N/A if (max - min <= 1) {
4632N/A return Math.max(current + 1, tabCount - 1);
4632N/A }
4632N/A } else {
4632N/A return current;
4632N/A }
4632N/A }
4632N/A return min;
4632N/A }
4632N/A
4632N/A /**
4632N/A * Returns a point which is translated from the specified point in the
4632N/A * JTabbedPane's coordinate space to the coordinate space of the
4632N/A * ScrollableTabPanel. This is used for SCROLL_TAB_LAYOUT ONLY.
4632N/A */
4632N/A private Point translatePointToTabPanel(final int srcx, final int srcy, final Point dest) {
4632N/A final Point vpp = tabScroller.viewport.getLocation();
4632N/A final Point viewp = tabScroller.viewport.getViewPosition();
4632N/A dest.x = srcx - vpp.x + viewp.x;
4632N/A dest.y = srcy - vpp.y + viewp.y;
4632N/A return dest;
4632N/A }
4632N/A
4632N/A// BasicTabbedPaneUI methods
4632N/A
4632N/A protected Component getVisibleComponent() {
4632N/A return visibleComponent;
4632N/A }
4632N/A
4632N/A protected void setVisibleComponent(final Component component) {
4632N/A if (visibleComponent != null && visibleComponent != component && visibleComponent.getParent() == tabPane && visibleComponent.isVisible()) {
4632N/A
4632N/A visibleComponent.setVisible(false);
4632N/A }
4632N/A if (component != null && !component.isVisible()) {
4632N/A component.setVisible(true);
4632N/A }
4632N/A visibleComponent = component;
4632N/A }
4632N/A
4632N/A protected void assureRectsCreated(final int tabCount) {
4632N/A final int rectArrayLen = rects.length;
4632N/A if (tabCount != rectArrayLen) {
4632N/A final Rectangle[] tempRectArray = new Rectangle[tabCount];
4632N/A System.arraycopy(rects, 0, tempRectArray, 0, Math.min(rectArrayLen, tabCount));
4632N/A rects = tempRectArray;
4632N/A for (int rectIndex = rectArrayLen; rectIndex < tabCount; rectIndex++) {
4632N/A rects[rectIndex] = new Rectangle();
4632N/A }
4632N/A }
4632N/A
4632N/A }
4632N/A
4632N/A protected void expandTabRunsArray() {
4632N/A final int rectLen = tabRuns.length;
4632N/A final int[] newArray = new int[rectLen + 10];
4632N/A System.arraycopy(tabRuns, 0, newArray, 0, runCount);
4632N/A tabRuns = newArray;
4632N/A }
4632N/A
4632N/A protected int getRunForTab(final int tabCount, final int tabIndex) {
4632N/A for (int i = 0; i < runCount; i++) {
4632N/A final int first = tabRuns[i];
4632N/A final int last = lastTabInRun(tabCount, i);
4632N/A if (tabIndex >= first && tabIndex <= last) {
4632N/A return i;
4632N/A }
4632N/A }
4632N/A return 0;
4632N/A }
4632N/A
4632N/A protected int lastTabInRun(final int tabCount, final int run) {
4632N/A if (runCount == 1) {
4632N/A return tabCount - 1;
4632N/A }
4632N/A final int nextRun = (run == runCount - 1 ? 0 : run + 1);
4632N/A if (tabRuns[nextRun] == 0) {
4632N/A return tabCount - 1;
4632N/A }
4632N/A return tabRuns[nextRun] - 1;
4632N/A }
4632N/A
4632N/A protected int getTabRunOverlay(final int tabPlacement) {
4632N/A return tabRunOverlay;
4632N/A }
4632N/A
4632N/A protected int getTabRunIndent(final int tabPlacement, final int run) {
4632N/A return 0;
4632N/A }
4632N/A
4632N/A protected boolean shouldPadTabRun(final int tabPlacement, final int run) {
4632N/A return runCount > 1;
4632N/A }
4632N/A
4632N/A protected boolean shouldRotateTabRuns(final int tabPlacement) {
4632N/A return true;
4632N/A }
4632N/A
4632N/A protected Icon getIconForTab(final int tabIndex) {
4632N/A return (!tabPane.isEnabled() || !tabPane.isEnabledAt(tabIndex)) ? tabPane.getDisabledIconAt(tabIndex) : tabPane.getIconAt(tabIndex);
4632N/A }
4632N/A
4632N/A /**
4632N/A * Returns the text View object required to render stylized text (HTML) for
4632N/A * the specified tab or null if no specialized text rendering is needed
4632N/A * for this tab. This is provided to support html rendering inside tabs.
4632N/A *
4632N/A * @param tabIndex the index of the tab
4632N/A * @return the text view to render the tab's text or null if no
4632N/A * specialized rendering is required
4632N/A *
4632N/A * @since 1.4
4632N/A */
4632N/A protected View getTextViewForTab(final int tabIndex) {
4632N/A if (htmlViews != null) {
4632N/A return htmlViews.elementAt(tabIndex);
4632N/A }
4632N/A return null;
4632N/A }
4632N/A
4632N/A protected int calculateTabHeight(final int tabPlacement, final int tabIndex, final int fontHeight) {
4632N/A int height = 0;
4632N/A final Component c = tabPane.getTabComponentAt(tabIndex);
4632N/A if (c != null) {
4632N/A height = c.getPreferredSize().height;
4632N/A } else {
4632N/A final View v = getTextViewForTab(tabIndex);
4632N/A if (v != null) {
4632N/A // html
4632N/A height += (int)v.getPreferredSpan(View.Y_AXIS);
4632N/A } else {
4632N/A // plain text
4632N/A height += fontHeight;
4632N/A }
4632N/A final Icon icon = getIconForTab(tabIndex);
4632N/A
4632N/A if (icon != null) {
4632N/A height = Math.max(height, icon.getIconHeight());
4632N/A }
4632N/A }
4632N/A final Insets tabInsets = getTabInsets(tabPlacement, tabIndex);
4632N/A height += tabInsets.top + tabInsets.bottom + 2;
4632N/A return height;
4632N/A }
4632N/A
4632N/A protected int calculateMaxTabHeight(final int tabPlacement) {
4632N/A final FontMetrics metrics = getFontMetrics();
4632N/A final int tabCount = tabPane.getTabCount();
4632N/A int result = 0;
4632N/A final int fontHeight = metrics.getHeight();
4632N/A for (int i = 0; i < tabCount; i++) {
4632N/A result = Math.max(calculateTabHeight(tabPlacement, i, fontHeight), result);
4632N/A }
4632N/A return result;
4632N/A }
4632N/A
4632N/A protected int calculateTabWidth(final int tabPlacement, final int tabIndex, final FontMetrics metrics) {
4632N/A final Insets tabInsets = getTabInsets(tabPlacement, tabIndex);
4632N/A int width = tabInsets.left + tabInsets.right + 3;
4632N/A final Component tabComponent = tabPane.getTabComponentAt(tabIndex);
4632N/A if (tabComponent != null) {
4632N/A width += tabComponent.getPreferredSize().width;
4632N/A } else {
4632N/A final Icon icon = getIconForTab(tabIndex);
4632N/A if (icon != null) {
4632N/A width += icon.getIconWidth() + textIconGap;
4632N/A }
4632N/A final View v = getTextViewForTab(tabIndex);
4632N/A if (v != null) {
4632N/A // html
4632N/A width += (int)v.getPreferredSpan(View.X_AXIS);
4632N/A } else {
4632N/A // plain text
4632N/A final String title = tabPane.getTitleAt(tabIndex);
4632N/A width += SwingUtilities2.stringWidth(tabPane, metrics, title);
4632N/A }
4632N/A }
4632N/A return width;
4632N/A }
4632N/A
4632N/A protected int calculateMaxTabWidth(final int tabPlacement) {
4632N/A final FontMetrics metrics = getFontMetrics();
4632N/A final int tabCount = tabPane.getTabCount();
4632N/A int result = 0;
4632N/A for (int i = 0; i < tabCount; i++) {
4632N/A result = Math.max(calculateTabWidth(tabPlacement, i, metrics), result);
4632N/A }
4632N/A return result;
4632N/A }
4632N/A
4632N/A protected int calculateTabAreaHeight(final int tabPlacement, final int horizRunCount, final int maxTabHeight) {
4632N/A final Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
4632N/A final int tabRunOverlay = getTabRunOverlay(tabPlacement);
4632N/A return (horizRunCount > 0 ? horizRunCount * (maxTabHeight - tabRunOverlay) + tabRunOverlay + tabAreaInsets.top + tabAreaInsets.bottom : 0);
4632N/A }
4632N/A
4632N/A protected int calculateTabAreaWidth(final int tabPlacement, final int vertRunCount, final int maxTabWidth) {
4632N/A final Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
4632N/A final int tabRunOverlay = getTabRunOverlay(tabPlacement);
4632N/A return (vertRunCount > 0 ? vertRunCount * (maxTabWidth - tabRunOverlay) + tabRunOverlay + tabAreaInsets.left + tabAreaInsets.right : 0);
4632N/A }
4632N/A
4632N/A protected Insets getTabInsets(final int tabPlacement, final int tabIndex) {
4632N/A return tabInsets;
4632N/A }
4632N/A
4632N/A protected Insets getSelectedTabPadInsets(final int tabPlacement) {
4632N/A rotateInsets(selectedTabPadInsets, currentPadInsets, tabPlacement);
4632N/A return currentPadInsets;
4632N/A }
4632N/A
4632N/A protected Insets getTabAreaInsets(final int tabPlacement) {
4632N/A rotateInsets(tabAreaInsets, currentTabAreaInsets, tabPlacement);
4632N/A return currentTabAreaInsets;
4632N/A }
4632N/A
4632N/A protected Insets getContentBorderInsets(final int tabPlacement) {
4632N/A return contentBorderInsets;
4632N/A }
4632N/A
4632N/A protected FontMetrics getFontMetrics() {
4632N/A final Font font = tabPane.getFont();
4632N/A return tabPane.getFontMetrics(font);
4632N/A }
4632N/A
4632N/A// Tab Navigation methods
4632N/A
4632N/A protected void navigateSelectedTab(final int direction) {
4632N/A final int tabPlacement = tabPane.getTabPlacement();
4632N/A final int current = DefaultLookup.getBoolean(tabPane, this, "TabbedPane.selectionFollowsFocus", true) ? tabPane.getSelectedIndex() : getFocusIndex();
4632N/A final int tabCount = tabPane.getTabCount();
4632N/A final boolean leftToRight = AquaUtils.isLeftToRight(tabPane);
4632N/A
4632N/A // If we have no tabs then don't navigate.
4632N/A if (tabCount <= 0) {
4632N/A return;
4632N/A }
4632N/A
4632N/A int offset;
4632N/A switch (tabPlacement) {
4632N/A case LEFT:
4632N/A case RIGHT:
4632N/A switch (direction) {
4632N/A case NEXT:
4632N/A selectNextTab(current);
4632N/A break;
4632N/A case PREVIOUS:
4632N/A selectPreviousTab(current);
4632N/A break;
4632N/A case NORTH:
4632N/A selectPreviousTabInRun(current);
4632N/A break;
4632N/A case SOUTH:
4632N/A selectNextTabInRun(current);
4632N/A break;
4632N/A case WEST:
4632N/A offset = getTabRunOffset(tabPlacement, tabCount, current, false);
4632N/A selectAdjacentRunTab(tabPlacement, current, offset);
4632N/A break;
4632N/A case EAST:
4632N/A offset = getTabRunOffset(tabPlacement, tabCount, current, true);
4632N/A selectAdjacentRunTab(tabPlacement, current, offset);
4632N/A break;
4632N/A default:
4632N/A }
4632N/A break;
4632N/A case BOTTOM:
4632N/A case TOP:
4632N/A default:
4632N/A switch (direction) {
4632N/A case NEXT:
4632N/A selectNextTab(current);
4632N/A break;
4632N/A case PREVIOUS:
4632N/A selectPreviousTab(current);
4632N/A break;
4632N/A case NORTH:
4632N/A offset = getTabRunOffset(tabPlacement, tabCount, current, false);
4632N/A selectAdjacentRunTab(tabPlacement, current, offset);
4632N/A break;
4632N/A case SOUTH:
4632N/A offset = getTabRunOffset(tabPlacement, tabCount, current, true);
4632N/A selectAdjacentRunTab(tabPlacement, current, offset);
4632N/A break;
4632N/A case EAST:
4632N/A if (leftToRight) {
4632N/A selectNextTabInRun(current);
4632N/A } else {
4632N/A selectPreviousTabInRun(current);
4632N/A }
4632N/A break;
4632N/A case WEST:
4632N/A if (leftToRight) {
4632N/A selectPreviousTabInRun(current);
4632N/A } else {
4632N/A selectNextTabInRun(current);
4632N/A }
4632N/A break;
4632N/A default:
4632N/A }
4632N/A }
4632N/A }
4632N/A
4632N/A protected void selectNextTabInRun(final int current) {
4632N/A final int tabCount = tabPane.getTabCount();
4632N/A int tabIndex = getNextTabIndexInRun(tabCount, current);
4632N/A
4632N/A while (tabIndex != current && !tabPane.isEnabledAt(tabIndex)) {
4632N/A tabIndex = getNextTabIndexInRun(tabCount, tabIndex);
4632N/A }
4632N/A navigateTo(tabIndex);
4632N/A }
4632N/A
4632N/A protected void selectPreviousTabInRun(final int current) {
4632N/A final int tabCount = tabPane.getTabCount();
4632N/A int tabIndex = getPreviousTabIndexInRun(tabCount, current);
4632N/A
4632N/A while (tabIndex != current && !tabPane.isEnabledAt(tabIndex)) {
4632N/A tabIndex = getPreviousTabIndexInRun(tabCount, tabIndex);
4632N/A }
4632N/A navigateTo(tabIndex);
4632N/A }
4632N/A
4632N/A protected void selectNextTab(final int current) {
4632N/A int tabIndex = getNextTabIndex(current);
4632N/A
4632N/A while (tabIndex != current && !tabPane.isEnabledAt(tabIndex)) {
4632N/A tabIndex = getNextTabIndex(tabIndex);
4632N/A }
4632N/A navigateTo(tabIndex);
4632N/A }
4632N/A
4632N/A protected void selectPreviousTab(final int current) {
4632N/A int tabIndex = getPreviousTabIndex(current);
4632N/A
4632N/A while (tabIndex != current && !tabPane.isEnabledAt(tabIndex)) {
4632N/A tabIndex = getPreviousTabIndex(tabIndex);
4632N/A }
4632N/A navigateTo(tabIndex);
4632N/A }
4632N/A
4632N/A protected void selectAdjacentRunTab(final int tabPlacement, final int tabIndex, final int offset) {
4632N/A if (runCount < 2) {
4632N/A return;
4632N/A }
4632N/A int newIndex;
4632N/A final Rectangle r = rects[tabIndex];
4632N/A switch (tabPlacement) {
4632N/A case LEFT:
4632N/A case RIGHT:
4632N/A newIndex = tabForCoordinate(tabPane, r.x + r.width / 2 + offset, r.y + r.height / 2);
4632N/A break;
4632N/A case BOTTOM:
4632N/A case TOP:
4632N/A default:
4632N/A newIndex = tabForCoordinate(tabPane, r.x + r.width / 2, r.y + r.height / 2 + offset);
4632N/A }
4632N/A if (newIndex != -1) {
4632N/A while (!tabPane.isEnabledAt(newIndex) && newIndex != tabIndex) {
4632N/A newIndex = getNextTabIndex(newIndex);
4632N/A }
4632N/A navigateTo(newIndex);
4632N/A }
4632N/A }
4632N/A
4632N/A private void navigateTo(final int index) {
4632N/A if (DefaultLookup.getBoolean(tabPane, this, "TabbedPane.selectionFollowsFocus", true)) {
4632N/A tabPane.setSelectedIndex(index);
4632N/A } else {
4632N/A // Just move focus (not selection)
4632N/A setFocusIndex(index, true);
4632N/A }
4632N/A }
4632N/A
4632N/A void setFocusIndex(final int index, final boolean repaint) {
4632N/A if (repaint && !isRunsDirty) {
4632N/A repaintTab(focusIndex);
4632N/A focusIndex = index;
4632N/A repaintTab(focusIndex);
4632N/A } else {
4632N/A focusIndex = index;
4632N/A }
4632N/A }
4632N/A
4632N/A /**
4632N/A * Repaints the specified tab.
4632N/A */
4632N/A private void repaintTab(final int index) {
4632N/A // If we're not valid that means we will shortly be validated and
4632N/A // painted, which means we don't have to do anything here.
4632N/A if (!isRunsDirty && index >= 0 && index < tabPane.getTabCount()) {
4632N/A tabPane.repaint(getTabBounds(tabPane, index));
4632N/A }
4632N/A }
4632N/A
4632N/A /**
4632N/A * Makes sure the focusIndex is valid.
4632N/A */
4632N/A private void validateFocusIndex() {
4632N/A if (focusIndex >= tabPane.getTabCount()) {
4632N/A setFocusIndex(tabPane.getSelectedIndex(), false);
4632N/A }
4632N/A }
4632N/A
4632N/A /**
4632N/A * Returns the index of the tab that has focus.
4632N/A *
4632N/A * @return index of tab that has focus
4632N/A * @since 1.5
4632N/A */
4632N/A protected int getFocusIndex() {
4632N/A return focusIndex;
4632N/A }
4632N/A
4632N/A protected int getTabRunOffset(final int tabPlacement, final int tabCount, final int tabIndex, final boolean forward) {
4632N/A final int run = getRunForTab(tabCount, tabIndex);
4632N/A int offset;
4632N/A switch (tabPlacement) {
4632N/A case LEFT: {
4632N/A if (run == 0) {
4632N/A offset = (forward ? -(calculateTabAreaWidth(tabPlacement, runCount, maxTabWidth) - maxTabWidth) : -maxTabWidth);
4632N/A
4632N/A } else if (run == runCount - 1) {
4632N/A offset = (forward ? maxTabWidth : calculateTabAreaWidth(tabPlacement, runCount, maxTabWidth) - maxTabWidth);
4632N/A } else {
4632N/A offset = (forward ? maxTabWidth : -maxTabWidth);
4632N/A }
4632N/A break;
4632N/A }
4632N/A case RIGHT: {
4632N/A if (run == 0) {
4632N/A offset = (forward ? maxTabWidth : calculateTabAreaWidth(tabPlacement, runCount, maxTabWidth) - maxTabWidth);
4632N/A } else if (run == runCount - 1) {
4632N/A offset = (forward ? -(calculateTabAreaWidth(tabPlacement, runCount, maxTabWidth) - maxTabWidth) : -maxTabWidth);
4632N/A } else {
4632N/A offset = (forward ? maxTabWidth : -maxTabWidth);
4632N/A }
4632N/A break;
4632N/A }
4632N/A case BOTTOM: {
4632N/A if (run == 0) {
4632N/A offset = (forward ? maxTabHeight : calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight) - maxTabHeight);
4632N/A } else if (run == runCount - 1) {
4632N/A offset = (forward ? -(calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight) - maxTabHeight) : -maxTabHeight);
4632N/A } else {
4632N/A offset = (forward ? maxTabHeight : -maxTabHeight);
4632N/A }
4632N/A break;
4632N/A }
4632N/A case TOP:
4632N/A default: {
4632N/A if (run == 0) {
4632N/A offset = (forward ? -(calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight) - maxTabHeight) : -maxTabHeight);
4632N/A } else if (run == runCount - 1) {
4632N/A offset = (forward ? maxTabHeight : calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight) - maxTabHeight);
4632N/A } else {
4632N/A offset = (forward ? maxTabHeight : -maxTabHeight);
4632N/A }
4632N/A }
4632N/A }
4632N/A return offset;
4632N/A }
4632N/A
4632N/A protected int getPreviousTabIndex(final int base) {
4632N/A final int tabIndex = (base - 1 >= 0 ? base - 1 : tabPane.getTabCount() - 1);
4632N/A return (tabIndex >= 0 ? tabIndex : 0);
4632N/A }
4632N/A
4632N/A protected int getNextTabIndex(final int base) {
4632N/A return (base + 1) % tabPane.getTabCount();
4632N/A }
4632N/A
4632N/A protected int getNextTabIndexInRun(final int tabCount, final int base) {
4632N/A if (runCount < 2) {
4632N/A return getNextTabIndex(base);
4632N/A }
4632N/A final int currentRun = getRunForTab(tabCount, base);
4632N/A final int next = getNextTabIndex(base);
4632N/A if (next == tabRuns[getNextTabRun(currentRun)]) {
4632N/A return tabRuns[currentRun];
4632N/A }
4632N/A return next;
4632N/A }
4632N/A
4632N/A protected int getPreviousTabIndexInRun(final int tabCount, final int base) {
4632N/A if (runCount < 2) {
4632N/A return getPreviousTabIndex(base);
4632N/A }
4632N/A final int currentRun = getRunForTab(tabCount, base);
4632N/A if (base == tabRuns[currentRun]) {
4632N/A final int previous = tabRuns[getNextTabRun(currentRun)] - 1;
4632N/A return (previous != -1 ? previous : tabCount - 1);
4632N/A }
4632N/A return getPreviousTabIndex(base);
4632N/A }
4632N/A
4632N/A protected int getPreviousTabRun(final int baseRun) {
4632N/A final int runIndex = (baseRun - 1 >= 0 ? baseRun - 1 : runCount - 1);
4632N/A return (runIndex >= 0 ? runIndex : 0);
4632N/A }
4632N/A
4632N/A protected int getNextTabRun(final int baseRun) {
4632N/A return (baseRun + 1) % runCount;
4632N/A }
4632N/A
4632N/A protected static void rotateInsets(final Insets topInsets, final Insets targetInsets, final int targetPlacement) {
4632N/A
4632N/A switch (targetPlacement) {
4632N/A case LEFT:
4632N/A targetInsets.top = topInsets.left;
4632N/A targetInsets.left = topInsets.top;
4632N/A targetInsets.bottom = topInsets.right;
4632N/A targetInsets.right = topInsets.bottom;
4632N/A break;
4632N/A case BOTTOM:
4632N/A targetInsets.top = topInsets.bottom;
4632N/A targetInsets.left = topInsets.left;
4632N/A targetInsets.bottom = topInsets.top;
4632N/A targetInsets.right = topInsets.right;
4632N/A break;
4632N/A case RIGHT:
4632N/A targetInsets.top = topInsets.left;
4632N/A targetInsets.left = topInsets.bottom;
4632N/A targetInsets.bottom = topInsets.right;
4632N/A targetInsets.right = topInsets.top;
4632N/A break;
4632N/A case TOP:
4632N/A default:
4632N/A targetInsets.top = topInsets.top;
4632N/A targetInsets.left = topInsets.left;
4632N/A targetInsets.bottom = topInsets.bottom;
4632N/A targetInsets.right = topInsets.right;
4632N/A }
4632N/A }
4632N/A
4632N/A // REMIND(aim,7/29/98): This method should be made
4632N/A // protected in the next release where
4632N/A // API changes are allowed
4632N/A boolean requestFocusForVisibleComponent() {
4632N/A return SwingUtilities2.tabbedPaneChangeFocusTo(getVisibleComponent());
4632N/A }
4632N/A
4632N/A private static class Actions extends UIAction {
4632N/A final static String NEXT = "navigateNext";
4632N/A final static String PREVIOUS = "navigatePrevious";
4632N/A final static String RIGHT = "navigateRight";
4632N/A final static String LEFT = "navigateLeft";
4632N/A final static String UP = "navigateUp";
4632N/A final static String DOWN = "navigateDown";
4632N/A final static String PAGE_UP = "navigatePageUp";
4632N/A final static String PAGE_DOWN = "navigatePageDown";
4632N/A final static String REQUEST_FOCUS = "requestFocus";
4632N/A final static String REQUEST_FOCUS_FOR_VISIBLE = "requestFocusForVisibleComponent";
4632N/A final static String SET_SELECTED = "setSelectedIndex";
4632N/A final static String SELECT_FOCUSED = "selectTabWithFocus";
4632N/A final static String SCROLL_FORWARD = "scrollTabsForwardAction";
4632N/A final static String SCROLL_BACKWARD = "scrollTabsBackwardAction";
4632N/A
4632N/A Actions(final String key) {
4632N/A super(key);
4632N/A }
4632N/A
4632N/A static Object getUIOfType(final ComponentUI ui, final Class<AquaTabbedPaneCopyFromBasicUI> klass) {
4632N/A if (klass.isInstance(ui)) {
4632N/A return ui;
4632N/A }
4632N/A return null;
4632N/A }
4632N/A
4632N/A public void actionPerformed(final ActionEvent e) {
4632N/A final String key = getName();
4632N/A final JTabbedPane pane = (JTabbedPane)e.getSource();
4632N/A final AquaTabbedPaneCopyFromBasicUI ui = (AquaTabbedPaneCopyFromBasicUI)getUIOfType(pane.getUI(), AquaTabbedPaneCopyFromBasicUI.class);
4632N/A
4632N/A if (ui == null) {
4632N/A return;
4632N/A }
4632N/A
4632N/A if (key == NEXT) {
4632N/A ui.navigateSelectedTab(SwingConstants.NEXT);
4632N/A } else if (key == PREVIOUS) {
4632N/A ui.navigateSelectedTab(SwingConstants.PREVIOUS);
4632N/A } else if (key == RIGHT) {
4632N/A ui.navigateSelectedTab(SwingConstants.EAST);
4632N/A } else if (key == LEFT) {
4632N/A ui.navigateSelectedTab(SwingConstants.WEST);
4632N/A } else if (key == UP) {
4632N/A ui.navigateSelectedTab(SwingConstants.NORTH);
4632N/A } else if (key == DOWN) {
4632N/A ui.navigateSelectedTab(SwingConstants.SOUTH);
4632N/A } else if (key == PAGE_UP) {
4632N/A final int tabPlacement = pane.getTabPlacement();
4632N/A if (tabPlacement == TOP || tabPlacement == BOTTOM) {
4632N/A ui.navigateSelectedTab(SwingConstants.WEST);
4632N/A } else {
4632N/A ui.navigateSelectedTab(SwingConstants.NORTH);
4632N/A }
4632N/A } else if (key == PAGE_DOWN) {
4632N/A final int tabPlacement = pane.getTabPlacement();
4632N/A if (tabPlacement == TOP || tabPlacement == BOTTOM) {
4632N/A ui.navigateSelectedTab(SwingConstants.EAST);
4632N/A } else {
4632N/A ui.navigateSelectedTab(SwingConstants.SOUTH);
4632N/A }
4632N/A } else if (key == REQUEST_FOCUS) {
4632N/A pane.requestFocus();
4632N/A } else if (key == REQUEST_FOCUS_FOR_VISIBLE) {
4632N/A ui.requestFocusForVisibleComponent();
4632N/A } else if (key == SET_SELECTED) {
4632N/A final String command = e.getActionCommand();
4632N/A
4632N/A if (command != null && command.length() > 0) {
4632N/A int mnemonic = e.getActionCommand().charAt(0);
4632N/A if (mnemonic >= 'a' && mnemonic <= 'z') {
4632N/A mnemonic -= ('a' - 'A');
4632N/A }
4632N/A final Integer index = ui.mnemonicToIndexMap.get(new Integer(mnemonic));
4632N/A if (index != null && pane.isEnabledAt(index.intValue())) {
4632N/A pane.setSelectedIndex(index.intValue());
4632N/A }
4632N/A }
4632N/A } else if (key == SELECT_FOCUSED) {
4632N/A final int focusIndex = ui.getFocusIndex();
4632N/A if (focusIndex != -1) {
4632N/A pane.setSelectedIndex(focusIndex);
4632N/A }
4632N/A } else if (key == SCROLL_FORWARD) {
4632N/A if (ui.scrollableTabLayoutEnabled()) {
4632N/A ui.tabScroller.scrollForward(pane.getTabPlacement());
4632N/A }
4632N/A } else if (key == SCROLL_BACKWARD) {
4632N/A if (ui.scrollableTabLayoutEnabled()) {
4632N/A ui.tabScroller.scrollBackward(pane.getTabPlacement());
4632N/A }
4632N/A }
4632N/A }
4632N/A }
4632N/A
4632N/A /**
4632N/A * This class should be treated as a &quot;protected&quot; inner class.
4632N/A * Instantiate it only within subclasses of BasicTabbedPaneUI.
4632N/A */
4632N/A public class TabbedPaneLayout implements LayoutManager {
4632N/A // MACOSX adding accessor for superclass
4632N/A protected Container getTabContainer() {
4632N/A return tabContainer;
4632N/A }
4632N/A // END MACOSX
4632N/A
4632N/A public void addLayoutComponent(final String name, final Component comp) {}
4632N/A
4632N/A public void removeLayoutComponent(final Component comp) {}
4632N/A
4632N/A public Dimension preferredLayoutSize(final Container parent) {
4632N/A return calculateSize(false);
4632N/A }
4632N/A
4632N/A public Dimension minimumLayoutSize(final Container parent) {
4632N/A return calculateSize(true);
4632N/A }
4632N/A
4632N/A protected Dimension calculateSize(final boolean minimum) {
4632N/A final int tabPlacement = tabPane.getTabPlacement();
4632N/A final Insets insets = tabPane.getInsets();
4632N/A final Insets contentInsets = getContentBorderInsets(tabPlacement);
4632N/A final Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
4632N/A
4632N/A final Dimension zeroSize = new Dimension(0, 0);
4632N/A int height = 0;
4632N/A int width = 0;
4632N/A int cWidth = 0;
4632N/A int cHeight = 0;
4632N/A
4632N/A // Determine minimum size required to display largest
4632N/A // child in each dimension
4632N/A //
4632N/A for (int i = 0; i < tabPane.getTabCount(); i++) {
4632N/A final Component component = tabPane.getComponentAt(i);
4632N/A if (component != null) {
4632N/A Dimension size = zeroSize;
4632N/A size = minimum ? component.getMinimumSize() : component.getPreferredSize();
4632N/A
4632N/A if (size != null) {
4632N/A cHeight = Math.max(size.height, cHeight);
4632N/A cWidth = Math.max(size.width, cWidth);
4632N/A }
4632N/A }
4632N/A }
4632N/A // Add content border insets to minimum size
4632N/A width += cWidth;
4632N/A height += cHeight;
4632N/A int tabExtent = 0;
4632N/A
4632N/A // Calculate how much space the tabs will need, based on the
4632N/A // minimum size required to display largest child + content border
4632N/A //
4632N/A switch (tabPlacement) {
4632N/A case LEFT:
4632N/A case RIGHT:
4632N/A height = Math.max(height, calculateMaxTabHeight(tabPlacement));
4632N/A tabExtent = preferredTabAreaWidth(tabPlacement, height - tabAreaInsets.top - tabAreaInsets.bottom);
4632N/A width += tabExtent;
4632N/A break;
4632N/A case TOP:
4632N/A case BOTTOM:
4632N/A default:
4632N/A width = Math.max(width, calculateMaxTabWidth(tabPlacement));
4632N/A tabExtent = preferredTabAreaHeight(tabPlacement, width - tabAreaInsets.left - tabAreaInsets.right);
4632N/A height += tabExtent;
4632N/A }
4632N/A return new Dimension(width + insets.left + insets.right + contentInsets.left + contentInsets.right, height + insets.bottom + insets.top + contentInsets.top + contentInsets.bottom);
4632N/A
4632N/A }
4632N/A
4632N/A protected int preferredTabAreaHeight(final int tabPlacement, final int width) {
4632N/A final FontMetrics metrics = getFontMetrics();
4632N/A final int tabCount = tabPane.getTabCount();
4632N/A int total = 0;
4632N/A if (tabCount > 0) {
4632N/A int rows = 1;
4632N/A int x = 0;
4632N/A
4632N/A final int maxTabHeight = calculateMaxTabHeight(tabPlacement);
4632N/A
4632N/A for (int i = 0; i < tabCount; i++) {
4632N/A final int tabWidth = calculateTabWidth(tabPlacement, i, metrics);
4632N/A
4632N/A if (x != 0 && x + tabWidth > width) {
4632N/A rows++;
4632N/A x = 0;
4632N/A }
4632N/A x += tabWidth;
4632N/A }
4632N/A total = calculateTabAreaHeight(tabPlacement, rows, maxTabHeight);
4632N/A }
4632N/A return total;
4632N/A }
4632N/A
4632N/A protected int preferredTabAreaWidth(final int tabPlacement, final int height) {
4632N/A final FontMetrics metrics = getFontMetrics();
4632N/A final int tabCount = tabPane.getTabCount();
4632N/A int total = 0;
4632N/A if (tabCount > 0) {
4632N/A int columns = 1;
4632N/A int y = 0;
4632N/A final int fontHeight = metrics.getHeight();
4632N/A
4632N/A maxTabWidth = calculateMaxTabWidth(tabPlacement);
4632N/A
4632N/A for (int i = 0; i < tabCount; i++) {
4632N/A final int tabHeight = calculateTabHeight(tabPlacement, i, fontHeight);
4632N/A
4632N/A if (y != 0 && y + tabHeight > height) {
4632N/A columns++;
4632N/A y = 0;
4632N/A }
4632N/A y += tabHeight;
4632N/A }
4632N/A total = calculateTabAreaWidth(tabPlacement, columns, maxTabWidth);
4632N/A }
4632N/A return total;
4632N/A }
4632N/A
4632N/A public void layoutContainer(final Container parent) {
4632N/A /* Some of the code in this method deals with changing the
4632N/A * visibility of components to hide and show the contents for the
4632N/A * selected tab. This is older code that has since been duplicated
4632N/A * in JTabbedPane.fireStateChanged(), so as to allow visibility
4632N/A * changes to happen sooner (see the note there). This code remains
4632N/A * for backward compatibility as there are some cases, such as
4632N/A * subclasses that don't fireStateChanged() where it may be used.
4632N/A * Any changes here need to be kept in synch with
4632N/A * JTabbedPane.fireStateChanged().
4632N/A */
4632N/A
4632N/A setRolloverTab(-1);
4632N/A
4632N/A final int tabPlacement = tabPane.getTabPlacement();
4632N/A final Insets insets = tabPane.getInsets();
4632N/A final int selectedIndex = tabPane.getSelectedIndex();
4632N/A final Component visibleComponent = getVisibleComponent();
4632N/A
4632N/A calculateLayoutInfo();
4632N/A
4632N/A Component selectedComponent = null;
4632N/A if (selectedIndex < 0) {
4632N/A if (visibleComponent != null) {
4632N/A // The last tab was removed, so remove the component
4632N/A setVisibleComponent(null);
4632N/A }
4632N/A } else {
4632N/A selectedComponent = tabPane.getComponentAt(selectedIndex);
4632N/A }
4632N/A int cx, cy, cw, ch;
4632N/A int totalTabWidth = 0;
4632N/A int totalTabHeight = 0;
4632N/A final Insets contentInsets = getContentBorderInsets(tabPlacement);
4632N/A
4632N/A boolean shouldChangeFocus = false;
4632N/A
4632N/A // In order to allow programs to use a single component
4632N/A // as the display for multiple tabs, we will not change
4632N/A // the visible compnent if the currently selected tab
4632N/A // has a null component. This is a bit dicey, as we don't
4632N/A // explicitly state we support this in the spec, but since
4632N/A // programs are now depending on this, we're making it work.
4632N/A //
4632N/A if (selectedComponent != null) {
4632N/A if (selectedComponent != visibleComponent && visibleComponent != null) {
4632N/A if (SwingUtilities.findFocusOwner(visibleComponent) != null) {
4632N/A shouldChangeFocus = true;
4632N/A }
4632N/A }
4632N/A setVisibleComponent(selectedComponent);
4632N/A }
4632N/A
4632N/A final Rectangle bounds = tabPane.getBounds();
4632N/A final int numChildren = tabPane.getComponentCount();
4632N/A
4632N/A if (numChildren > 0) {
4632N/A
4632N/A switch (tabPlacement) {
4632N/A case LEFT:
4632N/A totalTabWidth = calculateTabAreaWidth(tabPlacement, runCount, maxTabWidth);
4632N/A cx = insets.left + totalTabWidth + contentInsets.left;
4632N/A cy = insets.top + contentInsets.top;
4632N/A break;
4632N/A case RIGHT:
4632N/A totalTabWidth = calculateTabAreaWidth(tabPlacement, runCount, maxTabWidth);
4632N/A cx = insets.left + contentInsets.left;
4632N/A cy = insets.top + contentInsets.top;
4632N/A break;
4632N/A case BOTTOM:
4632N/A totalTabHeight = calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight);
4632N/A cx = insets.left + contentInsets.left;
4632N/A cy = insets.top + contentInsets.top;
4632N/A break;
4632N/A case TOP:
4632N/A default:
4632N/A totalTabHeight = calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight);
4632N/A cx = insets.left + contentInsets.left;
4632N/A cy = insets.top + totalTabHeight + contentInsets.top;
4632N/A }
4632N/A
4632N/A cw = bounds.width - totalTabWidth - insets.left - insets.right - contentInsets.left - contentInsets.right;
4632N/A ch = bounds.height - totalTabHeight - insets.top - insets.bottom - contentInsets.top - contentInsets.bottom;
4632N/A
4632N/A for (int i = 0; i < numChildren; i++) {
4632N/A final Component child = tabPane.getComponent(i);
4632N/A if (child == tabContainer) {
4632N/A
4632N/A final int tabContainerWidth = totalTabWidth == 0 ? bounds.width : totalTabWidth + insets.left + insets.right + contentInsets.left + contentInsets.right;
4632N/A final int tabContainerHeight = totalTabHeight == 0 ? bounds.height : totalTabHeight + insets.top + insets.bottom + contentInsets.top + contentInsets.bottom;
4632N/A
4632N/A int tabContainerX = 0;
4632N/A int tabContainerY = 0;
4632N/A if (tabPlacement == BOTTOM) {
4632N/A tabContainerY = bounds.height - tabContainerHeight;
4632N/A } else if (tabPlacement == RIGHT) {
4632N/A tabContainerX = bounds.width - tabContainerWidth;
4632N/A }
4632N/A child.setBounds(tabContainerX, tabContainerY, tabContainerWidth, tabContainerHeight);
4632N/A } else {
4632N/A child.setBounds(cx, cy, cw, ch);
4632N/A }
4632N/A }
4632N/A }
4632N/A layoutTabComponents();
4632N/A if (shouldChangeFocus) {
4632N/A if (!requestFocusForVisibleComponent()) {
4632N/A tabPane.requestFocus();
4632N/A }
4632N/A }
4632N/A }
4632N/A
4632N/A public void calculateLayoutInfo() {
4632N/A final int tabCount = tabPane.getTabCount();
4632N/A assureRectsCreated(tabCount);
4632N/A calculateTabRects(tabPane.getTabPlacement(), tabCount);
4632N/A isRunsDirty = false;
4632N/A }
4632N/A
4632N/A protected void layoutTabComponents() {
4632N/A if (tabContainer == null) {
4632N/A return;
4632N/A }
4632N/A final Rectangle rect = new Rectangle();
4632N/A final Point delta = new Point(-tabContainer.getX(), -tabContainer.getY());
4632N/A if (scrollableTabLayoutEnabled()) {
4632N/A translatePointToTabPanel(0, 0, delta);
4632N/A }
4632N/A for (int i = 0; i < tabPane.getTabCount(); i++) {
4632N/A final Component c = tabPane.getTabComponentAt(i);
4632N/A if (c == null) {
4632N/A continue;
4632N/A }
4632N/A getTabBounds(i, rect);
4632N/A final Dimension preferredSize = c.getPreferredSize();
4632N/A final Insets insets = getTabInsets(tabPane.getTabPlacement(), i);
4632N/A final int outerX = rect.x + insets.left + delta.x;
4632N/A final int outerY = rect.y + insets.top + delta.y;
4632N/A final int outerWidth = rect.width - insets.left - insets.right;
4632N/A final int outerHeight = rect.height - insets.top - insets.bottom;
4632N/A // centralize component
4632N/A final int x = outerX + (outerWidth - preferredSize.width) / 2;
4632N/A final int y = outerY + (outerHeight - preferredSize.height) / 2;
4632N/A final int tabPlacement = tabPane.getTabPlacement();
4632N/A final boolean isSeleceted = i == tabPane.getSelectedIndex();
4632N/A c.setBounds(x + getTabLabelShiftX(tabPlacement, i, isSeleceted), y + getTabLabelShiftY(tabPlacement, i, isSeleceted), preferredSize.width, preferredSize.height);
4632N/A }
4632N/A }
4632N/A
4632N/A protected void calculateTabRects(final int tabPlacement, final int tabCount) {
4632N/A final FontMetrics metrics = getFontMetrics();
4632N/A final Dimension size = tabPane.getSize();
4632N/A final Insets insets = tabPane.getInsets();
4632N/A final Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
4632N/A final int fontHeight = metrics.getHeight();
4632N/A final int selectedIndex = tabPane.getSelectedIndex();
4632N/A int tabRunOverlay;
4632N/A int i, j;
4632N/A int x, y;
4632N/A int returnAt;
4632N/A boolean verticalTabRuns = (tabPlacement == LEFT || tabPlacement == RIGHT);
4632N/A boolean leftToRight = AquaUtils.isLeftToRight(tabPane);
4632N/A
4632N/A //
4632N/A // Calculate bounds within which a tab run must fit
4632N/A //
4632N/A switch (tabPlacement) {
4632N/A case LEFT:
4632N/A maxTabWidth = calculateMaxTabWidth(tabPlacement);
4632N/A x = insets.left + tabAreaInsets.left;
4632N/A y = insets.top + tabAreaInsets.top;
4632N/A returnAt = size.height - (insets.bottom + tabAreaInsets.bottom);
4632N/A break;
4632N/A case RIGHT:
4632N/A maxTabWidth = calculateMaxTabWidth(tabPlacement);
4632N/A x = size.width - insets.right - tabAreaInsets.right - maxTabWidth;
4632N/A y = insets.top + tabAreaInsets.top;
4632N/A returnAt = size.height - (insets.bottom + tabAreaInsets.bottom);
4632N/A break;
4632N/A case BOTTOM:
4632N/A maxTabHeight = calculateMaxTabHeight(tabPlacement);
4632N/A x = insets.left + tabAreaInsets.left;
4632N/A y = size.height - insets.bottom - tabAreaInsets.bottom - maxTabHeight;
4632N/A returnAt = size.width - (insets.right + tabAreaInsets.right);
4632N/A break;
4632N/A case TOP:
4632N/A default:
4632N/A maxTabHeight = calculateMaxTabHeight(tabPlacement);
4632N/A x = insets.left + tabAreaInsets.left;
4632N/A y = insets.top + tabAreaInsets.top;
4632N/A returnAt = size.width - (insets.right + tabAreaInsets.right);
4632N/A break;
4632N/A }
4632N/A
4632N/A tabRunOverlay = getTabRunOverlay(tabPlacement);
4632N/A
4632N/A runCount = 0;
4632N/A selectedRun = -1;
4632N/A
4632N/A if (tabCount == 0) {
4632N/A return;
4632N/A }
4632N/A
4632N/A // Run through tabs and partition them into runs
4632N/A Rectangle rect;
4632N/A for (i = 0; i < tabCount; i++) {
4632N/A rect = rects[i];
4632N/A
4632N/A if (!verticalTabRuns) {
4632N/A // Tabs on TOP or BOTTOM....
4632N/A if (i > 0) {
4632N/A rect.x = rects[i - 1].x + rects[i - 1].width;
4632N/A } else {
4632N/A tabRuns[0] = 0;
4632N/A runCount = 1;
4632N/A maxTabWidth = 0;
4632N/A rect.x = x;
4632N/A }
4632N/A rect.width = calculateTabWidth(tabPlacement, i, metrics);
4632N/A maxTabWidth = Math.max(maxTabWidth, rect.width);
4632N/A
4632N/A // Never move a TAB down a run if it is in the first column.
4632N/A // Even if there isn't enough room, moving it to a fresh
4632N/A // line won't help.
4632N/A if (rect.x != 2 + insets.left && rect.x + rect.width > returnAt) {
4632N/A if (runCount > tabRuns.length - 1) {
4632N/A expandTabRunsArray();
4632N/A }
4632N/A tabRuns[runCount] = i;
4632N/A runCount++;
4632N/A rect.x = x;
4632N/A }
4632N/A // Initialize y position in case there's just one run
4632N/A rect.y = y;
4632N/A rect.height = maxTabHeight/* - 2*/;
4632N/A
4632N/A } else {
4632N/A // Tabs on LEFT or RIGHT...
4632N/A if (i > 0) {
4632N/A rect.y = rects[i - 1].y + rects[i - 1].height;
4632N/A } else {
4632N/A tabRuns[0] = 0;
4632N/A runCount = 1;
4632N/A maxTabHeight = 0;
4632N/A rect.y = y;
4632N/A }
4632N/A rect.height = calculateTabHeight(tabPlacement, i, fontHeight);
4632N/A maxTabHeight = Math.max(maxTabHeight, rect.height);
4632N/A
4632N/A // Never move a TAB over a run if it is in the first run.
4632N/A // Even if there isn't enough room, moving it to a fresh
4632N/A // column won't help.
4632N/A if (rect.y != 2 + insets.top && rect.y + rect.height > returnAt) {
4632N/A if (runCount > tabRuns.length - 1) {
4632N/A expandTabRunsArray();
4632N/A }
4632N/A tabRuns[runCount] = i;
4632N/A runCount++;
4632N/A rect.y = y;
4632N/A }
4632N/A // Initialize x position in case there's just one column
4632N/A rect.x = x;
4632N/A rect.width = maxTabWidth/* - 2*/;
4632N/A
4632N/A }
4632N/A if (i == selectedIndex) {
4632N/A selectedRun = runCount - 1;
4632N/A }
4632N/A }
4632N/A
4632N/A if (runCount > 1) {
4632N/A // Re-distribute tabs in case last run has leftover space
4632N/A normalizeTabRuns(tabPlacement, tabCount, verticalTabRuns ? y : x, returnAt);
4632N/A
4632N/A selectedRun = getRunForTab(tabCount, selectedIndex);
4632N/A
4632N/A // Rotate run array so that selected run is first
4632N/A if (shouldRotateTabRuns(tabPlacement)) {
4632N/A rotateTabRuns(tabPlacement, selectedRun);
4632N/A }
4632N/A }
4632N/A
4632N/A // Step through runs from back to front to calculate
4632N/A // tab y locations and to pad runs appropriately
4632N/A for (i = runCount - 1; i >= 0; i--) {
4632N/A final int start = tabRuns[i];
4632N/A final int next = tabRuns[i == (runCount - 1) ? 0 : i + 1];
4632N/A final int end = (next != 0 ? next - 1 : tabCount - 1);
4632N/A if (!verticalTabRuns) {
4632N/A for (j = start; j <= end; j++) {
4632N/A rect = rects[j];
4632N/A rect.y = y;
4632N/A rect.x += getTabRunIndent(tabPlacement, i);
4632N/A }
4632N/A if (shouldPadTabRun(tabPlacement, i)) {
4632N/A padTabRun(tabPlacement, start, end, returnAt);
4632N/A }
4632N/A if (tabPlacement == BOTTOM) {
4632N/A y -= (maxTabHeight - tabRunOverlay);
4632N/A } else {
4632N/A y += (maxTabHeight - tabRunOverlay);
4632N/A }
4632N/A } else {
4632N/A for (j = start; j <= end; j++) {
4632N/A rect = rects[j];
4632N/A rect.x = x;
4632N/A rect.y += getTabRunIndent(tabPlacement, i);
4632N/A }
4632N/A if (shouldPadTabRun(tabPlacement, i)) {
4632N/A padTabRun(tabPlacement, start, end, returnAt);
4632N/A }
4632N/A if (tabPlacement == RIGHT) {
4632N/A x -= (maxTabWidth - tabRunOverlay);
4632N/A } else {
4632N/A x += (maxTabWidth - tabRunOverlay);
4632N/A }
4632N/A }
4632N/A }
4632N/A
4632N/A // Pad the selected tab so that it appears raised in front
4632N/A padSelectedTab(tabPlacement, selectedIndex);
4632N/A
4632N/A // if right to left and tab placement on the top or
4632N/A // the bottom, flip x positions and adjust by widths
4632N/A if (!leftToRight && !verticalTabRuns) {
4632N/A final int rightMargin = size.width - (insets.right + tabAreaInsets.right);
4632N/A for (i = 0; i < tabCount; i++) {
4632N/A rects[i].x = rightMargin - rects[i].x - rects[i].width;
4632N/A }
4632N/A }
4632N/A }
4632N/A
4632N/A /*
4632N/A * Rotates the run-index array so that the selected run is run[0]
4632N/A */
4632N/A protected void rotateTabRuns(final int tabPlacement, final int selectedRun) {
4632N/A for (int i = 0; i < selectedRun; i++) {
4632N/A final int save = tabRuns[0];
4632N/A for (int j = 1; j < runCount; j++) {
4632N/A tabRuns[j - 1] = tabRuns[j];
4632N/A }
4632N/A tabRuns[runCount - 1] = save;
4632N/A }
4632N/A }
4632N/A
4632N/A protected void normalizeTabRuns(final int tabPlacement, final int tabCount, final int start, final int max) {
4632N/A boolean verticalTabRuns = (tabPlacement == LEFT || tabPlacement == RIGHT);
4632N/A int run = runCount - 1;
4632N/A boolean keepAdjusting = true;
4632N/A double weight = 1.25;
4632N/A
4632N/A // At this point the tab runs are packed to fit as many
4632N/A // tabs as possible, which can leave the last run with a lot
4632N/A // of extra space (resulting in very fat tabs on the last run).
4632N/A // So we'll attempt to distribute this extra space more evenly
4632N/A // across the runs in order to make the runs look more consistent.
4632N/A //
4632N/A // Starting with the last run, determine whether the last tab in
4632N/A // the previous run would fit (generously) in this run; if so,
4632N/A // move tab to current run and shift tabs accordingly. Cycle
4632N/A // through remaining runs using the same algorithm.
4632N/A //
4632N/A while (keepAdjusting) {
4632N/A final int last = lastTabInRun(tabCount, run);
4632N/A final int prevLast = lastTabInRun(tabCount, run - 1);
4632N/A int end;
4632N/A int prevLastLen;
4632N/A
4632N/A if (!verticalTabRuns) {
4632N/A end = rects[last].x + rects[last].width;
4632N/A prevLastLen = (int)(maxTabWidth * weight);
4632N/A } else {
4632N/A end = rects[last].y + rects[last].height;
4632N/A prevLastLen = (int)(maxTabHeight * weight * 2);
4632N/A }
4632N/A
4632N/A // Check if the run has enough extra space to fit the last tab
4632N/A // from the previous row...
4632N/A if (max - end > prevLastLen) {
4632N/A
4632N/A // Insert tab from previous row and shift rest over
4632N/A tabRuns[run] = prevLast;
4632N/A if (!verticalTabRuns) {
4632N/A rects[prevLast].x = start;
4632N/A } else {
4632N/A rects[prevLast].y = start;
4632N/A }
4632N/A for (int i = prevLast + 1; i <= last; i++) {
4632N/A if (!verticalTabRuns) {
4632N/A rects[i].x = rects[i - 1].x + rects[i - 1].width;
4632N/A } else {
4632N/A rects[i].y = rects[i - 1].y + rects[i - 1].height;
4632N/A }
4632N/A }
4632N/A
4632N/A } else if (run == runCount - 1) {
4632N/A // no more room left in last run, so we're done!
4632N/A keepAdjusting = false;
4632N/A }
4632N/A if (run - 1 > 0) {
4632N/A // check previous run next...
4632N/A run -= 1;
4632N/A } else {
4632N/A // check last run again...but require a higher ratio
4632N/A // of extraspace-to-tabsize because we don't want to
4632N/A // end up with too many tabs on the last run!
4632N/A run = runCount - 1;
4632N/A weight += .25;
4632N/A }
4632N/A }
4632N/A }
4632N/A
4632N/A protected void padTabRun(final int tabPlacement, final int start, final int end, final int max) {
4632N/A final Rectangle lastRect = rects[end];
4632N/A if (tabPlacement == TOP || tabPlacement == BOTTOM) {
4632N/A final int runWidth = (lastRect.x + lastRect.width) - rects[start].x;
4632N/A final int deltaWidth = max - (lastRect.x + lastRect.width);
4632N/A final float factor = (float)deltaWidth / (float)runWidth;
4632N/A
4632N/A for (int j = start; j <= end; j++) {
4632N/A final Rectangle pastRect = rects[j];
4632N/A if (j > start) {
4632N/A pastRect.x = rects[j - 1].x + rects[j - 1].width;
4632N/A }
4632N/A pastRect.width += Math.round(pastRect.width * factor);
4632N/A }
4632N/A lastRect.width = max - lastRect.x;
4632N/A } else {
4632N/A final int runHeight = (lastRect.y + lastRect.height) - rects[start].y;
4632N/A final int deltaHeight = max - (lastRect.y + lastRect.height);
4632N/A final float factor = (float)deltaHeight / (float)runHeight;
4632N/A
4632N/A for (int j = start; j <= end; j++) {
4632N/A final Rectangle pastRect = rects[j];
4632N/A if (j > start) {
4632N/A pastRect.y = rects[j - 1].y + rects[j - 1].height;
4632N/A }
4632N/A pastRect.height += Math.round(pastRect.height * factor);
4632N/A }
4632N/A lastRect.height = max - lastRect.y;
4632N/A }
4632N/A }
4632N/A
4632N/A protected void padSelectedTab(final int tabPlacement, final int selectedIndex) {
4632N/A
4632N/A if (selectedIndex >= 0) {
4632N/A final Rectangle selRect = rects[selectedIndex];
4632N/A final Insets padInsets = getSelectedTabPadInsets(tabPlacement);
4632N/A selRect.x -= padInsets.left;
4632N/A selRect.width += (padInsets.left + padInsets.right);
4632N/A selRect.y -= padInsets.top;
4632N/A selRect.height += (padInsets.top + padInsets.bottom);
4632N/A
4632N/A if (!scrollableTabLayoutEnabled()) { // WRAP_TAB_LAYOUT
4632N/A // do not expand selected tab more then necessary
4632N/A final Dimension size = tabPane.getSize();
4632N/A final Insets insets = tabPane.getInsets();
4632N/A
4632N/A if ((tabPlacement == LEFT) || (tabPlacement == RIGHT)) {
4632N/A final int top = insets.top - selRect.y;
4632N/A if (top > 0) {
4632N/A selRect.y += top;
4632N/A selRect.height -= top;
4632N/A }
4632N/A final int bottom = (selRect.y + selRect.height) + insets.bottom - size.height;
4632N/A if (bottom > 0) {
4632N/A selRect.height -= bottom;
4632N/A }
4632N/A } else {
4632N/A final int left = insets.left - selRect.x;
4632N/A if (left > 0) {
4632N/A selRect.x += left;
4632N/A selRect.width -= left;
4632N/A }
4632N/A final int right = (selRect.x + selRect.width) + insets.right - size.width;
4632N/A if (right > 0) {
4632N/A selRect.width -= right;
4632N/A }
4632N/A }
4632N/A }
4632N/A }
4632N/A }
4632N/A }
4632N/A
4632N/A class TabbedPaneScrollLayout extends TabbedPaneLayout {
4632N/A
4632N/A protected int preferredTabAreaHeight(final int tabPlacement, final int width) {
4632N/A return calculateMaxTabHeight(tabPlacement);
4632N/A }
4632N/A
4632N/A protected int preferredTabAreaWidth(final int tabPlacement, final int height) {
4632N/A return calculateMaxTabWidth(tabPlacement);
4632N/A }
4632N/A
4632N/A public void layoutContainer(final Container parent) {
4632N/A /* Some of the code in this method deals with changing the
4632N/A * visibility of components to hide and show the contents for the
4632N/A * selected tab. This is older code that has since been duplicated
4632N/A * in JTabbedPane.fireStateChanged(), so as to allow visibility
4632N/A * changes to happen sooner (see the note there). This code remains
4632N/A * for backward compatibility as there are some cases, such as
4632N/A * subclasses that don't fireStateChanged() where it may be used.
4632N/A * Any changes here need to be kept in synch with
4632N/A * JTabbedPane.fireStateChanged().
4632N/A */
4632N/A
4632N/A setRolloverTab(-1);
4632N/A
4632N/A final int tabPlacement = tabPane.getTabPlacement();
4632N/A final int tabCount = tabPane.getTabCount();
4632N/A final Insets insets = tabPane.getInsets();
4632N/A final int selectedIndex = tabPane.getSelectedIndex();
4632N/A final Component visibleComponent = getVisibleComponent();
4632N/A
4632N/A calculateLayoutInfo();
4632N/A
4632N/A Component selectedComponent = null;
4632N/A if (selectedIndex < 0) {
4632N/A if (visibleComponent != null) {
4632N/A // The last tab was removed, so remove the component
4632N/A setVisibleComponent(null);
4632N/A }
4632N/A } else {
4632N/A selectedComponent = tabPane.getComponentAt(selectedIndex);
4632N/A }
4632N/A
4632N/A if (tabPane.getTabCount() == 0) {
4632N/A tabScroller.croppedEdge.resetParams();
4632N/A tabScroller.scrollForwardButton.setVisible(false);
4632N/A tabScroller.scrollBackwardButton.setVisible(false);
4632N/A return;
4632N/A }
4632N/A
4632N/A boolean shouldChangeFocus = false;
4632N/A
4632N/A // In order to allow programs to use a single component
4632N/A // as the display for multiple tabs, we will not change
4632N/A // the visible compnent if the currently selected tab
4632N/A // has a null component. This is a bit dicey, as we don't
4632N/A // explicitly state we support this in the spec, but since
4632N/A // programs are now depending on this, we're making it work.
4632N/A //
4632N/A if (selectedComponent != null) {
4632N/A if (selectedComponent != visibleComponent && visibleComponent != null) {
4632N/A if (SwingUtilities.findFocusOwner(visibleComponent) != null) {
4632N/A shouldChangeFocus = true;
4632N/A }
4632N/A }
4632N/A setVisibleComponent(selectedComponent);
4632N/A }
4632N/A int tx, ty, tw, th; // tab area bounds
4632N/A int cx, cy, cw, ch; // content area bounds
4632N/A final Insets contentInsets = getContentBorderInsets(tabPlacement);
4632N/A final Rectangle bounds = tabPane.getBounds();
4632N/A final int numChildren = tabPane.getComponentCount();
4632N/A
4632N/A if (numChildren > 0) {
4632N/A switch (tabPlacement) {
4632N/A case LEFT:
4632N/A // calculate tab area bounds
4632N/A tw = calculateTabAreaWidth(tabPlacement, runCount, maxTabWidth);
4632N/A th = bounds.height - insets.top - insets.bottom;
4632N/A tx = insets.left;
4632N/A ty = insets.top;
4632N/A
4632N/A // calculate content area bounds
4632N/A cx = tx + tw + contentInsets.left;
4632N/A cy = ty + contentInsets.top;
4632N/A cw = bounds.width - insets.left - insets.right - tw - contentInsets.left - contentInsets.right;
4632N/A ch = bounds.height - insets.top - insets.bottom - contentInsets.top - contentInsets.bottom;
4632N/A break;
4632N/A case RIGHT:
4632N/A // calculate tab area bounds
4632N/A tw = calculateTabAreaWidth(tabPlacement, runCount, maxTabWidth);
4632N/A th = bounds.height - insets.top - insets.bottom;
4632N/A tx = bounds.width - insets.right - tw;
4632N/A ty = insets.top;
4632N/A
4632N/A // calculate content area bounds
4632N/A cx = insets.left + contentInsets.left;
4632N/A cy = insets.top + contentInsets.top;
4632N/A cw = bounds.width - insets.left - insets.right - tw - contentInsets.left - contentInsets.right;
4632N/A ch = bounds.height - insets.top - insets.bottom - contentInsets.top - contentInsets.bottom;
4632N/A break;
4632N/A case BOTTOM:
4632N/A // calculate tab area bounds
4632N/A tw = bounds.width - insets.left - insets.right;
4632N/A th = calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight);
4632N/A tx = insets.left;
4632N/A ty = bounds.height - insets.bottom - th;
4632N/A
4632N/A // calculate content area bounds
4632N/A cx = insets.left + contentInsets.left;
4632N/A cy = insets.top + contentInsets.top;
4632N/A cw = bounds.width - insets.left - insets.right - contentInsets.left - contentInsets.right;
4632N/A ch = bounds.height - insets.top - insets.bottom - th - contentInsets.top - contentInsets.bottom;
4632N/A break;
4632N/A case TOP:
4632N/A default:
4632N/A // calculate tab area bounds
4632N/A tw = bounds.width - insets.left - insets.right;
4632N/A th = calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight);
4632N/A tx = insets.left;
4632N/A ty = insets.top;
4632N/A
4632N/A // calculate content area bounds
4632N/A cx = tx + contentInsets.left;
4632N/A cy = ty + th + contentInsets.top;
4632N/A cw = bounds.width - insets.left - insets.right - contentInsets.left - contentInsets.right;
4632N/A ch = bounds.height - insets.top - insets.bottom - th - contentInsets.top - contentInsets.bottom;
4632N/A }
4632N/A
4632N/A for (int i = 0; i < numChildren; i++) {
4632N/A final Component child = tabPane.getComponent(i);
4632N/A
4632N/A if (tabScroller != null && child == tabScroller.viewport) {
4632N/A final JViewport viewport = (JViewport)child;
4632N/A final Rectangle viewRect = viewport.getViewRect();
4632N/A int vw = tw;
4632N/A int vh = th;
4632N/A final Dimension butSize = tabScroller.scrollForwardButton.getPreferredSize();
4632N/A switch (tabPlacement) {
4632N/A case LEFT:
4632N/A case RIGHT:
4632N/A final int totalTabHeight = rects[tabCount - 1].y + rects[tabCount - 1].height;
4632N/A if (totalTabHeight > th) {
4632N/A // Allow space for scrollbuttons
4632N/A vh = (th > 2 * butSize.height) ? th - 2 * butSize.height : 0;
4632N/A if (totalTabHeight - viewRect.y <= vh) {
4632N/A // Scrolled to the end, so ensure the viewport size is
4632N/A // such that the scroll offset aligns with a tab
4632N/A vh = totalTabHeight - viewRect.y;
4632N/A }
4632N/A }
4632N/A break;
4632N/A case BOTTOM:
4632N/A case TOP:
4632N/A default:
4632N/A final int totalTabWidth = rects[tabCount - 1].x + rects[tabCount - 1].width;
4632N/A if (totalTabWidth > tw) {
4632N/A // Need to allow space for scrollbuttons
4632N/A vw = (tw > 2 * butSize.width) ? tw - 2 * butSize.width : 0;
4632N/A if (totalTabWidth - viewRect.x <= vw) {
4632N/A // Scrolled to the end, so ensure the viewport size is
4632N/A // such that the scroll offset aligns with a tab
4632N/A vw = totalTabWidth - viewRect.x;
4632N/A }
4632N/A }
4632N/A }
4632N/A child.setBounds(tx, ty, vw, vh);
4632N/A
4632N/A } else if (tabScroller != null && (child == tabScroller.scrollForwardButton || child == tabScroller.scrollBackwardButton)) {
4632N/A final Component scrollbutton = child;
4632N/A final Dimension bsize = scrollbutton.getPreferredSize();
4632N/A int bx = 0;
4632N/A int by = 0;
4632N/A final int bw = bsize.width;
4632N/A final int bh = bsize.height;
4632N/A boolean visible = false;
4632N/A
4632N/A switch (tabPlacement) {
4632N/A case LEFT:
4632N/A case RIGHT:
4632N/A final int totalTabHeight = rects[tabCount - 1].y + rects[tabCount - 1].height;
4632N/A if (totalTabHeight > th) {
4632N/A visible = true;
4632N/A bx = (tabPlacement == LEFT ? tx + tw - bsize.width : tx);
4632N/A by = (child == tabScroller.scrollForwardButton) ? bounds.height - insets.bottom - bsize.height : bounds.height - insets.bottom - 2 * bsize.height;
4632N/A }
4632N/A break;
4632N/A
4632N/A case BOTTOM:
4632N/A case TOP:
4632N/A default:
4632N/A final int totalTabWidth = rects[tabCount - 1].x + rects[tabCount - 1].width;
4632N/A
4632N/A if (totalTabWidth > tw) {
4632N/A visible = true;
4632N/A bx = (child == tabScroller.scrollForwardButton) ? bounds.width - insets.left - bsize.width : bounds.width - insets.left - 2 * bsize.width;
4632N/A by = (tabPlacement == TOP ? ty + th - bsize.height : ty);
4632N/A }
4632N/A }
4632N/A child.setVisible(visible);
4632N/A if (visible) {
4632N/A child.setBounds(bx, by, bw, bh);
4632N/A }
4632N/A
4632N/A } else {
4632N/A // All content children...
4632N/A child.setBounds(cx, cy, cw, ch);
4632N/A }
4632N/A }
4632N/A super.layoutTabComponents();
4632N/A layoutCroppedEdge();
4632N/A if (shouldChangeFocus) {
4632N/A if (!requestFocusForVisibleComponent()) {
4632N/A tabPane.requestFocus();
4632N/A }
4632N/A }
4632N/A }
4632N/A }
4632N/A
4632N/A private void layoutCroppedEdge() {
4632N/A tabScroller.croppedEdge.resetParams();
4632N/A final Rectangle viewRect = tabScroller.viewport.getViewRect();
4632N/A int cropline;
4632N/A for (int i = 0; i < rects.length; i++) {
4632N/A final Rectangle tabRect = rects[i];
4632N/A switch (tabPane.getTabPlacement()) {
4632N/A case LEFT:
4632N/A case RIGHT:
4632N/A cropline = viewRect.y + viewRect.height;
4632N/A if ((tabRect.y < cropline) && (tabRect.y + tabRect.height > cropline)) {
4632N/A tabScroller.croppedEdge.setParams(i, cropline - tabRect.y - 1, -currentTabAreaInsets.left, 0);
4632N/A }
4632N/A break;
4632N/A case TOP:
4632N/A case BOTTOM:
4632N/A default:
4632N/A cropline = viewRect.x + viewRect.width;
4632N/A if ((tabRect.x < cropline - 1) && (tabRect.x + tabRect.width > cropline)) {
4632N/A tabScroller.croppedEdge.setParams(i, cropline - tabRect.x - 1, 0, -currentTabAreaInsets.top);
4632N/A }
4632N/A }
4632N/A }
4632N/A }
4632N/A
4632N/A protected void calculateTabRects(final int tabPlacement, final int tabCount) {
4632N/A final FontMetrics metrics = getFontMetrics();
4632N/A final Dimension size = tabPane.getSize();
4632N/A final Insets insets = tabPane.getInsets();
4632N/A final Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
4632N/A final int fontHeight = metrics.getHeight();
4632N/A final int selectedIndex = tabPane.getSelectedIndex();
4632N/A int i;
4632N/A boolean verticalTabRuns = (tabPlacement == LEFT || tabPlacement == RIGHT);
4632N/A boolean leftToRight = AquaUtils.isLeftToRight(tabPane);
4632N/A final int x = tabAreaInsets.left;
4632N/A final int y = tabAreaInsets.top;
4632N/A int totalWidth = 0;
4632N/A int totalHeight = 0;
4632N/A
4632N/A //
4632N/A // Calculate bounds within which a tab run must fit
4632N/A //
4632N/A switch (tabPlacement) {
4632N/A case LEFT:
4632N/A case RIGHT:
4632N/A maxTabWidth = calculateMaxTabWidth(tabPlacement);
4632N/A break;
4632N/A case BOTTOM:
4632N/A case TOP:
4632N/A default:
4632N/A maxTabHeight = calculateMaxTabHeight(tabPlacement);
4632N/A }
4632N/A
4632N/A runCount = 0;
4632N/A selectedRun = -1;
4632N/A
4632N/A if (tabCount == 0) {
4632N/A return;
4632N/A }
4632N/A
4632N/A selectedRun = 0;
4632N/A runCount = 1;
4632N/A
4632N/A // Run through tabs and lay them out in a single run
4632N/A Rectangle rect;
4632N/A for (i = 0; i < tabCount; i++) {
4632N/A rect = rects[i];
4632N/A
4632N/A if (!verticalTabRuns) {
4632N/A // Tabs on TOP or BOTTOM....
4632N/A if (i > 0) {
4632N/A rect.x = rects[i - 1].x + rects[i - 1].width;
4632N/A } else {
4632N/A tabRuns[0] = 0;
4632N/A maxTabWidth = 0;
4632N/A totalHeight += maxTabHeight;
4632N/A rect.x = x;
4632N/A }
4632N/A rect.width = calculateTabWidth(tabPlacement, i, metrics);
4632N/A totalWidth = rect.x + rect.width;
4632N/A maxTabWidth = Math.max(maxTabWidth, rect.width);
4632N/A
4632N/A rect.y = y;
4632N/A rect.height = maxTabHeight/* - 2*/;
4632N/A
4632N/A } else {
4632N/A // Tabs on LEFT or RIGHT...
4632N/A if (i > 0) {
4632N/A rect.y = rects[i - 1].y + rects[i - 1].height;
4632N/A } else {
4632N/A tabRuns[0] = 0;
4632N/A maxTabHeight = 0;
4632N/A totalWidth = maxTabWidth;
4632N/A rect.y = y;
4632N/A }
4632N/A rect.height = calculateTabHeight(tabPlacement, i, fontHeight);
4632N/A totalHeight = rect.y + rect.height;
4632N/A maxTabHeight = Math.max(maxTabHeight, rect.height);
4632N/A
4632N/A rect.x = x;
4632N/A rect.width = maxTabWidth/* - 2*/;
4632N/A
4632N/A }
4632N/A }
4632N/A
4632N/A if (tabsOverlapBorder) {
4632N/A // Pad the selected tab so that it appears raised in front
4632N/A padSelectedTab(tabPlacement, selectedIndex);
4632N/A }
4632N/A
4632N/A // if right to left and tab placement on the top or
4632N/A // the bottom, flip x positions and adjust by widths
4632N/A if (!leftToRight && !verticalTabRuns) {
4632N/A final int rightMargin = size.width - (insets.right + tabAreaInsets.right);
4632N/A for (i = 0; i < tabCount; i++) {
4632N/A rects[i].x = rightMargin - rects[i].x - rects[i].width;
4632N/A }
4632N/A }
4632N/A tabScroller.tabPanel.setPreferredSize(new Dimension(totalWidth, totalHeight));
4632N/A }
4632N/A }
4632N/A
4632N/A private class ScrollableTabSupport implements ActionListener, ChangeListener {
4632N/A public ScrollableTabViewport viewport;
4632N/A public ScrollableTabPanel tabPanel;
4632N/A public JButton scrollForwardButton;
4632N/A public JButton scrollBackwardButton;
4632N/A public CroppedEdge croppedEdge;
4632N/A public int leadingTabIndex;
4632N/A
4632N/A private final Point tabViewPosition = new Point(0, 0);
4632N/A
4632N/A ScrollableTabSupport(final int tabPlacement) {
4632N/A viewport = new ScrollableTabViewport();
4632N/A tabPanel = new ScrollableTabPanel();
4632N/A viewport.setView(tabPanel);
4632N/A viewport.addChangeListener(this);
4632N/A croppedEdge = new CroppedEdge();
4632N/A createButtons();
4632N/A }
4632N/A
4632N/A /**
4632N/A * Recreates the scroll buttons and adds them to the TabbedPane.
4632N/A */
4632N/A void createButtons() {
4632N/A if (scrollForwardButton != null) {
4632N/A tabPane.remove(scrollForwardButton);
4632N/A scrollForwardButton.removeActionListener(this);
4632N/A tabPane.remove(scrollBackwardButton);
4632N/A scrollBackwardButton.removeActionListener(this);
4632N/A }
4632N/A final int tabPlacement = tabPane.getTabPlacement();
4632N/A if (tabPlacement == TOP || tabPlacement == BOTTOM) {
4632N/A scrollForwardButton = createScrollButton(EAST);
4632N/A scrollBackwardButton = createScrollButton(WEST);
4632N/A
4632N/A } else { // tabPlacement = LEFT || RIGHT
4632N/A scrollForwardButton = createScrollButton(SOUTH);
4632N/A scrollBackwardButton = createScrollButton(NORTH);
4632N/A }
4632N/A scrollForwardButton.addActionListener(this);
4632N/A scrollBackwardButton.addActionListener(this);
4632N/A tabPane.add(scrollForwardButton);
4632N/A tabPane.add(scrollBackwardButton);
4632N/A }
4632N/A
4632N/A public void scrollForward(final int tabPlacement) {
4632N/A final Dimension viewSize = viewport.getViewSize();
4632N/A final Rectangle viewRect = viewport.getViewRect();
4632N/A
4632N/A if (tabPlacement == TOP || tabPlacement == BOTTOM) {
4632N/A if (viewRect.width >= viewSize.width - viewRect.x) {
4632N/A return; // no room left to scroll
4632N/A }
4632N/A } else { // tabPlacement == LEFT || tabPlacement == RIGHT
4632N/A if (viewRect.height >= viewSize.height - viewRect.y) {
4632N/A return;
4632N/A }
4632N/A }
4632N/A setLeadingTabIndex(tabPlacement, leadingTabIndex + 1);
4632N/A }
4632N/A
4632N/A public void scrollBackward(final int tabPlacement) {
4632N/A if (leadingTabIndex == 0) {
4632N/A return; // no room left to scroll
4632N/A }
4632N/A setLeadingTabIndex(tabPlacement, leadingTabIndex - 1);
4632N/A }
4632N/A
4632N/A public void setLeadingTabIndex(final int tabPlacement, final int index) {
4632N/A leadingTabIndex = index;
4632N/A final Dimension viewSize = viewport.getViewSize();
4632N/A final Rectangle viewRect = viewport.getViewRect();
4632N/A
4632N/A switch (tabPlacement) {
4632N/A case TOP:
4632N/A case BOTTOM:
4632N/A tabViewPosition.x = leadingTabIndex == 0 ? 0 : rects[leadingTabIndex].x;
4632N/A
4632N/A if ((viewSize.width - tabViewPosition.x) < viewRect.width) {
4632N/A // We've scrolled to the end, so adjust the viewport size
4632N/A // to ensure the view position remains aligned on a tab boundary
4632N/A final Dimension extentSize = new Dimension(viewSize.width - tabViewPosition.x, viewRect.height);
4632N/A viewport.setExtentSize(extentSize);
4632N/A }
4632N/A break;
4632N/A case LEFT:
4632N/A case RIGHT:
4632N/A tabViewPosition.y = leadingTabIndex == 0 ? 0 : rects[leadingTabIndex].y;
4632N/A
4632N/A if ((viewSize.height - tabViewPosition.y) < viewRect.height) {
4632N/A // We've scrolled to the end, so adjust the viewport size
4632N/A // to ensure the view position remains aligned on a tab boundary
4632N/A final Dimension extentSize = new Dimension(viewRect.width, viewSize.height - tabViewPosition.y);
4632N/A viewport.setExtentSize(extentSize);
4632N/A }
4632N/A }
4632N/A viewport.setViewPosition(tabViewPosition);
4632N/A }
4632N/A
4632N/A public void stateChanged(final ChangeEvent e) {
4632N/A updateView();
4632N/A }
4632N/A
4632N/A private void updateView() {
4632N/A final int tabPlacement = tabPane.getTabPlacement();
4632N/A final int tabCount = tabPane.getTabCount();
4632N/A final Rectangle vpRect = viewport.getBounds();
4632N/A final Dimension viewSize = viewport.getViewSize();
4632N/A final Rectangle viewRect = viewport.getViewRect();
4632N/A
4632N/A leadingTabIndex = getClosestTab(viewRect.x, viewRect.y);
4632N/A
4632N/A // If the tab isn't right aligned, adjust it.
4632N/A if (leadingTabIndex + 1 < tabCount) {
4632N/A switch (tabPlacement) {
4632N/A case TOP:
4632N/A case BOTTOM:
4632N/A if (rects[leadingTabIndex].x < viewRect.x) {
4632N/A leadingTabIndex++;
4632N/A }
4632N/A break;
4632N/A case LEFT:
4632N/A case RIGHT:
4632N/A if (rects[leadingTabIndex].y < viewRect.y) {
4632N/A leadingTabIndex++;
4632N/A }
4632N/A break;
4632N/A }
4632N/A }
4632N/A final Insets contentInsets = getContentBorderInsets(tabPlacement);
4632N/A switch (tabPlacement) {
4632N/A case LEFT:
4632N/A tabPane.repaint(vpRect.x + vpRect.width, vpRect.y, contentInsets.left, vpRect.height);
4632N/A scrollBackwardButton.setEnabled(viewRect.y > 0 && leadingTabIndex > 0);
4632N/A scrollForwardButton.setEnabled(leadingTabIndex < tabCount - 1 && viewSize.height - viewRect.y > viewRect.height);
4632N/A break;
4632N/A case RIGHT:
4632N/A tabPane.repaint(vpRect.x - contentInsets.right, vpRect.y, contentInsets.right, vpRect.height);
4632N/A scrollBackwardButton.setEnabled(viewRect.y > 0 && leadingTabIndex > 0);
4632N/A scrollForwardButton.setEnabled(leadingTabIndex < tabCount - 1 && viewSize.height - viewRect.y > viewRect.height);
4632N/A break;
4632N/A case BOTTOM:
4632N/A tabPane.repaint(vpRect.x, vpRect.y - contentInsets.bottom, vpRect.width, contentInsets.bottom);
4632N/A scrollBackwardButton.setEnabled(viewRect.x > 0 && leadingTabIndex > 0);
4632N/A scrollForwardButton.setEnabled(leadingTabIndex < tabCount - 1 && viewSize.width - viewRect.x > viewRect.width);
4632N/A break;
4632N/A case TOP:
4632N/A default:
4632N/A tabPane.repaint(vpRect.x, vpRect.y + vpRect.height, vpRect.width, contentInsets.top);
4632N/A scrollBackwardButton.setEnabled(viewRect.x > 0 && leadingTabIndex > 0);
4632N/A scrollForwardButton.setEnabled(leadingTabIndex < tabCount - 1 && viewSize.width - viewRect.x > viewRect.width);
4632N/A }
4632N/A }
4632N/A
4632N/A /**
4632N/A * ActionListener for the scroll buttons.
4632N/A */
4632N/A public void actionPerformed(final ActionEvent e) {
4632N/A final ActionMap map = tabPane.getActionMap();
4632N/A
4632N/A if (map != null) {
4632N/A String actionKey;
4632N/A
4632N/A if (e.getSource() == scrollForwardButton) {
4632N/A actionKey = "scrollTabsForwardAction";
4632N/A } else {
4632N/A actionKey = "scrollTabsBackwardAction";
4632N/A }
4632N/A final Action action = map.get(actionKey);
4632N/A
4632N/A if (action != null && action.isEnabled()) {
4632N/A action.actionPerformed(new ActionEvent(tabPane, ActionEvent.ACTION_PERFORMED, null, e.getWhen(), e.getModifiers()));
4632N/A }
4632N/A }
4632N/A }
4632N/A
4632N/A public String toString() {
4632N/A return new String("viewport.viewSize=" + viewport.getViewSize() + "\n" + "viewport.viewRectangle=" + viewport.getViewRect() + "\n" + "leadingTabIndex=" + leadingTabIndex + "\n" + "tabViewPosition=" + tabViewPosition);
4632N/A }
4632N/A
4632N/A }
4632N/A
4632N/A private class ScrollableTabViewport extends JViewport implements UIResource {
4632N/A public ScrollableTabViewport() {
4632N/A super();
4632N/A setName("TabbedPane.scrollableViewport");
4632N/A setScrollMode(SIMPLE_SCROLL_MODE);
4632N/A setOpaque(tabPane.isOpaque());
4632N/A Color bgColor = UIManager.getColor("TabbedPane.tabAreaBackground");
4632N/A if (bgColor == null) {
4632N/A bgColor = tabPane.getBackground();
4632N/A }
4632N/A setBackground(bgColor);
4632N/A }
4632N/A }
4632N/A
4632N/A private class ScrollableTabPanel extends JPanel implements UIResource {
4632N/A public ScrollableTabPanel() {
4632N/A super(null);
4632N/A setOpaque(tabPane.isOpaque());
4632N/A Color bgColor = UIManager.getColor("TabbedPane.tabAreaBackground");
4632N/A if (bgColor == null) {
4632N/A bgColor = tabPane.getBackground();
4632N/A }
4632N/A setBackground(bgColor);
4632N/A }
4632N/A
4632N/A public void paintComponent(final Graphics g) {
4632N/A super.paintComponent(g);
4632N/A AquaTabbedPaneCopyFromBasicUI.this.paintTabArea(g, tabPane.getTabPlacement(), tabPane.getSelectedIndex());
4632N/A if (tabScroller.croppedEdge.isParamsSet() && tabContainer == null) {
4632N/A final Rectangle croppedRect = rects[tabScroller.croppedEdge.getTabIndex()];
4632N/A g.translate(croppedRect.x, croppedRect.y);
4632N/A tabScroller.croppedEdge.paintComponent(g);
4632N/A g.translate(-croppedRect.x, -croppedRect.y);
4632N/A }
4632N/A }
4632N/A
4632N/A public void doLayout() {
4632N/A if (getComponentCount() > 0) {
4632N/A final Component child = getComponent(0);
4632N/A child.setBounds(0, 0, getWidth(), getHeight());
4632N/A }
4632N/A }
4632N/A }
4632N/A
4632N/A private class ScrollableTabButton extends javax.swing.plaf.basic.BasicArrowButton implements UIResource, SwingConstants {
4632N/A public ScrollableTabButton(final int direction) {
4632N/A super(direction, UIManager.getColor("TabbedPane.selected"), UIManager.getColor("TabbedPane.shadow"), UIManager.getColor("TabbedPane.darkShadow"), UIManager.getColor("TabbedPane.highlight"));
4632N/A }
4632N/A }
4632N/A
4632N/A// Controller: event listeners
4632N/A
4632N/A private class Handler implements ChangeListener, ContainerListener, FocusListener, MouseListener, MouseMotionListener, PropertyChangeListener {
4632N/A //
4632N/A // PropertyChangeListener
4632N/A //
4632N/A public void propertyChange(final PropertyChangeEvent e) {
4632N/A final JTabbedPane pane = (JTabbedPane)e.getSource();
4632N/A final String name = e.getPropertyName();
4632N/A final boolean isScrollLayout = scrollableTabLayoutEnabled();
4632N/A if (name == "mnemonicAt") {
4632N/A updateMnemonics();
4632N/A pane.repaint();
4632N/A } else if (name == "displayedMnemonicIndexAt") {
4632N/A pane.repaint();
4632N/A } else if (name == "indexForTitle") {
4632N/A calculatedBaseline = false;
4639N/A updateHtmlViews((Integer) e.getNewValue());
4632N/A } else if (name == "tabLayoutPolicy") {
4632N/A AquaTabbedPaneCopyFromBasicUI.this.uninstallUI(pane);
4632N/A AquaTabbedPaneCopyFromBasicUI.this.installUI(pane);
4632N/A calculatedBaseline = false;
4632N/A } else if (name == "tabPlacement") {
4632N/A if (scrollableTabLayoutEnabled()) {
4632N/A tabScroller.createButtons();
4632N/A }
4632N/A calculatedBaseline = false;
4632N/A } else if (name == "opaque" && isScrollLayout) {
4632N/A final boolean newVal = ((Boolean)e.getNewValue()).booleanValue();
4632N/A tabScroller.tabPanel.setOpaque(newVal);
4632N/A tabScroller.viewport.setOpaque(newVal);
4632N/A } else if (name == "background" && isScrollLayout) {
4632N/A final Color newVal = (Color)e.getNewValue();
4632N/A tabScroller.tabPanel.setBackground(newVal);
4632N/A tabScroller.viewport.setBackground(newVal);
4632N/A final Color newColor = selectedColor == null ? newVal : selectedColor;
4632N/A tabScroller.scrollForwardButton.setBackground(newColor);
4632N/A tabScroller.scrollBackwardButton.setBackground(newColor);
4632N/A } else if (name == "indexForTabComponent") {
4632N/A if (tabContainer != null) {
4632N/A tabContainer.removeUnusedTabComponents();
4632N/A }
4632N/A final Component c = tabPane.getTabComponentAt((Integer)e.getNewValue());
4632N/A if (c != null) {
4632N/A if (tabContainer == null) {
4632N/A installTabContainer();
4632N/A } else {
4632N/A tabContainer.add(c);
4632N/A }
4632N/A }
4632N/A tabPane.revalidate();
4632N/A tabPane.repaint();
4632N/A calculatedBaseline = false;
4639N/A } else if (name == "indexForNullComponent") {
4639N/A isRunsDirty = true;
4639N/A updateHtmlViews((Integer) e.getNewValue());
4632N/A } else if (name == "font") {
4632N/A calculatedBaseline = false;
4632N/A }
4632N/A }
4632N/A
4632N/A //
4632N/A // ChangeListener
4632N/A //
4632N/A public void stateChanged(final ChangeEvent e) {
4632N/A final JTabbedPane tabPane = (JTabbedPane)e.getSource();
4632N/A tabPane.revalidate();
4632N/A tabPane.repaint();
4632N/A
4632N/A setFocusIndex(tabPane.getSelectedIndex(), false);
4632N/A
4632N/A if (scrollableTabLayoutEnabled()) {
4632N/A final int index = tabPane.getSelectedIndex();
4632N/A if (index < rects.length && index != -1) {
4632N/A tabScroller.tabPanel.scrollRectToVisible((Rectangle)rects[index].clone());
4632N/A }
4632N/A }
4632N/A }
4632N/A
4632N/A //
4632N/A // MouseListener
4632N/A //
4632N/A public void mouseClicked(final MouseEvent e) {}
4632N/A
4632N/A public void mouseReleased(final MouseEvent e) {}
4632N/A
4632N/A public void mouseEntered(final MouseEvent e) {
4632N/A setRolloverTab(e.getX(), e.getY());
4632N/A }
4632N/A
4632N/A public void mouseExited(final MouseEvent e) {
4632N/A setRolloverTab(-1);
4632N/A }
4632N/A
4632N/A public void mousePressed(final MouseEvent e) {
4632N/A if (!tabPane.isEnabled()) {
4632N/A return;
4632N/A }
4632N/A final int tabIndex = tabForCoordinate(tabPane, e.getX(), e.getY());
4632N/A if (tabIndex >= 0 && tabPane.isEnabledAt(tabIndex)) {
4632N/A if (tabIndex != tabPane.getSelectedIndex()) {
4632N/A // Clicking on unselected tab, change selection, do NOT
4632N/A // request focus.
4632N/A // This will trigger the focusIndex to change by way
4632N/A // of stateChanged.
4632N/A tabPane.setSelectedIndex(tabIndex);
4632N/A } else if (tabPane.isRequestFocusEnabled()) {
4632N/A // Clicking on selected tab, try and give the tabbedpane
4632N/A // focus. Repaint will occur in focusGained.
4632N/A tabPane.requestFocus();
4632N/A }
4632N/A }
4632N/A }
4632N/A
4632N/A //
4632N/A // MouseMotionListener
4632N/A //
4632N/A public void mouseDragged(final MouseEvent e) {}
4632N/A
4632N/A public void mouseMoved(final MouseEvent e) {
4632N/A setRolloverTab(e.getX(), e.getY());
4632N/A }
4632N/A
4632N/A //
4632N/A // FocusListener
4632N/A //
4632N/A public void focusGained(final FocusEvent e) {
4632N/A setFocusIndex(tabPane.getSelectedIndex(), true);
4632N/A }
4632N/A
4632N/A public void focusLost(final FocusEvent e) {
4632N/A repaintTab(focusIndex);
4632N/A }
4632N/A
4632N/A //
4632N/A // ContainerListener
4632N/A //
4632N/A /* GES 2/3/99:
4632N/A The container listener code was added to support HTML
4632N/A rendering of tab titles.
4632N/A
4632N/A Ideally, we would be able to listen for property changes
4632N/A when a tab is added or its text modified. At the moment
4632N/A there are no such events because the Beans spec doesn't
4632N/A allow 'indexed' property changes (i.e. tab 2's text changed
4632N/A from A to B).
4632N/A
4632N/A In order to get around this, we listen for tabs to be added
4632N/A or removed by listening for the container events. we then
4632N/A queue up a runnable (so the component has a chance to complete
4632N/A the add) which checks the tab title of the new component to see
4632N/A if it requires HTML rendering.
4632N/A
4632N/A The Views (one per tab title requiring HTML rendering) are
4632N/A stored in the htmlViews Vector, which is only allocated after
4632N/A the first time we run into an HTML tab. Note that this vector
4632N/A is kept in step with the number of pages, and nulls are added
4632N/A for those pages whose tab title do not require HTML rendering.
4632N/A
4632N/A This makes it easy for the paint and layout code to tell
4632N/A whether to invoke the HTML engine without having to check
4632N/A the string during time-sensitive operations.
4632N/A
4632N/A When we have added a way to listen for tab additions and
4632N/A changes to tab text, this code should be removed and
4632N/A replaced by something which uses that. */
4632N/A
4632N/A public void componentAdded(final ContainerEvent e) {
4632N/A final JTabbedPane tp = (JTabbedPane)e.getContainer();
4632N/A final Component child = e.getChild();
4632N/A if (child instanceof UIResource) {
4632N/A return;
4632N/A }
4639N/A isRunsDirty = true;
4639N/A updateHtmlViews(tp.indexOfComponent(child));
4639N/A }
4639N/A
4639N/A private void updateHtmlViews(int index) {
4639N/A final String title = tabPane.getTitleAt(index);
4632N/A final boolean isHTML = BasicHTML.isHTMLString(title);
4632N/A if (isHTML) {
4632N/A if (htmlViews == null) { // Initialize vector
4632N/A htmlViews = createHTMLVector();
4632N/A } else { // Vector already exists
4639N/A final View v = BasicHTML.createHTMLView(tabPane, title);
4632N/A htmlViews.insertElementAt(v, index);
4632N/A }
4632N/A } else { // Not HTML
4632N/A if (htmlViews != null) { // Add placeholder
4632N/A htmlViews.insertElementAt(null, index);
4632N/A } // else nada!
4632N/A }
4632N/A updateMnemonics();
4632N/A }
4632N/A
4632N/A public void componentRemoved(final ContainerEvent e) {
4632N/A final JTabbedPane tp = (JTabbedPane)e.getContainer();
4632N/A final Component child = e.getChild();
4632N/A if (child instanceof UIResource) {
4632N/A return;
4632N/A }
4632N/A
4632N/A // NOTE 4/15/2002 (joutwate):
4632N/A // This fix is implemented using client properties since there is
4632N/A // currently no IndexPropertyChangeEvent. Once
4632N/A // IndexPropertyChangeEvents have been added this code should be
4632N/A // modified to use it.
4632N/A final Integer indexObj = (Integer)tp.getClientProperty("__index_to_remove__");
4632N/A if (indexObj != null) {
4632N/A final int index = indexObj.intValue();
4632N/A if (htmlViews != null && htmlViews.size() > index) {
4632N/A htmlViews.removeElementAt(index);
4632N/A }
4632N/A tp.putClientProperty("__index_to_remove__", null);
4632N/A }
4632N/A isRunsDirty = true;
4632N/A updateMnemonics();
4632N/A
4632N/A validateFocusIndex();
4632N/A }
4632N/A }
4632N/A
4632N/A /**
4632N/A * This class should be treated as a &quot;protected&quot; inner class.
4632N/A * Instantiate it only within subclasses of BasicTabbedPaneUI.
4632N/A */
4632N/A public class PropertyChangeHandler implements PropertyChangeListener {
4632N/A // NOTE: This class exists only for backward compatability. All
4632N/A // its functionality has been moved into Handler. If you need to add
4632N/A // new functionality add it to the Handler, but make sure this
4632N/A // class calls into the Handler.
4632N/A public void propertyChange(final PropertyChangeEvent e) {
4632N/A getHandler().propertyChange(e);
4632N/A }
4632N/A }
4632N/A
4632N/A /**
4632N/A * This class should be treated as a &quot;protected&quot; inner class.
4632N/A * Instantiate it only within subclasses of BasicTabbedPaneUI.
4632N/A */
4632N/A public class TabSelectionHandler implements ChangeListener {
4632N/A // NOTE: This class exists only for backward compatability. All
4632N/A // its functionality has been moved into Handler. If you need to add
4632N/A // new functionality add it to the Handler, but make sure this
4632N/A // class calls into the Handler.
4632N/A public void stateChanged(final ChangeEvent e) {
4632N/A getHandler().stateChanged(e);
4632N/A }
4632N/A }
4632N/A
4632N/A /**
4632N/A * This class should be treated as a &quot;protected&quot; inner class.
4632N/A * Instantiate it only within subclasses of BasicTabbedPaneUI.
4632N/A */
4632N/A public class MouseHandler extends MouseAdapter {
4632N/A // NOTE: This class exists only for backward compatability. All
4632N/A // its functionality has been moved into Handler. If you need to add
4632N/A // new functionality add it to the Handler, but make sure this
4632N/A // class calls into the Handler.
4632N/A public void mousePressed(final MouseEvent e) {
4632N/A getHandler().mousePressed(e);
4632N/A }
4632N/A }
4632N/A
4632N/A /**
4632N/A * This class should be treated as a &quot;protected&quot; inner class.
4632N/A * Instantiate it only within subclasses of BasicTabbedPaneUI.
4632N/A */
4632N/A public class FocusHandler extends FocusAdapter {
4632N/A // NOTE: This class exists only for backward compatability. All
4632N/A // its functionality has been moved into Handler. If you need to add
4632N/A // new functionality add it to the Handler, but make sure this
4632N/A // class calls into the Handler.
4632N/A public void focusGained(final FocusEvent e) {
4632N/A getHandler().focusGained(e);
4632N/A }
4632N/A
4632N/A public void focusLost(final FocusEvent e) {
4632N/A getHandler().focusLost(e);
4632N/A }
4632N/A }
4632N/A
4632N/A private Vector<View> createHTMLVector() {
4632N/A final Vector<View> htmlViews = new Vector<View>();
4632N/A final int count = tabPane.getTabCount();
4632N/A if (count > 0) {
4632N/A for (int i = 0; i < count; i++) {
4632N/A final String title = tabPane.getTitleAt(i);
4632N/A if (BasicHTML.isHTMLString(title)) {
4632N/A htmlViews.addElement(BasicHTML.createHTMLView(tabPane, title));
4632N/A } else {
4632N/A htmlViews.addElement(null);
4632N/A }
4632N/A }
4632N/A }
4632N/A return htmlViews;
4632N/A }
4632N/A
4632N/A private class TabContainer extends JPanel implements UIResource {
4632N/A private boolean notifyTabbedPane = true;
4632N/A
4632N/A public TabContainer() {
4632N/A super(null);
4632N/A setOpaque(false);
4632N/A }
4632N/A
4632N/A public void remove(final Component comp) {
4632N/A final int index = tabPane.indexOfTabComponent(comp);
4632N/A super.remove(comp);
4632N/A if (notifyTabbedPane && index != -1) {
4632N/A tabPane.setTabComponentAt(index, null);
4632N/A }
4632N/A }
4632N/A
4632N/A private void removeUnusedTabComponents() {
4632N/A for (final Component c : getComponents()) {
4632N/A if (!(c instanceof UIResource)) {
4632N/A final int index = tabPane.indexOfTabComponent(c);
4632N/A if (index == -1) {
4632N/A super.remove(c);
4632N/A }
4632N/A }
4632N/A }
4632N/A }
4632N/A
4632N/A public boolean isOptimizedDrawingEnabled() {
4632N/A return tabScroller != null && !tabScroller.croppedEdge.isParamsSet();
4632N/A }
4632N/A
4632N/A public void doLayout() {
4632N/A // We layout tabComponents in JTabbedPane's layout manager
4632N/A // and use this method as a hook for repainting tabs
4632N/A // to update tabs area e.g. when the size of tabComponent was changed
4632N/A if (scrollableTabLayoutEnabled()) {
4632N/A tabScroller.tabPanel.repaint();
4632N/A tabScroller.updateView();
4632N/A } else {
4632N/A tabPane.repaint(getBounds());
4632N/A }
4632N/A }
4632N/A }
4632N/A
4632N/A private class CroppedEdge extends JPanel implements UIResource {
4632N/A private Shape shape;
4632N/A private int tabIndex;
4632N/A private int cropline;
4632N/A private int cropx, cropy;
4632N/A
4632N/A public CroppedEdge() {
4632N/A setOpaque(false);
4632N/A }
4632N/A
4632N/A public void setParams(final int tabIndex, final int cropline, final int cropx, final int cropy) {
4632N/A this.tabIndex = tabIndex;
4632N/A this.cropline = cropline;
4632N/A this.cropx = cropx;
4632N/A this.cropy = cropy;
4632N/A final Rectangle tabRect = rects[tabIndex];
4632N/A setBounds(tabRect);
4632N/A shape = createCroppedTabShape(tabPane.getTabPlacement(), tabRect, cropline);
4632N/A if (getParent() == null && tabContainer != null) {
4632N/A tabContainer.add(this, 0);
4632N/A }
4632N/A }
4632N/A
4632N/A public void resetParams() {
4632N/A shape = null;
4632N/A if (getParent() == tabContainer && tabContainer != null) {
4632N/A tabContainer.remove(this);
4632N/A }
4632N/A }
4632N/A
4632N/A public boolean isParamsSet() {
4632N/A return shape != null;
4632N/A }
4632N/A
4632N/A public int getTabIndex() {
4632N/A return tabIndex;
4632N/A }
4632N/A
4632N/A public int getCropline() {
4632N/A return cropline;
4632N/A }
4632N/A
4632N/A public int getCroppedSideWidth() {
4632N/A return 3;
4632N/A }
4632N/A
4632N/A private Color getBgColor() {
4632N/A final Component parent = tabPane.getParent();
4632N/A if (parent != null) {
4632N/A final Color bg = parent.getBackground();
4632N/A if (bg != null) {
4632N/A return bg;
4632N/A }
4632N/A }
4632N/A return UIManager.getColor("control");
4632N/A }
4632N/A
4632N/A protected void paintComponent(final Graphics g) {
4632N/A super.paintComponent(g);
4632N/A if (isParamsSet() && g instanceof Graphics2D) {
4632N/A final Graphics2D g2 = (Graphics2D)g;
4632N/A g2.clipRect(0, 0, getWidth(), getHeight());
4632N/A g2.setColor(getBgColor());
4632N/A g2.translate(cropx, cropy);
4632N/A g2.fill(shape);
4632N/A paintCroppedTabEdge(g);
4632N/A g2.translate(-cropx, -cropy);
4632N/A }
4632N/A }
4632N/A }
4632N/A
4632N/A /**
4632N/A * An ActionMap that populates its contents as necessary. The
4632N/A * contents are populated by invoking the <code>loadActionMap</code>
4632N/A * method on the passed in Object.
4632N/A *
4632N/A * @version 1.6, 11/17/05
4632N/A * @author Scott Violet
4632N/A */
4632N/A static class LazyActionMap extends ActionMapUIResource {
4632N/A /**
4632N/A * Object to invoke <code>loadActionMap</code> on. This may be
4632N/A * a Class object.
4632N/A */
4632N/A private transient Object _loader;
4632N/A
4632N/A /**
4632N/A * Installs an ActionMap that will be populated by invoking the
4632N/A * <code>loadActionMap</code> method on the specified Class
4632N/A * when necessary.
4632N/A * <p>
4632N/A * This should be used if the ActionMap can be shared.
4632N/A *
4632N/A * @param c JComponent to install the ActionMap on.
4632N/A * @param loaderClass Class object that gets loadActionMap invoked
4632N/A * on.
4632N/A * @param defaultsKey Key to use to defaults table to check for
4632N/A * existing map and what resulting Map will be registered on.
4632N/A */
4632N/A static void installLazyActionMap(final JComponent c, final Class<AquaTabbedPaneCopyFromBasicUI> loaderClass, final String defaultsKey) {
4632N/A ActionMap map = (ActionMap)UIManager.get(defaultsKey);
4632N/A if (map == null) {
4632N/A map = new LazyActionMap(loaderClass);
4632N/A UIManager.getLookAndFeelDefaults().put(defaultsKey, map);
4632N/A }
4632N/A SwingUtilities.replaceUIActionMap(c, map);
4632N/A }
4632N/A
4632N/A /**
4632N/A * Returns an ActionMap that will be populated by invoking the
4632N/A * <code>loadActionMap</code> method on the specified Class
4632N/A * when necessary.
4632N/A * <p>
4632N/A * This should be used if the ActionMap can be shared.
4632N/A *
4632N/A * @param c JComponent to install the ActionMap on.
4632N/A * @param loaderClass Class object that gets loadActionMap invoked
4632N/A * on.
4632N/A * @param defaultsKey Key to use to defaults table to check for
4632N/A * existing map and what resulting Map will be registered on.
4632N/A */
4632N/A static ActionMap getActionMap(final Class<AquaTabbedPaneCopyFromBasicUI> loaderClass, final String defaultsKey) {
4632N/A ActionMap map = (ActionMap)UIManager.get(defaultsKey);
4632N/A if (map == null) {
4632N/A map = new LazyActionMap(loaderClass);
4632N/A UIManager.getLookAndFeelDefaults().put(defaultsKey, map);
4632N/A }
4632N/A return map;
4632N/A }
4632N/A
4632N/A private LazyActionMap(final Class<AquaTabbedPaneCopyFromBasicUI> loader) {
4632N/A _loader = loader;
4632N/A }
4632N/A
4632N/A public void put(final Action action) {
4632N/A put(action.getValue(Action.NAME), action);
4632N/A }
4632N/A
4632N/A public void put(final Object key, final Action action) {
4632N/A loadIfNecessary();
4632N/A super.put(key, action);
4632N/A }
4632N/A
4632N/A public Action get(final Object key) {
4632N/A loadIfNecessary();
4632N/A return super.get(key);
4632N/A }
4632N/A
4632N/A public void remove(final Object key) {
4632N/A loadIfNecessary();
4632N/A super.remove(key);
4632N/A }
4632N/A
4632N/A public void clear() {
4632N/A loadIfNecessary();
4632N/A super.clear();
4632N/A }
4632N/A
4632N/A public Object[] keys() {
4632N/A loadIfNecessary();
4632N/A return super.keys();
4632N/A }
4632N/A
4632N/A public int size() {
4632N/A loadIfNecessary();
4632N/A return super.size();
4632N/A }
4632N/A
4632N/A public Object[] allKeys() {
4632N/A loadIfNecessary();
4632N/A return super.allKeys();
4632N/A }
4632N/A
4632N/A public void setParent(final ActionMap map) {
4632N/A loadIfNecessary();
4632N/A super.setParent(map);
4632N/A }
4632N/A
4632N/A private void loadIfNecessary() {
4632N/A if (_loader != null) {
4632N/A final Object loader = _loader;
4632N/A
4632N/A _loader = null;
4632N/A final Class<?> klass = (Class<?>)loader;
4632N/A try {
4632N/A final java.lang.reflect.Method method = klass.getDeclaredMethod("loadActionMap", new Class[] { LazyActionMap.class });
4632N/A method.invoke(klass, new Object[] { this });
4632N/A } catch (final NoSuchMethodException nsme) {
4632N/A assert false : "LazyActionMap unable to load actions " + klass;
4632N/A } catch (final IllegalAccessException iae) {
4632N/A assert false : "LazyActionMap unable to load actions " + iae;
4632N/A } catch (final InvocationTargetException ite) {
4632N/A assert false : "LazyActionMap unable to load actions " + ite;
4632N/A } catch (final IllegalArgumentException iae) {
4632N/A assert false : "LazyActionMap unable to load actions " + iae;
4632N/A }
4632N/A }
4632N/A }
4632N/A }
4632N/A}