Hi,
as mentioned in PR 26157[0] I observed that the JDK's JTextArea adjusts its size
automatically when the characters leave the allocation area of the component.
Our JTextArea did not have this functionality until now.

It took me a while to find out where to place the code that could do the
neccessary checks which should prevent unneeded revalidate() calls.

While implementing this I found and fixed two problems in PlainView:

1) The switch statement in getPreferredSpan always fell into the Y_AXIS case.

2) In changeUpdate() the maxLineLength value could never shrink when characters
are removed on one line only. I added a check whether the characters are removed
from the current longest line and update the maxLineLength value if that is the
case.

Please comment.

2006-02-21  Robert Schuster  <[EMAIL PROTECTED]>

        * javax/swing/text/PlainDocument.java:
        (getPreferredSpan): Removed variable, use 'return' in switch
        statement which corrects an unwanted fall through.
        (changeUpdate): Update maxLineLength correctly when text is
        removed.
        * javax/swing/plaf/basic/BasicTextUI.java:
        (BasicTextUI.RootView): Made class package private.
        * javax/swing/plaf/basic/BasicTextAreaUI.java:
        (BasicTextAreaUI.TextAreaRootView): New class.
        (BasicTextAreaUI): Set new rootView instance.

cya
Robert

[0] - http://gcc.gnu.org/bugzilla/show_bug.cgi?id=26157
Index: javax/swing/text/PlainView.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/PlainView.java,v
retrieving revision 1.36
diff -u -r1.36 PlainView.java
--- javax/swing/text/PlainView.java	8 Feb 2006 15:57:41 -0000	1.36
+++ javax/swing/text/PlainView.java	22 Feb 2006 07:56:57 -0000
@@ -307,19 +307,16 @@
     // make sure we have the metrics
     updateMetrics();
 
-    float span = 0;
     Element el = getElement();
 
     switch (axis)
       {
       case X_AXIS:
-        span = determineMaxLineLength();
+        return determineMaxLineLength();
       case Y_AXIS:
       default:
-        span = metrics.getHeight() * el.getElementCount();
-        break;
+        return metrics.getHeight() * el.getElementCount();
       }
-    return span;
   }
 
   /**
@@ -383,7 +380,18 @@
     // repaint the changed line
     if (ec == null)
       {
-        int line = getElement().getElementIndex(changes.getOffset());
+        int line = el.getElementIndex(changes.getOffset());
+        
+        // If characters have been removed from the current longest line
+        // we have to find out which one is the longest now otherwise
+        // the preferred x-axis span will not shrink.
+        if (changes.getType() == DocumentEvent.EventType.REMOVE
+            && el.getElement(line) == longestLine)
+          {
+            maxLineLength = -1;
+            determineMaxLineLength();
+          }
+        
         damageLineRange(line, line, a, getContainer());
         return;
       }
@@ -396,6 +404,7 @@
     if (removed == null && newElements == null)
       {
         int line = getElement().getElementIndex(changes.getOffset());
+        
         damageLineRange(line, line, a, getContainer());
         return;
       }
@@ -410,7 +419,9 @@
               // reset maxLineLength and search through all lines for longest one
               maxLineLength = -1;
               determineMaxLineLength();
+              
               ((JTextComponent)getContainer()).repaint();
+              
               return;
             }
       }
@@ -420,6 +431,7 @@
       {
         // No lines were added, just repaint the container and exit
         ((JTextComponent)getContainer()).repaint();
+        
         return;
       }
 
@@ -468,6 +480,7 @@
         maxLineLength = longestNewLength;
         longestLine = longestNewLine;
       }
+    
     // Repaint the container
     ((JTextComponent)getContainer()).repaint();
   }
Index: javax/swing/plaf/basic/BasicTextUI.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/plaf/basic/BasicTextUI.java,v
retrieving revision 1.71
diff -u -r1.71 BasicTextUI.java
--- javax/swing/plaf/basic/BasicTextUI.java	21 Feb 2006 14:03:19 -0000	1.71
+++ javax/swing/plaf/basic/BasicTextUI.java	22 Feb 2006 07:56:57 -0000
@@ -125,7 +125,7 @@
    * calls like [EMAIL PROTECTED] #preferenceChanged}, [EMAIL PROTECTED] #getViewFactory} and
    * [EMAIL PROTECTED] #getContainer}.
    */
-  private class RootView extends View
+  class RootView extends View
   {
     /** The real root view. */
     private View view;
Index: javax/swing/plaf/basic/BasicTextAreaUI.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/plaf/basic/BasicTextAreaUI.java,v
retrieving revision 1.6
diff -u -r1.6 BasicTextAreaUI.java
--- javax/swing/plaf/basic/BasicTextAreaUI.java	31 Oct 2005 21:29:52 -0000	1.6
+++ javax/swing/plaf/basic/BasicTextAreaUI.java	22 Feb 2006 07:56:57 -0000
@@ -39,19 +39,73 @@
 package javax.swing.plaf.basic;
 
 
+import java.awt.FontMetrics;
+import java.awt.Rectangle;
+import java.awt.Shape;
 import java.beans.PropertyChangeEvent;
 
 import javax.swing.JComponent;
 import javax.swing.JTextArea;
 import javax.swing.UIDefaults;
+import javax.swing.event.DocumentEvent;
 import javax.swing.plaf.ComponentUI;
 import javax.swing.text.Element;
 import javax.swing.text.PlainView;
 import javax.swing.text.View;
+import javax.swing.text.ViewFactory;
 import javax.swing.text.WrappedPlainView;
 
 public class BasicTextAreaUI extends BasicTextUI
 {
+  /** Extends the RootView of BasicTextUI with the ability to adjust the size
+   * of the component after text was inserted, removed or changed.
+   */
+  class TextAreaRootView extends BasicTextUI.RootView
+  {
+    public void changedUpdate(DocumentEvent ev, Shape shape, ViewFactory vf)
+    {
+      super.changedUpdate(ev, shape, vf);
+      checkBounds(shape);
+    }
+     
+    public void removeUpdate(DocumentEvent ev, Shape shape, ViewFactory vf)
+    {
+      super.removeUpdate(ev, shape, vf);
+      checkBounds(shape);
+    }
+    
+    public void insertUpdate(DocumentEvent ev, Shape shape, ViewFactory vf)
+    {
+      super.insertUpdate(ev, shape, vf);
+      checkBounds(shape);
+    }
+    
+    private void checkBounds(Shape allocation)
+    {
+      Rectangle a = allocation.getBounds();
+      int neededWidth = (int) getPreferredSpan(View.HORIZONTAL);
+      int neededHeight = (int) getPreferredSpan(View.VERTICAL);
+      
+      JTextArea ta = (JTextArea) textComponent;
+      if (a.width != neededWidth)
+        {
+          FontMetrics metrics = ta.getFontMetrics(ta.getFont());
+          int reqWidth = ta.getColumns() * metrics.charWidth('m');
+          if (reqWidth < neededWidth)
+            ta.revalidate();
+        }
+      else if (a.height != neededHeight)
+        {
+          FontMetrics metrics = ta.getFontMetrics(ta.getFont());
+          int reqHeight = ta.getRows() * metrics.getHeight();
+
+          if (reqHeight < neededHeight)
+            ta.revalidate();
+        }
+    }
+    
+  }
+  
   public static ComponentUI createUI(JComponent comp)
   {
     return new BasicTextAreaUI();
@@ -59,7 +113,10 @@
 
   public BasicTextAreaUI()
   {
-    // Nothing to do here.
+    // Cannot use special constructor for this as TextAreaRootView is a
+    // non-static inner class. The assignment displaces the instance
+    // that was created in BasicTextUI.
+    rootView = new TextAreaRootView();
   }
 
   /**

Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to