JDK-6480543 : JXTableHeader: throws AIOOB on removing dragged column
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 5.0
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • OS: windows_2000
  • CPU: x86
  • Submitted: 2006-10-11
  • Updated: 2011-04-28
Description
FULL PRODUCT VERSION :
probably all, seem with 1.5u6, 1.6b84

ADDITIONAL OS VERSION INFORMATION :
not relevant

EXTRA RELEVANT SYSTEM CONFIGURATION :
not relevant

A DESCRIPTION OF THE PROBLEM :

The error happens if the dragged column is removed during the drag. To reproduce

- compile and run the example
- drag a column
- press F1

The ArrayIndexOutOfBounds is thrown when either the BasicTableHeaderUI or the BasicTableUI attempt to paint the dragged column (seems to be indeterministic which is first)

  Evaluation (for BasicTableHeaderUI, didn't look into TableUI, probably similar):

the relevant code fragment of paint is

[code]
void paint(..)
     ...
        // Paint the dragged column if we are dragging.
        if (draggedColumn != null) {
            int draggedColumnIndex = viewIndexForColumn(draggedColumn);
     
}
[/code]

the code assumes that a draggedColumn != null is sufficient to guarantee a valid column index. The assumption is wrong if the dragged column was removed during dragging.


ERROR MESSAGES/STACK TRACES THAT OCCUR :
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: -1
	at java.util.Vector.elementAt(Vector.java:434)
	at javax.swing.table.DefaultTableColumnModel.getColumn(DefaultTableColumnModel.java:277)
	at javax.swing.plaf.basic.BasicTableHeaderUI.getHeaderRenderer(BasicTableHeaderUI.java:648)
	at javax.swing.plaf.basic.BasicTableHeaderUI.paintCell(BasicTableHeaderUI.java:664)
	at javax.swing.plaf.basic.BasicTableHeaderUI.paint(BasicTableHeaderUI.java:640)

This stacktrace is from Java SE 6.0. Java SE 5.0 has a similar (obviously with different line numbers). Occasionally, a similar exception is thrown by the BasicTableUI (when trying to paint the dragged column)

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
/*
 * Created on 21.09.2006
 *
 */
package swing;

import java.awt.Component;
import java.awt.event.ActionEvent;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.table.TableColumn;

/**
 * Bug: Remove dragged column throws ArrayIndexOOBException.
 * To reproduce: run, drag a column, press f1 while dragging.
 *
 * @author Jeanette Winzenburg
 */
public class DragginHeaderBug {
    protected Component getContent() {
        final JTable table = new JTable(10, 5);
        Action deleteColumn = new AbstractAction("deleteCurrentColumn") {

            public void actionPerformed(ActionEvent e) {
                TableColumn column = table.getTableHeader().getDraggedColumn();
                if (column == null) return;
                table.getColumnModel().removeColumn(column);
            }
            
        };
        KeyStroke keyStroke = KeyStroke.getKeyStroke("F1");
        table.getInputMap(JTable.WHEN_IN_FOCUSED_WINDOW).put(keyStroke, "f1");
        table.getActionMap().put("f1", deleteColumn);
        return new JScrollPane(table);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JFrame frame = new JFrame("Drag Column and press F1");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new DragginHeaderBug().getContent());
                frame.setSize(600, 400);
                frame.setVisible(true);
            }
        });
    }

}

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

CUSTOMER SUBMITTED WORKAROUND :
The real fix should be done in the ui delegates: trace all occurences of the wrong assumption, check the actual value of viewIndexForColumn and gracefully end (probably some cleanup needed) the drag if -1.

Until that happens, client code can subclass JTableHeader, override getDraggedColumn and return null if the column is no longer visible. That's what SwingX JXTableHeader is currently doing.

Comments
EVALUATION Contribution forum : https://jdk-collaboration.dev.java.net/servlets/ProjectForumMessageView?forumID=1463&messageID=17144
27-11-2006