/* BasicTabbedPaneUI.java -- Copyright (C) 2002, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. GNU Classpath is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Classpath is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Classpath; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Linking this library statically or dynamically with other modules is making a combined work based on this library. Thus, the terms and conditions of the GNU General Public License cover the whole combination. As a special exception, the copyright holders of this library give you permission to link this library with independent modules to produce an executable, regardless of the license terms of these independent modules, and to copy and distribute the resulting executable under terms of your choice, provided that you also meet, for each linked independent module, the terms and conditions of the license of that module. An independent module is a module which is not derived from or based on this library. If you modify this library, you may extend this exception to your version of the library, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ package javax.swing.plaf.basic; import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Insets; import java.awt.LayoutManager; import java.awt.Point; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import javax.swing.AbstractAction; import javax.swing.ActionMap; import javax.swing.Icon; import javax.swing.InputMap; import javax.swing.JComponent; import javax.swing.JPanel; import javax.swing.JTabbedPane; import javax.swing.JViewport; import javax.swing.KeyStroke; import javax.swing.LookAndFeel; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.plaf.ActionMapUIResource; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.TabbedPaneUI; import javax.swing.plaf.UIResource; import javax.swing.text.View; /** * This is the Basic Look and Feel's UI delegate for JTabbedPane. * * @author Lillian Angel (langel@redhat.com) * @author Kim Ho (kho@redhat.com) * @author Roman Kennke (kennke@aicas.com) * @author Robert Schuster (robertschuster@fsfe.org) */ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants { static class NavigateAction extends AbstractAction { int direction; NavigateAction(String name, int dir) { super(name); direction = dir; } public void actionPerformed(ActionEvent event) { JTabbedPane tp = (JTabbedPane) event.getSource(); BasicTabbedPaneUI ui = (BasicTabbedPaneUI) tp.getUI(); ui.navigateSelectedTab(direction); } } static class NavigatePageDownAction extends AbstractAction { public NavigatePageDownAction() { super("navigatePageDown"); } public void actionPerformed(ActionEvent event) { JTabbedPane tp = (JTabbedPane) event.getSource(); BasicTabbedPaneUI ui = (BasicTabbedPaneUI) tp.getUI(); int i = tp.getSelectedIndex(); if (i < 0) i = 0; ui.selectNextTabInRun(i); } } static class NavigatePageUpAction extends AbstractAction { public NavigatePageUpAction() { super("navigatePageUp"); } public void actionPerformed(ActionEvent event) { JTabbedPane tp = (JTabbedPane) event.getSource(); BasicTabbedPaneUI ui = (BasicTabbedPaneUI) tp.getUI(); int i = tp.getSelectedIndex(); if (i < 0) i = 0; ui.selectPreviousTabInRun(i); } } static class RequestFocusAction extends AbstractAction { public RequestFocusAction() { super("requestFocus"); } public void actionPerformed(ActionEvent event) { ((JTabbedPane) event.getSource()).requestFocus(); } } static class RequestFocusForVisibleComponentAction extends AbstractAction { public RequestFocusForVisibleComponentAction() { super("requestFocusForVisibleComponent"); } public void actionPerformed(ActionEvent event) { JTabbedPane tp = (JTabbedPane) event.getSource(); // FIXME: This should select a suitable component within // the tab content. However I dont know whether we have // to search for this component or wether the called is // supposed to do that. tp.getSelectedComponent().requestFocus(); } } /** * A helper class that handles focus. *
The purpose of this class is to implement a more flexible focus * handling for the tabbed pane, which is used to determine whether the * focus indicator should be painted or not. When in scrolling layout * mode the area containing the tabs is a scrollpane, so simply testing * whether the tabbed pane has the focus does not work.
*The FocusHandler
is installed on the scrollpane and
* the tabbed pane and sets the variable hasFocus
to
* false
only when both components do not hold the focus.
The value at index i denotes the index of the first tab in run i.
*If the value for any index (i > 0) is 0 then (i - 1) is the last * run.
*/ protected int[] tabRuns; /** * Indicates if the layout of the tab runs is ok or not. This is package * private to avoid a synthetic accessor method. */ boolean tabRunsDirty; /** * This is the keystroke for moving down. * * @deprecated 1.3 */ protected KeyStroke downKey; /** * This is the keystroke for moving left. * * @deprecated 1.3 */ protected KeyStroke leftKey; /** * This is the keystroke for moving right. * * @deprecated 1.3 */ protected KeyStroke rightKey; /** * This is the keystroke for moving up. * * @deprecated 1.3 */ protected KeyStroke upKey; /** The listener that listens for focus events. */ protected FocusListener focusListener; /** The listener that listens for mouse events. */ protected MouseListener mouseListener; /** The listener that listens for property change events. */ protected PropertyChangeListener propertyChangeListener; /** The listener that listens for change events. */ protected ChangeListener tabChangeListener; /** The tab pane that this UI paints. */ protected JTabbedPane tabPane; /** The current layout manager for the tabPane. * This is package-private to avoid an accessor method. */ transient LayoutManager layoutManager; /** The rectangle that describes the tab area's position and size. * This is package-private to avoid an accessor method. */ transient Rectangle tabAreaRect; /** The rectangle that describes the content area's position and * size. This is package-private to avoid an accessor method. */ transient Rectangle contentRect; /** * The index over which the mouse is currently moving. */ private int rolloverTab; /** * Determines if tabs are painted opaque or not. This can be adjusted using * the UIManager property 'TabbedPane.tabsOpaque'. */ private boolean tabsOpaque; /** * The currently visible component. */ private Component visibleComponent; private Color selectedColor; private Rectangle tempTextRect = new Rectangle(); private Rectangle tempIconRect = new Rectangle(); /** * Creates a new BasicTabbedPaneUI object. */ public BasicTabbedPaneUI() { super(); rects = new Rectangle[0]; tabRuns = new int[10]; } /** * This method creates a ScrollingButton that points in the appropriate * direction for an increasing button. * This is package-private to avoid an accessor method. * * @return The increase ScrollingButton. */ ScrollingButton createIncreaseButton() { if (incrButton == null) incrButton = new ScrollingButton(SwingConstants.NORTH); if (tabPane.getTabPlacement() == SwingConstants.TOP || tabPane.getTabPlacement() == SwingConstants.BOTTOM) incrButton.setDirection(SwingConstants.EAST); else incrButton.setDirection(SwingConstants.SOUTH); return incrButton; } /** * This method creates a ScrollingButton that points in the appropriate * direction for a decreasing button. * This is package-private to avoid an accessor method. * * @return The decrease ScrollingButton. */ ScrollingButton createDecreaseButton() { if (decrButton == null) decrButton = new ScrollingButton(SwingConstants.SOUTH); if (tabPane.getTabPlacement() == SwingConstants.TOP || tabPane.getTabPlacement() == SwingConstants.BOTTOM) decrButton.setDirection(SwingConstants.WEST); else decrButton.setDirection(SwingConstants.NORTH); return decrButton; } /** * This method finds the point to set the view position at given the index * of a tab. The tab will be the first visible tab in the run. * This is package-private to avoid an accessor method. * * @param index The index of the first visible tab. * * @return The position of the first visible tab. */ Point findPointForIndex(int index) { int tabPlacement = tabPane.getTabPlacement(); int selectedIndex = tabPane.getSelectedIndex(); Insets insets = getSelectedTabPadInsets(tabPlacement); int w = 0; int h = 0; if (tabPlacement == TOP || tabPlacement == BOTTOM) { if (index > 0) { w += rects[index - 1].x + rects[index - 1].width; if (index > selectedIndex) w -= insets.left + insets.right; } } else { if (index > 0) { h += rects[index - 1].y + rects[index - 1].height; if (index > selectedIndex) h -= insets.top + insets.bottom; } } Point p = new Point(w, h); return p; } /** TabbedPanes in scrolling mode should use this method to * scroll properly to the tab given by the index argument. * * @param index The tab to scroll to. * @param placement The tab's placement. */ final void scrollTab(int index, int placement) { int diff; if (index >= 0 && tabPane.isEnabledAt(index)) { // If the user clicked on the last tab and that one was // only partially visible shift the scroll offset to make // it completely visible. switch (placement) { case JTabbedPane.TOP: case JTabbedPane.BOTTOM: if ((diff = rects[index].x + rects[index].width - decrButton.getX() - currentScrollOffset) > 0) currentScrollOffset += diff; else if ((diff = rects[index].x - currentScrollOffset) < 0) { if (index == 0) currentScrollOffset = 0; else currentScrollOffset += diff; } currentScrollLocation = tabForCoordinate(tabPane, currentScrollOffset, rects[index].y); break; default: if ((diff = rects[index].y + rects[index].height - decrButton.getY() - currentScrollOffset) > 0) currentScrollOffset += diff; else if ((diff = rects[index].y - currentScrollOffset) < 0) { if (index == 0) currentScrollOffset = 0; else currentScrollOffset += diff; } currentScrollLocation = tabForCoordinate(tabPane, rects[index].x, currentScrollOffset); } updateViewPosition(); updateButtons(); } } /** Sets the enabled state of the increase and decrease button * according to the current scrolling offset and tab pane width * (or height in TOP/BOTTOM placement). */ final void updateButtons() { int tc = tabPane.getTabCount(); // The increase button should be enabled as long as the // right/bottom border of the last tab is under the left/top // border of the decrease button. switch (tabPane.getTabPlacement()) { case JTabbedPane.BOTTOM: case JTabbedPane.TOP: incrButton.setEnabled(currentScrollLocation + 1 < tc && rects[tc-1].x + rects[tc-1].width - currentScrollOffset > decrButton.getX()); break; default: incrButton.setEnabled(currentScrollLocation + 1 < tc && rects[tc-1].y + rects[tc-1].height - currentScrollOffset > decrButton.getY()); } // The decrease button is enabled when the tab pane is scrolled in any way. decrButton.setEnabled(currentScrollOffset > 0); } /** * Updates the position of the scrolling viewport's view * according to the current scroll offset. */ final void updateViewPosition() { Point p = viewport.getViewPosition(); // The unneeded coordinate must be set to zero // in order to correctly handle placement changes. switch (tabPane.getTabPlacement()) { case JTabbedPane.LEFT: case JTabbedPane.RIGHT: p.x = 0; p.y = currentScrollOffset; break; default: p.x = currentScrollOffset; p.y = 0; } viewport.setViewPosition(p); } /** * This method creates a new BasicTabbedPaneUI. * * @param c The JComponent to create a UI for. * * @return A new BasicTabbedPaneUI. */ public static ComponentUI createUI(JComponent c) { return new BasicTabbedPaneUI(); } /** * This method installs the UI for the given JComponent. * * @param c The JComponent to install the UI for. */ public void installUI(JComponent c) { super.installUI(c); if (c instanceof JTabbedPane) { tabPane = (JTabbedPane) c; installComponents(); installDefaults(); installListeners(); installKeyboardActions(); layoutManager = createLayoutManager(); tabPane.setLayout(layoutManager); } } /** * This method uninstalls the UI for the given JComponent. * * @param c The JComponent to uninstall the UI for. */ public void uninstallUI(JComponent c) { layoutManager = null; uninstallKeyboardActions(); uninstallListeners(); uninstallDefaults(); uninstallComponents(); tabPane = null; } /** * This method creates the appropriate layout manager for the JTabbedPane's * current tab layout policy. If the tab layout policy is * SCROLL_TAB_LAYOUT, then all the associated components that need to be * created will be done so now. * * @return A layout manager given the tab layout policy. */ protected LayoutManager createLayoutManager() { if (tabPane.getTabLayoutPolicy() == JTabbedPane.WRAP_TAB_LAYOUT) return new TabbedPaneLayout(); else { runCount = 1; tabRuns[0] = 0; incrButton = createIncreaseButton(); incrButton.addMouseListener(mouseListener); decrButton = createDecreaseButton(); decrButton.addMouseListener(mouseListener); decrButton.setEnabled(false); panel = new ScrollingPanel(); panel.setSize(Integer.MAX_VALUE, Integer.MAX_VALUE); panel.addMouseListener(mouseListener); panel.addFocusListener(focusListener); viewport = new ScrollingViewport(); viewport.setBackground(Color.LIGHT_GRAY); viewport.setView(panel); viewport.setLayout(null); tabPane.add(incrButton); tabPane.add(decrButton); tabPane.add(viewport); return new TabbedPaneScrollLayout(); } } /** * This method installs components for this JTabbedPane. */ protected void installComponents() { // Nothing to be done. } /** * This method uninstalls components for this JTabbedPane. */ protected void uninstallComponents() { if (incrButton != null) tabPane.remove(incrButton); if (decrButton != null) tabPane.remove(decrButton); if (viewport != null) tabPane.remove(viewport); } /** * This method installs defaults for the Look and Feel. */ protected void installDefaults() { LookAndFeel.installColorsAndFont(tabPane, "TabbedPane.background", "TabbedPane.foreground", "TabbedPane.font"); tabPane.setOpaque(false); lightHighlight = UIManager.getColor("TabbedPane.highlight"); highlight = UIManager.getColor("TabbedPane.light"); shadow = UIManager.getColor("TabbedPane.shadow"); darkShadow = UIManager.getColor("TabbedPane.darkShadow"); focus = UIManager.getColor("TabbedPane.focus"); textIconGap = UIManager.getInt("TabbedPane.textIconGap"); tabRunOverlay = UIManager.getInt("TabbedPane.tabRunOverlay"); tabInsets = UIManager.getInsets("TabbedPane.tabInsets"); selectedTabPadInsets = UIManager.getInsets("TabbedPane.selectedTabPadInsets"); tabAreaInsets = UIManager.getInsets("TabbedPane.tabAreaInsets"); contentBorderInsets = UIManager.getInsets("TabbedPane.contentBorderInsets"); tabsOpaque = UIManager.getBoolean("TabbedPane.tabsOpaque"); // Although 'TabbedPane.contentAreaColor' is not defined in the defaults // of BasicLookAndFeel it is used by this class. selectedColor = UIManager.getColor("TabbedPane.contentAreaColor"); if (selectedColor == null) selectedColor = UIManager.getColor("control"); calcRect = new Rectangle(); tabRuns = new int[10]; tabAreaRect = new Rectangle(); contentRect = new Rectangle(); } /** * This method uninstalls defaults for the Look and Feel. */ protected void uninstallDefaults() { calcRect = null; tabAreaRect = null; contentRect = null; tabRuns = null; tempIconRect = null; tempTextRect = null; contentBorderInsets = null; tabAreaInsets = null; selectedTabPadInsets = null; tabInsets = null; focus = null; darkShadow = null; shadow = null; lightHighlight = null; highlight = null; selectedColor = null; } /** * This method creates and installs the listeners for this UI. */ protected void installListeners() { mouseListener = createMouseListener(); tabChangeListener = createChangeListener(); propertyChangeListener = createPropertyChangeListener(); focusListener = createFocusListener(); tabPane.addMouseListener(mouseListener); tabPane.addChangeListener(tabChangeListener); tabPane.addPropertyChangeListener(propertyChangeListener); tabPane.addFocusListener(focusListener); } /** * This method removes and nulls the listeners for this UI. */ protected void uninstallListeners() { tabPane.removeFocusListener(focusListener); tabPane.removePropertyChangeListener(propertyChangeListener); tabPane.removeChangeListener(tabChangeListener); tabPane.removeMouseListener(mouseListener); if (incrButton != null) incrButton.removeMouseListener(mouseListener); if (decrButton != null) decrButton.removeMouseListener(mouseListener); if (panel != null) { panel.removeMouseListener(mouseListener); panel.removeFocusListener(focusListener); } focusListener = null; propertyChangeListener = null; tabChangeListener = null; mouseListener = null; } /** * This method creates a new MouseListener. * * @return A new MouseListener. */ protected MouseListener createMouseListener() { return new MouseHandler(); } /** * This method creates a new FocusListener. * * @return A new FocusListener. */ protected FocusListener createFocusListener() { return new FocusHandler(); } /** * This method creates a new ChangeListener. * * @return A new ChangeListener. */ protected ChangeListener createChangeListener() { return new TabSelectionHandler(); } /** * This method creates a new PropertyChangeListener. * * @return A new PropertyChangeListener. */ protected PropertyChangeListener createPropertyChangeListener() { return new PropertyChangeHandler(); } /** * This method installs keyboard actions for the JTabbedPane. */ protected void installKeyboardActions() { InputMap keyMap = (InputMap) UIManager.get("TabbedPane.focusInputMap"); SwingUtilities.replaceUIInputMap(tabPane, JComponent.WHEN_FOCUSED, keyMap); keyMap = (InputMap) UIManager.get("TabbedPane.ancestorInputMap"); SwingUtilities .replaceUIInputMap(tabPane, JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, keyMap); ActionMap map = getActionMap(); SwingUtilities.replaceUIActionMap(tabPane, map); } /** * This method uninstalls keyboard actions for the JTabbedPane. */ protected void uninstallKeyboardActions() { SwingUtilities.replaceUIActionMap(tabPane, null); SwingUtilities.replaceUIInputMap(tabPane, JComponent.WHEN_FOCUSED, null); SwingUtilities .replaceUIInputMap(tabPane, JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null); } /** * This method returns the minimum size of the JTabbedPane. * * @param c The JComponent to find a size for. * * @return The minimum size. */ public Dimension getMinimumSize(JComponent c) { return layoutManager.minimumLayoutSize(tabPane); } /** * This method returns the maximum size of the JTabbedPane. * * @param c The JComponent to find a size for. * * @return The maximum size. */ public Dimension getMaximumSize(JComponent c) { return new Dimension(Short.MAX_VALUE, Short.MAX_VALUE); } /** * This method paints the JTabbedPane. * * @param g The Graphics object to paint with. * @param c The JComponent to paint. */ public void paint(Graphics g, JComponent c) { if (!tabPane.isValid()) tabPane.validate(); if (tabPane.getTabCount() == 0) return; int index = tabPane.getSelectedIndex(); if (index < 0) index = 0; int tabPlacement = tabPane.getTabPlacement(); // Paint the tab area only in WRAP_TAB_LAYOUT Mode from this method // because it is done through the ScrollingViewport.paint() method // for the SCROLL_TAB_LAYOUT mode. if (tabPane.getTabLayoutPolicy() == JTabbedPane.WRAP_TAB_LAYOUT) { g.setColor(highlight); g.fillRect(tabAreaRect.x, tabAreaRect.y, tabAreaRect.width, tabAreaRect.height); paintTabArea(g, tabPlacement, index); } paintContentBorder(g, tabPlacement, index); } /** * This method paints the tab area. This includes painting the rectangles * that make up the tabs. * * @param g The Graphics object to paint with. * @param tabPlacement The JTabbedPane's tab placement. * @param selectedIndex The selected index. */ protected void paintTabArea(Graphics g, int tabPlacement, int selectedIndex) { // Please note: the ordering of the painting is important. // we WANT to paint the outermost run first and then work our way in. // The following drawing code works for both tab layouts. int tabCount = tabPane.getTabCount(); for (int i = runCount - 1; i >= 0; --i) { int start = tabRuns[i]; int next; if (i == runCount - 1) next = tabRuns[0]; else next = tabRuns[i + 1]; int end = next != 0 ? next - 1 : tabCount - 1; for (int j = start; j <= end; ++j) { if (j != selectedIndex) { paintTab(g, tabPlacement, rects, j, tempIconRect, tempTextRect); } } } // Paint selected tab in front of every other tab. if (selectedIndex >= 0) paintTab(g, tabPlacement, rects, selectedIndex, tempIconRect, tempTextRect); } /** * This method paints an individual tab. * * @param g The Graphics object to paint with. * @param tabPlacement The JTabbedPane's tab placement. * @param rects The array of rectangles that keep the size and position of * the tabs. * @param tabIndex The tab index to paint. * @param iconRect The rectangle to use for the icon. * @param textRect The rectangle to use for the text. */ protected void paintTab(Graphics g, int tabPlacement, Rectangle[] rects, int tabIndex, Rectangle iconRect, Rectangle textRect) { Rectangle rect = rects[tabIndex]; boolean isSelected = tabIndex == tabPane.getSelectedIndex(); // Paint background if necessary. if (tabsOpaque || tabPane.isOpaque()) { paintTabBackground(g, tabPlacement, tabIndex, rect.x, rect.y, rect.width, rect.height, isSelected); } // Paint border. paintTabBorder(g, tabPlacement, tabIndex, rect.x, rect.y, rect.width, rect.height, isSelected); // Layout label. FontMetrics fm = getFontMetrics(); Icon icon = getIconForTab(tabIndex); String title = tabPane.getTitleAt(tabIndex); layoutLabel(tabPlacement, fm, tabIndex, title, icon, rect, iconRect, textRect, isSelected); // Paint the text. paintText(g, tabPlacement, tabPane.getFont(), fm, tabIndex, title, textRect, isSelected); // Paint icon if necessary. paintIcon(g, tabPlacement, tabIndex, icon, iconRect, isSelected); // Paint focus indicator. paintFocusIndicator(g, tabPlacement, rects, tabIndex, iconRect, textRect, isSelected); } /** * This method lays out the tab and finds the location to paint the icon * and text. * * @param tabPlacement The JTabbedPane's tab placement. * @param metrics The font metrics for the font to paint with. * @param tabIndex The tab index to paint. * @param title The string painted. * @param icon The icon painted. * @param tabRect The tab bounds. * @param iconRect The calculated icon bounds. * @param textRect The calculated text bounds. * @param isSelected Whether this tab is selected. */ protected void layoutLabel(int tabPlacement, FontMetrics metrics, int tabIndex, String title, Icon icon, Rectangle tabRect, Rectangle iconRect, Rectangle textRect, boolean isSelected) { // Reset the icon and text rectangles, as the result is not specified // when the locations are not (0,0). textRect.x = 0; textRect.y = 0; textRect.width = 0; textRect.height = 0; iconRect.x = 0; iconRect.y = 0; iconRect.width = 0; iconRect.height = 0; SwingUtilities.layoutCompoundLabel(tabPane, metrics, title, icon, SwingConstants.CENTER, SwingConstants.CENTER, SwingConstants.CENTER, SwingConstants.RIGHT, tabRect, iconRect, textRect, textIconGap); int shiftX = getTabLabelShiftX(tabPlacement, tabIndex, isSelected); int shiftY = getTabLabelShiftY(tabPlacement, tabIndex, isSelected); iconRect.x += shiftX; iconRect.y += shiftY; textRect.x += shiftX; textRect.y += shiftY; } /** * This method paints the icon. * * @param g The Graphics object to paint. * @param tabPlacement The JTabbedPane's tab placement. * @param tabIndex The tab index to paint. * @param icon The icon to paint. * @param iconRect The bounds of the icon. * @param isSelected Whether this tab is selected. */ protected void paintIcon(Graphics g, int tabPlacement, int tabIndex, Icon icon, Rectangle iconRect, boolean isSelected) { if (icon != null) icon.paintIcon(tabPane, g, iconRect.x, iconRect.y); } /** * This method paints the text for the given tab. * * @param g The Graphics object to paint with. * @param tabPlacement The JTabbedPane's tab placement. * @param font The font to paint with. * @param metrics The fontmetrics of the given font. * @param tabIndex The tab index. * @param title The string to paint. * @param textRect The bounds of the string. * @param isSelected Whether this tab is selected. */ protected void paintText(Graphics g, int tabPlacement, Font font, FontMetrics metrics, int tabIndex, String title, Rectangle textRect, boolean isSelected) { g.setFont(font); View textView = getTextViewForTab(tabIndex); if (textView != null) { textView.paint(g, textRect); return; } int ascent = metrics.getAscent(); int mnemIndex = tabPane.getDisplayedMnemonicIndexAt(tabIndex); if (tabPane.isEnabled() && tabPane.isEnabledAt(tabIndex)) { Color fg = tabPane.getForegroundAt(tabIndex); if (isSelected && (fg instanceof UIResource)) { Color selectionForeground = UIManager.getColor("TabbedPane.selectionForeground"); if (selectionForeground != null) fg = selectionForeground; } g.setColor(fg); if (mnemIndex != -1) BasicGraphicsUtils.drawStringUnderlineCharAt(g, title, mnemIndex, textRect.x, textRect.y + ascent); else g.drawString(title, textRect.x, textRect.y + ascent); } else { Color bg = tabPane.getBackgroundAt(tabIndex); g.setColor(bg.brighter()); if (mnemIndex != -1) BasicGraphicsUtils.drawStringUnderlineCharAt(g, title, mnemIndex, textRect.x, textRect.y + ascent); else g.drawString(title, textRect.x, textRect.y + ascent); g.setColor(bg.darker()); if (mnemIndex != -1) BasicGraphicsUtils.drawStringUnderlineCharAt(g, title, mnemIndex, textRect.x + 1, textRect.y + 1 + ascent); else g.drawString(title, textRect.x + 1, textRect.y + 1 + ascent); } } /** * This method returns how much the label for the tab should shift in the X * direction. * * @param tabPlacement The JTabbedPane's tab placement. * @param tabIndex The tab index being painted. * @param isSelected Whether this tab is selected. * * @return The amount the label should shift by in the X direction. */ protected int getTabLabelShiftX(int tabPlacement, int tabIndex, boolean isSelected) { switch (tabPlacement) { default: case SwingUtilities.TOP: case SwingUtilities.BOTTOM: return 1; case SwingUtilities.LEFT: return (isSelected) ? -1 : 1; case SwingUtilities.RIGHT: return (isSelected) ? 1 : -1; } } /** * This method returns how much the label for the tab should shift in the Y * direction. * * @param tabPlacement The JTabbedPane's tab placement. * @param tabIndex The tab index being painted. * @param isSelected Whether this tab is selected. * * @return The amount the label should shift by in the Y direction. */ protected int getTabLabelShiftY(int tabPlacement, int tabIndex, boolean isSelected) { switch (tabPlacement) { default: case SwingUtilities.TOP: return (isSelected) ? -1 : 1; case SwingUtilities.BOTTOM: return (isSelected) ? 1 : -1; case SwingUtilities.LEFT: case SwingUtilities.RIGHT: return 0; } } /** * This method paints the focus rectangle around the selected tab. * * @param g The Graphics object to paint with. * @param tabPlacement The JTabbedPane's tab placement. * @param rects The array of rectangles keeping track of size and position. * @param tabIndex The tab index. * @param iconRect The icon bounds. * @param textRect The text bounds. * @param isSelected Whether this tab is selected. */ protected void paintFocusIndicator(Graphics g, int tabPlacement, Rectangle[] rects, int tabIndex, Rectangle iconRect, Rectangle textRect, boolean isSelected) { if (tabPane.hasFocus() && isSelected) { Rectangle rect = rects[tabIndex]; // The focus rectangle. int x; int y; int w; int h; g.setColor(focus); switch (tabPlacement) { case LEFT: x = rect.x + 3; y = rect.y + 3; w = rect.width - 5; h = rect.height - 6; break; case RIGHT: x = rect.x + 2; y = rect.y + 3; w = rect.width - 6; h = rect.height - 5; break; case BOTTOM: x = rect.x + 3; y = rect.y + 2; w = rect.width - 6; h = rect.height - 5; break; case TOP: default: x = rect.x + 3; y = rect.y + 3; w = rect.width - 6; h = rect.height - 5; } BasicGraphicsUtils.drawDashedRect(g, x, y, w, h); } } /** * This method paints the border for an individual tab. * * @param g The Graphics object to paint with. * @param tabPlacement The JTabbedPane's tab placement. * @param tabIndex The tab index. * @param x The x position of the tab. * @param y The y position of the tab. * @param w The width of the tab. * @param h The height of the tab. * @param isSelected Whether the tab is selected. */ protected void paintTabBorder(Graphics g, int tabPlacement, int tabIndex, int x, int y, int w, int h, boolean isSelected) { Color saved = g.getColor(); switch (tabPlacement) { case SwingConstants.TOP: g.setColor(shadow); // Inner right line. g.drawLine(x + w - 2, y + 2, x + w - 2, y + h); g.setColor(darkShadow); // Outer right line. g.drawLine(x + w - 1, y + 2, x + w - 1, y + h); // Upper right corner. g.drawLine(x + w - 2, y + 1, x + w - 1, y + 2); g.setColor(lightHighlight); // Left line. g.drawLine(x, y + 3, x, y + h); // Upper line. g.drawLine(x + 3, y, x + w - 3, y); // Upper left corner. g.drawLine(x, y + 2, x + 2, y); break; case SwingConstants.LEFT: g.setColor(lightHighlight); // Top line. g.drawLine(x + 3, y, x + w - 1, y); // Top left border. g.drawLine(x + 2, y, x, y + 2); // Left line. g.drawLine(x, y + 3, x, y + h - 4); // Bottom left corner. g.drawLine(x, y + h - 3, x + 1, y + h - 2); g.setColor(darkShadow); // Outer bottom line. g.drawLine(x + 2, y + h - 1, x + w - 1, y + h - 1); g.setColor(shadow); // Inner bottom line. g.drawLine(x + 2, y + h - 2, x + w - 1, y + h - 2); break; case SwingConstants.BOTTOM: g.setColor(shadow); // Inner right line. g.drawLine(x + w - 2, y, x + w - 2, y + h - 2); // Inner bottom line. g.drawLine(x + 2, y + h - 1, x + w - 3, y + h - 1); g.setColor(darkShadow); // Outer right line. g.drawLine(x + w - 1, y, x + w - 1, y + h - 3); // Bottom right corner. g.drawLine(x + w - 1, y + h - 2, x + w - 3, y + h); // Bottom line. g.drawLine(x + 2, y + h, x + w - 4, y + h); g.setColor(lightHighlight); // Left line. g.drawLine(x, y, x, y + h - 3); // Bottom left corner. g.drawLine(x, y + h - 2, x + 1, y + h - 1); break; case SwingConstants.RIGHT: g.setColor(lightHighlight); // Top line. g.drawLine(x, y, x + w - 3, y); g.setColor(darkShadow); // Top right corner. g.drawLine(x + w - 2, y + 1, x + w - 1, y + 2); // Outer right line. g.drawLine(x + w - 1, y + 3, x + w - 1, y + h - 3); // Bottom right corner. g.drawLine(x + w - 2, y + h - 2, x + w - 3, y + h - 1); // Bottom line. g.drawLine(x, y + h - 1, x + w - 4, y + h - 1); g.setColor(shadow); // Inner right line. g.drawLine(x + w - 2, y + 2, x + w - 2, y + h - 3); // Inner bottom line. g.drawLine(x, y + h - 2, x + w - 3, y + h - 2); break; } g.setColor(saved); } /** * This method paints the background for an individual tab. * * @param g The Graphics object to paint with. * @param tabPlacement The JTabbedPane's tab placement. * @param tabIndex The tab index. * @param x The x position of the tab. * @param y The y position of the tab. * @param w The width of the tab. * @param h The height of the tab. * @param isSelected Whether the tab is selected. */ protected void paintTabBackground(Graphics g, int tabPlacement, int tabIndex, int x, int y, int w, int h, boolean isSelected) { Color saved = g.getColor(); if (isSelected) g.setColor(selectedColor); else { Color bg = tabPane.getBackgroundAt(tabIndex); if (bg == null) bg = Color.LIGHT_GRAY; g.setColor(bg); } switch (tabPlacement) { case SwingConstants.TOP: g.fillRect(x + 1, y + 1, w - 1, h - 1); break; case SwingConstants.BOTTOM: g.fillRect(x, y, w - 1, h - 1); break; case SwingConstants.LEFT: g.fillRect(x + 1, y + 1, w - 1, h - 2); break; case SwingConstants.RIGHT: g.fillRect(x, y + 1, w - 1, h - 2); break; } g.setColor(saved); } /** * This method paints the border around the content area. * * @param g The Graphics object to paint with. * @param tabPlacement The JTabbedPane's tab placement. * @param selectedIndex The index of the selected tab. */ protected void paintContentBorder(Graphics g, int tabPlacement, int selectedIndex) { int width = tabPane.getWidth(); int height = tabPane.getHeight(); Insets insets = tabPane.getInsets(); // Calculate coordinates of content area. int x = insets.left; int y = insets.top; int w = width - insets.left - insets.right; int h = height - insets.top - insets.bottom; switch (tabPlacement) { case LEFT: x += calculateTabAreaWidth(tabPlacement, runCount, maxTabWidth); w -= x - insets.left; break; case RIGHT: w -= calculateTabAreaWidth(tabPlacement, runCount, maxTabWidth); break; case BOTTOM: h -= calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight); break; case TOP: default: y += calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight); h -= y - insets.top; } // Fill background if necessary. if (tabPane.isOpaque()) { Color bg = UIManager.getColor("TabbedPane.contentAreaColor"); g.setColor(bg); g.fillRect(x, y, w, h); } // Paint border. paintContentBorderTopEdge(g, tabPlacement, selectedIndex, x, y, w, h); paintContentBorderLeftEdge(g, tabPlacement, selectedIndex, x, y, w, h); paintContentBorderBottomEdge(g, tabPlacement, selectedIndex, x, y, w, h); paintContentBorderRightEdge(g, tabPlacement, selectedIndex, x, y, w, h); } /** * This method paints the top edge of the content border. * * @param g The Graphics object to paint with. * @param tabPlacement The JTabbedPane's tab placement. * @param selectedIndex The selected tab index. * @param x The x coordinate for the content area. * @param y The y coordinate for the content area. * @param w The width of the content area. * @param h The height of the content area. */ protected void paintContentBorderTopEdge(Graphics g, int tabPlacement, int selectedIndex, int x, int y, int w, int h) { Color saved = g.getColor(); g.setColor(lightHighlight); int startgap = rects[selectedIndex].x - currentScrollOffset; int endgap = rects[selectedIndex].x + rects[selectedIndex].width - currentScrollOffset; // Paint the highlight line with a gap if the tabs are at the top // and the selected tab is inside the visible area. if (tabPlacement == SwingConstants.TOP && startgap >= 0) { g.drawLine(x, y, startgap, y); g.drawLine(endgap, y, x + w - 1, y); g.setColor(selectedColor); g.drawLine(startgap, y, endgap - 1, y); } else g.drawLine(x, y, x + w, y); g.setColor(selectedColor); g.drawLine(x, y + 1, x + w - 1, y + 1); g.drawLine(x, y + 2, x + w - 1, y + 2); g.setColor(saved); } /** * This method paints the left edge of the content border. * * @param g The Graphics object to paint with. * @param tabPlacement The JTabbedPane's tab placement. * @param selectedIndex The selected tab index. * @param x The x coordinate for the content area. * @param y The y coordinate for the content area. * @param w The width of the content area. * @param h The height of the content area. */ protected void paintContentBorderLeftEdge(Graphics g, int tabPlacement, int selectedIndex, int x, int y, int w, int h) { Color saved = g.getColor(); g.setColor(lightHighlight); int startgap = rects[selectedIndex].y - currentScrollOffset; int endgap = rects[selectedIndex].y + rects[selectedIndex].height - currentScrollOffset; if (tabPlacement == SwingConstants.LEFT && startgap >= 0) { g.drawLine(x, y, x, startgap); g.drawLine(x, endgap, x, y + h - 1); g.setColor(selectedColor); g.drawLine(x, startgap, x, endgap - 1); } else g.drawLine(x, y, x, y + h - 1); g.setColor(selectedColor); g.drawLine(x + 1, y + 1, x + 1, y + h - 4); g.setColor(saved); } /** * This method paints the bottom edge of the content border. * * @param g The Graphics object to paint with. * @param tabPlacement The JTabbedPane's tab placement. * @param selectedIndex The selected tab index. * @param x The x coordinate for the content area. * @param y The y coordinate for the content area. * @param w The width of the content area. * @param h The height of the content area. */ protected void paintContentBorderBottomEdge(Graphics g, int tabPlacement, int selectedIndex, int x, int y, int w, int h) { Color saved = g.getColor(); int startgap = rects[selectedIndex].x - currentScrollOffset; int endgap = rects[selectedIndex].x + rects[selectedIndex].width - currentScrollOffset; if (tabPlacement == SwingConstants.BOTTOM && startgap >= 0) { g.setColor(shadow); g.drawLine(x + 1, y + h - 2, startgap, y + h - 2); g.drawLine(endgap, y + h - 2, x + w - 2, y + h - 2); g.setColor(darkShadow); g.drawLine(x, y + h - 1, startgap , y + h - 1); g.drawLine(endgap, y + h - 1, x + w - 1, y + h - 1); g.setColor(selectedColor); g.drawLine(startgap, y + h - 1, endgap - 1, y + h - 1); g.drawLine(startgap, y + h - 2, endgap - 1, y + h - 2); } else { g.setColor(shadow); g.drawLine(x + 1, y + h - 2, x + w - 1, y + h - 2); g.setColor(darkShadow); g.drawLine(x, y + h - 1, x + w - 1, y + h - 1); } g.setColor(selectedColor); g.drawLine(x + 1, y + h - 3, x + w - 2, y + h - 3); g.setColor(saved); } /** * This method paints the right edge of the content border. * * @param g The Graphics object to paint with. * @param tabPlacement The JTabbedPane's tab placement. * @param selectedIndex The selected tab index. * @param x The x coordinate for the content area. * @param y The y coordinate for the content area. * @param w The width of the content area. * @param h The height of the content area. */ protected void paintContentBorderRightEdge(Graphics g, int tabPlacement, int selectedIndex, int x, int y, int w, int h) { Color saved = g.getColor(); int startgap = rects[selectedIndex].y - currentScrollOffset; int endgap = rects[selectedIndex].y + rects[selectedIndex].height - currentScrollOffset; if (tabPlacement == SwingConstants.RIGHT && startgap >= 0) { g.setColor(shadow); g.drawLine(x + w - 2, y + 1, x + w - 2, startgap); g.drawLine(x + w - 2, endgap, x + w - 2, y + h - 2); g.setColor(darkShadow); g.drawLine(x + w - 1, y, x + w - 1, startgap); g.drawLine(x + w - 1, endgap, x + w - 1, y + h - 2); g.setColor(selectedColor); g.drawLine(x + w - 2, startgap, x + w - 2, endgap - 1); g.drawLine(x + w - 1, startgap, x + w - 1, endgap - 1); } else { g.setColor(shadow); g.drawLine(x + w - 2, y + 1, x + w - 2, y + h - 2); g.setColor(darkShadow); g.drawLine(x + w - 1, y, x + w - 1, y + h - 2); } g.setColor(selectedColor); g.drawLine(x + w - 3, y + 1, x + w - 3, y + h - 4); g.setColor(saved); } /** *This method returns the bounds of a tab for the given index * and shifts it by the current scrolling offset if the tabbed * pane is in scrolling tab layout mode.
* *Subclassses should retrievs a tab's bounds by this method * if they want to find out whether the tab is currently visible.
* * @param pane The JTabbedPane. * @param i The index to look for. * * @return The bounds of the tab with the given index. */ public Rectangle getTabBounds(JTabbedPane pane, int i) { // Need to re-layout container if tab does not exist. if (i >= rects.length) layoutManager.layoutContainer(pane); // Properly shift coordinates if scrolling has taken // place. if (pane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT) { Rectangle r = new Rectangle(rects[i]); switch(pane.getTabPlacement()) { case SwingConstants.TOP: case SwingConstants.BOTTOM: r.x -= currentScrollOffset; break; default: r.y -= currentScrollOffset; } return r; } return rects[i]; } /** * This method returns the number of runs. * * @param pane The JTabbedPane. * * @return The number of runs. */ public int getTabRunCount(JTabbedPane pane) { return runCount; } /** * This method returns the tab index given a coordinate. * * @param pane The JTabbedPane. * @param x The x coordinate. * @param y The y coordinate. * * @return The tab index that the coordinate lands in. */ public int tabForCoordinate(JTabbedPane pane, int x, int y) { // Note: This code is tab layout mode agnostic. if (! tabPane.isValid()) tabPane.validate(); int tabCount = tabPane.getTabCount(); // If the user clicked outside of any tab rect the // selection should not change. int index = tabPane.getSelectedIndex(); for (int i = 0; i < tabCount; ++i) { if (rects[i].contains(x, y)) { index = i; break; } } return index; } /** *This method returns the tab bounds in the given rectangle.
* *The returned rectangle will be shifted by the current scroll * offset if the tabbed pane is in scrolling tab layout mode.
. * * @param tabIndex The index to get bounds for. * @param dest The rectangle to store bounds in. * * @return The rectangle passed in. */ protected Rectangle getTabBounds(int tabIndex, Rectangle dest) { dest.setBounds(getTabBounds(tabPane, tabIndex)); return dest; } /** * This method returns the component that is shown in the content area. * * @return The component that is shown in the content area. */ protected Component getVisibleComponent() { return visibleComponent; } /** * This method sets the visible component. * * @param component The component to be set visible. */ protected void setVisibleComponent(Component component) { // Make old component invisible. if (visibleComponent != null && visibleComponent != component && visibleComponent.getParent() == tabPane) { visibleComponent.setVisible(false); } // Make new component visible. if (component != null && ! component.isVisible()) { component.setVisible(true); } visibleComponent = component; } /** * This method assures that enough rectangles are created given the * tabCount. The old array is copied to the new one. * * @param tabCount The number of tabs. */ protected void assureRectsCreated(int tabCount) { if (rects.length < tabCount) { Rectangle[] old = rects; rects = new Rectangle[tabCount]; System.arraycopy(old, 0, rects, 0, old.length); for (int i = old.length; i < rects.length; i++) rects[i] = new Rectangle(); } } /** * This method expands the tabRuns array to give it more room. The old array * is copied to the new one. */ protected void expandTabRunsArray() { // This method adds another 10 index positions to the tabRuns array. if (tabRuns == null) tabRuns = new int[10]; else { int[] newRuns = new int[tabRuns.length + 10]; System.arraycopy(tabRuns, 0, newRuns, 0, tabRuns.length); tabRuns = newRuns; } } /** * This method returns which run a particular tab belongs to. * * @param tabCount The number of tabs. * @param tabIndex The tab to find. * * @return The tabRuns index that it belongs to. */ protected int getRunForTab(int tabCount, int tabIndex) { if (runCount == 1 && tabIndex < tabCount && tabIndex >= 0) return 0; for (int i = 0; i < runCount; i++) { int first = lastTabInRun(tabCount, getPreviousTabRun(i)) + 1; if (first == tabCount) first = 0; int last = lastTabInRun(tabCount, i); if (last >= tabIndex && first <= tabIndex) return i; } return -1; } /** * This method returns the index of the last tab in a run. * * @param tabCount The number of tabs. * @param run The run to check. * * @return The last tab in the given run. */ protected int lastTabInRun(int tabCount, int run) { int lastTab; if (runCount == 1) lastTab = tabCount - 1; else { int nextRun; if (run == runCount - 1) nextRun = 0; else nextRun = run + 1; if (tabRuns[nextRun] == 0) lastTab = tabCount - 1; else lastTab = tabRuns[nextRun] - 1; } return lastTab; } /** * This method returns the tab run overlay. * * @param tabPlacement The JTabbedPane's tab placement. * * @return The tab run overlay. */ protected int getTabRunOverlay(int tabPlacement) { return tabRunOverlay; } /** * This method returns the tab run indent. It is used in WRAP_TAB_LAYOUT and * makes each tab run start indented by a certain amount. * * @param tabPlacement The JTabbedPane's tab placement. * @param run The run to get indent for. * * @return The amount a run should be indented. */ protected int getTabRunIndent(int tabPlacement, int run) { return 0; } /** * This method returns whether a tab run should be padded. * * @param tabPlacement The JTabbedPane's tab placement. * @param run The run to check. * * @return Whether the given run should be padded. */ protected boolean shouldPadTabRun(int tabPlacement, int run) { return true; } /** * This method returns whether the tab runs should be rotated. * * @param tabPlacement The JTabbedPane's tab placement. * * @return Whether runs should be rotated. */ protected boolean shouldRotateTabRuns(int tabPlacement) { return true; } /** * This method returns an icon for the tab. If the tab is disabled, it * should return the disabledIcon. If it is enabled, then it should return * the default icon. * * @param tabIndex The tab index to get an icon for. * * @return The icon for the tab index. */ protected Icon getIconForTab(int tabIndex) { if (tabPane.isEnabledAt(tabIndex)) return tabPane.getIconAt(tabIndex); else return tabPane.getDisabledIconAt(tabIndex); } /** * This method returns a view that can paint the text for the label. * * @param tabIndex The tab index to get a view for. * * @return The view for the tab index. */ protected View getTextViewForTab(int tabIndex) { // FIXME: When the label contains HTML this should return something // non-null. return null; } /** * This method returns the tab height, including insets, for the given index * and fontheight. * * @param tabPlacement The JTabbedPane's tab placement. * @param tabIndex The index of the tab to calculate. * @param fontHeight The font height. * * @return This tab's height. */ protected int calculateTabHeight(int tabPlacement, int tabIndex, int fontHeight) { // FIXME: Handle HTML by using the view (see getTextViewForTab). int height = fontHeight; Icon icon = getIconForTab(tabIndex); Insets tabInsets = getTabInsets(tabPlacement, tabIndex); if (icon != null) height = Math.max(height, icon.getIconHeight()); height += tabInsets.top + tabInsets.bottom + 2; return height; } /** * This method returns the max tab height. * * @param tabPlacement The JTabbedPane's tab placement. * * @return The maximum tab height. */ protected int calculateMaxTabHeight(int tabPlacement) { maxTabHeight = 0; FontMetrics fm = getFontMetrics(); int fontHeight = fm.getHeight(); for (int i = 0; i < tabPane.getTabCount(); i++) maxTabHeight = Math.max(calculateTabHeight(tabPlacement, i, fontHeight), maxTabHeight); return maxTabHeight; } /** * This method calculates the tab width, including insets, for the given tab * index and font metrics. * * @param tabPlacement The JTabbedPane's tab placement. * @param tabIndex The tab index to calculate for. * @param metrics The font's metrics. * * @return The tab width for the given index. */ protected int calculateTabWidth(int tabPlacement, int tabIndex, FontMetrics metrics) { Icon icon = getIconForTab(tabIndex); Insets insets = getTabInsets(tabPlacement, tabIndex); int width = insets.bottom + insets.right + 3; if (icon != null) { width += icon.getIconWidth() + textIconGap; } View v = getTextViewForTab(tabIndex); if (v != null) width += v.getPreferredSpan(View.X_AXIS); else { String label = tabPane.getTitleAt(tabIndex); width += metrics.stringWidth(label); } return width; } /** * This method calculates the max tab width. * * @param tabPlacement The JTabbedPane's tab placement. * * @return The maximum tab width. */ protected int calculateMaxTabWidth(int tabPlacement) { maxTabWidth = 0; FontMetrics fm = getFontMetrics(); for (int i = 0; i < tabPane.getTabCount(); i++) maxTabWidth = Math.max(calculateTabWidth(tabPlacement, i, fm), maxTabWidth); return maxTabWidth; } /** * This method calculates the tab area height, including insets, for the * given amount of runs and tab height. * * @param tabPlacement The JTabbedPane's tab placement. * @param horizRunCount The number of runs. * @param maxTabHeight The max tab height. * * @return The tab area height. */ protected int calculateTabAreaHeight(int tabPlacement, int horizRunCount, int maxTabHeight) { Insets insets = getTabAreaInsets(tabPlacement); int tabAreaHeight = horizRunCount * maxTabHeight - (horizRunCount - 1) * getTabRunOverlay(tabPlacement); tabAreaHeight += insets.top + insets.bottom; return tabAreaHeight; } /** * This method calculates the tab area width, including insets, for the * given amount of runs and tab width. * * @param tabPlacement The JTabbedPane's tab placement. * @param vertRunCount The number of runs. * @param maxTabWidth The max tab width. * * @return The tab area width. */ protected int calculateTabAreaWidth(int tabPlacement, int vertRunCount, int maxTabWidth) { Insets insets = getTabAreaInsets(tabPlacement); int tabAreaWidth = vertRunCount * maxTabWidth - (vertRunCount - 1) * getTabRunOverlay(tabPlacement); tabAreaWidth += insets.left + insets.right; return tabAreaWidth; } /** * This method returns the tab insets appropriately rotated. * * @param tabPlacement The JTabbedPane's tab placement. * @param tabIndex The tab index. * * @return The tab insets for the given index. */ protected Insets getTabInsets(int tabPlacement, int tabIndex) { return tabInsets; } /** * This method returns the selected tab pad insets appropriately rotated. * * @param tabPlacement The JTabbedPane's tab placement. * * @return The selected tab pad insets. */ protected Insets getSelectedTabPadInsets(int tabPlacement) { Insets target = new Insets(0, 0, 0, 0); rotateInsets(selectedTabPadInsets, target, tabPlacement); return target; } /** * This method returns the tab area insets appropriately rotated. * * @param tabPlacement The JTabbedPane's tab placement. * * @return The tab area insets. */ protected Insets getTabAreaInsets(int tabPlacement) { Insets target = new Insets(0, 0, 0, 0); rotateInsets(tabAreaInsets, target, tabPlacement); return target; } /** * This method returns the content border insets appropriately rotated. * * @param tabPlacement The JTabbedPane's tab placement. * * @return The content border insets. */ protected Insets getContentBorderInsets(int tabPlacement) { Insets target = new Insets(0, 0, 0, 0); rotateInsets(contentBorderInsets, target, tabPlacement); return target; } /** * This method returns the fontmetrics for the font of the JTabbedPane. * * @return The font metrics for the JTabbedPane. */ protected FontMetrics getFontMetrics() { FontMetrics fm = tabPane.getFontMetrics(tabPane.getFont()); return fm; } /** * This method navigates from the selected tab into the given direction. As * a result, a new tab will be selected (if possible). * * @param direction The direction to navigate in. */ protected void navigateSelectedTab(int direction) { int tabPlacement = tabPane.getTabPlacement(); if (tabPlacement == SwingConstants.TOP || tabPlacement == SwingConstants.BOTTOM) { if (direction == SwingConstants.WEST) selectPreviousTabInRun(tabPane.getSelectedIndex()); else if (direction == SwingConstants.EAST) selectNextTabInRun(tabPane.getSelectedIndex()); else { int offset = getTabRunOffset(tabPlacement, tabPane.getTabCount(), tabPane.getSelectedIndex(), (tabPlacement == SwingConstants.TOP) ? direction == SwingConstants.NORTH : direction == SwingConstants.SOUTH); selectAdjacentRunTab(tabPlacement, tabPane.getSelectedIndex(), offset); } } if (tabPlacement == SwingConstants.LEFT || tabPlacement == SwingConstants.RIGHT) { if (direction == SwingConstants.NORTH) selectPreviousTabInRun(tabPane.getSelectedIndex()); else if (direction == SwingConstants.SOUTH) selectNextTabInRun(tabPane.getSelectedIndex()); else { int offset = getTabRunOffset(tabPlacement, tabPane.getTabCount(), tabPane.getSelectedIndex(), (tabPlacement == SwingConstants.LEFT) ? direction == SwingConstants.WEST : direction == SwingConstants.EAST); selectAdjacentRunTab(tabPlacement, tabPane.getSelectedIndex(), offset); } } } /** * This method selects the next tab in the run. * * @param current The current selected index. */ protected void selectNextTabInRun(int current) { current = getNextTabIndexInRun(tabPane.getTabCount(), current); if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT) scrollTab(current, tabPane.getTabPlacement()); tabPane.setSelectedIndex(current); } /** * This method selects the previous tab in the run. * * @param current The current selected index. */ protected void selectPreviousTabInRun(int current) { current = getPreviousTabIndexInRun(tabPane.getTabCount(), current); if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT) scrollTab(current, tabPane.getTabPlacement()); tabPane.setSelectedIndex(current); } /** * This method selects the next tab (regardless of runs). * * @param current The current selected index. */ protected void selectNextTab(int current) { current = getNextTabIndex(current); if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT) scrollTab(current, tabPane.getTabPlacement()); tabPane.setSelectedIndex(current); } /** * This method selects the previous tab (regardless of runs). * * @param current The current selected index. */ protected void selectPreviousTab(int current) { current = getPreviousTabIndex(current); if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT) scrollTab(current, tabPane.getTabPlacement()); tabPane.setSelectedIndex(current); } /** * This method selects the correct tab given an offset from the current tab * index. If the tab placement is TOP or BOTTOM, the offset will be in the * y direction, otherwise, it will be in the x direction. A new coordinate * will be found by adding the offset to the current location of the tab. * The tab that the new location will be selected. * * @param tabPlacement The JTabbedPane's tab placement. * @param tabIndex The tab to start from. * @param offset The coordinate offset. */ protected void selectAdjacentRunTab(int tabPlacement, int tabIndex, int offset) { int x = rects[tabIndex].x + rects[tabIndex].width / 2; int y = rects[tabIndex].y + rects[tabIndex].height / 2; switch (tabPlacement) { case SwingConstants.TOP: case SwingConstants.BOTTOM: y += offset; break; case SwingConstants.RIGHT: case SwingConstants.LEFT: x += offset; break; } int index = tabForCoordinate(tabPane, x, y); if (index != -1) { if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT) scrollTab(index, tabPlacement); tabPane.setSelectedIndex(index); } } // This method is called when you press up/down to cycle through tab runs. // it returns the distance (between the two runs' x/y position. // where one run is the current selected run and the other run is the run in the // direction of the scroll (dictated by the forward flag) // the offset is an absolute value of the difference /** * This method calculates the offset distance for use in * selectAdjacentRunTab. The offset returned will be a difference in the y * coordinate between the run in the desired direction and the current run * (for tabPlacement in TOP or BOTTOM). Use x coordinate for LEFT and * RIGHT. * * @param tabPlacement The JTabbedPane's tab placement. * @param tabCount The number of tabs. * @param tabIndex The starting index. * @param forward If forward, the run in the desired direction will be the * next run. * * @return The offset between the two runs. */ protected int getTabRunOffset(int tabPlacement, int tabCount, int tabIndex, boolean forward) { int currRun = getRunForTab(tabCount, tabIndex); int offset; int nextRun = forward ? getNextTabRun(currRun) : getPreviousTabRun(currRun); if (tabPlacement == SwingConstants.TOP || tabPlacement == SwingConstants.BOTTOM) offset = rects[lastTabInRun(tabCount, nextRun)].y - rects[lastTabInRun(tabCount, currRun)].y; else offset = rects[lastTabInRun(tabCount, nextRun)].x - rects[lastTabInRun(tabCount, currRun)].x; return offset; } /** * This method returns the previous tab index. * * @param base The index to start from. * * @return The previous tab index. */ protected int getPreviousTabIndex(int base) { base--; if (base < 0) return tabPane.getTabCount() - 1; return base; } /** * This method returns the next tab index. * * @param base The index to start from. * * @return The next tab index. */ protected int getNextTabIndex(int base) { base++; if (base == tabPane.getTabCount()) return 0; return base; } /** * This method returns the next tab index in the run. If the next index is * out of this run, it will return the starting tab index for the run. * * @param tabCount The number of tabs. * @param base The index to start from. * * @return The next tab index in the run. */ protected int getNextTabIndexInRun(int tabCount, int base) { int index = getNextTabIndex(base); int run = getRunForTab(tabCount, base); if (base == lastTabInRun(tabCount, run)) index = (run > 0) ? lastTabInRun(tabCount, getPreviousTabRun(run)) + 1 : 0; return index; } /** * This method returns the previous tab index in the run. If the previous * index is out of this run, it will return the last index for the run. * * @param tabCount The number of tabs. * @param base The index to start from. * * @return The previous tab index in the run. */ protected int getPreviousTabIndexInRun(int tabCount, int base) { int index = getPreviousTabIndex(base); int run = getRunForTab(tabCount, base); if (index == lastTabInRun(tabCount, getPreviousTabRun(run))) index = lastTabInRun(tabCount, run); return index; } /** * This method returns the index of the previous run. * * @param baseRun The run to start from. * * @return The index of the previous run. */ protected int getPreviousTabRun(int baseRun) { if (getTabRunCount(tabPane) == 1) return 1; int prevRun = --baseRun; if (prevRun < 0) prevRun = getTabRunCount(tabPane) - 1; return prevRun; } /** * This method returns the index of the next run. * * @param baseRun The run to start from. * * @return The index of the next run. */ protected int getNextTabRun(int baseRun) { if (getTabRunCount(tabPane) == 1) return 1; int nextRun = ++baseRun; if (nextRun == getTabRunCount(tabPane)) nextRun = 0; return nextRun; } /** * This method rotates the insets given a direction to rotate them in. * Target placement should be one of TOP, LEFT, BOTTOM, RIGHT. The rotated * insets will be stored in targetInsets. Passing in TOP as the direction * does nothing. Passing in LEFT switches top and left, right and bottom. * Passing in BOTTOM switches top and bottom. Passing in RIGHT switches top * for left, left for bottom, bottom for right, and right for top. * * @param topInsets The reference insets. * @param targetInsets An Insets object to store the new insets. * @param targetPlacement The rotation direction. */ protected static void rotateInsets(Insets topInsets, Insets targetInsets, int targetPlacement) { // Sun's version will happily throw an NPE if params are null, // so I won't check it either. switch (targetPlacement) { default: case SwingConstants.TOP: targetInsets.top = topInsets.top; targetInsets.left = topInsets.left; targetInsets.right = topInsets.right; targetInsets.bottom = topInsets.bottom; break; case SwingConstants.LEFT: targetInsets.left = topInsets.top; targetInsets.top = topInsets.left; targetInsets.right = topInsets.bottom; targetInsets.bottom = topInsets.right; break; case SwingConstants.BOTTOM: targetInsets.top = topInsets.bottom; targetInsets.bottom = topInsets.top; targetInsets.left = topInsets.left; targetInsets.right = topInsets.right; break; case SwingConstants.RIGHT: targetInsets.top = topInsets.left; targetInsets.left = topInsets.bottom; targetInsets.bottom = topInsets.right; targetInsets.right = topInsets.top; break; } } ActionMap getActionMap() { ActionMap map = (ActionMap) UIManager.get("TabbedPane.actionMap"); if (map == null) // first time here { map = createActionMap(); if (map != null) UIManager.put("TabbedPane.actionMap", map); } return map; } ActionMap createActionMap() { ActionMap map = new ActionMapUIResource(); map.put("navigatePageDown", new NavigatePageDownAction()); map.put("navigatePageUp", new NavigatePageUpAction()); map.put("navigateDown", new NavigateAction("navigateDown", SwingConstants.SOUTH)); map.put("navigateUp", new NavigateAction("navigateUp", SwingConstants.NORTH)); map.put("navigateLeft", new NavigateAction("navigateLeft", SwingConstants.WEST)); map.put("navigateRight", new NavigateAction("navigateRight", SwingConstants.EAST)); map.put("requestFocusForVisibleComponent", new RequestFocusForVisibleComponentAction()); map.put("requestFocus", new RequestFocusAction()); return map; } /** * Sets the tab which should be highlighted when in rollover mode. And *index
of -1
means that the rollover tab
* is deselected (i.e. the mouse is outside of the tabarea).
*
* @param index the index of the tab that is under the mouse, -1
* for no tab
*
* @since 1.5
*/
protected void setRolloverTab(int index)
{
rolloverTab = index;
}
/**
* Retunrs the index of the tab over which the mouse is currently moving,
* or -1
for no tab.
*
* @return the index of the tab over which the mouse is currently moving,
* or -1
for no tab
*
* @since 1.5
*/
protected int getRolloverTab()
{
return rolloverTab;
}
}