Hi, I have a strange problem. I googled/searched the forums and found several entries - but no solution (it is
not a threading problem).
I think I am missing something obvious...
Okay, here is a test case that fails:
import junit.framework.TestCase;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
/**
*
*/
public class TreeProblem extends TestCase {
public void testSmallTest() throws InvocationTargetException, InterruptedException {
//Just to ensure that threading is *not* a problem...
SwingUtilities.invokeAndWait( new Runnable() {
public void run() {
MyTreeModel model = new MyTreeModel();
JTree tree = new JTree( model );
assertEquals( 21, tree.getRowCount() );
model.removeIt(); //throws the exception thrown....
assertEquals( 19, model.children.size() );
}
} );
}
/**
* A simple model with just 20 children
*/
private static class MyTreeModel implements TreeModel {
private static final String ROOT = "root";
private List<String> children = new ArrayList<String>();
private MyTreeModel() {
for ( int i = 0; i < 20; i++ ) {
children.add( String.valueOf( i ) );
}
}
public Object getRoot() {
return ROOT;
}
public Object getChild( Object parent, int index ) {
assertSame( ROOT, parent );
return children.get( index );
}
public int getChildCount( Object parent ) {
return children.size();
}
public boolean isLeaf( Object node ) {
return node != ROOT;
}
public void valueForPathChanged( TreePath path, Object newValue ) {
throw new UnsupportedOperationException();
}
public int getIndexOfChild( Object parent, Object child ) {
return children.indexOf( child );
}
private final List<TreeModelListener> listeners = new ArrayList<TreeModelListener>();
public void addTreeModelListener( TreeModelListener l ) {
listeners.add( l );
}
public void removeTreeModelListener( TreeModelListener l ) {
throw new UnsupportedOperationException();
}
/**
* This method has everything hardcoded (only for testing purposes). Call only once...
*/
public void removeIt() {
assertEquals( 20, children.size() );
//Remove the last two entries...
Object[] removed = new Object[2];
removed[0] = children.remove( 19 );
removed[1] = children.remove( 18 );
assertEquals( 18, children.size() );
int[] indicies = new int[]{19, 18};
for ( TreeModelListener listener : listeners ) {
listener.treeNodesRemoved( new TreeModelEvent( this, new TreePath( ROOT ), indicies, removed ) );
}
}
}
}
This code throws the following exception:
Caused by: java.lang.ArrayIndexOutOfBoundsException: 19 >= 19
at java.util.Vector.elementAt(Vector.java:432)
at javax.swing.tree.DefaultMutableTreeNode.getChildAt(DefaultMutableTreeNode.java:230)
at javax.swing.tree.VariableHeightLayoutCache.treeNodesRemoved(VariableHeightLayoutCache.java:543)
at javax.swing.plaf.basic.BasicTreeUI$Handler.treeNodesRemoved(BasicTreeUI.java:3707)
at de.avat.jview.diary.model.TreeProblem$MyTreeModel.removeIt(TreeProblem.java:99)
at de.avat.jview.diary.model.TreeProblem$1.run(TreeProblem.java:28)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:199)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:461)
at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:242)
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)