JDK-4446522 : JTextArea.getPreferredSize() incorrect when line wrapping is used
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 1.3.1_01,1.4.1,1.4.1_02,1.4.2,5.0
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • OS: solaris_9,windows_2000
  • CPU: generic,x86,sparc
  • Submitted: 2001-04-17
  • Updated: 2003-09-26
  • Resolved: 2003-09-26
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
5.0 tigerFixed
Related Reports
Duplicate :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
java -version:

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

JTextArea returns the incorrect preferred size when line wrapping is used. The following sample program puts a line-wrapped JTextArea in a JDialog. It prints out the preferred size of the JTextArea before and after the dialog's pack() method is called. These 2 dimensions are not the same - its only correct after pack() has been called.


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

public class JTextAreaWrappingTest {

    private String testStr = "This string should be sufficiently long to demonstrate the problem.";
    WrapArea wrapArea;

    public static void main(String argv[]) {

        JTextAreaWrappingTest myTest = new JTextAreaWrappingTest();

    }

    public JTextAreaWrappingTest () {

        JDialog dialog = new JDialog();

        WrapArea wrapArea = new WrapArea(testStr);
        dialog.getContentPane().setLayout(new FlowLayout());
        dialog.getContentPane().add(wrapArea);

        System.out.println("pre-pack() prefSize = " + wrapArea.getPreferredSize());
        dialog.pack();

// UNCOMMENT THIS LINE AND RE-COMPILE TO DEMONSTRATE THE WORK AROUND
//      dialog.pack();
        System.out.println("post-pack() prefSize = " + wrapArea.getPreferredSize());
        dialog.show();

    } // constructor

    public class WrapArea extends JTextArea {

        public WrapArea(String str) {

            super(str);
            wrapArea = this;

            wrapArea.setColumns(30);
            wrapArea.setLineWrap(true);

        } // constructor

    } // WrapArea

} // JTextAreaWrappingTest

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: tiger FIXED IN: tiger INTEGRATED IN: tiger tiger-b22
14-06-2004

EVALUATION Name: anR10225 Date: 06/06/2003 The matter is BasicTextUI sets the initial size of the root view to (Integer.MAX_VALUE, Integer.MAX_VALUE). The WrappedPlainView in this case calculates its preferred width as 100 but calculating height it relays on getWidth() value (which is MAX_VALUE). So all lines are assumed not to be broken during preferred height calculation. On preferred height calculation some other width (e.g. getPreferredSpan(X_AXIS)) should be used if getWidth() returns MAX_VALUE. ====================================================================== Name: anR10225 Date: 06/06/2003 Another problem arises when JTextArea has width specified by columns. While processing JTextArea.getPreferredSize() it first asks for UI about its preferred size and if it is smaller than required by columns JTextArea substitutes its own preferred width without recalculating preferred height of UI. If JTextArea.getPreferredSize() wants to have preferred width according to column number it should inform the UI about its new width and recalculate UI height. ======================================================================
11-06-2004

WORK AROUND calling dialog.pack() twice shows lays out the JTextArea with the correct size. Name: anR10225 Date: 06/06/2003 another work around is to invoke textArea.setSize(requiredWidth, 1) before pack() to set initial width of WrappedPlainView. setColumns() doesn't do it. ======================================================================
11-06-2004

SUGGESTED FIX Name: anR10225 Date: 09/19/2003 *** /net/crown/export1/naa/tiger//webrev/4446522/src/share/classes/javax/swing/JTextArea.java- ?? ??? 6 18:51:00 2003 --- JTextArea.java ?? ??? 6 17:33:36 2003 *************** *** 614,622 **** Insets insets = getInsets(); if (columns != 0) { ! d.width = Math.max(d.width, columns * getColumnWidth() + ! insets.left + insets.right); } if (rows != 0) { d.height = Math.max(d.height, rows * getRowHeight() + insets.top + insets.bottom); --- 614,632 ---- Insets insets = getInsets(); if (columns != 0) { ! int viewWidth = columns * getColumnWidth(); ! int colWidth = viewWidth + insets.left + insets.right; ! if (colWidth > d.width) { ! d.width = colWidth; ! if (getLineWrap()) { ! // need to recalculate view height taking into account ! // actual text area width ! View v = getUI().getRootView(this); ! v.setSize(viewWidth, 1); ! d.height = super.getPreferredSize().height; } + } + } if (rows != 0) { d.height = Math.max(d.height, rows * getRowHeight() + insets.top + insets.bottom); *** /net/crown/export1/naa/tiger//webrev/4446522/src/share/classes/javax/swing/text/WrappedPlainView.java- ?? ??? 6 18:51:00 2003 --- WrappedPlainView.java ?? ??? 6 17:35:14 2003 *************** *** 217,229 **** int p; Segment segment = SegmentCache.getSharedSegment(); loadText(segment, p0, p1); if (wordWrap) { p = p0 + Utilities.getBreakLocation(segment, metrics, ! tabBase, tabBase + getWidth(), this, p0); } else { p = p0 + Utilities.getTabbedTextOffset(segment, metrics, ! tabBase, tabBase + getWidth(), this, p0, false); } SegmentCache.releaseSharedSegment(segment); --- 217,236 ---- int p; Segment segment = SegmentCache.getSharedSegment(); loadText(segment, p0, p1); + int currentWidth = getWidth(); + if (currentWidth == Integer.MAX_VALUE) { + // width is still not initialized + // layout using preferred width + // bug #4446522 + currentWidth = (int) getPreferredSpan(X_AXIS); + } if (wordWrap) { p = p0 + Utilities.getBreakLocation(segment, metrics, ! tabBase, tabBase + currentWidth, this, p0); } else { p = p0 + Utilities.getTabbedTextOffset(segment, metrics, ! tabBase, tabBase + currentWidth, this, p0, false); } SegmentCache.releaseSharedSegment(segment); *** /net/crown/export1/naa/tiger//webrev/4446522/src/share/classes/javax/swing/plaf/basic/BasicTextUI.java- ?? ??? 6 18:51:01 2003 --- BasicTextUI.java ?? ??? 6 17:36:24 2003 *************** *** 786,791 **** --- 786,793 ---- } } + private boolean sizeInitialized = false; + /** * Gets the preferred size for the editor component. If the component * has been given a size prior to receiving this request, it will *************** *** 810,819 **** if ((d.width > (i.left + i.right)) && (d.height > (i.top + i.bottom))) { rootView.setSize(d.width - i.left - i.right, d.height - i.top - i.bottom); } ! else if (d.width == 0 && d.height == 0) { // Probably haven't been layed out yet, force some sort of // initial sizing. rootView.setSize(Integer.MAX_VALUE, Integer.MAX_VALUE); } d.width = (int) Math.min((long) rootView.getPreferredSpan(View.X_AXIS) + (long) i.left + (long) i.right, Integer.MAX_VALUE); --- 812,822 ---- if ((d.width > (i.left + i.right)) && (d.height > (i.top + i.bottom))) { rootView.setSize(d.width - i.left - i.right, d.height - i.top - i.bottom); } ! else if (d.width == 0 && d.height == 0 && !sizeInitialized) { // Probably haven't been layed out yet, force some sort of // initial sizing. rootView.setSize(Integer.MAX_VALUE, Integer.MAX_VALUE); + sizeInitialized = true; } d.width = (int) Math.min((long) rootView.getPreferredSpan(View.X_AXIS) + (long) i.left + (long) i.right, Integer.MAX_VALUE); ###@###.### ======================================================================
11-06-2004