FileDocCategorySizeDatePackage
BasicTabbedPaneUI.javaAPI DocJava SE 6 API151792Tue Jun 10 00:26:48 BST 2008javax.swing.plaf.basic

BasicTabbedPaneUI

public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
A Basic L&F implementation of TabbedPaneUI.
version
1.87 06/08/99
author
Amy Fowler
author
Philip Milne
author
Steve Wilson
author
Tom Santos
author
Dave Moore

Fields Summary
protected JTabbedPane
tabPane
protected Color
highlight
protected Color
lightHighlight
protected Color
shadow
protected Color
darkShadow
protected Color
focus
private Color
selectedColor
protected int
textIconGap
protected int
tabRunOverlay
protected Insets
tabInsets
protected Insets
selectedTabPadInsets
protected Insets
tabAreaInsets
protected Insets
contentBorderInsets
private boolean
tabsOverlapBorder
private boolean
tabsOpaque
private boolean
contentOpaque
protected KeyStroke
upKey
As of Java 2 platform v1.3 this previously undocumented field is no longer used. Key bindings are now defined by the LookAndFeel, please refer to the key bindings specification for further details.
protected KeyStroke
downKey
As of Java 2 platform v1.3 this previously undocumented field is no longer used. Key bindings are now defined by the LookAndFeel, please refer to the key bindings specification for further details.
protected KeyStroke
leftKey
As of Java 2 platform v1.3 this previously undocumented field is no longer used. Key bindings are now defined by the LookAndFeel, please refer to the key bindings specification for further details.
protected KeyStroke
rightKey
As of Java 2 platform v1.3 this previously undocumented field is no longer used. Key bindings are now defined by the LookAndFeel, please refer to the key bindings specification for further details.
protected int[]
tabRuns
protected int
runCount
protected int
selectedRun
protected Rectangle[]
rects
protected int
maxTabHeight
protected int
maxTabWidth
protected ChangeListener
tabChangeListener
protected PropertyChangeListener
propertyChangeListener
protected MouseListener
mouseListener
protected FocusListener
focusListener
private Insets
currentPadInsets
private Insets
currentTabAreaInsets
private Component
visibleComponent
private Vector
htmlViews
private Hashtable
mnemonicToIndexMap
private InputMap
mnemonicInputMap
InputMap used for mnemonics. Only non-null if the JTabbedPane has mnemonics associated with it. Lazily created in initMnemonics.
private ScrollableTabSupport
tabScroller
private TabContainer
tabContainer
protected transient Rectangle
calcRect
A rectangle used for general layout calculations in order to avoid constructing many new Rectangles on the fly.
private int
focusIndex
Tab that has focus.
private Handler
handler
Combined listeners.
private int
rolloverTabIndex
Index of the tab the mouse is over.
private boolean
isRunsDirty
This is set to true when a component is added/removed from the tab pane and set to false when layout happens. If true it indicates that tabRuns is not valid and shouldn't be used.
private boolean
calculatedBaseline
private int
baseline
private static int[]
xCropLen
private static int[]
yCropLen
private static final int
CROP_SEGMENT
Constructors Summary
Methods Summary
private voidaddMnemonic(int index, int mnemonic)
Adds the specified mnemonic at the specified index.

        if (mnemonicToIndexMap == null) {
            initMnemonics();
        }
        mnemonicInputMap.put(KeyStroke.getKeyStroke(mnemonic, Event.ALT_MASK),
                             "setSelectedIndex");
        mnemonicToIndexMap.put(new Integer(mnemonic), new Integer(index));
    
protected voidassureRectsCreated(int tabCount)

        int rectArrayLen = rects.length; 
        if (tabCount != rectArrayLen ) {
            Rectangle[] tempRectArray = new Rectangle[tabCount];
            System.arraycopy(rects, 0, tempRectArray, 0, 
                             Math.min(rectArrayLen, tabCount));
            rects = tempRectArray;
            for (int rectIndex = rectArrayLen; rectIndex < tabCount; rectIndex++) {
                rects[rectIndex] = new Rectangle();
            }
        } 

    
private voidcalculateBaseline()

        int tabCount = tabPane.getTabCount();
        int tabPlacement = tabPane.getTabPlacement();
        maxTabHeight = calculateMaxTabHeight(tabPlacement);
        baseline = getBaseline(0);
        if (isHorizontalTabPlacement()) {
            for(int i = 1; i < tabCount; i++) {
                if (getBaseline(i) != baseline) {
                    baseline = -1;
                    break;
                }
            }
        }
        else {
            // left/right, tabs may be different sizes.
            FontMetrics fontMetrics = getFontMetrics();
            int fontHeight = fontMetrics.getHeight();
            int height = calculateTabHeight(tabPlacement, 0, fontHeight);
            for(int i = 1; i < tabCount; i++) {
                int newHeight = calculateTabHeight(tabPlacement, i,fontHeight);
                if (height != newHeight) {
                    // assume different baseline
                    baseline = -1;
                    break;
                }
            }
        }
    
private intcalculateBaselineIfNecessary()

        if (!calculatedBaseline) {
            calculatedBaseline = true;
            baseline = -1;
            if (tabPane.getTabCount() > 0) {
                calculateBaseline();
            }
        }
        return baseline;
    
protected intcalculateMaxTabHeight(int tabPlacement)

        FontMetrics metrics = getFontMetrics();
        int tabCount = tabPane.getTabCount();
        int result = 0; 
        int fontHeight = metrics.getHeight();
        for(int i = 0; i < tabCount; i++) {
            result = Math.max(calculateTabHeight(tabPlacement, i, fontHeight), result);
        }
        return result; 
    
protected intcalculateMaxTabWidth(int tabPlacement)

        FontMetrics metrics = getFontMetrics();
        int tabCount = tabPane.getTabCount();
        int result = 0; 
        for(int i = 0; i < tabCount; i++) {
            result = Math.max(calculateTabWidth(tabPlacement, i, metrics), result);
        }
        return result; 
    
protected intcalculateTabAreaHeight(int tabPlacement, int horizRunCount, int maxTabHeight)

        Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
        int tabRunOverlay = getTabRunOverlay(tabPlacement);
        return (horizRunCount > 0? 
                horizRunCount * (maxTabHeight-tabRunOverlay) + tabRunOverlay + 
                tabAreaInsets.top + tabAreaInsets.bottom : 
                0);
    
protected intcalculateTabAreaWidth(int tabPlacement, int vertRunCount, int maxTabWidth)

 
        Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
        int tabRunOverlay = getTabRunOverlay(tabPlacement);
        return (vertRunCount > 0? 
                vertRunCount * (maxTabWidth-tabRunOverlay) + tabRunOverlay + 
                tabAreaInsets.left + tabAreaInsets.right : 
                0);
    
protected intcalculateTabHeight(int tabPlacement, int tabIndex, int fontHeight)

        int height = 0;
        Component c = tabPane.getTabComponentAt(tabIndex);
        if (c != null) {
            height = c.getPreferredSize().height;
        } else {
            View v = getTextViewForTab(tabIndex);
            if (v != null) {
                // html
                height += (int) v.getPreferredSpan(View.Y_AXIS);
            } else {
                // plain text
                height += fontHeight;
            }
            Icon icon = getIconForTab(tabIndex);

            if (icon != null) {
                height = Math.max(height, icon.getIconHeight());
            }
        }
        Insets tabInsets = getTabInsets(tabPlacement, tabIndex);
        height += tabInsets.top + tabInsets.bottom + 2;
        return height;
    
protected intcalculateTabWidth(int tabPlacement, int tabIndex, java.awt.FontMetrics metrics)

        Insets tabInsets = getTabInsets(tabPlacement, tabIndex);
        int width = tabInsets.left + tabInsets.right + 3;
        Component tabComponent = tabPane.getTabComponentAt(tabIndex);
        if (tabComponent != null) {
            width += tabComponent.getPreferredSize().width;
        } else {
            Icon icon = getIconForTab(tabIndex);
            if (icon != null) {
                width += icon.getIconWidth() + textIconGap;
            }
            View v = getTextViewForTab(tabIndex);
            if (v != null) {
                // html
                width += (int) v.getPreferredSpan(View.X_AXIS);
            } else {
                // plain text
                String title = tabPane.getTitleAt(tabIndex);
                width += SwingUtilities2.stringWidth(tabPane, metrics, title);
            }
        }
        return width;
    
protected javax.swing.event.ChangeListenercreateChangeListener()

        return getHandler();
    
private static java.awt.PolygoncreateCroppedTabShape(int tabPlacement, java.awt.Rectangle tabRect, int cropline)


             
        int rlen = 0;
        int start = 0;
        int end = 0;
        int ostart = 0;

        switch(tabPlacement) {
          case LEFT:
          case RIGHT:
              rlen = tabRect.width;
              start = tabRect.x;
              end = tabRect.x + tabRect.width;
              ostart = tabRect.y + tabRect.height;
              break;
          case TOP:
          case BOTTOM:
          default:
             rlen = tabRect.height;            
             start = tabRect.y;
             end = tabRect.y + tabRect.height;
             ostart = tabRect.x + tabRect.width;
        }
        int rcnt = rlen/CROP_SEGMENT;
        if (rlen%CROP_SEGMENT > 0) {
            rcnt++;
        }
        int npts = 2 + (rcnt*8);
        int xp[] = new int[npts];
        int yp[] = new int[npts];
        int pcnt = 0;
 
        xp[pcnt] = ostart;
        yp[pcnt++] = end;
        xp[pcnt] = ostart;
        yp[pcnt++] = start;
        for(int i = 0; i < rcnt; i++) {
            for(int j = 0; j < xCropLen.length; j++) {
                xp[pcnt] = cropline - xCropLen[j];
                yp[pcnt] = start + (i*CROP_SEGMENT) + yCropLen[j];
                if (yp[pcnt] >= end) {
                    yp[pcnt] = end;
                    pcnt++;
                    break;
                }
                pcnt++;
            }                           
        }
        if (tabPlacement == JTabbedPane.TOP || tabPlacement == JTabbedPane.BOTTOM) {
           return new Polygon(xp, yp, pcnt);

        } else { // LEFT or RIGHT
           return new Polygon(yp, xp, pcnt);
        }           
    
protected java.awt.event.FocusListenercreateFocusListener()

        return getHandler();
    
private java.util.VectorcreateHTMLVector()

        Vector htmlViews = new Vector();
        int count = tabPane.getTabCount();
        if (count>0) {
            for (int i=0 ; i<count; i++) {
                String title = tabPane.getTitleAt(i);
                if (BasicHTML.isHTMLString(title)) {
                    htmlViews.addElement(BasicHTML.createHTMLView(tabPane, title));
                } else {
                    htmlViews.addElement(null);
                }
            }
        }
        return htmlViews;
    
protected java.awt.LayoutManagercreateLayoutManager()
Invoked by installUI to create a layout manager object to manage the JTabbedPane.

return
a layout manager object
see
TabbedPaneLayout
see
javax.swing.JTabbedPane#getTabLayoutPolicy

        if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT) {
            return new TabbedPaneScrollLayout();
        } else { /* WRAP_TAB_LAYOUT */
            return new TabbedPaneLayout();
        }
    
protected java.awt.event.MouseListenercreateMouseListener()

        return getHandler();
    
protected java.beans.PropertyChangeListenercreatePropertyChangeListener()

        return getHandler();
    
protected javax.swing.JButtoncreateScrollButton(int direction)
Creates and returns a JButton that will provide the user with a way to scroll the tabs in a particular direction. The returned JButton must be instance of UIResource.

param
direction One of the SwingConstants constants: SOUTH, NORTH, EAST or WEST
return
Widget for user to
see
javax.swing.JTabbedPane#setTabPlacement
see
javax.swing.SwingConstants
throws
IllegalArgumentException if direction is not one of NORTH, SOUTH, EAST or WEST
since
1.5

        if (direction != SOUTH && direction != NORTH && direction != EAST &&
                                  direction != WEST) {
            throw new IllegalArgumentException("Direction must be one of: " +
                                               "SOUTH, NORTH, EAST or WEST");
        }
        return new ScrollableTabButton(direction);
    
public static javax.swing.plaf.ComponentUIcreateUI(javax.swing.JComponent c)


// UI creation

         
        return new BasicTabbedPaneUI();
    
private voidensureCurrentLayout()

        if (!tabPane.isValid()) {
            tabPane.validate();
        } 
        /* If tabPane doesn't have a peer yet, the validate() call will
         * silently fail.  We handle that by forcing a layout if tabPane
         * is still invalid.  See bug 4237677.
         */
        if (!tabPane.isValid()) {
            TabbedPaneLayout layout = (TabbedPaneLayout)tabPane.getLayout();
            layout.calculateLayoutInfo();          
        }
    
protected voidexpandTabRunsArray()

        int rectLen = tabRuns.length;
        int[] newArray = new int[rectLen+10];
        System.arraycopy(tabRuns, 0, newArray, 0, runCount);
        tabRuns = newArray;
    
public intgetBaseline(javax.swing.JComponent c, int width, int height)
Returns the baseline.

throws
NullPointerException {@inheritDoc}
throws
IllegalArgumentException {@inheritDoc}
see
javax.swing.JComponent#getBaseline(int, int)
since
1.6

        super.getBaseline(c, width, height);
        int baseline = calculateBaselineIfNecessary();
        if (baseline != -1) {
            int placement = tabPane.getTabPlacement();
            Insets insets = tabPane.getInsets();
            Insets tabAreaInsets = getTabAreaInsets(placement);
            switch(placement) {
            case JTabbedPane.TOP:
                baseline += insets.top + tabAreaInsets.top;
                return baseline;
            case JTabbedPane.BOTTOM:
                baseline = height - insets.bottom -
                    tabAreaInsets.bottom - maxTabHeight + baseline;
                return baseline;
            case JTabbedPane.LEFT:
            case JTabbedPane.RIGHT:
                baseline += insets.top + tabAreaInsets.top;
                return baseline;
            }
        }
        return -1;
    
protected intgetBaseline(int tab)
Returns the baseline for the specified tab.

param
tab index of tab to get baseline for
exception
IndexOutOfBoundsException if index is out of range (index < 0 || index >= tab count)
return
baseline or a value < 0 indicating there is no reasonable baseline
since
1.6

        if (tabPane.getTabComponentAt(tab) != null) {
            int offset = getBaselineOffset();
            if (offset != 0) {
                // The offset is not applied to the tab component, and so
                // in general we can't get good alignment like with components
                // in the tab.
                return -1;
            }
            Component c = tabPane.getTabComponentAt(tab);
            Dimension pref = c.getPreferredSize();
            Insets tabInsets = getTabInsets(tabPane.getTabPlacement(), tab);
            int cellHeight = maxTabHeight - tabInsets.top - tabInsets.bottom;
            return c.getBaseline(pref.width, pref.height) +
                    (cellHeight - pref.height) / 2 + tabInsets.top;
        }
        else {
            View view = getTextViewForTab(tab);
            if (view != null) {
                int viewHeight = (int)view.getPreferredSpan(View.Y_AXIS);
                int baseline = BasicHTML.getHTMLBaseline(
                    view, (int)view.getPreferredSpan(View.X_AXIS), viewHeight);
                if (baseline >= 0) {
                    return maxTabHeight / 2 - viewHeight / 2 + baseline +
                        getBaselineOffset();
                }
                return -1;
            }
        }
        FontMetrics metrics = getFontMetrics();
        int fontHeight = metrics.getHeight();
        int fontBaseline = metrics.getAscent();
        return maxTabHeight / 2 - fontHeight / 2 + fontBaseline +
                getBaselineOffset();
    
protected intgetBaselineOffset()
Returns the amount the baseline is offset by. This is typically the same as getTabLabelShiftY.

return
amount to offset the baseline by
since
1.6

        switch(tabPane.getTabPlacement()) {
        case JTabbedPane.TOP:
            if (tabPane.getTabCount() > 1) {
                return 1;
            }
            else {
                return -1;
            }
        case JTabbedPane.BOTTOM:
            if (tabPane.getTabCount() > 1) {
                return -1;
            }
            else {
                return 1;
            }
        default: // RIGHT|LEFT
            return (maxTabHeight % 2);
        }
    
public java.awt.Component$BaselineResizeBehaviorgetBaselineResizeBehavior(javax.swing.JComponent c)
Returns an enum indicating how the baseline of the component changes as the size changes.

throws
NullPointerException {@inheritDoc}
see
javax.swing.JComponent#getBaseline(int, int)
since
1.6

        super.getBaselineResizeBehavior(c);
        switch(tabPane.getTabPlacement()) {
        case JTabbedPane.LEFT:
        case JTabbedPane.RIGHT:
        case JTabbedPane.TOP:
            return Component.BaselineResizeBehavior.CONSTANT_ASCENT;
        case JTabbedPane.BOTTOM:
            return Component.BaselineResizeBehavior.CONSTANT_DESCENT;
        }
        return Component.BaselineResizeBehavior.OTHER;
    
private intgetClosestTab(int x, int y)
Returns the index of the tab closest to the passed in location, note that the returned tab may not contain the location x,y.

        int min = 0;
        int tabCount = Math.min(rects.length, tabPane.getTabCount());
        int max = tabCount;
        int tabPlacement = tabPane.getTabPlacement();
        boolean useX = (tabPlacement == TOP || tabPlacement == BOTTOM);
        int want = (useX) ? x : y;

        while (min != max) {
            int current = (max + min) / 2;
            int minLoc;
            int maxLoc;

            if (useX) {
                minLoc = rects[current].x;
                maxLoc = minLoc + rects[current].width;
            }
            else {
                minLoc = rects[current].y;
                maxLoc = minLoc + rects[current].height;
            }
            if (want < minLoc) {
                max = current;
                if (min == max) {
                    return Math.max(0, current - 1);
                }
            }
            else if (want >= maxLoc) {
                min = current;
                if (max - min <= 1) {
                    return Math.max(current + 1, tabCount - 1);
                }
            }
            else {
                return current;
            }
        }
        return min;
    
protected java.awt.InsetsgetContentBorderInsets(int tabPlacement)

        return contentBorderInsets;
    
protected intgetFocusIndex()
Returns the index of the tab that has focus.

return
index of tab that has focus
since
1.5

        return focusIndex;
    
protected java.awt.FontMetricsgetFontMetrics()

        Font font = tabPane.getFont();
        return tabPane.getFontMetrics(font);
    
private javax.swing.plaf.basic.BasicTabbedPaneUI$HandlergetHandler()

        if (handler == null) {
            handler = new Handler();
        }
        return handler;
    
protected javax.swing.IcongetIconForTab(int tabIndex)

        return (!tabPane.isEnabled() || !tabPane.isEnabledAt(tabIndex))?
                          tabPane.getDisabledIconAt(tabIndex) : tabPane.getIconAt(tabIndex);
    
javax.swing.InputMapgetInputMap(int condition)

        if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) {
            return (InputMap)DefaultLookup.get(tabPane, this,
                                               "TabbedPane.ancestorInputMap");
        }
        else if (condition == JComponent.WHEN_FOCUSED) {
            return (InputMap)DefaultLookup.get(tabPane, this,
                                               "TabbedPane.focusInputMap");
        }
        return null;
    
public java.awt.DimensiongetMaximumSize(javax.swing.JComponent c)

        // Default to LayoutManager's maximumLayoutSize
        return null;
    
public java.awt.DimensiongetMinimumSize(javax.swing.JComponent c)

        // Default to LayoutManager's minimumLayoutSize
        return null;
    
protected intgetNextTabIndex(int base)

        return (base+1)%tabPane.getTabCount();
    
protected intgetNextTabIndexInRun(int tabCount, int base)

        if (runCount < 2) {
            return getNextTabIndex(base);
        }
        int currentRun = getRunForTab(tabCount, base);
        int next = getNextTabIndex(base);
        if (next == tabRuns[getNextTabRun(currentRun)]) {
            return tabRuns[currentRun];
        }
        return next;
    
protected intgetNextTabRun(int baseRun)

        return (baseRun+1)%runCount;
    
protected intgetPreviousTabIndex(int base)

        int tabIndex = (base - 1 >= 0? base - 1 : tabPane.getTabCount() - 1);
        return (tabIndex >= 0? tabIndex : 0);
    
protected intgetPreviousTabIndexInRun(int tabCount, int base)

        if (runCount < 2) {
            return getPreviousTabIndex(base);
        }
        int currentRun = getRunForTab(tabCount, base);
        if (base == tabRuns[currentRun]) {
            int previous = tabRuns[getNextTabRun(currentRun)]-1;
            return (previous != -1? previous : tabCount-1);
        }
        return getPreviousTabIndex(base);
    
protected intgetPreviousTabRun(int baseRun)

        int runIndex = (baseRun - 1 >= 0? baseRun - 1 : runCount - 1);
        return (runIndex >= 0? runIndex : 0);
    
protected intgetRolloverTab()
Returns the tab the mouse is currently over, or {@code -1} if the mouse is no longer over any tab.

return
the tab the mouse is currently over, or {@code -1} if the mouse is no longer over any tab
since
1.5

        return rolloverTabIndex;
    
protected intgetRunForTab(int tabCount, int tabIndex)

        for (int i = 0; i < runCount; i++) {
            int first = tabRuns[i];
            int last = lastTabInRun(tabCount, i);
            if (tabIndex >= first && tabIndex <= last) {
                return i;
            }
        }
        return 0;
    
protected java.awt.InsetsgetSelectedTabPadInsets(int tabPlacement)

        rotateInsets(selectedTabPadInsets, currentPadInsets, tabPlacement);
        return currentPadInsets;
    
protected java.awt.InsetsgetTabAreaInsets(int tabPlacement)

        rotateInsets(tabAreaInsets, currentTabAreaInsets, tabPlacement);
        return currentTabAreaInsets;
    
public java.awt.RectanglegetTabBounds(javax.swing.JTabbedPane pane, int i)
Returns the bounds of the specified tab index. The bounds are with respect to the JTabbedPane's coordinate space.

 
        ensureCurrentLayout();
        Rectangle tabRect = new Rectangle();
        return getTabBounds(i, tabRect);
    
protected java.awt.RectanglegetTabBounds(int tabIndex, java.awt.Rectangle dest)
Returns the bounds of the specified tab in the coordinate space of the JTabbedPane component. This is required because the tab rects are by default defined in the coordinate space of the component where they are rendered, which could be the JTabbedPane (for WRAP_TAB_LAYOUT) or a ScrollableTabPanel (SCROLL_TAB_LAYOUT). This method should be used whenever the tab rectangle must be relative to the JTabbedPane itself and the result should be placed in a designated Rectangle object (rather than instantiating and returning a new Rectangle each time). The tab index parameter must be a valid tabbed pane tab index (0 to tab count - 1, inclusive). The destination rectangle parameter must be a valid Rectangle instance. The handling of invalid parameters is unspecified.

param
tabIndex the index of the tab
param
dest the rectangle where the result should be placed
return
the resulting rectangle
since
1.4

        dest.width = rects[tabIndex].width;
        dest.height = rects[tabIndex].height;

        if (scrollableTabLayoutEnabled()) { // SCROLL_TAB_LAYOUT
            // Need to translate coordinates based on viewport location & 
            // view position
            Point vpp = tabScroller.viewport.getLocation();
            Point viewp = tabScroller.viewport.getViewPosition();
            dest.x = rects[tabIndex].x + vpp.x - viewp.x;
            dest.y = rects[tabIndex].y + vpp.y - viewp.y;

        } else { // WRAP_TAB_LAYOUT
            dest.x = rects[tabIndex].x;
            dest.y = rects[tabIndex].y;
        }
        return dest;
    
protected java.awt.InsetsgetTabInsets(int tabPlacement, int tabIndex)

        return tabInsets;
    
protected intgetTabLabelShiftX(int tabPlacement, int tabIndex, boolean isSelected)

        Rectangle tabRect = rects[tabIndex];
        int nudge = 0;
        switch(tabPlacement) {
          case LEFT:
              nudge = isSelected? -1 : 1;
              break;
          case RIGHT:
              nudge = isSelected? 1 : -1;
              break;
          case BOTTOM:
          case TOP:
          default:
              nudge = tabRect.width % 2;
        }
        return nudge;
    
protected intgetTabLabelShiftY(int tabPlacement, int tabIndex, boolean isSelected)

        Rectangle tabRect = rects[tabIndex];
        int nudge = 0;
        switch(tabPlacement) {
           case BOTTOM:
              nudge = isSelected? 1 : -1;
              break;
          case LEFT:
          case RIGHT:
              nudge = tabRect.height % 2;
              break;
          case TOP:
          default:
              nudge = isSelected? -1 : 1;;
        }
        return nudge;
    
public intgetTabRunCount(javax.swing.JTabbedPane pane)

        ensureCurrentLayout();
        return runCount;
    
protected intgetTabRunIndent(int tabPlacement, int run)

        return 0;
    
protected intgetTabRunOffset(int tabPlacement, int tabCount, int tabIndex, boolean forward)

        int run = getRunForTab(tabCount, tabIndex);
        int offset;
        switch(tabPlacement) {
          case LEFT: {
              if (run == 0) {
                  offset = (forward? 
                            -(calculateTabAreaWidth(tabPlacement, runCount, maxTabWidth)-maxTabWidth) :
                            -maxTabWidth);

              } else if (run == runCount - 1) {
                  offset = (forward?
                            maxTabWidth :
                            calculateTabAreaWidth(tabPlacement, runCount, maxTabWidth)-maxTabWidth);
              } else {
                  offset = (forward? maxTabWidth : -maxTabWidth);
              }
              break;
          }
          case RIGHT: {
              if (run == 0) {
                  offset = (forward? 
                            maxTabWidth :
                            calculateTabAreaWidth(tabPlacement, runCount, maxTabWidth)-maxTabWidth);
              } else if (run == runCount - 1) {
                  offset = (forward?
                            -(calculateTabAreaWidth(tabPlacement, runCount, maxTabWidth)-maxTabWidth) :
                            -maxTabWidth);
              } else {
                  offset = (forward? maxTabWidth : -maxTabWidth);
              } 
              break;
          }
          case BOTTOM: {
              if (run == 0) {
                  offset = (forward? 
                            maxTabHeight :
                            calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight)-maxTabHeight);
              } else if (run == runCount - 1) {
                  offset = (forward?
                            -(calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight)-maxTabHeight) :
                            -maxTabHeight);
              } else {
                  offset = (forward? maxTabHeight : -maxTabHeight);
              } 
              break;
          }
          case TOP:
          default: {
              if (run == 0) {
                  offset = (forward? 
                            -(calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight)-maxTabHeight) :
                            -maxTabHeight);
              } else if (run == runCount - 1) {
                  offset = (forward?
                            maxTabHeight :
                            calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight)-maxTabHeight);
              } else {
                  offset = (forward? maxTabHeight : -maxTabHeight);
              }
          }
        }
        return offset;
    
protected intgetTabRunOverlay(int tabPlacement)

        return tabRunOverlay;
    
protected javax.swing.text.ViewgetTextViewForTab(int tabIndex)
Returns the text View object required to render stylized text (HTML) for the specified tab or null if no specialized text rendering is needed for this tab. This is provided to support html rendering inside tabs.

param
tabIndex the index of the tab
return
the text view to render the tab's text or null if no specialized rendering is required
since
1.4

        if (htmlViews != null) {
            return (View)htmlViews.elementAt(tabIndex);
        }
        return null;
    
protected java.awt.ComponentgetVisibleComponent()

        return visibleComponent;
    
private voidinitMnemonics()
Installs the state needed for mnemonics.

        mnemonicToIndexMap = new Hashtable();
        mnemonicInputMap = new ComponentInputMapUIResource(tabPane);
        mnemonicInputMap.setParent(SwingUtilities.getUIInputMap(tabPane,
                              JComponent.WHEN_IN_FOCUSED_WINDOW));
        SwingUtilities.replaceUIInputMap(tabPane,
                              JComponent.WHEN_IN_FOCUSED_WINDOW,
                                         mnemonicInputMap);
    
protected voidinstallComponents()
Creates and installs any required subcomponents for the JTabbedPane. Invoked by installUI.

since
1.4

        if (scrollableTabLayoutEnabled()) {
            if (tabScroller == null) {
                tabScroller = new ScrollableTabSupport(tabPane.getTabPlacement());
                tabPane.add(tabScroller.viewport);
            }
        }
        installTabContainer();
    
protected voidinstallDefaults()

        LookAndFeel.installColorsAndFont(tabPane, "TabbedPane.background",
                                    "TabbedPane.foreground", "TabbedPane.font");     
        highlight = UIManager.getColor("TabbedPane.light");
        lightHighlight = UIManager.getColor("TabbedPane.highlight");
        shadow = UIManager.getColor("TabbedPane.shadow");
        darkShadow = UIManager.getColor("TabbedPane.darkShadow");
        focus = UIManager.getColor("TabbedPane.focus");
        selectedColor = UIManager.getColor("TabbedPane.selected");

        textIconGap = UIManager.getInt("TabbedPane.textIconGap");
        tabInsets = UIManager.getInsets("TabbedPane.tabInsets");
        selectedTabPadInsets = UIManager.getInsets("TabbedPane.selectedTabPadInsets");
        tabAreaInsets = UIManager.getInsets("TabbedPane.tabAreaInsets");
	tabsOverlapBorder = UIManager.getBoolean("TabbedPane.tabsOverlapBorder");
        contentBorderInsets = UIManager.getInsets("TabbedPane.contentBorderInsets");
        tabRunOverlay = UIManager.getInt("TabbedPane.tabRunOverlay");
        tabsOpaque = UIManager.getBoolean("TabbedPane.tabsOpaque");
        contentOpaque = UIManager.getBoolean("TabbedPane.contentOpaque");
        Object opaque = UIManager.get("TabbedPane.opaque");
        if (opaque == null) {
            opaque = Boolean.FALSE;
        }
        LookAndFeel.installProperty(tabPane, "opaque", opaque);
    
protected voidinstallKeyboardActions()

        InputMap km = getInputMap(JComponent.
                                  WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);

        SwingUtilities.replaceUIInputMap(tabPane, JComponent.
                                         WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
                                         km);
        km = getInputMap(JComponent.WHEN_FOCUSED);
        SwingUtilities.replaceUIInputMap(tabPane, JComponent.WHEN_FOCUSED, km);

        LazyActionMap.installLazyActionMap(tabPane, BasicTabbedPaneUI.class,
                                           "TabbedPane.actionMap");
        updateMnemonics();
    
protected voidinstallListeners()

        if ((propertyChangeListener = createPropertyChangeListener()) != null) {
            tabPane.addPropertyChangeListener(propertyChangeListener);
        }
        if ((tabChangeListener = createChangeListener()) != null) {            
            tabPane.addChangeListener(tabChangeListener);
        }
        if ((mouseListener = createMouseListener()) != null) {
            tabPane.addMouseListener(mouseListener);
        }
        tabPane.addMouseMotionListener(getHandler());
        if ((focusListener = createFocusListener()) != null) {
            tabPane.addFocusListener(focusListener);
        }
        tabPane.addContainerListener(getHandler());
        if (tabPane.getTabCount()>0) {
            htmlViews = createHTMLVector();
        }
    
private voidinstallTabContainer()

         for (int i = 0; i < tabPane.getTabCount(); i++) {
             Component tabComponent = tabPane.getTabComponentAt(i);
             if (tabComponent != null) {
                 if(tabContainer == null) {
                     tabContainer = new TabContainer();
                 }
                 tabContainer.add(tabComponent);
             }
         }
         if(tabContainer == null) {
             return;
         }
         if (scrollableTabLayoutEnabled()) {
             tabScroller.tabPanel.add(tabContainer);
         } else {
             tabPane.add(tabContainer);
         }
    
public voidinstallUI(javax.swing.JComponent c)

        this.tabPane = (JTabbedPane)c;

        calculatedBaseline = false;
        rolloverTabIndex = -1;
        focusIndex = -1;
        c.setLayout(createLayoutManager());
        installComponents();
        installDefaults(); 
        installListeners();
        installKeyboardActions();
    
private booleanisHorizontalTabPlacement()

        return tabPane.getTabPlacement() == TOP || tabPane.getTabPlacement() == BOTTOM; 
    
protected intlastTabInRun(int tabCount, int run)

        if (runCount == 1) {
            return tabCount - 1;
        }
        int nextRun = (run == runCount - 1? 0 : run + 1);
        if (tabRuns[nextRun] == 0) {
            return tabCount - 1;
        }
        return tabRuns[nextRun]-1;
    
protected voidlayoutLabel(int tabPlacement, java.awt.FontMetrics metrics, int tabIndex, java.lang.String title, javax.swing.Icon icon, java.awt.Rectangle tabRect, java.awt.Rectangle iconRect, java.awt.Rectangle textRect, boolean isSelected)

        textRect.x = textRect.y = iconRect.x = iconRect.y = 0;

        View v = getTextViewForTab(tabIndex);
        if (v != null) {
            tabPane.putClientProperty("html", v);
        }

        SwingUtilities.layoutCompoundLabel((JComponent) tabPane,
                                           metrics, title, icon,
                                           SwingUtilities.CENTER,
                                           SwingUtilities.CENTER,
                                           SwingUtilities.CENTER,
                                           SwingUtilities.TRAILING,
                                           tabRect,
                                           iconRect,
                                           textRect,
                                           textIconGap);

        tabPane.putClientProperty("html", null);

        int xNudge = getTabLabelShiftX(tabPlacement, tabIndex, isSelected);
        int yNudge = getTabLabelShiftY(tabPlacement, tabIndex, isSelected);
        iconRect.x += xNudge;
        iconRect.y += yNudge;
        textRect.x += xNudge;
        textRect.y += yNudge;
    
static voidloadActionMap(javax.swing.plaf.basic.LazyActionMap map)

        map.put(new Actions(Actions.NEXT));
        map.put(new Actions(Actions.PREVIOUS));
        map.put(new Actions(Actions.RIGHT));
        map.put(new Actions(Actions.LEFT));
        map.put(new Actions(Actions.UP));
        map.put(new Actions(Actions.DOWN));
        map.put(new Actions(Actions.PAGE_UP));
        map.put(new Actions(Actions.PAGE_DOWN));
        map.put(new Actions(Actions.REQUEST_FOCUS));
        map.put(new Actions(Actions.REQUEST_FOCUS_FOR_VISIBLE));
        map.put(new Actions(Actions.SET_SELECTED));
        map.put(new Actions(Actions.SELECT_FOCUSED));
        map.put(new Actions(Actions.SCROLL_FORWARD));
        map.put(new Actions(Actions.SCROLL_BACKWARD));
    
protected voidnavigateSelectedTab(int direction)

        int tabPlacement = tabPane.getTabPlacement();
        int current = DefaultLookup.getBoolean(tabPane, this,
                             "TabbedPane.selectionFollowsFocus", true) ?
                             tabPane.getSelectedIndex() : getFocusIndex();
        int tabCount = tabPane.getTabCount();
        boolean leftToRight = BasicGraphicsUtils.isLeftToRight(tabPane);

        // If we have no tabs then don't navigate.
        if (tabCount <= 0) {
            return;
        }

        int offset;
        switch(tabPlacement) {
          case LEFT:
          case RIGHT:
              switch(direction) {
                 case NEXT:
                     selectNextTab(current);
                     break;
                 case PREVIOUS:
                     selectPreviousTab(current);
                     break;
                case NORTH:
                    selectPreviousTabInRun(current);
                    break;
                case SOUTH:
                    selectNextTabInRun(current);
                    break;
                case WEST:
                    offset = getTabRunOffset(tabPlacement, tabCount, current, false);
                    selectAdjacentRunTab(tabPlacement, current, offset);
                    break;
                case EAST:
                    offset = getTabRunOffset(tabPlacement, tabCount, current, true);
                    selectAdjacentRunTab(tabPlacement, current, offset);
                    break;
                default:
              }
              break;
          case BOTTOM:
          case TOP:
          default:
              switch(direction) {
                case NEXT:
                    selectNextTab(current);
                    break;
                case PREVIOUS:
                    selectPreviousTab(current);
                    break;
                case NORTH:
                    offset = getTabRunOffset(tabPlacement, tabCount, current, false);
                    selectAdjacentRunTab(tabPlacement, current, offset);
                    break;
                case SOUTH:
                    offset = getTabRunOffset(tabPlacement, tabCount, current, true);
                    selectAdjacentRunTab(tabPlacement, current, offset);
                    break;
                case EAST:
                    if (leftToRight) {
                        selectNextTabInRun(current);
                    } else {
                        selectPreviousTabInRun(current);
                    }
                    break;
                case WEST:
                    if (leftToRight) {
                        selectPreviousTabInRun(current);
                    } else {
                        selectNextTabInRun(current);
                    }
                    break;
                default:
              }
        }
    
private voidnavigateTo(int index)

        if (DefaultLookup.getBoolean(tabPane, this,
                             "TabbedPane.selectionFollowsFocus", true)) {
            tabPane.setSelectedIndex(index);
        } else {
            // Just move focus (not selection)
            setFocusIndex(index, true);
        }
    
public voidpaint(java.awt.Graphics g, javax.swing.JComponent c)

        int selectedIndex = tabPane.getSelectedIndex();
        int tabPlacement = tabPane.getTabPlacement();

        ensureCurrentLayout();

        // Paint content border and tab area
	if (tabsOverlapBorder) {
	    paintContentBorder(g, tabPlacement, selectedIndex);
	}
        // If scrollable tabs are enabled, the tab area will be
        // painted by the scrollable tab panel instead.
        //
        if (!scrollableTabLayoutEnabled()) { // WRAP_TAB_LAYOUT
            paintTabArea(g, tabPlacement, selectedIndex);
        }
	if (!tabsOverlapBorder) {
	    paintContentBorder(g, tabPlacement, selectedIndex);
	}
    
protected voidpaintContentBorder(java.awt.Graphics g, int tabPlacement, int selectedIndex)

        int width = tabPane.getWidth();
        int height = tabPane.getHeight();
        Insets insets = tabPane.getInsets();
        Insets tabAreaInsets = getTabAreaInsets(tabPlacement);

        int x = insets.left;
        int y = insets.top;
        int w = width - insets.right - insets.left;
        int h = height - insets.top - insets.bottom;

        switch(tabPlacement) {
          case LEFT:
              x += calculateTabAreaWidth(tabPlacement, runCount, maxTabWidth);
	      if (tabsOverlapBorder) {
		  x -= tabAreaInsets.right;
	      }
              w -= (x - insets.left);
              break;
          case RIGHT:
              w -= calculateTabAreaWidth(tabPlacement, runCount, maxTabWidth);
	      if (tabsOverlapBorder) {
		  w += tabAreaInsets.left;
	      }
              break;            
          case BOTTOM: 
              h -= calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight);
	      if (tabsOverlapBorder) {
		  h += tabAreaInsets.top;
	      }
              break;
          case TOP:
          default:
              y += calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight);
	      if (tabsOverlapBorder) {
		  y -= tabAreaInsets.bottom;
	      }
              h -= (y - insets.top);
        } 

            if ( tabPane.getTabCount() > 0 && (contentOpaque || tabPane.isOpaque()) ) {
            // Fill region behind content area
            Color color = UIManager.getColor("TabbedPane.contentAreaColor");
            if (color != null) {
                g.setColor(color);
            }
            else if ( selectedColor == null || selectedIndex == -1 ) {
                g.setColor(tabPane.getBackground());
            }
            else {
                g.setColor(selectedColor);
            }
            g.fillRect(x,y,w,h);
        }

        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); 

    
protected voidpaintContentBorderBottomEdge(java.awt.Graphics g, int tabPlacement, int selectedIndex, int x, int y, int w, int h)

 
        Rectangle selRect = selectedIndex < 0? null :
                               getTabBounds(selectedIndex, calcRect);

        g.setColor(shadow);

        // Draw unbroken line if tabs are not on BOTTOM, OR
        // selected tab is not in run adjacent to content, OR
        // selected tab is not visible (SCROLL_TAB_LAYOUT)
        //
        if (tabPlacement != BOTTOM || selectedIndex < 0 ||
             (selRect.y - 1 > h) ||
             (selRect.x < x || selRect.x > x + w)) {
            g.drawLine(x+1, y+h-2, x+w-2, y+h-2);
            g.setColor(darkShadow);
            g.drawLine(x, y+h-1, x+w-1, y+h-1);
        } else {
            // Break line to show visual connection to selected tab
            g.drawLine(x+1, y+h-2, selRect.x - 1, y+h-2);
            g.setColor(darkShadow);
            g.drawLine(x, y+h-1, selRect.x - 1, y+h-1);
            if (selRect.x + selRect.width < x + w - 2) {
                g.setColor(shadow);
                g.drawLine(selRect.x + selRect.width, y+h-2, x+w-2, y+h-2);
                g.setColor(darkShadow);
                g.drawLine(selRect.x + selRect.width, y+h-1, x+w-1, y+h-1);
            } 
        }

    
protected voidpaintContentBorderLeftEdge(java.awt.Graphics g, int tabPlacement, int selectedIndex, int x, int y, int w, int h)

 
        Rectangle selRect = selectedIndex < 0? null :
                               getTabBounds(selectedIndex, calcRect);

        g.setColor(lightHighlight); 

        // Draw unbroken line if tabs are not on LEFT, OR
        // selected tab is not in run adjacent to content, OR
        // selected tab is not visible (SCROLL_TAB_LAYOUT)
        //
        if (tabPlacement != LEFT || selectedIndex < 0 ||
            (selRect.x + selRect.width + 1 < x) ||
            (selRect.y < y || selRect.y > y + h)) {
            g.drawLine(x, y, x, y+h-2);
        } else {
            // Break line to show visual connection to selected tab
            g.drawLine(x, y, x, selRect.y - 1);
            if (selRect.y + selRect.height < y + h - 2) {
                g.drawLine(x, selRect.y + selRect.height, 
                           x, y+h-2);
            } 
        }
    
protected voidpaintContentBorderRightEdge(java.awt.Graphics g, int tabPlacement, int selectedIndex, int x, int y, int w, int h)

        Rectangle selRect = selectedIndex < 0? null :
                               getTabBounds(selectedIndex, calcRect);

        g.setColor(shadow);

        // Draw unbroken line if tabs are not on RIGHT, OR
        // selected tab is not in run adjacent to content, OR
        // selected tab is not visible (SCROLL_TAB_LAYOUT)
        //
        if (tabPlacement != RIGHT || selectedIndex < 0 ||
             (selRect.x - 1 > w) ||
             (selRect.y < y || selRect.y > y + h)) {
            g.drawLine(x+w-2, y+1, x+w-2, y+h-3);
            g.setColor(darkShadow);
            g.drawLine(x+w-1, y, x+w-1, y+h-1);
        } else {
            // Break line to show visual connection to selected tab
            g.drawLine(x+w-2, y+1, x+w-2, selRect.y - 1);
            g.setColor(darkShadow);
            g.drawLine(x+w-1, y, x+w-1, selRect.y - 1);

            if (selRect.y + selRect.height < y + h - 2) {
                g.setColor(shadow);
                g.drawLine(x+w-2, selRect.y + selRect.height, 
                           x+w-2, y+h-2);
                g.setColor(darkShadow);
                g.drawLine(x+w-1, selRect.y + selRect.height, 
                           x+w-1, y+h-2);
            } 
        }
    
protected voidpaintContentBorderTopEdge(java.awt.Graphics g, int tabPlacement, int selectedIndex, int x, int y, int w, int h)

        Rectangle selRect = selectedIndex < 0? null :
                               getTabBounds(selectedIndex, calcRect);

        g.setColor(lightHighlight);

        // Draw unbroken line if tabs are not on TOP, OR
        // selected tab is not in run adjacent to content, OR
        // selected tab is not visible (SCROLL_TAB_LAYOUT)
        //
        if (tabPlacement != TOP || selectedIndex < 0 || 
            (selRect.y + selRect.height + 1 < y) ||
            (selRect.x < x || selRect.x > x + w)) {
            g.drawLine(x, y, x+w-2, y);
        } else {
            // Break line to show visual connection to selected tab
            g.drawLine(x, y, selRect.x - 1, y);
            if (selRect.x + selRect.width < x + w - 2) {
                g.drawLine(selRect.x + selRect.width, y, 
                           x+w-2, y);
            } else {
                g.setColor(shadow); 
                g.drawLine(x+w-2, y, x+w-2, y);
            }
        }
    
private voidpaintCroppedTabEdge(java.awt.Graphics g)

        int tabIndex = tabScroller.croppedEdge.getTabIndex();
        int cropline = tabScroller.croppedEdge.getCropline();
        int x,y; 
        switch(tabPane.getTabPlacement()) {
          case LEFT:
          case RIGHT:
            x = rects[tabIndex].x;
            y = cropline; 
            int xx = x;
            g.setColor(shadow);
            while(xx <= x+rects[tabIndex].width) {
                for (int i=0; i < xCropLen.length; i+=2) {
                    g.drawLine(xx+yCropLen[i],y-xCropLen[i],
                               xx+yCropLen[i+1]-1,y-xCropLen[i+1]);
                }
                xx+=CROP_SEGMENT;
            }       
            break;
          case TOP:
          case BOTTOM:
          default:
            x = cropline;
            y = rects[tabIndex].y; 
            int yy = y;       
            g.setColor(shadow);
            while(yy <= y+rects[tabIndex].height) {
                for (int i=0; i < xCropLen.length; i+=2) {
                    g.drawLine(x-xCropLen[i],yy+yCropLen[i],
                               x-xCropLen[i+1],yy+yCropLen[i+1]-1);
                }
                yy+=CROP_SEGMENT;
            }       
        }
    
protected voidpaintFocusIndicator(java.awt.Graphics g, int tabPlacement, java.awt.Rectangle[] rects, int tabIndex, java.awt.Rectangle iconRect, java.awt.Rectangle textRect, boolean isSelected)

        Rectangle tabRect = rects[tabIndex];
        if (tabPane.hasFocus() && isSelected) {
            int x, y, w, h;
            g.setColor(focus);
            switch(tabPlacement) {
              case LEFT:
                  x = tabRect.x + 3;
                  y = tabRect.y + 3;
                  w = tabRect.width - 5;
                  h = tabRect.height - 6;
                  break;
              case RIGHT:
                  x = tabRect.x + 2;
                  y = tabRect.y + 3;
                  w = tabRect.width - 5;
                  h = tabRect.height - 6;
                  break;
              case BOTTOM:
                  x = tabRect.x + 3;
                  y = tabRect.y + 2;
                  w = tabRect.width - 6;
                  h = tabRect.height - 5;
                  break;
              case TOP:
              default:
                  x = tabRect.x + 3;
                  y = tabRect.y + 3;
                  w = tabRect.width - 6;
                  h = tabRect.height - 5;
            }
            BasicGraphicsUtils.drawDashedRect(g, x, y, w, h);
        }
    
protected voidpaintIcon(java.awt.Graphics g, int tabPlacement, int tabIndex, javax.swing.Icon icon, java.awt.Rectangle iconRect, boolean isSelected)

        if (icon != null) {
            icon.paintIcon(tabPane, g, iconRect.x, iconRect.y);
        }
    
protected voidpaintTab(java.awt.Graphics g, int tabPlacement, java.awt.Rectangle[] rects, int tabIndex, java.awt.Rectangle iconRect, java.awt.Rectangle textRect)

        Rectangle tabRect = rects[tabIndex];
        int selectedIndex = tabPane.getSelectedIndex();
        boolean isSelected = selectedIndex == tabIndex;

        if (tabsOpaque || tabPane.isOpaque()) {
            paintTabBackground(g, tabPlacement, tabIndex, tabRect.x, tabRect.y,
                    tabRect.width, tabRect.height, isSelected);
        }

        paintTabBorder(g, tabPlacement, tabIndex, tabRect.x, tabRect.y, 
                       tabRect.width, tabRect.height, isSelected);
        
        String title = tabPane.getTitleAt(tabIndex);
        Font font = tabPane.getFont();
        FontMetrics metrics = SwingUtilities2.getFontMetrics(tabPane, g, font);
        Icon icon = getIconForTab(tabIndex);

        layoutLabel(tabPlacement, metrics, tabIndex, title, icon, 
                    tabRect, iconRect, textRect, isSelected);

        if (tabPane.getTabComponentAt(tabIndex) == null) {
            String clippedTitle = title;

            if (scrollableTabLayoutEnabled() && tabScroller.croppedEdge.isParamsSet() &&
                    tabScroller.croppedEdge.getTabIndex() == tabIndex && isHorizontalTabPlacement()) {
                int availTextWidth = tabScroller.croppedEdge.getCropline() -
                        (textRect.x - tabRect.x) - tabScroller.croppedEdge.getCroppedSideWidth();
                clippedTitle = SwingUtilities2.clipStringIfNecessary(null, metrics, title, availTextWidth);
            }

            paintText(g, tabPlacement, font, metrics,
                    tabIndex, clippedTitle, textRect, isSelected);

            paintIcon(g, tabPlacement, tabIndex, icon, iconRect, isSelected);
        }
        paintFocusIndicator(g, tabPlacement, rects, tabIndex, 
                  iconRect, textRect, isSelected);
    
protected voidpaintTabArea(java.awt.Graphics g, int tabPlacement, int selectedIndex)
Paints the tabs in the tab area. Invoked by paint(). The graphics parameter must be a valid Graphics object. Tab placement may be either: JTabbedPane.TOP, JTabbedPane.BOTTOM, JTabbedPane.LEFT, or JTabbedPane.RIGHT. The selected index must be a valid tabbed pane tab index (0 to tab count - 1, inclusive) or -1 if no tab is currently selected. The handling of invalid parameters is unspecified.

param
g the graphics object to use for rendering
param
tabPlacement the placement for the tabs within the JTabbedPane
param
selectedIndex the tab index of the selected component
since
1.4

        int tabCount = tabPane.getTabCount();

        Rectangle iconRect = new Rectangle(),
                  textRect = new Rectangle();
        Rectangle clipRect = g.getClipBounds();  

        // Paint tabRuns of tabs from back to front
        for (int i = runCount - 1; i >= 0; i--) {
            int start = tabRuns[i];
            int next = tabRuns[(i == runCount - 1)? 0 : i + 1];
            int end = (next != 0? next - 1: tabCount - 1);
            for (int j = start; j <= end; j++) {
                if (j != selectedIndex && rects[j].intersects(clipRect)) {
                    paintTab(g, tabPlacement, rects, j, iconRect, textRect);
                }
            }
        }

        // Paint selected tab if its in the front run
        // since it may overlap other tabs
        if (selectedIndex >= 0 && rects[selectedIndex].intersects(clipRect)) {
            paintTab(g, tabPlacement, rects, selectedIndex, iconRect, textRect);
        }
    
protected voidpaintTabBackground(java.awt.Graphics g, int tabPlacement, int tabIndex, int x, int y, int w, int h, boolean isSelected)

        g.setColor(!isSelected || selectedColor == null? 
                   tabPane.getBackgroundAt(tabIndex) : selectedColor);
        switch(tabPlacement) {
          case LEFT:
              g.fillRect(x+1, y+1, w-1, h-3);
              break;
          case RIGHT:
              g.fillRect(x, y+1, w-2, h-3);
              break;
          case BOTTOM:
              g.fillRect(x+1, y, w-3, h-1);
              break;
          case TOP:
          default:
              g.fillRect(x+1, y+1, w-3, h-1);
        }
    
protected voidpaintTabBorder(java.awt.Graphics g, int tabPlacement, int tabIndex, int x, int y, int w, int h, boolean isSelected)
this function draws the border around each tab note that this function does now draw the background of the tab. that is done elsewhere

        g.setColor(lightHighlight);  

        switch (tabPlacement) {
          case LEFT:
              g.drawLine(x+1, y+h-2, x+1, y+h-2); // bottom-left highlight
              g.drawLine(x, y+2, x, y+h-3); // left highlight
              g.drawLine(x+1, y+1, x+1, y+1); // top-left highlight
              g.drawLine(x+2, y, x+w-1, y); // top highlight

              g.setColor(shadow);
              g.drawLine(x+2, y+h-2, x+w-1, y+h-2); // bottom shadow

              g.setColor(darkShadow);
              g.drawLine(x+2, y+h-1, x+w-1, y+h-1); // bottom dark shadow
              break;
          case RIGHT:
              g.drawLine(x, y, x+w-3, y); // top highlight

              g.setColor(shadow);
              g.drawLine(x, y+h-2, x+w-3, y+h-2); // bottom shadow
              g.drawLine(x+w-2, y+2, x+w-2, y+h-3); // right shadow

              g.setColor(darkShadow);
              g.drawLine(x+w-2, y+1, x+w-2, y+1); // top-right dark shadow
              g.drawLine(x+w-2, y+h-2, x+w-2, y+h-2); // bottom-right dark shadow
              g.drawLine(x+w-1, y+2, x+w-1, y+h-3); // right dark shadow
              g.drawLine(x, y+h-1, x+w-3, y+h-1); // bottom dark shadow
              break;              
          case BOTTOM:
              g.drawLine(x, y, x, y+h-3); // left highlight
              g.drawLine(x+1, y+h-2, x+1, y+h-2); // bottom-left highlight

              g.setColor(shadow);
              g.drawLine(x+2, y+h-2, x+w-3, y+h-2); // bottom shadow
              g.drawLine(x+w-2, y, x+w-2, y+h-3); // right shadow

              g.setColor(darkShadow);
              g.drawLine(x+2, y+h-1, x+w-3, y+h-1); // bottom dark shadow
              g.drawLine(x+w-2, y+h-2, x+w-2, y+h-2); // bottom-right dark shadow
              g.drawLine(x+w-1, y, x+w-1, y+h-3); // right dark shadow
              break;
          case TOP:
          default:           
              g.drawLine(x, y+2, x, y+h-1); // left highlight
              g.drawLine(x+1, y+1, x+1, y+1); // top-left highlight
              g.drawLine(x+2, y, x+w-3, y); // top highlight              

              g.setColor(shadow);  
              g.drawLine(x+w-2, y+2, x+w-2, y+h-1); // right shadow

              g.setColor(darkShadow); 
              g.drawLine(x+w-1, y+2, x+w-1, y+h-1); // right dark-shadow
              g.drawLine(x+w-2, y+1, x+w-2, y+1); // top-right shadow
        }
    
protected voidpaintText(java.awt.Graphics g, int tabPlacement, java.awt.Font font, java.awt.FontMetrics metrics, int tabIndex, java.lang.String title, java.awt.Rectangle textRect, boolean isSelected)


        g.setFont(font);

        View v = getTextViewForTab(tabIndex);
        if (v != null) {
            // html
            v.paint(g, textRect);
        } else {
            // plain text
            int mnemIndex = tabPane.getDisplayedMnemonicIndexAt(tabIndex);

            if (tabPane.isEnabled() && tabPane.isEnabledAt(tabIndex)) {
                Color fg = tabPane.getForegroundAt(tabIndex);
                if (isSelected && (fg instanceof UIResource)) {
                    Color selectedFG = UIManager.getColor(
                                  "TabbedPane.selectedForeground");
                    if (selectedFG != null) {
                        fg = selectedFG;
                    }
                }
                g.setColor(fg);
                SwingUtilities2.drawStringUnderlineCharAt(tabPane, g,
                             title, mnemIndex,
                             textRect.x, textRect.y + metrics.getAscent());
                
            } else { // tab disabled
                g.setColor(tabPane.getBackgroundAt(tabIndex).brighter());
                SwingUtilities2.drawStringUnderlineCharAt(tabPane, g,
                             title, mnemIndex,
                             textRect.x, textRect.y + metrics.getAscent());
                g.setColor(tabPane.getBackgroundAt(tabIndex).darker());
                SwingUtilities2.drawStringUnderlineCharAt(tabPane, g,
                             title, mnemIndex,
                             textRect.x - 1, textRect.y + metrics.getAscent() - 1);

            }
        }
    
private voidrepaintTab(int index)
Repaints the specified tab.

        // If we're not valid that means we will shortly be validated and
        // painted, which means we don't have to do anything here.
        if (!isRunsDirty && index >= 0 && index < tabPane.getTabCount()) {
            tabPane.repaint(getTabBounds(tabPane, index));
        }
    
booleanrequestFocusForVisibleComponent()

        return SwingUtilities2.tabbedPaneChangeFocusTo(getVisibleComponent());
    
private voidresetMnemonics()
Resets the mnemonics bindings to an empty state.

        if (mnemonicToIndexMap != null) {
            mnemonicToIndexMap.clear();
            mnemonicInputMap.clear();
        }
    
protected static voidrotateInsets(java.awt.Insets topInsets, java.awt.Insets targetInsets, int targetPlacement)

        
        switch(targetPlacement) {
          case LEFT:
              targetInsets.top = topInsets.left;
              targetInsets.left = topInsets.top;
              targetInsets.bottom = topInsets.right;
              targetInsets.right = topInsets.bottom;
              break;
          case BOTTOM:
              targetInsets.top = topInsets.bottom;
              targetInsets.left = topInsets.left;
              targetInsets.bottom = topInsets.top;
              targetInsets.right = topInsets.right;              
              break;
          case RIGHT:
              targetInsets.top = topInsets.left;
              targetInsets.left = topInsets.bottom;
              targetInsets.bottom = topInsets.right;
              targetInsets.right = topInsets.top;
              break;
          case TOP:
          default:
              targetInsets.top = topInsets.top;
              targetInsets.left = topInsets.left;
              targetInsets.bottom = topInsets.bottom;
              targetInsets.right = topInsets.right;              
        }
    
private booleanscrollableTabLayoutEnabled()

        return (tabPane.getLayout() instanceof TabbedPaneScrollLayout);
    
protected voidselectAdjacentRunTab(int tabPlacement, int tabIndex, int offset)

        if ( runCount < 2 ) {
            return; 
        }
        int newIndex;
        Rectangle r = rects[tabIndex]; 
        switch(tabPlacement) {
          case LEFT:
          case RIGHT:
              newIndex = tabForCoordinate(tabPane, r.x + r.width/2 + offset,
                                       r.y + r.height/2);
              break;
          case BOTTOM:  
          case TOP:
          default:
              newIndex = tabForCoordinate(tabPane, r.x + r.width/2, 
                                       r.y + r.height/2 + offset);
        }
        if (newIndex != -1) {
            while (!tabPane.isEnabledAt(newIndex) && newIndex != tabIndex) {
                newIndex = getNextTabIndex(newIndex);
            }        
            navigateTo(newIndex);
        }
    
protected voidselectNextTab(int current)

        int tabIndex = getNextTabIndex(current);
        
        while (tabIndex != current && !tabPane.isEnabledAt(tabIndex)) {
            tabIndex = getNextTabIndex(tabIndex);
        }
        navigateTo(tabIndex);
    
protected voidselectNextTabInRun(int current)

        int tabCount = tabPane.getTabCount();
        int tabIndex = getNextTabIndexInRun(tabCount, current);

        while(tabIndex != current && !tabPane.isEnabledAt(tabIndex)) {
            tabIndex = getNextTabIndexInRun(tabCount, tabIndex);
        }
        navigateTo(tabIndex);
    
protected voidselectPreviousTab(int current)

        int tabIndex = getPreviousTabIndex(current);
        
        while (tabIndex != current && !tabPane.isEnabledAt(tabIndex)) {
            tabIndex = getPreviousTabIndex(tabIndex);
        }
        navigateTo(tabIndex);
    
protected voidselectPreviousTabInRun(int current)

        int tabCount = tabPane.getTabCount();
        int tabIndex = getPreviousTabIndexInRun(tabCount, current);

        while(tabIndex != current && !tabPane.isEnabledAt(tabIndex)) {
            tabIndex = getPreviousTabIndexInRun(tabCount, tabIndex);
        }
        navigateTo(tabIndex);
    
voidsetFocusIndex(int index, boolean repaint)

        if (repaint && !isRunsDirty) {
            repaintTab(focusIndex);
            focusIndex = index;
            repaintTab(focusIndex);
        }
        else {
            focusIndex = index;
        }
    
private voidsetRolloverTab(int x, int y)
Sets the tab the mouse is over by location. This is a cover method for setRolloverTab(tabForCoordinate(x, y, false)).

        // NOTE:
        // This calls in with false otherwise it could trigger a validate,
        // which should NOT happen if the user is only dragging the
        // mouse around.
        setRolloverTab(tabForCoordinate(tabPane, x, y, false));
    
protected voidsetRolloverTab(int index)
Sets the tab the mouse is currently over to index. index will be -1 if the mouse is no longer over any tab. No checking is done to ensure the passed in index identifies a valid tab.

param
index Index of the tab the mouse is over.
since
1.5

        rolloverTabIndex = index;
    
protected voidsetVisibleComponent(java.awt.Component component)

        if (visibleComponent != null
                && visibleComponent != component
                && visibleComponent.getParent() == tabPane
                && visibleComponent.isVisible()) {

            visibleComponent.setVisible(false);
        }
        if (component != null && !component.isVisible()) {
            component.setVisible(true);
        }
        visibleComponent = component;
    
protected booleanshouldPadTabRun(int tabPlacement, int run)

        return runCount > 1;
    
protected booleanshouldRotateTabRuns(int tabPlacement)

        return true;
    
public inttabForCoordinate(javax.swing.JTabbedPane pane, int x, int y)
Returns the tab index which intersects the specified point in the JTabbedPane's coordinate space.

        return tabForCoordinate(pane, x, y, true);
    
private inttabForCoordinate(javax.swing.JTabbedPane pane, int x, int y, boolean validateIfNecessary)

        if (validateIfNecessary) {
            ensureCurrentLayout();
        }
        if (isRunsDirty) {
            // We didn't recalculate the layout, runs and tabCount may not
            // line up, bail.
            return -1;
        }
        Point p = new Point(x, y);

        if (scrollableTabLayoutEnabled()) {
            translatePointToTabPanel(x, y, p);
            Rectangle viewRect = tabScroller.viewport.getViewRect();
            if (!viewRect.contains(p)) {
                return -1;
            }
        }
        int tabCount = tabPane.getTabCount();
        for (int i = 0; i < tabCount; i++) {
            if (rects[i].contains(p.x, p.y)) {
                return i;
            }
        }
        return -1;
    
private java.awt.PointtranslatePointToTabPanel(int srcx, int srcy, java.awt.Point dest)
Returns a point which is translated from the specified point in the JTabbedPane's coordinate space to the coordinate space of the ScrollableTabPanel. This is used for SCROLL_TAB_LAYOUT ONLY.

        Point vpp = tabScroller.viewport.getLocation();
        Point viewp = tabScroller.viewport.getViewPosition();
        dest.x = srcx - vpp.x + viewp.x;
        dest.y = srcy - vpp.y + viewp.y;
        return dest;
    
protected voiduninstallComponents()
Removes any installed subcomponents from the JTabbedPane. Invoked by uninstallUI.

since
1.4

        uninstallTabContainer();
        if (scrollableTabLayoutEnabled()) {
            tabPane.remove(tabScroller.viewport);
            tabPane.remove(tabScroller.scrollForwardButton);
            tabPane.remove(tabScroller.scrollBackwardButton);
            tabScroller = null;
        }
    
protected voiduninstallDefaults()

        highlight = null;
        lightHighlight = null;
        shadow = null;
        darkShadow = null;
        focus = null;
        tabInsets = null;
        selectedTabPadInsets = null;
        tabAreaInsets = null;
        contentBorderInsets = null;
    
protected voiduninstallKeyboardActions()

        SwingUtilities.replaceUIActionMap(tabPane, null);
        SwingUtilities.replaceUIInputMap(tabPane, JComponent.
                                         WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
                                         null);
        SwingUtilities.replaceUIInputMap(tabPane, JComponent.WHEN_FOCUSED,
                                         null);
        SwingUtilities.replaceUIInputMap(tabPane,
                                         JComponent.WHEN_IN_FOCUSED_WINDOW,
                                         null);
        mnemonicToIndexMap = null;
        mnemonicInputMap = null;
    
protected voiduninstallListeners()

        if (mouseListener != null) {
            tabPane.removeMouseListener(mouseListener);
            mouseListener = null;
        }
        tabPane.removeMouseMotionListener(getHandler());
        if (focusListener != null) {
            tabPane.removeFocusListener(focusListener);
            focusListener = null;
        }
            
        tabPane.removeContainerListener(getHandler());
        if (htmlViews!=null) {
            htmlViews.removeAllElements();
            htmlViews = null;
        }
        if (tabChangeListener != null) {
            tabPane.removeChangeListener(tabChangeListener);
            tabChangeListener = null;
        }
        if (propertyChangeListener != null) {
            tabPane.removePropertyChangeListener(propertyChangeListener);
            propertyChangeListener = null;
        }
        handler = null;
    
private voiduninstallTabContainer()

         if(tabContainer == null) {
             return;
         }
         // Remove all the tabComponents, making sure not to notify
         // the tabbedpane.
         tabContainer.notifyTabbedPane = false;
         tabContainer.removeAll();
         if(scrollableTabLayoutEnabled()) {
             tabContainer.remove(tabScroller.croppedEdge);
             tabScroller.tabPanel.remove(tabContainer);
         } else {
           tabPane.remove(tabContainer);  
         }
         tabContainer = null;
    
public voiduninstallUI(javax.swing.JComponent c)

        uninstallKeyboardActions();
        uninstallListeners();
        uninstallDefaults();
        uninstallComponents();
        c.setLayout(null);
 
        this.tabPane = null;
    
private voidupdateMnemonics()
Reloads the mnemonics. This should be invoked when a memonic changes, when the title of a mnemonic changes, or when tabs are added/removed.

        resetMnemonics();
        for (int counter = tabPane.getTabCount() - 1; counter >= 0;
             counter--) {
            int mnemonic = tabPane.getMnemonicAt(counter);

            if (mnemonic > 0) {
                addMnemonic(counter, mnemonic);
            }
        }
    
private voidvalidateFocusIndex()
Makes sure the focusIndex is valid.

        if (focusIndex >= tabPane.getTabCount()) {
            setFocusIndex(tabPane.getSelectedIndex(), false);
        }