classpath-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[cp-patches] FYI: StyledText stuff, part 2


From: Roman Kennke
Subject: [cp-patches] FYI: StyledText stuff, part 2
Date: Fri, 29 Jul 2005 12:51:44 +0200
User-agent: Mozilla Thunderbird 1.0.2 (X11/20050317)

Here comes part two of the big patch. This fixes and implements some more things in javax.swing.text. Most notably this adds an implementation of the Position interface to the GapContent, which can track a mark within a document even if the actual content changes.

2005-07-29  Roman Kennke  <address@hidden>

        * javax/swing/text/AbstractDocument.java
        (createPosition): Delegate this call to the actual Content.
        (LeafElement.constructor): Manage the start and end marks via
        Position objects.
        (LeafElement.getEndOffset): Use Position instead of static mark.
        (LeafElement.getStartOffset): Use Position instead of static mark.
        * javax/swing/text/DefaultStyledDocument.java
        (ElementBuffer.change): New method. Performs structural changes
        in the element tree that are necessary in order to change
        text attributes.
        (ElementBuffer.changeUpdate): New method. This is the method for
        change().
        (ElementBuffer.split): New package-private method. Splits an
        element into two elements.
        (setCharacterAttributes): Implemented this method. This sets
        character attributes on a piece of content.
        * javax/swing/text/GapContent.java
        (GapContentPosition): New inner class. Implements the Position
        interface for GapContent.
(constructor): Initialize the list that stores the Position objects.
        (createPosition): Reimplemented. Now uses the GapContentPosition
        class.
        (shiftEnd): Update the stored positions.
        (shiftGap): Update the stored positions.
        * javax/swing/text/LabelView.java: New class.
        * javax/swing/text/PlainDocument.java
        (removeUpdate): Don't update the element positions, this should
        now be handled by the Positions.

/Roman
Index: javax/swing/text/AbstractDocument.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/AbstractDocument.java,v
retrieving revision 1.19
diff -u -r1.19 AbstractDocument.java
--- javax/swing/text/AbstractDocument.java      2 Jul 2005 20:32:51 -0000       
1.19
+++ javax/swing/text/AbstractDocument.java      29 Jul 2005 10:41:29 -0000
@@ -108,16 +108,7 @@
 
   public Position createPosition(final int offset) throws BadLocationException
   {
-    if (offset < 0 || offset > getLength())
-      throw new BadLocationException(getText(0, getLength()), offset);
-
-    return new Position()
-      {
-       public int getOffset()
-       {
-         return offset;
-       }
-      };
+    return content.createPosition(offset);
   }
 
   protected void fireChangedUpdate(DocumentEvent event)
@@ -847,15 +838,28 @@
   public class LeafElement extends AbstractElement
   {
     private static final long serialVersionUID = 5115368706941283802L;
-    int start;
-    int end;
+
+    /** Manages the start offset of this element. */
+    Position startPos;
+
+    /** Manages the end offset of this element. */
+    Position endPos;
 
     public LeafElement(Element parent, AttributeSet attributes, int start,
                        int end)
     {
       super(parent, attributes);
-      this.start = start;
-      this.end = end;
+      try
+       {
+         startPos = parent.getDocument().createPosition(start);
+         endPos = parent.getDocument().createPosition(end);
+       }
+      catch (BadLocationException ex)
+       {
+         throw new AssertionError("BadLocationException must not be thrown "
+                                  + "here. start=" + start + ", end=" + end
+                                  + ", length=" + getLength());
+       }
     }
 
     public Enumeration children()
@@ -885,7 +889,7 @@
 
     public int getEndOffset()
     {
-      return end;
+      return endPos.getOffset();
     }
 
     public String getName()
@@ -895,7 +899,7 @@
 
     public int getStartOffset()
     {
-      return start;
+      return startPos.getOffset();
     }
 
     public boolean isLeaf()
Index: javax/swing/text/DefaultStyledDocument.java
===================================================================
RCS file: 
/cvsroot/classpath/classpath/javax/swing/text/DefaultStyledDocument.java,v
retrieving revision 1.3
diff -u -r1.3 DefaultStyledDocument.java
--- javax/swing/text/DefaultStyledDocument.java 2 Jul 2005 20:32:51 -0000       
1.3
+++ javax/swing/text/DefaultStyledDocument.java 29 Jul 2005 10:41:29 -0000
@@ -42,6 +42,8 @@
 import java.awt.Font;
 import java.io.Serializable;
 
+import javax.swing.event.DocumentEvent;
+
 /**
  * @author Michael Koch (address@hidden)
  */
@@ -52,7 +54,13 @@
     implements Serializable
   {
     private Element root;
-    
+
+    /** Holds the offset for structural changes. */
+    private int offset;
+
+    /** Holds the length of structural changes. */
+    private int length;
+
     public ElementBuffer(Element root)
     {
       this.root = root;
@@ -62,6 +70,82 @@
     {
       return root;
     }
+
+    /**
+     * Modifies the element structure so that the specified interval starts
+     * and ends at an element boundary. Content and paragraph elements
+     * are split and created as necessary.
+     *
+     * This also updates the <code>DefaultDocumentEvent</code> to reflect the
+     * structural changes.
+     *
+     * The bulk work is delegated to address@hidden #changeUpdate()}.
+     *
+     * @param offset the start index of the interval to be changed
+     * @param length the length of the interval to be changed
+     * @param ev the <code>DefaultDocumentEvent</code> describing the change
+     */
+    public void change(int offset, int length, DefaultDocumentEvent ev)
+    {
+      this.offset = offset;
+      this.length = length;
+      changeUpdate();
+    }
+
+    /**
+     * Performs the actual work for address@hidden #change}.
+     * The elements at the interval boundaries are split up (if necessary)
+     * so that the interval boundaries are located at element boundaries.
+     */
+    protected void changeUpdate()
+    {
+      // Split up the element at the start offset if necessary.
+      Element el = getCharacterElement(offset);
+      split(el, offset);
+
+      int endOffset = offset + length;
+      el = getCharacterElement(endOffset);
+      split(el, endOffset);
+    }
+
+    /**
+     * Splits an element if <code>offset</code> is not alread at its boundary.
+     *
+     * @param el the Element to possibly split
+     * @param offset the offset at which to possibly split
+     */
+    void split(Element el, int offset)
+    {
+      if (el instanceof AbstractElement)
+       {
+         AbstractElement ael = (AbstractElement) el;
+         int startOffset = ael.getStartOffset();
+         int endOffset = ael.getEndOffset();
+         int len = endOffset - startOffset;
+         if (startOffset != offset && endOffset != offset)
+           {
+             Element paragraph = ael.getParentElement();
+             if (paragraph instanceof BranchElement)
+               {
+                 BranchElement par = (BranchElement) paragraph;
+                 Element child1 = createLeafElement(par, ael, startOffset,
+                                                    offset);
+                 Element child2 = createLeafElement(par, ael, offset,
+                                                    endOffset);
+                 int index = par.getElementIndex(startOffset);
+                 par.replace(index, 1, new Element[]{ child1, child2 });
+               }
+           }
+         else
+           throw new AssertionError("paragraph elements are expected to be "
+                                    + "instances of "
+                         + "javax.swing.text.AbstractDocument.BranchElement");
+       }
+      else
+       throw new AssertionError("content elements are expected to be "
+                                + "instances of "
+                       + "javax.swing.text.AbstractDocument.AbstractElement");
+    }
   }
   
   public static final int BUFFER_SIZE_DEFAULT = 4096;
@@ -175,8 +259,48 @@
                                     AttributeSet attributes,
                                     boolean replace)
   {
-    // FIXME: Implement me.
-    throw new Error("not implemented");
+    DefaultDocumentEvent ev =
+      new DefaultDocumentEvent(offset, length,
+                              DocumentEvent.EventType.CHANGE);
+
+    // Modify the element structure so that the interval begins at an element
+    // start and ends at an element end.
+    buffer.change(offset, length, ev);
+
+    Element root = getDefaultRootElement();
+    // Visit all paragraph elements within the specified interval
+    int paragraphCount =  root.getElementCount();
+    for (int pindex = 0; pindex < paragraphCount; pindex++)
+      {
+       Element paragraph = root.getElement(pindex);
+       // Skip paragraphs that lie outside the interval.
+       if ((paragraph.getStartOffset() > offset + length)
+           || (paragraph.getEndOffset() < offset))
+         continue;
+
+       // Visit content elements within this paragraph
+       int contentCount = paragraph.getElementCount();
+       for (int cindex = 0; cindex < contentCount; cindex++)
+         {
+           Element content = paragraph.getElement(cindex);
+           // Skip content that lies outside the interval.
+           if ((content.getStartOffset() > offset + length)
+               || (content.getEndOffset() < offset))
+             continue;
+
+           if (content instanceof AbstractElement)
+             {
+               AbstractElement el = (AbstractElement) content;
+               if (replace)
+                 el.removeAttributes(el);
+               el.addAttributes(attributes);
+             }
+           else
+             throw new AssertionError("content elements are expected to be"
+                                      + "instances of "
+                      + "javax.swing.text.AbstractDocument.AbstractElement");
+         }
+      }
   }
   
   public void setLogicalStyle(int position, Style style)
Index: javax/swing/text/GapContent.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/GapContent.java,v
retrieving revision 1.13
diff -u -r1.13 GapContent.java
--- javax/swing/text/GapContent.java    21 Jul 2005 15:05:45 -0000      1.13
+++ javax/swing/text/GapContent.java    29 Jul 2005 10:41:29 -0000
@@ -39,6 +39,9 @@
 package javax.swing.text;
 
 import java.io.Serializable;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.ListIterator;
 
 import javax.swing.undo.UndoableEdit;
 
@@ -57,6 +60,67 @@
 public class GapContent
   implements AbstractDocument.Content, Serializable
 {
+
+  /**
+   * A address@hidden Position} implementation for <code>GapContent</code>.
+   */
+  class GapContentPosition implements Position, Comparable
+  {
+
+    /** The index within the buffer array. */
+    int mark;
+
+    /**
+     * Creates a new GapContentPosition object.
+     *
+     * @param mark the mark of this Position
+     */
+    GapContentPosition(int mark)
+    {
+      this.mark = mark;
+    }
+
+    /**
+     * Comparable interface implementation. This is used to store all
+     * positions in an ordered fashion.
+     *
+     * @param o the object to be compared to this
+     *
+     * @return a negative integer if this is less than <code>o</code>, zero
+     *         if both are equal or a positive integer if this is greater
+     *         than <code>o</code>
+     *
+     * @throws ClassCastException if <code>o</code> is not a GapContentPosition
+     *         or Integer object
+     */
+    public int compareTo(Object o)
+    {
+      if (o instanceof Integer)
+       {
+         int otherMark = ((Integer) o).intValue();
+         return mark - otherMark;
+       }
+      else
+       {
+         GapContentPosition other = (GapContentPosition) o;
+         return mark - other.mark;
+       }
+    }
+
+    /**
+     * Returns the current offset of this Position within the content.
+     *
+     * @return the current offset of this Position within the content.
+     */
+    public int getOffset()
+    {
+      if (mark < gapStart)
+       return mark;
+      else
+       return mark - (gapEnd - gapStart);
+    }
+  }
+    
   private static final long serialVersionUID = 8374645204155842629L;
 
   /**
@@ -81,6 +145,12 @@
   int gapEnd;
 
   /**
+   * The positions generated by this GapContent. They are kept in an
+   * ordered fashion, so they can be looked up easily.
+   */
+  LinkedList positions;
+
+  /**
    * Creates a new GapContent object.
    */
   public GapContent()
@@ -99,6 +169,7 @@
     gapStart = 0;
     gapEnd = size - 1;
     buffer[size - 1] = '\n';
+    positions = new LinkedList();
   }
 
   /**
@@ -288,15 +359,24 @@
    */
   public Position createPosition(final int offset) throws BadLocationException
   {
-    return new Position()
-      {
-       int off = offset;
-
-       public int getOffset()
-       {
-         return off;
-       }
-      };
+    if (offset < 0 || offset > length())
+      throw new BadLocationException("The offset was out of the bounds of this"
+                                    + " buffer", offset);
+
+    // We store the actual array index in the GapContentPosition. The real
+    // offset is then calculated in the GapContentPosition.
+    int mark = offset;
+    if (offset > gapStart)
+      mark += gapEnd - gapStart;
+    GapContentPosition pos = new GapContentPosition(mark);
+
+    // Add this into our list in a sorted fashion.
+    int index = Collections.binarySearch(positions, pos);
+    if (index < 0)
+      index = -(index + 1);
+    positions.add(index, pos);
+    
+    return pos;
   }
 
   /**
@@ -309,12 +389,25 @@
    */
   protected void shiftEnd(int newSize)
   {
+    int delta = (gapEnd - gapStart) - newSize;
     char[] newBuf = (char[]) allocateArray(length() + newSize);
     System.arraycopy(buffer, 0, newBuf, 0, gapStart);
     System.arraycopy(buffer, gapEnd, newBuf, gapStart + newSize,
                      buffer.length - gapEnd);
     gapEnd = gapStart + newSize;
     buffer = newBuf;
+
+    // Update the marks after the gapEnd.
+    int index = Collections.binarySearch(positions, new Integer(gapEnd));
+    if (index < 0)
+      {
+       index = -(index + 1);
+      }
+    for (ListIterator i = positions.listIterator(index); i.hasNext();)
+      {
+       GapContentPosition p = (GapContentPosition) i.next();
+       p.mark += delta;
+      }
   }
 
   /**
@@ -325,6 +418,22 @@
   protected void shiftGap(int newGapStart)
   {
     int newGapEnd = newGapStart + (gapEnd - gapStart);
+
+
+    // Update the positions between newGapEnd and (old) gapEnd. The marks
+    // must be shifted by (gapEnd - newGapEnd).
+    int index1 = Collections.binarySearch(positions, new Integer(gapEnd));
+    int index2 = Collections.binarySearch(positions, new Integer(newGapEnd));
+    int i1 = Math.min(index1, index2);
+    int i2 = Math.max(index1, index2);
+    for (ListIterator i = positions.listIterator(i1); i.hasNext();)
+      {
+       if (i.nextIndex() > i2)
+         break;
+
+       GapContentPosition p = (GapContentPosition) i.next();
+       p.mark += gapEnd - newGapEnd;
+      }
 
     if (newGapStart == gapStart)
       return;
Index: javax/swing/text/LabelView.java
===================================================================
RCS file: javax/swing/text/LabelView.java
diff -N javax/swing/text/LabelView.java
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ javax/swing/text/LabelView.java     29 Jul 2005 10:41:29 -0000
@@ -0,0 +1,54 @@
+/* LabelView.java -- A view to render styled text
+   Copyright (C) 2005  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.text;
+
+// TODO: Implement this class.
+public class LabelView
+  extends GlyphView
+{
+  /**
+   * Creates a new <code>GlyphView</code> for the given <code>Element</code>.
+   *
+   * @param element the element that is rendered by this GlyphView
+   */
+  public LabelView(Element element)
+  {
+    super(element);
+  }
+}
Index: javax/swing/text/PlainDocument.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/PlainDocument.java,v
retrieving revision 1.12
diff -u -r1.12 PlainDocument.java
--- javax/swing/text/PlainDocument.java 2 Jul 2005 20:32:51 -0000       1.12
+++ javax/swing/text/PlainDocument.java 29 Jul 2005 10:41:29 -0000
@@ -135,22 +135,6 @@
                                           start, end - len);
         rootElement.replace(i1, i2 - i1, new Element[]{ newEl });
       }
-    else
-      {
-        // otherwise only adjust indices of the element
-        LeafElement el1 = (LeafElement) rootElement.getElement(i1);
-        el1.end -= len;
-      }
-
-    // reindex remaining elements
-    for (int i = rootElement.getElementIndex(p0) + 1;
-         i < rootElement.getElementCount(); i++)
-      {
-        LeafElement el = (LeafElement) rootElement.getElement(i);
-        el.start -= len;
-        el.end -= len;
-      }
-      
   }
 
   public Element getDefaultRootElement()

reply via email to

[Prev in Thread] Current Thread [Next in Thread]