JDK-5075526 : REGRESSION: ArrayIndexOutOfBoundsException in BasicTabbedPaneUI.getTabBounds()
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 5.0
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2004-07-19
  • Updated: 2004-12-16
  • Resolved: 2004-12-01
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other JDK 6
5.0u3Fixed 6 b14Fixed
Description

Name: jl125535			Date: 07/19/2004


FULL PRODUCT VERSION :
java version "1.5.0-beta3"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0-beta3-b57)
Java HotSpot(TM) Client VM (build 1.5.0-beta3-b57, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]

EXTRA RELEVANT SYSTEM CONFIGURATION :
This bug only occurs when using the windows XP look and feel.

A DESCRIPTION OF THE PROBLEM :
With java 1.5.0 when a tab in a JTabbedPane is closed, _while the mouse is over that tab_, a NullPointerException is thrown. This is a regression from java 1.4.2.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the program, below,  on windows with the windows XP look and feel (not windows classic).


EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
No exception should be thrown.
ACTUAL -
An exception is thrown, see below.

ERROR MESSAGES/STACK TRACES THAT OCCUR :
The full traceback is:

Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException:
 1
        at javax.swing.plaf.basic.BasicTabbedPaneUI.getTabBounds(BasicTabbedPaneUI.java:1313)
        at javax.swing.plaf.basic.BasicTabbedPaneUI.getTabBounds(BasicTabbedPaneUI.java:1248)
        at com.sun.java.swing.plaf.windows.WindowsTabbedPaneUI.setRolloverTab(WindowsTabbedPaneUI.java:82)
        at javax.swing.plaf.basic.BasicTabbedPaneUI$TabbedPaneLayout.layoutContainer(BasicTabbedPaneUI.java:2149)
        at java.awt.Container.layout(Container.java:1401)
        at java.awt.Container.doLayout(Container.java:1390)
        at java.awt.Container.validateTree(Container.java:1473)
        at java.awt.Container.validateTree(Container.java:1480)
        at java.awt.Container.validateTree(Container.java:1480)
        at java.awt.Container.validate(Container.java:1448)
        at javax.swing.RepaintManager.validateInvalidComponents(RepaintManager.java:379)
        at javax.swing.SystemEventQueueUtilities$ComponentWorkRequest.run(SystemEventQueueUtilities.java:113)
        at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:461)
        at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:234)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:163)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:157)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:149)
        at java.awt.EventDispatchThread.run(EventDispatchThread.java:110)



REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------

import java.awt.*;
import javax.swing.*;

public class BugReport
{  
   public static void main(String[] args) throws Exception
   {
      UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());

      final JTabbedPane tabs = new JTabbedPane();
      tabs.addTab("Tab 1",new JPanel());
      tabs.addTab("Tab 2",new JPanel());
      JFrame frame = new JFrame("Bug Report");
      frame.setContentPane(tabs);
      frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
      frame.pack();
      frame.show();
      
      Thread.sleep(2000);
      
      Rectangle d = tabs.getBoundsAt(1);
      Point p = new Point(d.x+d.width/2,d.y+d.height/2);
      SwingUtilities.convertPointToScreen(p,tabs);
      Robot robot = new Robot();
      robot.mouseMove(p.x,p.y);
      
      Thread.sleep(2000);
      
      Runnable run = new Runnable()
      {
         public void run()
         {
            tabs.removeTabAt(1);
            tabs.revalidate();
            tabs.repaint();
         }
      };
      SwingUtilities.invokeAndWait(run);
   }
}

---------- END SOURCE ----------

Release Regression From : 1.4.2
The above release value was the last known release where this 
bug was known to work. Since then there has been a regression.

(Incident Review ID: 286223) 
======================================================================

Comments
SUGGESTED FIX http://sa.sfbay.sun.com/projects/swing_data/mustang/5075526.4 ###@###.### 2004-11-25 17:46:15 GMT
25-11-2004

CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: dragon mustang
25-09-2004

EVALUATION Name: sh120115 Date: 07/20/2004 ###@###.###, would you please check to see if this is a duplicate of 5056403? Thanks! ###@###.### 2004-07-20 ====================================================================== This is different than 5056403. When basictabbedpaneui's layoutmanager runs (layoutContainer) it first sets the rollover tab to -1. WindowsTabbedPaneUI.setRolloverTab will first repaint the old rollover tab by invoking getTabBounds. The problem with this logic is that if rolloverTab is greater than the number of tabs, because the tab the mouse was over was removed, getTabBounds will throw an exception. There are a number of ways to fix this. I can think of at least two: . Modfy WindowsTabbedPaneUI to make sure the old index is valid. . Modify BasicTabbedPaneUI to directly reset the field it maintains to -1 if the tab was removed. The first approach is simple and straightforward, but has the disadvantage that anyone subclassing basic has to deal with this. The second has the disadvantage that anyone maintaining state based on the old rollover tab would find it confusing that the setter wasn't always invoked. I would go with the first, it's more consistant. The doc should also be updated to indicate this. ###@###.### 2004-07-22 I changed WindowsTabbedPaneUI, so I implemented the first way of two ways, described above by ###@###.###. ###@###.### ###@###.### 2004-11-25 17:46:15 GMT ###@###.### 2004-11-30 19:56:55 GMT
25-09-2004