United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: 4353673 Array out of bounds exceptions when using a JTextPane with embedded components
4353673 : Array out of bounds exceptions when using a JTextPane with embedded components

Details
Type:
Bug
Submit Date:
2000-07-17
Status:
Resolved
Updated Date:
2001-01-17
Project Name:
JDK
Resolved Date:
2001-01-17
Component:
client-libs
OS:
windows_nt,generic,windows_98,windows_2000
Sub-Component:
javax.swing
CPU:
x86,generic
Priority:
P3
Resolution:
Fixed
Affected Versions:
1.3.0
Fixed Versions:
1.4.0

Related Reports
Duplicate:
Duplicate:
Relates:

Sub Tasks

Description
layLayout.layoutContainer(OverlayLayout.java:207)
                              at java.awt.Container.layout(Container.java:686)
                              at java.awt.Container.doLayout(Container.java:676)
                              at
java.awt.Container.validateTree(Container.java:750)
                              at
java.awt.Container.validateTree(Container.java:757)
                              at
java.awt.Container.validateTree(Container.java:757)
                              at
java.awt.Container.validateTree(Container.java:757)
                              //...
(Review ID: 110389)
======================================================================


Name: jk109818			Date: 07/17/2000


java version "1.3.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0-C)
Java HotSpot(TM) Client VM (build 1.3.0-C, mixed mode)


When a JTextPane is given a JComponent to display within it, array out of
bounds exceptions are thrown. Here is some sample code. Run it, put the cursor
after the JTable and press enter. This should trigger the problem. It's /very/
annoying and /needs/ to be fixed :) This operation used to work fine, so this
is a recent bug.


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

/**
 * Small demo to show that the textpane is throwing exceptions for no
 * apparent reason. The exception is caused by just doing things with the
 * textpane such as pressing 'enter' after the embedded table.
 * Embedded components are definitely at fault here.
 * Here is the exception:
 *
Exception occurred during event dispatching:
java.lang.ArrayIndexOutOfBoundsException
	at javax.swing.SizeRequirements.calculateAlignedPositions
(SizeRequirements.java:338)
	at javax.swing.OverlayLayout.layoutContainer(OverlayLayout.java:207)
	at java.awt.Container.layout(Container.java:686)
	at java.awt.Container.doLayout(Container.java:676)
	at java.awt.Container.validateTree(Container.java:750)
	at java.awt.Container.validateTree(Container.java:757)
	at java.awt.Container.validateTree(Container.java:757)
	at java.awt.Container.validateTree(Container.java:757)
	at java.awt.Container.validateTree(Container.java:757)
	at java.awt.Container.validate(Container.java:728)
	at javax.swing.RepaintManager.validateInvalidComponents
(RepaintManager.java:313)
	at javax.swing.SystemEventQueueUtilities$ComponentWorkRequest.run
(SystemEventQueueUtilities.java:204)
	at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:154)
	at java.awt.EventQueue.dispatchEvent(EventQueue.java:317)
	at java.awt.EventDispatchThread.pumpOneEvent
(EventDispatchThread.java:103)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
	at java.awt.EventDispatchThread.run(EventDispatchThread.java:84)

 */
public class TextPaneDemo extends JFrame
{

   public TextPaneDemo()
   {
      JTextPane pane = new JTextPane();
      try
      { pane.getDocument().insertString(0, "Some random text", null); }
      catch (Exception e)
      { e.printStackTrace(); }
      pane.insertComponent(new JScrollPane(new JTable(20, 10)));

      getContentPane().setLayout(new BorderLayout());
      getContentPane().add(BorderLayout.NORTH, pane);
      pack();
      setVisible(true);
      addWindowListener(new ByeByeListener());
   }

   public static void main(String[] argv)
   {
      TextPaneDemo demo = new TextPaneDemo();
   }

   private class ByeByeListener extends WindowAdapter
   {
      public void windowClosing(WindowEvent e)
      {
         System.exit(0);
      }
   }
}
(Review ID: 106747) 
======================================================================

Name: jk109818			Date: 07/18/2000


java version "1.3.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0-C)
Java HotSpot(TM) Client VM (build 1.3.0-C, mixed mode)

1) Create a JTextPane
2) Create a JTable in a JScrollPane (in order to get column headings, etc.)
3) Insert JScrollPane into JTextPane using insertComponent
4) Click immediately after the JTable and type

Result: ArrayOutOfBoundsException thrown on each keystroke in the Java Container
layout code.

Problem does not occur for insertComponent of a simple JTable (no JScrollPane).

Problem does not occur for insertComponent of JScrollPane containing other
components (e.g. JTextArea).

The following code will illustrate the problem:

import javax.swing.*;
import javax.swing.text.*;

class TypingTest{
    static public void main(String args[]){
        JFrame frame = new JFrame("JTextPane typing test");
        frame.setSize(500,300);
        frame.setVisible(true);
                
        JTextPane pane = new JTextPane();
        frame.getContentPane().add(pane);

        pane.replaceSelection("Click immediately after the JTable and start "
           + "typing, get ArrayIndexOutOfBoundsException on each keystroke. ");
        pane.setCaretPosition(pane.getStyledDocument().getLength());

        Object[] columns = {"This", "is", "a", "JTable"};
        Object[][] data = {{"table", "", "", ""}, {"", "data", "", ""},
                           {"", "", "goes", ""}, {"", "", "", "here"}};

        //this doesn't work:
        JScrollPane jsp = new JScrollPane(new JTable(data,columns));
        jsp.setPreferredSize(new java.awt.Dimension(500,83));
	pane.insertComponent(jsp);

        //this works: pane.insertComponent(new JTable(data,columns));

        //this works:
        //JScrollPane jsp = new JScrollPane(new JTextArea("A\nB\nC\nD\n"));
        //jsp.setPreferredSize(new java.awt.Dimension(500,83));
        //pane.insertComponent(jsp);

        frame.addWindowListener( new java.awt.event.WindowAdapter() {
            public void windowClosing(java.awt.event.WindowEvent e)
                 {System.exit(0); }  }  );
      
    }
}
(Review ID: 107307)
======================================================================

Name: ks88420			Date: 09/05/2000


java version "1.3.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0-C)
Java HotSpot(TM) Client VM (build 1.3.0-C, mixed mode)

In a JTextPane I want to insert a JLabel and then some text.  I want to do this
programatically.  Under JRE 1.2.2 the following code works well.  Under 1.3 it
report errors intermittantly.  Following is a simple sample JApplet that
demonstates the problem followed by the runtime errors.  The real product is an
IRC chat applet that is ready to deploy.  You can see it on
www.ircplus.com/support/chat.asp.  Under 1.2.2 it works well under 1.3 it
crashes.  This is going to be real problem for our customers.

Simple Applet Code

//Title:       Test Project
//Version:
//Copyright:   Copyright (c) 2000
//Author:      Brian Akehurst
//Company:     Mad-Web Networks LLC
//Description: Test for inserting labels into Java JTextPane
package Tests;

import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import javax.swing.*;
import javax.swing.text.*;

public class TextPaneTest extends JApplet {
  boolean isStandalone = false;
  JPanel jPanel1 = new JPanel();
  BorderLayout borderLayout1 = new BorderLayout();
  JPanel jPanel2 = new JPanel();
  JPanel jPanel3 = new JPanel();
  JLabel jLabel1 = new JLabel();
  JScrollPane jScrollPane1 = new JScrollPane();
  JTextPane jTextPane1 = new JTextPane();

  //Construct the applet
  public TextPaneTest() {
  }

  //Initialize the applet
  public void init() {
    try  {
      jbInit();
    }
    catch(Exception e)  {
      e.printStackTrace();
    }
  }

  //Component initialization
  private void jbInit() throws Exception {
    this.setSize(new Dimension(400,300));
    jPanel1.setLayout(borderLayout1);
    jLabel1.setText("Test for inserting components into JTextPane");
    jTextPane1.setPreferredSize(new Dimension(300, 200));
    jScrollPane1.setPreferredSize(new Dimension(300, 200));
    this.getContentPane().add(jPanel1, BorderLayout.CENTER);
    jPanel1.add(jPanel2, BorderLayout.CENTER);
    jPanel2.add(jScrollPane1, null);
    jScrollPane1.getViewport().add(jTextPane1, null);
    jPanel1.add(jPanel3, BorderLayout.NORTH);
    jPanel3.add(jLabel1, null);

   for (int i = 1; i < 21 ; i++) {

   //Get the insert position and insert the label component

      Position pos = jTextPane1.getStyledDocument().getEndPosition();
      jTextPane1.setSelectionStart(pos.getOffset()-1);
      jTextPane1.insertComponent(new JLabel("Label "+new Integer(i).toString()
+" "));

   //reset the selection start position
      jTextPane1.setSelectionStart(pos.getOffset()-1);

   //Contruct a string and insert it after the label

    String stg = new String("Text String "+new Integer(i).toString()+"\n");
    int selStart = jTextPane1.getSelectionStart();
    jTextPane1.replaceSelection(stg);
    jTextPane1.setSelectionStart(selStart+stg.length());
   }

  }

  //Start the applet
  public void start() {
  }

  //Stop the applet
  public void stop() {
  }

  //Destroy the applet
  public void destroy() {
  }

  //Get Applet information
  public String getAppletInfo() {
    return "Applet Information";
  }

  //Get parameter info
  public String[][] getParameterInfo() {
    return null;
  }
  // static initializer for setting look & feel
  static {
    try {
      UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
      UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName
());
    }
    catch (Exception e) {}
  }

}  

Errors

java.lang.ArrayIndexOutOfBoundsException
        at javax.swing.SizeRequirements.calculateAlignedPositions(SizeRequiremen
ts.java:338)
        at javax.swing.OverlayLayout.layoutContainer(OverlayLayout.java:207)
        at java.awt.Container.layout(Container.java:686)
        at java.awt.Container.doLayout(Container.java:676)
        at java.awt.Container.validateTree(Container.java:750)
        at java.awt.Container.validateTree(Container.java:757)
        at java.awt.Container.validateTree(Container.java:757)
        at java.awt.Container.validateTree(Container.java:757)
        at java.awt.Container.validateTree(Container.java:757)
        at java.awt.Container.validateTree(Container.java:757)
        at java.awt.Container.validateTree(Container.java:757)
        at java.awt.Container.validateTree(Container.java:757)
        at java.awt.Container.validateTree(Container.java:757)
        at java.awt.Container.validateTree(Container.java:757)
        at java.awt.Container.validateTree(Container.java:757)
        at java.awt.Container.validate(Container.java:728)
        at sun.applet.AppletPanel.run(AppletPanel.java:347)
        at java.lang.Thread.run(Thread.java:484)
(Review ID: 109232)
======================================================================

Name: krC82822			Date: 12/20/2000


java version "1.3.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0-C)
Java HotSpot(TM) Client VM (build 1.3.0-C, mixed mode)

Here's a forum message that describes the problem.
I have had the same problem in my own code (far less minimal than
this code):

I'm traying to place JButtons in each row of an Document (JTextPane). One Button
at the end of the Document is not a problem,
                              but if placing anything after a Button... There's
a peace of Code and the Error Message that I'm getting.

                              //...

                              public class WindowAR extends JWindow {

                              //...

                              Style btn = jTextPaneErg.addStyle("button",
regular);
                              JButton button = new JButton();

                              //...

                              //Component initialization
                              private void jbInit() throws Exception {

                              button.setMargin(new Insets(0,0,0,0));
                              button.addActionListener(new ActionListener() {
                              public void actionPerformed(ActionEvent e) {
                              }
                              });
                              StyleConstants.setAlignment(btn,
StyleConstants.ALIGN_CENTER);
                              StyleConstants.setComponent(btn, button);

                              //...

                              // Show Objects
                              public void showARObjects(java.util.List list) {
                              StyledDocument doc =
arjTextPane.getStyledDocument();
                              ListIterator i = list.listIterator();

                              while (i.hasNext()) {
                              //...
                              arObject = (ARObject) i.next();

                              doc.insertString(doc.getLength(), " ", icon);
                              doc.insertString(doc.getLength(), " Area: "
arObject.area, italic);
                              doc.insertString(doc.getLength(), " ", btn); //
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                              doc.insertString(doc.getLength(), " Code: "
arObject.code, italic);
                              doc.insertString(doc.getLength(), "\n", regular);
                              }

                              //...

                              }
                              //EOF

                              ! Error !! Error !! Error !! Error !! Error !!
Error !! Error !! Error !! Error !...
                              Output Window:

                              Exception occurred during event dispatching:
                              java.lang.ArrayIndexOutOfBoundsException
                              at
javax.swing.SizeRequirements.calculateAlignedPositions(SizeRequirements.java:338
) 
                              at
javax.swing.OverlayLayout.layoutContainer(OverlayLayout.java:207)
                              at java.awt.Container.layout(Container.java:686)
                              at java.awt.Container.doLayout(Container.java:676)
                              at
java.awt.Container.validateTree(Container.java:750)
                              at
java.awt.Container.validateTree(Container.java:757)
                              at
java.awt.Container.validateTree(Container.java:757)
                              at
java.awt.Container.validateTree(Container.java:757)
                              at
java.awt.Container.validateTree(Container.java:757)
                              at
java.awt.Container.validateTree(Container.java:757)
                              at
java.awt.Container.validateTree(Container.java:757)
                              at
java.awt.Container.validateTree(Container.java:757)
                              at java.awt.Container.validate(Container.java:728)
                              at
javax.swing.RepaintManager.validateInvalidComponents(RepaintManager.java:313)
                              at
javax.swing.SystemEventQueueUtilities$ComponentWorkRequest.run(SystemEventQueueU
tilities.java:204)
                              at
java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:154)
                              at
java.awt.EventQueue.dispatchEvent(EventQueue.java:317)
                              at
java.awt.EventDispatchThread.pumpOneEvent(EventDispatchThread.java:103)
                              at
java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
                              at
java.awt.EventDispatchThread.run(EventDispatchThread.java:84) Exception occurred
during event dispatching:
                              java.lang.ArrayIndexOutOfBoundsException
                              at
javax.swing.SizeRequirements.calculateAlignedPositions(SizeRequirements.java:338
) 
                              at
javax.swing.Over

                                    

Comments
CONVERTED DATA

BugTraq+ Release Management Values

COMMIT TO FIX:
merlin-beta

FIXED IN:
merlin-beta

INTEGRATED IN:
merlin-beta


                                     
2004-06-14
WORK AROUND

This will potentially lock you into the current implementation of ComponentView, but it'll work at least until 1.4:

      component.addHierarchyListener(new HierarchyListener() {
          private Container oldParent;
          public void hierarchyChanged(HierarchyEvent e) {
              Container parent = component.getParent();

              if (parent != oldParent) {
                  if (oldParent != null) {
                      textPane.remove(oldParent);
                  }
                  oldParent = parent;
              }
          }
      });

Where component is the Component being added to the text pane (JScrollPane in the first example).
scott.violet@eng 2000-11-20

Name: krC82822			Date: 12/20/2000


This appears to be a bug in SizeRequirements where the xChildren (also
yChildren) array is not the same length as the offset and
                              span arrays. Calling invalidateLayout on the
button's OverlayLayout will clear the cached [xy]Children arrays and reallocate
them at
                              the correct length. Here's a method to call after
adding a new component (button but could be any JComponent) to a JTextPane:

                              /**
                              * Clear cached size calculations to work around
                              * ArrayIndexOutOfBounds exception
                              * in SizeRequirements. Button is a JComponent
                              * that has its own internal OverlayLayout that
                              * must be invalidated.
                              */
                              private void invalidateButtonLayout(JButton
button)
                              {
                              LayoutManager layout =
button.getParent().getLayout();
                              if(layout instanceof OverlayLayout) {
                              ((OverlayLayout)layout).
                              invalidateLayout((Container)(button.getParent()));
                              }
                              }
(Review ID: 110389)
======================================================================
                                     
2004-06-11
EVALUATION

This is happening because we are not forwarding setParent(null), so that ComponentView does not know when to remove the Component it creates from the JTextComponent.
scott.violet@eng 2000-11-20

The problem with forwarding setParent(null) is that it can potentially cause invoking a method on a large amount of Views every time they are removed.
Instead ComponentView should install a DocumentListener. When the range it represents is removed, it should do the necessary cleanup. This should be acceptable as typically not that many Components are created on a particular page.
scott.violet@eng 2000-12-07

We decided to change View to forward setParent(null) to all children. ComponentView has been changed to recognize this and properly remove the Component it represents. This also fixes bugid 4335120.
shannon.hickey@Eng 2001-01-10
                                     
2001-01-10



Hardware and Software, Engineered to Work Together