A couple of fixes for javax.swing.text that have been lying around on my
HD for too long now...

2006-06-21  Roman Kennke  <[EMAIL PROTECTED]>

        * javax/swing/text/AbstractDocument.java
        (BranchElement.numChildren): New field.
        (BranchElement.BranchElement): Initialize children array with
        one element (that's the least number of elements that makes sense).
        Initialize numChildren.
        (BranchElement.children): Use numChildren as boundary.
        (BranchElement.getElement): Use numChildren as boundary.
        (BranchElement.getElementCount): Use numChildren as boundary.
        (BranchElement.getElementIndex): Use numChildren as boundary.
        (BranchElement.getEndOffset): Use numChildren as boundary.
        (BranchElement.getStartOffset): Use numChildren as boundary.
        (BranchElement.positionToElement): Use numChildren as boundary.
        (BranchElement.replace): Handle the children array more efficiently
        by growing in blocks > 1, and reusing space from removed elements.
        (LeafElement.startDelta): Removed.
        (LeafElement.endDelta): Removed.
        (LeafElement.LeafElement): Removed handling of deltas.
        (LeafElement.getEndOffset): Likewise.
        (LeafElement.getStartOffset): Likewise.
        * javax/swing/text/JTextComponent.java
        (setDocument): Added locking of the old document to avoid dangling
        notification beeing delivered while the document is beeing
        disconnected.
        (getScrollableTracksViewportWidth): Fixed condition.
        * javax/swing/text/PlainDocument.java
        (createDefaultRoot): Create elements without AttributeSet.
        * javax/swing/text/rtf/RTFParser.java
        (parseFile): Handle slightly incorrect RTF gracefully.
        * javax/swing/text/rtf/RTFScanner.java
        (lastToken): New field.
        (readTokenImpl): New method.
        (peekToken): New method.
        (readToken): Changed to call readTokenImpl or return the lastToken
        if there's one present.
-- 
“Improvement makes straight roads, but the crooked roads, without
Improvement, are roads of Genius.” - William Blake
Index: javax/swing/text/AbstractDocument.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/AbstractDocument.java,v
retrieving revision 1.57
diff -u -1 -0 -r1.57 AbstractDocument.java
--- javax/swing/text/AbstractDocument.java	13 May 2006 23:11:13 -0000	1.57
+++ javax/swing/text/AbstractDocument.java	21 Jun 2006 17:02:57 -0000
@@ -1667,22 +1667,29 @@
 
   /**
    * An implementation of [EMAIL PROTECTED] Element} to represent composite
    * <code>Element</code>s that contain other <code>Element</code>s.
    */
   public class BranchElement extends AbstractElement
   {
     /** The serialization UID (compatible with JDK1.5). */
     private static final long serialVersionUID = -6037216547466333183L;
 
-    /** The child elements of this BranchElement. */
-    private Element[] children = new Element[0];
+    /**
+     * The child elements of this BranchElement.
+     */
+    private Element[] children;;
+
+    /**
+     * The number of children in the branch element.
+     */
+    private int numChildren;
 
     /**
      * The cached startOffset value. This is used in the case when a
      * BranchElement (temporarily) has no child elements.
      */
     private int startOffset;
 
     /**
      * The cached endOffset value. This is used in the case when a
      * BranchElement (temporarily) has no child elements.
@@ -1693,38 +1700,40 @@
      * Creates a new <code>BranchElement</code> with the specified
      * parent and attributes.
      *
      * @param parent the parent element of this <code>BranchElement</code>
      * @param attributes the attributes to set on this
      *        <code>BranchElement</code>
      */
     public BranchElement(Element parent, AttributeSet attributes)
     {
       super(parent, attributes);
+      children = new Element[1];
+      numChildren = 0;
       startOffset = -1;
       endOffset = -1;
     }
 
     /**
      * Returns the children of this <code>BranchElement</code>.
      *
      * @return the children of this <code>BranchElement</code>
      */
     public Enumeration children()
     {
       if (children.length == 0)
         return null;
 
       Vector tmp = new Vector();
 
-      for (int index = 0; index < children.length; ++index)
-	tmp.add(children[index]);
+      for (int index = 0; index < numChildren; ++index)
+        tmp.add(children[index]);
       
       return tmp.elements();
     }
 
     /**
      * Returns <code>true</code> since <code>BranchElements</code> allow
      * child elements.
      *
      * @return <code>true</code> since <code>BranchElements</code> allow
      *         child elements
@@ -1736,55 +1745,55 @@
 
     /**
      * Returns the child element at the specified <code>index</code>.
      *
      * @param index the index of the requested child element
      *
      * @return the requested element
      */
     public Element getElement(int index)
     {
-      if (index < 0 || index >= children.length)
-	return null;
+      if (index < 0 || index >= numChildren)
+        return null;
 
       return children[index];
     }
 
     /**
      * Returns the number of child elements of this element.
      *
      * @return the number of child elements of this element
      */
     public int getElementCount()
     {
-      return children.length;
+      return numChildren;
     }
 
     /**
      * Returns the index of the child element that spans the specified
      * offset in the document model.
      *
      * @param offset the offset for which the responsible element is searched
      *
      * @return the index of the child element that spans the specified
      *         offset in the document model
      */
     public int getElementIndex(int offset)
     {
       // If offset is less than the start offset of our first child,
       // return 0
       if (offset < getStartOffset())
         return 0;
 
       // XXX: There is surely a better algorithm
       // as beginning from first element each time.
-      for (int index = 0; index < children.length - 1; ++index)
+      for (int index = 0; index < numChildren - 1; ++index)
         {
           Element elem = children[index];
 
           if ((elem.getStartOffset() <= offset)
                && (offset < elem.getEndOffset()))
             return index;
           // If the next element's start offset is greater than offset
           // then we have to return the closest Element, since no Elements
           // will contain the offset
           if (children[index + 1].getStartOffset() > offset)
@@ -1807,27 +1816,27 @@
      * This is the end offset of the last child element. If this element
      * has no children, this method throws a <code>NullPointerException</code>.
      *
      * @return the offset inside the document model that is after the last
      *         character of this element
      *
      * @throws NullPointerException if this branch element has no children
      */
     public int getEndOffset()
     {
-      if (children.length == 0)
+      if (numChildren == 0)
         {
           if (endOffset == -1)
             throw new NullPointerException("BranchElement has no children.");
         }
       else
-        endOffset = children[children.length - 1].getEndOffset();
+        endOffset = children[numChildren - 1].getEndOffset();
 
       return endOffset;
     }
 
     /**
      * Returns the name of this element. This is [EMAIL PROTECTED] #ParagraphElementName}
      * in this case.
      *
      * @return the name of this element
      */
@@ -1841,21 +1850,21 @@
      * This is the start offset of the first child element. If this element
      * has no children, this method throws a <code>NullPointerException</code>.
      *
      * @return the start offset of this element inside the document model
      *
      * @throws NullPointerException if this branch element has no children and
      *         no startOffset value has been cached
      */
     public int getStartOffset()
     {
-      if (children.length == 0)
+      if (numChildren == 0)
         {
           if (startOffset == -1)
             throw new NullPointerException("BranchElement has no children.");
         }
       else
         startOffset = children[0].getStartOffset();
 
       return startOffset;
     }
 
@@ -1877,49 +1886,62 @@
      *
      * @return the <code>Element</code> at the specified <code>Document</code>
      *         offset
      *
      * @see #getElementIndex(int)
      */
     public Element positionToElement(int position)
     {
       // XXX: There is surely a better algorithm
       // as beginning from first element each time.
-      for (int index = 0; index < children.length; ++index)
+      for (int index = 0; index < numChildren; ++index)
         {
 	  Element elem = children[index];
 
 	  if ((elem.getStartOffset() <= position)
 	      && (position < elem.getEndOffset()))
 	    return elem;
         }
 
       return null;
     }
 
     /**
      * Replaces a set of child elements with a new set of child elemens.
      *
      * @param offset the start index of the elements to be removed
      * @param length the number of elements to be removed
      * @param elements the new elements to be inserted
      */
     public void replace(int offset, int length, Element[] elements)
     {
-      Element[] target = new Element[children.length - length
-				     + elements.length];
-      System.arraycopy(children, 0, target, 0, offset);
-      System.arraycopy(elements, 0, target, offset, elements.length);
-      System.arraycopy(children, offset + length, target,
-		       offset + elements.length,
-		       children.length - offset - length);
-      children = target;
+      if (numChildren + elements.length - length > children.length)
+        {
+          // Gotta grow the array.
+          int newSize = Math.max(2 * children.length,
+                                 numChildren + elements.length - length);
+          Element[] target = new Element[newSize];
+          System.arraycopy(children, 0, target, 0, offset);
+          System.arraycopy(elements, 0, target, offset, elements.length);
+          System.arraycopy(children, offset + length, target,
+                           offset + elements.length,
+                           numChildren - offset - length);
+          children = target;
+        }
+      else
+        {
+          System.arraycopy(children, offset + length, children,
+                           offset + elements.length,
+                           numChildren - offset - length);
+          System.arraycopy(elements, 0, children, offset, elements.length);
+        }
+      numChildren += elements.length - length;
     }
 
     /**
      * Returns a string representation of this element.
      *
      * @return a string representation of this element
      */
     public String toString()
     {
       return ("BranchElement(" + getName() + ") "
@@ -2158,65 +2180,46 @@
      * Manages the start offset of this element.
      */
     private Position startPos;
 
     /**
      * Manages the end offset of this element.
      */
     private Position endPos;
 
     /**
-     * This gets possible added to the startOffset when a startOffset
-     * outside the document range is requested.
-     */
-    private int startDelta;
-
-    /**
-     * This gets possible added to the endOffset when a endOffset
-     * outside the document range is requested.
-     */
-    private int endDelta;
-    
-    /**
      * Creates a new <code>LeafElement</code>.
      *
      * @param parent the parent of this <code>LeafElement</code>
      * @param attributes the attributes to be set
      * @param start the start index of this element inside the document model
      * @param end the end index of this element inside the document model
      */
     public LeafElement(Element parent, AttributeSet attributes, int start,
                        int end)
     {
       super(parent, attributes);
-      int len = content.length();
-      startDelta = 0;
-      if (start > len)
-        startDelta = start - len;
-      endDelta = 0;
-      if (end > len)
-        endDelta = end - len;
       try
-	    {
-		  startPos = createPosition(start - startDelta);
-		  endPos = createPosition(end - endDelta);
-		}
-	  catch (BadLocationException ex)
-	    {
-	      AssertionError as;
-	      as = new AssertionError("BadLocationException thrown "
-				      + "here. start=" + start
-				      + ", end=" + end
-				      + ", length=" + getLength());
-	      as.initCause(ex);
-	      throw as;
-	    }
+        {
+          startPos = createPosition(start);
+          endPos = createPosition(end);
+        }
+      catch (BadLocationException ex)
+        {
+          AssertionError as;
+          as = new AssertionError("BadLocationException thrown "
+                                  + "here. start=" + start
+                                  + ", end=" + end
+                                  + ", length=" + getLength());
+          as.initCause(ex);
+          throw as;
+        }
     }
 
     /**
      * Returns <code>null</code> since <code>LeafElement</code>s cannot have
      * children.
      *
      * @return <code>null</code> since <code>LeafElement</code>s cannot have
      *         children
      */
     public Enumeration children()
@@ -2274,21 +2277,21 @@
 
     /**
      * Returns the end offset of this <code>Element</code> inside the
      * document.
      *
      * @return the end offset of this <code>Element</code> inside the
      *         document
      */
     public int getEndOffset()
     {
-      return endPos.getOffset() + endDelta;
+      return endPos.getOffset();
     }
 
     /**
      * Returns the name of this <code>Element</code>. This is
      * [EMAIL PROTECTED] #ContentElementName} in this case.
      *
      * @return the name of this <code>Element</code>
      */
     public String getName()
     {
@@ -2300,21 +2303,21 @@
 
     /**
      * Returns the start offset of this <code>Element</code> inside the
      * document.
      *
      * @return the start offset of this <code>Element</code> inside the
      *         document
      */
     public int getStartOffset()
     {
-      return startPos.getOffset() + startDelta;
+      return startPos.getOffset();
     }
 
     /**
      * Returns <code>true</code>.
      *
      * @return <code>true</code>
      */
     public boolean isLeaf()
     {
       return true;
Index: javax/swing/text/JTextComponent.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/JTextComponent.java,v
retrieving revision 1.59
diff -u -1 -0 -r1.59 JTextComponent.java
--- javax/swing/text/JTextComponent.java	20 Jun 2006 18:24:14 -0000	1.59
+++ javax/swing/text/JTextComponent.java	21 Jun 2006 17:02:58 -0000
@@ -35,20 +35,21 @@
 obligated to do so.  If you do not wish to do so, delete this
 exception statement from your version. */
 
 
 package javax.swing.text;
 
 import gnu.classpath.NotImplementedException;
 
 import java.awt.AWTEvent;
 import java.awt.Color;
+import java.awt.Container;
 import java.awt.Dimension;
 import java.awt.Insets;
 import java.awt.Point;
 import java.awt.Rectangle;
 import java.awt.datatransfer.Clipboard;
 import java.awt.datatransfer.DataFlavor;
 import java.awt.datatransfer.StringSelection;
 import java.awt.datatransfer.Transferable;
 import java.awt.datatransfer.UnsupportedFlavorException;
 import java.awt.event.ActionEvent;
@@ -1172,22 +1173,33 @@
     setFocusable(true);
     setEditable(true);
     enableEvents(AWTEvent.KEY_EVENT_MASK);
     setOpaque(true);
     updateUI();
   }
 
   public void setDocument(Document newDoc)
   {
     Document oldDoc = doc;
-    doc = newDoc;
-    firePropertyChange("document", oldDoc, newDoc);
+    try
+      {
+        if (oldDoc instanceof AbstractDocument)
+          ((AbstractDocument) oldDoc).readLock();
+
+        doc = newDoc;
+        firePropertyChange("document", oldDoc, newDoc);
+      }
+    finally
+      {
+        if (oldDoc instanceof AbstractDocument)
+          ((AbstractDocument) oldDoc).readUnlock();
+      }
     revalidate();
     repaint();
   }
 
   public Document getDocument()
   {
     return doc;
   }
 
   /**
@@ -1650,24 +1662,26 @@
   public boolean getScrollableTracksViewportHeight()
   {
     if (getParent() instanceof JViewport)
       return getParent().getHeight() > getPreferredSize().height;
 
     return false;
   }
 
   public boolean getScrollableTracksViewportWidth()
   {
-    if (getParent() instanceof JViewport)
-      return getParent().getWidth() > getPreferredSize().width;
+    boolean res = false;;
+    Container c = getParent();
+    if (c instanceof JViewport)
+      res = ((JViewport) c).getExtentSize().width > getPreferredSize().width;
 
-    return false;
+    return res;
   }
 
   /**
    * Adds a <code>CaretListener</code> object to this text component.
    *
    * @param listener the listener to add
    */
   public void addCaretListener(CaretListener listener)
   {
     listenerList.add(CaretListener.class, listener);
Index: javax/swing/text/PlainDocument.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/PlainDocument.java,v
retrieving revision 1.21
diff -u -1 -0 -r1.21 PlainDocument.java
--- javax/swing/text/PlainDocument.java	6 Mar 2006 10:51:19 -0000	1.21
+++ javax/swing/text/PlainDocument.java	21 Jun 2006 17:02:58 -0000
@@ -98,24 +98,24 @@
         lines = new Element[1];
         lines[0] = createLeafElement(rootElement, SimpleAttributeSet.EMPTY, 0, 1);
       }
 
     ((BranchElement) rootElement).replace(0, rootElement.getElementCount(), lines);
   }
 
   protected AbstractDocument.AbstractElement createDefaultRoot()
   {
     BranchElement root =
-      (BranchElement) createBranchElement(null, SimpleAttributeSet.EMPTY);
+      (BranchElement) createBranchElement(null, null);
 
     Element[] array = new Element[1];
-    array[0] = createLeafElement(root, SimpleAttributeSet.EMPTY, 0, 1);
+    array[0] = createLeafElement(root, null, 0, 1);
     root.replace(0, 0, array);
     
     return root;
   }
 
   protected void insertUpdate(DefaultDocumentEvent event,
                               AttributeSet attributes)
   {
     int offset = event.getOffset();
     int eventLength = event.getLength();
Index: javax/swing/text/rtf/RTFParser.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/rtf/RTFParser.java,v
retrieving revision 1.3
diff -u -1 -0 -r1.3 RTFParser.java
--- javax/swing/text/rtf/RTFParser.java	2 Jul 2005 20:32:51 -0000	1.3
+++ javax/swing/text/rtf/RTFParser.java	21 Jun 2006 17:02:58 -0000
@@ -133,23 +133,31 @@
   private void parseFile()
     throws IOException, BadLocationException
   {
     Token t1 = scanner.readToken();
     if (t1.type != Token.LCURLY)
       throw new RTFParseException("expected left curly braces");
 
     parseHeader();
     parseDocument();
   
-    Token t2 = scanner.readToken();
-    if (t2.type != Token.RCURLY)
-      throw new RTFParseException("expected right curly braces");
+    Token t2 = scanner.peekToken();
+    if (t2.type == Token.RCURLY)
+      {
+        // Eat the token.
+        scanner.readToken();
+      }
+    else
+      {
+        // Ignore this for maximum robustness when file is broken.
+        System.err.println("RTF warning: expected right curly braces");
+      }
 
   }
 
   /**
    * The parse rules for &lt;header&gt;.
    *
    * TODO: implement this properly
    */
   private void parseHeader()
   //throws IOException, BadLocationException
Index: javax/swing/text/rtf/RTFScanner.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/rtf/RTFScanner.java,v
retrieving revision 1.3
diff -u -1 -0 -r1.3 RTFScanner.java
--- javax/swing/text/rtf/RTFScanner.java	2 Jul 2005 20:32:51 -0000	1.3
+++ javax/swing/text/rtf/RTFScanner.java	21 Jun 2006 17:02:58 -0000
@@ -64,20 +64,25 @@
    * The reader from which we read the RTF data.
    */
   private Reader in;
 
   /**
    * This is used to constuct strings from the read in chars.
    */
   private StringBuffer buffer;
 
   /**
+   * Lookahead token.
+   */
+  private Token lastToken;
+
+  /**
    * Constructs a new RTFScanner without initializing the [EMAIL PROTECTED] Reader}.
    */
   private RTFScanner()
   {
     buffer = new StringBuffer();
   }
 
   /**
    * Constructs a new RTFScanner for the given [EMAIL PROTECTED] InputStream}.
    * The stream is wrapped into an [EMAIL PROTECTED] InputStreamReader} and if it's
@@ -113,21 +118,21 @@
       }
   }
 
   /**
    * Reads in the next [EMAIL PROTECTED] Token} from the stream.
    *
    * @return the read [EMAIL PROTECTED] Token}
    *
    * @throws IOException if the underlying stream has problems
    */
-  public Token readToken()
+  private Token readTokenImpl()
     throws IOException
   {
     Token token = null;
 
     int c = in.read();
     switch(c)
       {
       case -1:
         token = new Token(Token.EOF);
         break;
@@ -149,20 +154,41 @@
       default:
         buffer.delete(0, buffer.length());
         buffer.append((char) c);
         token = readText();
         break;
       }
 
     return token;
   }
 
+  Token peekToken()
+    throws IOException
+  {
+    lastToken = readTokenImpl();
+    return lastToken;
+  }
+
+  Token readToken()
+    throws IOException
+  {
+    Token token;
+    if (lastToken != null)
+      {
+        token = lastToken;
+        lastToken = null;
+      }
+    else
+      token = readTokenImpl();
+    return token;
+  }
+
   /**
    * Reads in a control word and optional parameter.
    *
    * @return the read in control word as [EMAIL PROTECTED] ControlWordToken}
    *
    * @throws IOException if the underlying stream has problems
    */
   private Token readControlWord()
     throws IOException
   {

Attachment: signature.asc
Description: Dies ist ein digital signierter Nachrichtenteil

Reply via email to