I have reworked parts of the BasicTabbedPaneUI.TabbedPaneLayout layout
manager. This makes the layout and switching-between-tabs more efficient
and correct (I hope).

This also includes some JDK1.5 additions wrt rollover tabs which wrote
some time ago and which I originally wanted to complete first (in the
MetalTabbedPaneUI) but which I'll commit now anyway. Also this includes
some older adjustments to mouse handling in tabbed panes.

The painting of the metal tabs is still ugly, I'll work on this next.

2006-03-20  Roman Kennke  <[EMAIL PROTECTED]>

        * javax/swing/plaf/basic/BasicTabbedPaneUI.java
        (MouseHandler.mousePressed): Rewritten for clearer and simpler
        code.
        (MouseHandler.mouseEntered): Implemented to set the rollover
tab.
        (MouseHandler.mouseMoved): Implemented to set the rollover tab.
        (MouseHandler.mouseExited): Implemented to unset the rollover
tab.
        (TabbedPaneLayout.calculateLayoutInfo): Don't set the
component's
        bounds here. That is moved into layoutContainer().
        (calculateSize): Correctly respect insets. Made code slightly
more
        clear and efficient.
        (calculateTabRects): Rewritten completely. The old code was
        not quite right and unstable in some situations.
        (layoutContainer): Moved layout of tabbed pane's subcomponents
        here.
        (tabRunsDirty): New field.
        (rolloverTab): New field.
        (tabForCoordinate): Rewritten for simplicity and correctness.
        (setRolloverTab): New method.
        (getRolloverTab): New method.

/Roman
-- 
“Improvement makes straight roads, but the crooked roads, without
Improvement, are roads of Genius.” - William Blake
Index: javax/swing/plaf/basic/BasicTabbedPaneUI.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/plaf/basic/BasicTabbedPaneUI.java,v
retrieving revision 1.33
diff -u -r1.33 BasicTabbedPaneUI.java
--- javax/swing/plaf/basic/BasicTabbedPaneUI.java	16 Feb 2006 14:39:14 -0000	1.33
+++ javax/swing/plaf/basic/BasicTabbedPaneUI.java	20 Mar 2006 11:12:43 -0000
@@ -130,52 +130,49 @@
      */
     public void mousePressed(MouseEvent e)
     {
-      int x = e.getX();
-      int y = e.getY();
-      int tabCount = tabPane.getTabCount();
-
-      if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
+      if (tabPane.isEnabled())
         {
-          if (e.getSource() == incrButton)
+          int index = tabForCoordinate(tabPane, e.getX(), e.getY());
+          if (index >= 0 && tabPane.isEnabledAt(index))
             {
-              if (++currentScrollLocation >= tabCount)
-                currentScrollLocation = tabCount - 1;
-              
-              int width = 0;
-              for (int i = currentScrollLocation - 1; i < tabCount; i++)
-                width += rects[i].width;
-              if (width < viewport.getWidth())
-                // FIXME: Still getting mouse events after the button is disabled.
-                //	incrButton.setEnabled(false);
-                currentScrollLocation--;
-              else if (! decrButton.isEnabled())
-                decrButton.setEnabled(true);
-              tabPane.revalidate();
-              tabPane.repaint();
-              return;
-            }
-          else if (e.getSource() == decrButton)
-            {
-              if (--currentScrollLocation < 0)
-                currentScrollLocation = 0;
-              if (currentScrollLocation == 0)
-                decrButton.setEnabled(false);
-              else if (! incrButton.isEnabled())
-                incrButton.setEnabled(true);
-              tabPane.revalidate();
-              tabPane.repaint();
-              return;
+              tabPane.setSelectedIndex(index);
             }
         }
+    }
 
-      int index = tabForCoordinate(tabPane, x, y);
-
-      // We need to check since there are areas where tabs cannot be
-      // e.g. in the inset area.
-      if (index != -1 && tabPane.isEnabledAt(index))
-        tabPane.setSelectedIndex(index);
-      tabPane.revalidate();
-      tabPane.repaint();
+    /**
+     * Receives notification when the mouse pointer has entered the tabbed
+     * pane.
+     *
+     * @param ev the mouse event
+     */
+    public void mouseEntered(MouseEvent ev)
+    {
+      int tabIndex = tabForCoordinate(tabPane, ev.getX(), ev.getY());
+      setRolloverTab(tabIndex);
+    }
+
+    /**
+     * Receives notification when the mouse pointer has exited the tabbed
+     * pane.
+     *
+     * @param ev the mouse event
+     */
+    public void mouseExited(MouseEvent ev)
+    {
+      setRolloverTab(-1);
+    }
+
+    /**
+     * Receives notification when the mouse pointer has moved over the tabbed
+     * pane.
+     *
+     * @param ev the mouse event
+     */
+    public void mouseMoved(MouseEvent ev)
+    {
+      int tabIndex = tabForCoordinate(tabPane, ev.getX(), ev.getY());
+      setRolloverTab(tabIndex);
     }
   }
 
@@ -241,21 +238,10 @@
      */
     public void calculateLayoutInfo()
     {
-      assureRectsCreated(tabPane.getTabCount());
-      contentRect = SwingUtilities.calculateInnerArea(tabPane, contentRect);
-
-      calculateTabRects(tabPane.getTabPlacement(), tabPane.getTabCount());
-
-      if (tabPane.getSelectedIndex() != -1)
-        {
-          Component visible = getVisibleComponent();
-          Insets insets = getContentBorderInsets(tabPane.getTabPlacement());
-          if (visible != null)
-            visible.setBounds(contentRect.x + insets.left,
-                              contentRect.y + insets.top,
-                              contentRect.width - insets.left - insets.right,
-                              contentRect.height - insets.top - insets.bottom);
-        }
+      int count = tabPane.getTabCount();
+      assureRectsCreated(count);
+      calculateTabRects(tabPane.getTabPlacement(), count);
+      tabRunsDirty = false;
     }
 
     /**
@@ -269,45 +255,51 @@
     protected Dimension calculateSize(boolean minimum)
     {
       int tabPlacement = tabPane.getTabPlacement();
+
       int width = 0;
       int height = 0;
-
-      int componentHeight = 0;
-      int componentWidth = 0;
       Component c;
       Dimension dims;
+
+      // Find out the minimum/preferred size to display the largest child
+      // of the tabbed pane.
       for (int i = 0; i < tabPane.getTabCount(); i++)
         {
           c = tabPane.getComponentAt(i);
           if (c == null)
             continue;
-          calcRect = c.getBounds();
-          dims = c.getPreferredSize();
+          dims = minimum ? c.getMinimumSize() : c.getPreferredSize(); 
           if (dims != null)
             {
-              componentHeight = Math.max(componentHeight, dims.height);
-              componentWidth = Math.max(componentWidth, dims.width);
+              height = Math.max(height, dims.height);
+              width = Math.max(width, dims.width);
             }
         }
+
+      Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
       if (tabPlacement == SwingConstants.TOP
           || tabPlacement == SwingConstants.BOTTOM)
         {
           int min = calculateMaxTabWidth(tabPlacement);
-          width = Math.max(min, componentWidth);
-          
-          int tabAreaHeight = preferredTabAreaHeight(tabPlacement, width);
-          height = tabAreaHeight + componentHeight;
+          width = Math.max(min, width);
+          int tabAreaHeight = preferredTabAreaHeight(tabPlacement,
+                                                     width - tabAreaInsets.left
+                                                     -tabAreaInsets.right);
+          height += tabAreaHeight;
         }
       else
         {
           int min = calculateMaxTabHeight(tabPlacement);
-          height = Math.max(min, componentHeight);
-          
-          int tabAreaWidth = preferredTabAreaWidth(tabPlacement, height);
-          width = tabAreaWidth + componentWidth;
+          height = Math.max(min, height);
+          int tabAreaWidth = preferredTabAreaWidth(tabPlacement,
+                                                   height - tabAreaInsets.top
+                                                   - tabAreaInsets.bottom);
+          width += tabAreaWidth;
         }
 
-      return new Dimension(width, height);
+      Insets tabPaneInsets = tabPane.getInsets();
+      return new Dimension(width + tabPaneInsets.left + tabPaneInsets.right,
+                           height + tabPaneInsets.top + tabPaneInsets.bottom);
     }
 
     // if tab placement is LEFT OR RIGHT, they share width.
@@ -330,192 +322,197 @@
      */
     protected void calculateTabRects(int tabPlacement, int tabCount)
     {
+      Insets insets = tabPane.getInsets();
+      Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
+      Dimension size = tabPane.getSize();
+      
+      // The coordinates of the upper left corner of the tab area.
+      int x;
+      int y;
+      // The location at which the runs must be broken.
+      int breakAt;
+
+      // Calculate the bounds for the tab area.
+      switch (tabPlacement)
+      {
+        case LEFT:
+          maxTabWidth = calculateMaxTabWidth(tabPlacement);
+          x = insets.left + tabAreaInsets.left;
+          y = insets.top + tabAreaInsets.top;
+          breakAt = size.height - (insets.bottom + tabAreaInsets.bottom);
+          break;
+        case RIGHT:
+          maxTabWidth = calculateMaxTabWidth(tabPlacement);
+          x = size.width - (insets.right + tabAreaInsets.right) - maxTabWidth;
+          y = insets.top + tabAreaInsets.top;
+          breakAt = size.height - (insets.bottom + tabAreaInsets.bottom);
+          break;
+        case BOTTOM:
+          maxTabHeight = calculateMaxTabHeight(tabPlacement);
+          x = insets.left + tabAreaInsets.left;
+          y = size.height - (insets.bottom + tabAreaInsets.bottom)
+              - maxTabHeight;
+          breakAt = size.width - (insets.right + tabAreaInsets.right);
+          break;
+        case TOP:
+        default:
+          maxTabHeight = calculateMaxTabHeight(tabPlacement);
+          x = insets.left + tabAreaInsets.left;
+          y = insets.top + tabAreaInsets.top;
+          breakAt = size.width - (insets.right + tabAreaInsets.right);
+          break;
+      }
+
       if (tabCount == 0)
         return;
 
       FontMetrics fm = getFontMetrics();
-      SwingUtilities.calculateInnerArea(tabPane, calcRect);
-      Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
-      Insets insets = tabPane.getInsets();
-      int max = 0;
-      int runs = 0;
-      int start = getTabRunIndent(tabPlacement, 1);
+      runCount = 0;
+      selectedRun = -1;
+      int selectedIndex = tabPane.getSelectedIndex();
+
+      Rectangle rect;
+
+      // Go through all the tabs and build the tab runs.
       if (tabPlacement == SwingConstants.TOP
           || tabPlacement == SwingConstants.BOTTOM)
         {
-          int maxHeight = calculateMaxTabHeight(tabPlacement);
-
-          calcRect.width -= tabAreaInsets.left + tabAreaInsets.right;
-          max = calcRect.width + tabAreaInsets.left + insets.left;
-          start += tabAreaInsets.left + insets.left;
-          int width = 0;
-          int runWidth = start;
-
           for (int i = 0; i < tabCount; i++)
             {
-              width = calculateTabWidth(tabPlacement, i, fm);
-              if (runWidth + width > max)
+              rect = rects[i];
+              if (i > 0)
                 {
-                  runWidth = tabAreaInsets.left + insets.left
-                  + getTabRunIndent(tabPlacement, ++runs);
-                  rects[i] = new Rectangle(runWidth,
-                                           insets.top + tabAreaInsets.top,
-                                           width, maxHeight);
-                  runWidth += width;
-                  if (runs > tabRuns.length - 1)
-                    expandTabRunsArray();
-                  tabRuns[runs] = i;
+                  rect.x = rects[i - 1].x + rects[i - 1].width;
                 }
               else
                 {
-                  rects[i] = new Rectangle(runWidth,
-                                           insets.top + tabAreaInsets.top,
-                                           width, maxHeight);
-                  runWidth += width;
+                  tabRuns[0] = 0;
+                  runCount = 1;
+                  maxTabWidth = 0;
+                  rect.x = x;
                 }
-            }
-          runs++;
-          tabAreaRect.width = tabPane.getWidth() - insets.left - insets.right;
-          tabAreaRect.height = runs * maxTabHeight
-          - (runs - 1) * tabRunOverlay
-          + tabAreaInsets.top + tabAreaInsets.bottom;
-          contentRect.width = tabAreaRect.width;
-          contentRect.height = tabPane.getHeight() - insets.top
-          - insets.bottom - tabAreaRect.height;
-          contentRect.x = insets.left;
-          tabAreaRect.x = insets.left;
-          if (tabPlacement == SwingConstants.BOTTOM)
-            {
-              contentRect.y = insets.top;
-              tabAreaRect.y = contentRect.y + contentRect.height;
-            }
-          else
-            {
-              tabAreaRect.y = insets.top;
-              contentRect.y = tabAreaRect.y + tabAreaRect.height;
+              rect.width = calculateTabWidth(tabPlacement, i, fm);
+              maxTabWidth = Math.max(maxTabWidth, rect.width);
+
+              if (rect.x != 2 + insets.left && rect.x + rect.width > breakAt)
+                {
+                  if (runCount > tabRuns.length - 1)
+                    expandTabRunsArray();
+                  tabRuns[runCount] = i;
+                  runCount++;
+                  rect.x = x;
+                }
+
+              rect.y = y;
+              rect.height = maxTabHeight;
+              if (i == selectedIndex)
+                selectedRun = runCount - 1;
+                
             }
         }
       else
         {
-          int maxWidth = calculateMaxTabWidth(tabPlacement);
-          calcRect.height -= tabAreaInsets.top + tabAreaInsets.bottom;
-          max = calcRect.height + tabAreaInsets.top + insets.top;
-
-          int height = 0;
-          start += tabAreaInsets.top + insets.top;
-          int runHeight = start;
-
-          int fontHeight = fm.getHeight();
-
           for (int i = 0; i < tabCount; i++)
             {
-              height = calculateTabHeight(tabPlacement, i, fontHeight);
-              if (runHeight + height > max)
+              rect = rects[i];
+              if (i > 0)
                 {
-                  runHeight = tabAreaInsets.top + insets.top
-                  + getTabRunIndent(tabPlacement, ++runs);
-                  rects[i] = new Rectangle(insets.left + tabAreaInsets.left,
-                                           runHeight, maxWidth, height);
-                  runHeight += height;
-                  if (runs > tabRuns.length - 1)
-                    expandTabRunsArray();
-                  tabRuns[runs] = i;
+                  rect.y = rects[i - 1].y + rects[i - 1].height;
                 }
               else
                 {
-                  rects[i] = new Rectangle(insets.left + tabAreaInsets.left,
-                                           runHeight, maxWidth, height);
-                  runHeight += height;
+                  tabRuns[0] = 0;
+                  runCount = 1;
+                  maxTabHeight = 0;
+                  rect.y = y;
                 }
-            }
-          runs++;
+              rect.height = calculateTabHeight(tabPlacement, i,
+                                               fm.getHeight());
+              maxTabHeight = Math.max(maxTabHeight, rect.height);
 
-          tabAreaRect.width = runs * maxTabWidth - (runs - 1) * tabRunOverlay
-          + tabAreaInsets.left + tabAreaInsets.right;
-          tabAreaRect.height = tabPane.getHeight() - insets.top
-          - insets.bottom;
-          tabAreaRect.y = insets.top;
-          contentRect.width = tabPane.getWidth() - insets.left - insets.right
-          - tabAreaRect.width;
-          contentRect.height = tabAreaRect.height;
-          contentRect.y = insets.top;
-          if (tabPlacement == SwingConstants.LEFT)
-            {
-              tabAreaRect.x = insets.left;
-              contentRect.x = tabAreaRect.x + tabAreaRect.width;
-            }
-          else
-            {
-              contentRect.x = insets.left;
-              tabAreaRect.x = contentRect.x + contentRect.width;
-            }
-        }
-      runCount = runs;
-      if (runCount > tabRuns.length)
-        expandTabRunsArray();
+              if (rect.y != 2 + insets.top && rect.y + rect.height > breakAt)
+                {
+                  if (runCount > tabRuns.length - 1)
+                    expandTabRunsArray();
+                  tabRuns[runCount] = i;
+                  runCount++;
+                  rect.y = y;
+                }
 
-      tabRuns[0] = 0;
-      normalizeTabRuns(tabPlacement, tabCount, start, max);
-      selectedRun = getRunForTab(tabCount, tabPane.getSelectedIndex());
-      if (shouldRotateTabRuns(tabPlacement))
-        rotateTabRuns(tabPlacement, selectedRun);
-
-      // Need to pad the runs and move them to the correct location.
-      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 (shouldPadTabRun(tabPlacement, i))
-            padTabRun(tabPlacement, first, last, max);
+              rect.x = x;
+              rect.width = maxTabWidth;
 
-          // Done padding, now need to move it.
-          if (tabPlacement == SwingConstants.TOP && i > 0)
-            {
-              for (int j = first; j <= last; j++)
-                rects[j].y += (runCount - i) * maxTabHeight
-                - (runCount - i) * tabRunOverlay;
+              if (i == selectedIndex)
+                selectedRun = runCount - 1;
             }
+        }
 
-          if (tabPlacement == SwingConstants.BOTTOM)
+      if (runCount > 1)
+        {
+          int start;
+          if  (tabPlacement == SwingConstants.TOP
+              || tabPlacement == SwingConstants.BOTTOM)
+            start = y;
+          else
+            start = x;
+          normalizeTabRuns(tabPlacement, tabCount, start, breakAt);
+          selectedRun = getRunForTab(tabCount, selectedIndex);
+          if (shouldRotateTabRuns(tabPlacement))
             {
-              int height = tabPane.getBounds().height - insets.bottom
-              - tabAreaInsets.bottom;
-              int adjustment;
-              if (i == 0)
-                adjustment = height - maxTabHeight;
-              else
-                adjustment = height - (runCount - i + 1) * maxTabHeight
-                - (runCount - i) * tabRunOverlay;
-
-              for (int j = first; j <= last; j++)
-                rects[j].y = adjustment;
+              rotateTabRuns(tabPlacement, selectedRun);
             }
+        }
 
-          if (tabPlacement == SwingConstants.LEFT && i > 0)
+      // Pad the runs.
+      int tabRunOverlay = getTabRunOverlay(tabPlacement);
+      for (int i = runCount - 1; i >= 0; --i)
+        {
+          int start = tabRuns[i];
+          int nextIndex;
+          if (i == runCount - 1)
+            nextIndex = 0;
+          else
+            nextIndex = i + 1;
+          int next = tabRuns[nextIndex];
+          int end = (next != 0 ? next - 1 : tabCount - 1);
+          if (tabPlacement == SwingConstants.TOP
+              || tabPlacement == SwingConstants.BOTTOM)
             {
-              for (int j = first; j <= last; j++)
-                rects[j].x += (runCount - i) * maxTabWidth
-                - (runCount - i) * tabRunOverlay;
+              for (int j = start; j <= end; ++j)
+                {
+                  rect = rects[j];
+                  rect.y = y;
+                  rect.x += getTabRunIndent(tabPlacement, i);
+                }
+              if (shouldPadTabRun(tabPlacement, i))
+                {
+                  padTabRun(tabPlacement, start, end, breakAt);
+                }
+              if (tabPlacement == BOTTOM)
+                y -= (maxTabHeight - tabRunOverlay);
+              else
+                y += (maxTabHeight - tabRunOverlay);
             }
-
-          if (tabPlacement == SwingConstants.RIGHT)
+          else
             {
-              int width = tabPane.getBounds().width - insets.right
-              - tabAreaInsets.right;
-              int adjustment;
-              if (i == 0)
-                adjustment = width - maxTabWidth;
+              for (int j = start; j <= end; ++j)
+                {
+                  rect = rects[j];
+                  rect.x = x;
+                  rect.y += getTabRunIndent(tabPlacement, i);
+                }
+              if (shouldPadTabRun(tabPlacement, i))
+                {
+                  padTabRun(tabPlacement, start, end, breakAt);
+                }
+              if (tabPlacement == RIGHT)
+                x -= (maxTabWidth - tabRunOverlay);
               else
-                adjustment = width - (runCount - i + 1) * maxTabWidth
-                + (runCount - i) * tabRunOverlay;
-
-              for (int j = first; j <= last; j++)
-                rects[j].x = adjustment;
+                x += (maxTabWidth - tabRunOverlay);
+              
             }
         }
-      padSelectedTab(tabPlacement, tabPane.getSelectedIndex());
+      padSelectedTab(tabPlacement, selectedIndex);
     }
 
     /**
@@ -528,6 +525,58 @@
     public void layoutContainer(Container parent)
     {
       calculateLayoutInfo();
+
+      int tabPlacement = tabPane.getTabPlacement();
+      Insets insets = tabPane.getInsets();
+      int childCount = tabPane.getComponentCount();
+      if (childCount > 0)
+        {
+          int compX;
+          int compY;
+          int tabAreaWidth = 0;
+          int tabAreaHeight = 0;
+          switch (tabPlacement)
+          {
+            case LEFT:
+              tabAreaWidth = calculateTabAreaWidth(tabPlacement, runCount,
+                                                   maxTabWidth);
+              compX = tabAreaWidth + insets.left + contentBorderInsets.left;
+              compY = insets.top + contentBorderInsets.top;
+              break;
+            case RIGHT:
+              tabAreaWidth = calculateTabAreaWidth(tabPlacement, runCount,
+                                                   maxTabWidth);
+              compX = insets.left + contentBorderInsets.left;
+              compY = insets.top + contentBorderInsets.top;
+              break;
+            case BOTTOM: 
+              tabAreaHeight = calculateTabAreaHeight(tabPlacement, runCount,
+                                                     maxTabHeight);
+              compX = insets.left + contentBorderInsets.left;
+              compY = insets.top + contentBorderInsets.top;
+              break;
+            case TOP:
+            default:
+              tabAreaHeight = calculateTabAreaHeight(tabPlacement, runCount,
+                                                     maxTabHeight);
+              compX = insets.left + contentBorderInsets.left;
+              compY = tabAreaHeight + insets.top + contentBorderInsets.top;
+          }
+          Rectangle bounds = tabPane.getBounds();
+          int compWidth = bounds.width - tabAreaWidth - insets.left
+                          - insets.right - contentBorderInsets.left
+                          - contentBorderInsets.right;
+          int compHeight = bounds.height - tabAreaHeight - insets.top
+                           - insets.bottom - contentBorderInsets.top
+                           - contentBorderInsets.bottom;
+
+
+          for (int i = 0; i < childCount; ++i)
+            {
+              Component c = tabPane.getComponent(i);
+              c.setBounds(compX, compY, compWidth, compHeight);
+            }
+        }
     }
 
     /**
@@ -1288,6 +1337,12 @@
   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
@@ -1343,6 +1398,11 @@
   transient Rectangle contentRect;
 
   /**
+   * The index over which the mouse is currently moving.
+   */
+  private int rolloverTab;
+
+  /**
    * Creates a new BasicTabbedPaneUI object.
    */
   public BasicTabbedPaneUI()
@@ -2332,23 +2392,23 @@
    */
   public int tabForCoordinate(JTabbedPane pane, int x, int y)
   {
-    Point p = new Point(x, y);
+    if (! tabPane.isValid())
+      tabPane.validate();
+
     int tabCount = tabPane.getTabCount();
-    int currRun = 1;
-    for (int i = 0; i < runCount; i++)
+    int index = -1;
+    for (int i = 0; i < tabCount; ++i)
       {
-        int first = lastTabInRun(tabCount, getPreviousTabRun(currRun)) + 1;
-        if (first == tabCount)
-          first = 0;
-        int last = lastTabInRun(tabCount, currRun);
-        for (int j = first; j <= last; j++)
+        if (rects[i].contains(x, y))
           {
-            if (getTabBounds(pane, j).contains(p))
-              return j;
+            index = i;
+            break;
           }
-        currRun = getNextTabRun(currRun);
       }
-    return -1;
+
+    // FIXME: Handle scrollable tab layout.
+
+    return index;
   }
 
   /**
@@ -3068,4 +3128,33 @@
       break;
     }
   }
+
+  /**
+   * Sets the tab which should be highlighted when in rollover mode. And
+   * <code>index</code> of <code>-1</code> 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, <code>-1</code>
+   *        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 <code>-1</code> for no tab.
+   *
+   * @return the index of the tab over which the mouse is currently moving,
+   *         or <code>-1</code> for no tab
+   *
+   * @since 1.5
+   */
+  protected int getRolloverTab()
+  {
+    return rolloverTab;
+  }
 }

Attachment: signature.asc
Description: Dies ist ein digital signierter Nachrichtenteil

Reply via email to