From 8f523f3a1047919d3563daf1ef47ba87336ebe89 Mon Sep 17 00:00:00 2001
From: Mark Wielaard <mark@gcc.gnu.org>
Date: Tue, 15 Nov 2005 23:20:01 +0000
Subject: Imported GNU Classpath 0.19 + gcj-import-20051115.

       * sources.am: Regenerated.
       * Makefile.in: Likewise.
       * scripts/makemake.tcl: Use glob -nocomplain.

From-SVN: r107049
---
 .../javax/swing/text/AbstractDocument.java         |  326 +++++--
 .../classpath/javax/swing/text/AttributeSet.java   |    6 +-
 libjava/classpath/javax/swing/text/BoxView.java    |  256 ++---
 .../classpath/javax/swing/text/ComponentView.java  |  200 ++--
 .../classpath/javax/swing/text/CompositeView.java  |   66 +-
 .../classpath/javax/swing/text/DefaultCaret.java   |  409 +++++++-
 .../javax/swing/text/DefaultEditorKit.java         |   45 +-
 .../javax/swing/text/DefaultFormatter.java         |   15 +-
 .../javax/swing/text/DefaultHighlighter.java       |    2 +
 .../javax/swing/text/DefaultStyledDocument.java    | 1032 ++++++++++++++++++--
 .../classpath/javax/swing/text/DefaultTextUI.java  |   61 ++
 libjava/classpath/javax/swing/text/EditorKit.java  |   10 +-
 libjava/classpath/javax/swing/text/FieldView.java  |   17 +-
 libjava/classpath/javax/swing/text/FlowView.java   |   70 +-
 libjava/classpath/javax/swing/text/GapContent.java |  382 ++++++--
 libjava/classpath/javax/swing/text/GlyphView.java  |  652 ++++++++++++-
 libjava/classpath/javax/swing/text/IconView.java   |   32 +
 .../javax/swing/text/InternationalFormatter.java   |    5 +-
 .../classpath/javax/swing/text/JTextComponent.java |  211 ++--
 libjava/classpath/javax/swing/text/LabelView.java  |  242 ++++-
 .../classpath/javax/swing/text/LayoutQueue.java    |    1 +
 .../classpath/javax/swing/text/ParagraphView.java  |   30 +
 .../classpath/javax/swing/text/PlainDocument.java  |   28 +-
 libjava/classpath/javax/swing/text/PlainView.java  |  371 ++++++-
 libjava/classpath/javax/swing/text/Segment.java    |    4 +-
 .../javax/swing/text/SimpleAttributeSet.java       |   57 +-
 .../classpath/javax/swing/text/StringContent.java  |    3 +
 .../classpath/javax/swing/text/StyleConstants.java |    6 +-
 .../classpath/javax/swing/text/StyleContext.java   |   19 +-
 .../classpath/javax/swing/text/StyledDocument.java |  191 ++--
 .../javax/swing/text/StyledEditorKit.java          |   24 +-
 libjava/classpath/javax/swing/text/TabSet.java     |    3 +
 libjava/classpath/javax/swing/text/TabStop.java    |    3 +
 libjava/classpath/javax/swing/text/Utilities.java  |  410 ++++++++
 libjava/classpath/javax/swing/text/View.java       |   76 +-
 .../javax/swing/text/WrappedPlainView.java         |  700 +++++++++++++
 libjava/classpath/javax/swing/text/html/CSS.java   |  461 +++++++++
 libjava/classpath/javax/swing/text/html/HTML.java  |   13 +-
 .../javax/swing/text/html/HTMLDocument.java        |  215 ++++
 .../javax/swing/text/html/HTMLEditorKit.java       |   38 +-
 .../swing/text/html/HTMLFrameHyperlinkEvent.java   |    4 +-
 .../javax/swing/text/html/parser/ContentModel.java |    5 +-
 .../javax/swing/text/html/parser/DTD.java          |    6 +-
 .../swing/text/html/parser/DocumentParser.java     |    7 +
 .../javax/swing/text/html/parser/Element.java      |    2 +-
 .../javax/swing/text/html/parser/Parser.java       |   10 +
 46 files changed, 5911 insertions(+), 815 deletions(-)
 create mode 100644 libjava/classpath/javax/swing/text/DefaultTextUI.java
 create mode 100644 libjava/classpath/javax/swing/text/WrappedPlainView.java
 create mode 100644 libjava/classpath/javax/swing/text/html/CSS.java

(limited to 'libjava/classpath/javax/swing/text')

diff --git a/libjava/classpath/javax/swing/text/AbstractDocument.java b/libjava/classpath/javax/swing/text/AbstractDocument.java
index 3c9a4d4..baf8608 100644
--- a/libjava/classpath/javax/swing/text/AbstractDocument.java
+++ b/libjava/classpath/javax/swing/text/AbstractDocument.java
@@ -65,11 +65,10 @@ import javax.swing.undo.UndoableEdit;
  * @author original author unknown
  * @author Roman Kennke (roman@kennke.org)
  */
-public abstract class AbstractDocument
-  implements Document, Serializable
+public abstract class AbstractDocument implements Document, Serializable
 {
-  /** The serial version UID for this class as of JDK1.4. */
-  private static final long serialVersionUID = -116069779446114664L;
+  /** The serialization UID (compatible with JDK1.5). */
+  private static final long serialVersionUID = 6842927725919637215L;
 
   /**
    * Standard error message to indicate a bad location.
@@ -128,7 +127,28 @@ public abstract class AbstractDocument
    * Manages event listeners for this <code>Document</code>.
    */
   protected EventListenerList listenerList = new EventListenerList();
+  
+  /**
+   * Stores the current writer thread.  Used for locking.
+   */ 
+  private Thread currentWriter = null;
+  
+  /**
+   * The number of readers.  Used for locking.
+   */
+  private int numReaders = 0;
+  
+  /**
+   * Tells if there are one or more writers waiting.
+   */
+  private int numWritersWaiting = 0;  
+
+  /**
+   * A condition variable that readers and writers wait on.
+   */
+  Object documentCV = new Object();
 
+  
   /**
    * Creates a new <code>AbstractDocument</code> with the specified
    * {@link Content} model.
@@ -332,7 +352,7 @@ public abstract class AbstractDocument
    * @see GapContent
    * @see StringContent
    */
-  protected Content getContent()
+  protected final Content getContent()
   {
     return content;
   }
@@ -348,8 +368,7 @@ public abstract class AbstractDocument
    */
   protected Thread getCurrentWriter()
   {
-    // FIXME: Implement locking!
-    return null;
+    return currentWriter;
   }
 
   /**
@@ -516,13 +535,18 @@ public abstract class AbstractDocument
     // Just return when no text to insert was given.
     if (text == null || text.length() == 0)
       return;
-    
     DefaultDocumentEvent event =
       new DefaultDocumentEvent(offset, text.length(),
 			       DocumentEvent.EventType.INSERT);
-    content.insertString(offset, text);
+    
+    writeLock();
+    UndoableEdit undo = content.insertString(offset, text);
     insertUpdate(event, attributes);
+    writeUnlock();
+
     fireInsertUpdate(event);
+    if (undo != null)
+      fireUndoableEditUpdate(new UndoableEditEvent(this, undo));
   }
 
   /**
@@ -566,10 +590,28 @@ public abstract class AbstractDocument
   }
 
   /**
-   * Blocks until a read lock can be obtained.
+   * Blocks until a read lock can be obtained.  Must block if there is
+   * currently a writer modifying the <code>Document</code>.
    */
   public void readLock()
   {
+    if (currentWriter != null && currentWriter.equals(Thread.currentThread()))
+      return;
+    synchronized (documentCV)
+      {
+        while (currentWriter != null || numWritersWaiting > 0)
+          {
+            try
+              {
+                documentCV.wait();
+              }
+            catch (InterruptedException ie)
+              {
+                throw new Error("interrupted trying to get a readLock");
+              }
+          }
+          numReaders++;
+      }
   }
 
   /**
@@ -578,6 +620,40 @@ public abstract class AbstractDocument
    */
   public void readUnlock()
   {
+    // Note we could have a problem here if readUnlock was called without a
+    // prior call to readLock but the specs simply warn users to ensure that
+    // balance by using a finally block:
+    // readLock()
+    // try
+    // { 
+    //   doSomethingHere 
+    // }
+    // finally
+    // {
+    //   readUnlock();
+    // }
+    
+    // All that the JDK seems to check for is that you don't call unlock
+    // more times than you've previously called lock, but it doesn't make
+    // sure that the threads calling unlock were the same ones that called lock
+
+    // FIXME: the reference implementation throws a 
+    // javax.swing.text.StateInvariantError here
+    if (numReaders == 0)
+      throw new IllegalStateException("document lock failure");
+    
+    synchronized (documentCV)
+    {
+      // If currentWriter is not null, the application code probably had a 
+      // writeLock and then tried to obtain a readLock, in which case 
+      // numReaders wasn't incremented
+      if (currentWriter == null)
+        {
+          numReaders --;
+          if (numReaders == 0 && numWritersWaiting != 0)
+            documentCV.notify();
+        }
+    }
   }
 
   /**
@@ -595,10 +671,42 @@ public abstract class AbstractDocument
     DefaultDocumentEvent event =
       new DefaultDocumentEvent(offset, length,
 			       DocumentEvent.EventType.REMOVE);
+    
+    // Here we set up the parameters for an ElementChange, if one
+    // needs to be added to the DocumentEvent later
+    Element root = getDefaultRootElement();
+    int start = root.getElementIndex(offset);
+    int end = root.getElementIndex(offset + length);
+    
+    Element[] removed = new Element[end - start + 1];
+    for (int i = start; i <= end; i++)
+      removed[i - start] = root.getElement(i);
+    
     removeUpdate(event);
-    content.remove(offset, length);
+
+    Element[] added = new Element[1];
+    added[0] = root.getElement(start);
+    boolean shouldFire = content.getString(offset, length).length() != 0;
+    
+    writeLock();
+    UndoableEdit temp = content.remove(offset, length);
+    writeUnlock();
+    
     postRemoveUpdate(event);
-    fireRemoveUpdate(event);
+    
+    GapContent.UndoRemove changes = null;
+    if (content instanceof GapContent)
+      changes = (GapContent.UndoRemove) temp;
+
+    if (changes != null && !(start == end))
+      {
+        // We need to add an ElementChange to our DocumentEvent
+        ElementEdit edit = new ElementEdit (root, start, removed, added);
+        event.addEdit(edit);
+      }
+    
+    if (shouldFire)
+      fireRemoveUpdate(event);
   }
 
   /**
@@ -713,7 +821,15 @@ public abstract class AbstractDocument
    */
   public void render(Runnable runnable)
   {
-    // FIXME: Implement me!
+    readLock();
+    try
+    {
+      runnable.run();
+    }
+    finally
+    {
+      readUnlock();
+    }
   }
 
   /**
@@ -725,6 +841,7 @@ public abstract class AbstractDocument
    */
   public void setAsynchronousLoadPriority(int p)
   {
+    // TODO: Implement this properly.
   }
 
   /**
@@ -739,11 +856,30 @@ public abstract class AbstractDocument
   }
 
   /**
-   * Blocks until a write lock can be obtained.
+   * Blocks until a write lock can be obtained.  Must wait if there are 
+   * readers currently reading or another thread is currently writing.
    */
   protected void writeLock()
   {
-    // FIXME: Implement me.
+    if (currentWriter!= null && currentWriter.equals(Thread.currentThread()))
+      return;
+    synchronized (documentCV)
+      {
+        numWritersWaiting++;
+        while (numReaders > 0)
+          {
+            try
+              {
+                documentCV.wait();
+              }
+            catch (InterruptedException ie)
+              {
+                throw new Error("interruped while trying to obtain write lock");
+              }
+          }
+        numWritersWaiting --;
+        currentWriter = Thread.currentThread();
+      }
   }
 
   /**
@@ -752,7 +888,14 @@ public abstract class AbstractDocument
    */
   protected void writeUnlock()
   {
-    // FIXME: Implement me.
+    synchronized (documentCV)
+    {
+        if (Thread.currentThread().equals(currentWriter))
+          {
+            currentWriter = null;
+            documentCV.notifyAll();
+          }
+    }
   }
 
   /**
@@ -970,8 +1113,8 @@ public abstract class AbstractDocument
   public abstract class AbstractElement
     implements Element, MutableAttributeSet, TreeNode, Serializable
   {
-    /** The serial version UID for AbstractElement. */
-    private static final long serialVersionUID = 1265312733007397733L;
+    /** The serialization UID (compatible with JDK1.5). */
+    private static final long serialVersionUID = 1712240033321461704L;
 
     /** The number of characters that this Element spans. */
     int count;
@@ -1231,6 +1374,9 @@ public abstract class AbstractDocument
 
     /**
      * Returns the resolve parent of this element.
+     * This is taken from the AttributeSet, but if this is null,
+     * this method instead returns the Element's parent's 
+     * AttributeSet
      *
      * @return the resolve parent of this element
      *
@@ -1238,7 +1384,9 @@ public abstract class AbstractDocument
      */
     public AttributeSet getResolveParent()
     {
-      return attributes.getResolveParent();
+      if (attributes.getResolveParent() != null)
+        return attributes.getResolveParent();
+      return element_parent.getAttributes();
     }
 
     /**
@@ -1355,49 +1503,6 @@ public abstract class AbstractDocument
     public abstract int getStartOffset();
 
     /**
-     * Prints diagnostic information to the specified stream.
-     *
-     * @param stream the stream to dump to
-     * @param indent the indentation level
-     * @param element the element to be dumped
-     */
-    private void dumpElement(PrintStream stream, String indent,
-                             Element element)
-    {
-      // FIXME: Should the method be removed?
-      System.out.println(indent + "<" + element.getName() +">");
-
-      if (element.isLeaf())
-	{
-	  int start = element.getStartOffset();
-	  int end = element.getEndOffset();
-	  String text = "";
-	  try
-	    {
-	      text = getContent().getString(start, end - start);
-	    }
-	  catch (BadLocationException e)
-	    {
-          AssertionError error =
-            new AssertionError("BadLocationException should not be "
-                               + "thrown here. start = " + start
-                               + ", end = " + end);
-          error.initCause(e);
-          throw error;
-	    }
-	  System.out.println(indent + "  ["
-			     + start + ","
-			     + end + "]["
-			     + text + "]");
-	}
-      else
-	{
-	  for (int i = 0; i < element.getElementCount(); ++i)
-	    dumpElement(stream, indent + "  ", element.getElement(i));
-	}
-    }
-
-    /**
      * Prints diagnostic output to the specified stream.
      *
      * @param stream the stream to write to
@@ -1405,10 +1510,66 @@ public abstract class AbstractDocument
      */
     public void dump(PrintStream stream, int indent)
     {
-      String indentStr = "";
+      StringBuffer b = new StringBuffer();
       for (int i = 0; i < indent; ++i)
-	indentStr += "  ";
-      dumpElement(stream, indentStr, this);
+        b.append(' ');
+      b.append('<');
+      b.append(getName());
+      // Dump attributes if there are any.
+      if (getAttributeCount() > 0)
+        {
+          b.append('\n');
+          Enumeration attNames = getAttributeNames();
+          while (attNames.hasMoreElements())
+            {
+              for (int i = 0; i < indent + 2; ++i)
+                b.append(' ');
+              Object attName = attNames.nextElement();
+              b.append(attName);
+              b.append('=');
+              Object attribute = getAttribute(attName);
+              b.append(attribute);
+              b.append('\n');
+            }
+        }
+      b.append(">\n");
+
+      // Dump element content for leaf elements.
+      if (isLeaf())
+        {
+          for (int i = 0; i < indent + 2; ++i)
+            b.append(' ');
+          int start = getStartOffset();
+          int end = getEndOffset();
+          b.append('[');
+          b.append(start);
+          b.append(',');
+          b.append(end);
+          b.append("][");
+          try
+            {
+              b.append(getDocument().getText(start, end - start));
+            }
+          catch (BadLocationException ex)
+            {
+              AssertionError err = new AssertionError("BadLocationException "
+                                                      + "must not be thrown "
+                                                      + "here.");
+              err.initCause(ex);
+	      throw err;
+            }
+          b.append("]\n");
+        }
+      stream.print(b.toString());
+
+      // Dump child elements if any.
+      int count = getElementCount();
+      for (int i = 0; i < count; ++i)
+        {
+          Element el = getElement(i);
+          if (el instanceof AbstractElement)
+            ((AbstractElement) el).dump(stream, indent + 2);
+        }
     }
   }
 
@@ -1418,8 +1579,8 @@ public abstract class AbstractDocument
    */
   public class BranchElement extends AbstractElement
   {
-    /** The serial version UID for BranchElement. */
-    private static final long serialVersionUID = -8595176318868717313L;
+    /** 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];
@@ -1503,19 +1664,30 @@ public abstract class AbstractDocument
      */
     public int getElementIndex(int offset)
     {
-      // If we have no children, return -1.
-      if (getElementCount() == 0)
-        return - 1;
-
+      // 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; ++index)
+      for (int index = 0; index < children.length - 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)
+            {
+              if ((offset - elem.getEndOffset()) > (children[index + 1].getStartOffset() - offset))
+                return index + 1;
+              else
+                return index;
+            }
         }
 
       // If offset is greater than the index of the last element, return
@@ -1642,8 +1814,8 @@ public abstract class AbstractDocument
   public class DefaultDocumentEvent extends CompoundEdit
     implements DocumentEvent
   {
-    /** The serial version UID of DefaultDocumentEvent. */
-    private static final long serialVersionUID = -7406103236022413522L;
+    /** The serialization UID (compatible with JDK1.5). */
+    private static final long serialVersionUID = 5230037221564563284L;
 
     /** The starting offset of the change. */
     private int offset;
@@ -1748,7 +1920,7 @@ public abstract class AbstractDocument
       return (DocumentEvent.ElementChange) changes.get(elem);
     }
   }
-
+  
   /**
    * An implementation of {@link DocumentEvent.ElementChange} to be added
    * to {@link DefaultDocumentEvent}s.
@@ -1843,8 +2015,8 @@ public abstract class AbstractDocument
    */
   public class LeafElement extends AbstractElement
   {
-    /** The serial version UID of LeafElement. */
-    private static final long serialVersionUID = 5115368706941283802L;
+    /** The serialization UID (compatible with JDK1.5). */
+    private static final long serialVersionUID = -8906306331347768017L;
 
     /** Manages the start offset of this element. */
     Position startPos;
diff --git a/libjava/classpath/javax/swing/text/AttributeSet.java b/libjava/classpath/javax/swing/text/AttributeSet.java
index 2f1f189..01d148c 100644
--- a/libjava/classpath/javax/swing/text/AttributeSet.java
+++ b/libjava/classpath/javax/swing/text/AttributeSet.java
@@ -58,6 +58,7 @@ public interface AttributeSet
    */
   static interface CharacterAttribute
   {
+    // This interface is a marker interface and has no methods.
   }
 
   /**
@@ -65,6 +66,7 @@ public interface AttributeSet
    */
   static interface ColorAttribute
   {
+    // This interface is a marker interface and has no methods.
   }
 
   /**
@@ -72,6 +74,7 @@ public interface AttributeSet
    */
   static interface FontAttribute
   {
+    // This interface is a marker interface and has no methods.
   }
 
   /**
@@ -79,6 +82,7 @@ public interface AttributeSet
    */
   static interface ParagraphAttribute
   {
+    // This interface is a marker interface and has no methods.
   }
 
   /**
@@ -99,7 +103,7 @@ public interface AttributeSet
    * <code>false</code> otherwise.
    *
    * @param name the name of the requested attribute
-   * @param the value of the requested attribute
+   * @param value the value of the requested attribute
    *
    * @return <code>true</code> if this <code>AttributeSet</code> contains
    *         an attribute with the specified <code>name</code> and
diff --git a/libjava/classpath/javax/swing/text/BoxView.java b/libjava/classpath/javax/swing/text/BoxView.java
index 0f8ba1c..f201045 100644
--- a/libjava/classpath/javax/swing/text/BoxView.java
+++ b/libjava/classpath/javax/swing/text/BoxView.java
@@ -155,8 +155,9 @@ public class BoxView
    * automatically when any of the child view changes its preferences
    * via {@link #preferenceChanged(View, boolean, boolean)}.
    *
-   * The layout will be updated the next time when {@link #setSize()} is
-   * called, typically from within the {@link #paint()} method.
+   * The layout will be updated the next time when 
+   * {@link #setSize(float, float)} is called, typically from within the 
+   * {@link #paint(Graphics, Shape)} method.
    *
    * Valid values for the axis are {@link View#X_AXIS} and
    * {@link View#Y_AXIS}.
@@ -216,12 +217,11 @@ public class BoxView
    * @param alloc the allocated region for the child to paint into
    * @param index the index of the child to be painted
    *
-   * @see {@link #childAllocation}
+   * @see #childAllocation(int, Rectangle)
    */
   protected void paintChild(Graphics g, Rectangle alloc, int index)
   {
     View child = getView(index);
-    childAllocation(index, alloc);
     child.paint(g, alloc);
   }
 
@@ -301,18 +301,15 @@ public class BoxView
       setSize(bounds.width, bounds.height);
 
     Rectangle inside = getInsideAllocation(a);
-
     Rectangle copy = new Rectangle(inside);
     int count = getViewCount();
     for (int i = 0; i < count; ++i)
       {
-        // TODO: Figure out if the parameter to paintChild is meant to
-        // be the child allocation or the allocation of this BoxView.
-        // I assume the second option here.
-        // We pass this method a copy of the inside rectangle here because
-        // it modifies the actual values.
         copy.setBounds(inside);
-        paintChild(g, copy, i);
+        childAllocation(i, copy);
+        if (!copy.isEmpty()
+            && g.hitClip(copy.x, copy.y, copy.width, copy.height))
+          paintChild(g, copy, i);
       }
   }
 
@@ -362,6 +359,24 @@ public class BoxView
   }
 
   /**
+   * Calculates the layout of the children of this <code>BoxView</code> along
+   * the specified axis.
+   *
+   * @param span the target span
+   * @param axis the axis that is examined
+   * @param offsets an empty array, filled with the offsets of the children
+   * @param spans an empty array, filled with the spans of the children
+   */
+  protected void baselineLayout(int span, int axis, int[] offsets,
+                                int[] spans)
+  {
+    if (axis == myAxis)
+      layoutMajorAxis(span, axis, offsets, spans);
+    else
+      layoutMinorAxis(span, axis, offsets, spans);
+  }
+
+  /**
    * Calculates the size requirements of this <code>BoxView</code> along
    * its major axis, that is the axis specified in the constructor.
    *
@@ -375,27 +390,8 @@ public class BoxView
   protected SizeRequirements calculateMajorAxisRequirements(int axis,
                                                            SizeRequirements sr)
   {
-    if (sr == null)
-      sr = new SizeRequirements();
-    else
-      {
-        sr.maximum = 0;
-        sr.minimum = 0;
-        sr.preferred = 0;
-        sr.alignment = 0.5F;
-      }
-
-    int count = getViewCount();
-
-    // Sum up the sizes of the children along the specified axis.
-    for (int i = 0; i < count; ++i)
-      {
-        View child = getView(i);
-        sr.minimum += child.getMinimumSpan(axis);
-        sr.preferred += child.getPreferredSpan(axis);
-        sr.maximum += child.getMaximumSpan(axis);
-      }
-    return sr;
+    SizeRequirements[] childReqs = getChildRequirements(axis);
+    return SizeRequirements.getTiledSizeRequirements(childReqs);
   }
 
   /**
@@ -413,48 +409,8 @@ public class BoxView
   protected SizeRequirements calculateMinorAxisRequirements(int axis,
                                                            SizeRequirements sr)
   {
-    if (sr == null)
-      sr = new SizeRequirements();
-    else
-      {
-        sr.maximum = 0;
-        sr.minimum = 0;
-        sr.preferred = 0;
-        sr.alignment = 0.5F;
-      }
-
-    int count = getViewCount();
-
-    int aboveBaseline = 0;
-    int belowBaseline = 0;
-    int aboveBaselineMin = 0;
-    int belowBaselineMin = 0;
-    int aboveBaselineMax = 0;
-    int belowBaselineMax = 0;
-    
-    for (int i = 0; i < count; ++i)
-      {
-        View child = getView(i);
-        float align = child.getAlignment(axis);
-        int pref = (int) child.getPreferredSpan(axis);
-        int min = (int) child.getMinimumSpan(axis);
-        int max = (int) child.getMaximumSpan(axis);
-        aboveBaseline += (int) (align * pref);
-        belowBaseline += (int) ((1.F - align) * pref);
-        aboveBaselineMin += (int) (align * min);
-        belowBaselineMin += (int) ((1.F - align) * min);
-        aboveBaselineMax += (int) (align * max);
-        belowBaselineMax += (int) ((1.F - align) * max);
-      }
-    sr.minimum = aboveBaselineMin + belowBaselineMin;
-    sr.maximum = aboveBaselineMax + belowBaselineMax;
-    sr.preferred = aboveBaseline + belowBaseline;
-    if (aboveBaseline == 0)
-      sr.alignment = 1.0F;
-    else
-      sr.alignment = (float) (sr.preferred / aboveBaseline);
-
-    return sr;
+    SizeRequirements[] childReqs = getChildRequirements(axis);
+    return SizeRequirements.getAlignedSizeRequirements(childReqs);
   }
 
   /**
@@ -569,19 +525,8 @@ public class BoxView
    */
   protected void layout(int width, int height)
   {
-    this.width = width;
-    this.height = height;
-
-    if (myAxis == X_AXIS)
-      {
-        layoutMajorAxis(width, X_AXIS, offsetsX, spansX);
-        layoutMinorAxis(height, Y_AXIS, offsetsY, spansY);
-      }
-    else
-      {
-        layoutMajorAxis(height, Y_AXIS, offsetsY, spansY);
-        layoutMinorAxis(width, X_AXIS, offsetsX, spansX);
-      }
+    baselineLayout(width, X_AXIS, offsetsX, spansX);
+    baselineLayout(height, Y_AXIS, offsetsY, spansY);
   }
 
   /**
@@ -591,28 +536,16 @@ public class BoxView
    *        to layout the children
    * @param axis the axis along which the layout is performed
    * @param offsets the array that holds the offsets of the children on exit
-   * @param offsets the array that holds the spans of the children on exit
+   * @param spans the array that holds the spans of the children on exit
    */
   protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets,
                                  int[] spans)
   {
-    // Allocate SizeRequirements for each child view.
-    int count = getViewCount();
-    SizeRequirements[] childReqs = new SizeRequirements[count];
-    for (int i = 0; i < count; ++i)
-      {
-        View view = getView(i);
-        childReqs[i] = new SizeRequirements((int) view.getMinimumSpan(axis),
-                                            (int) view.getPreferredSpan(axis),
-                                            (int) view.getMaximumSpan(axis),
-                                            view.getAlignment(axis));
-      }
-
+    SizeRequirements[] childReqs = getChildRequirements(axis);
     // Calculate the spans and offsets using the SizeRequirements uility
     // methods.
     SizeRequirements.calculateTiledPositions(targetSpan, null, childReqs,
                                              offsets, spans);
-
     validateLayout(axis);
   }
 
@@ -623,26 +556,21 @@ public class BoxView
    *        to layout the children
    * @param axis the axis along which the layout is performed
    * @param offsets the array that holds the offsets of the children on exit
-   * @param offsets the array that holds the spans of the children on exit
+   * @param spans the array that holds the spans of the children on exit
    */
   protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets,
                                  int[] spans)
   {
-    // Allocate SizeRequirements for each child view.
-    int count = getViewCount();
-    SizeRequirements[] childReqs = new SizeRequirements[count];
-    for (int i = 0; i < count; ++i)
-      {
-        View view = getView(i);
-        childReqs[i] = new SizeRequirements((int) view.getMinimumSpan(axis),
-                                            (int) view.getPreferredSpan(axis),
-                                            (int) view.getMaximumSpan(axis),
-                                            view.getAlignment(axis));
-      }
-
+    SizeRequirements[] childReqs = getChildRequirements(axis);
     // Calculate the spans and offsets using the SizeRequirements uility
     // methods.
-    SizeRequirements.calculateAlignedPositions(targetSpan, null, childReqs,
+    // TODO: This might be an opportunity for performance optimization. Here
+    // we could use a cached instance of SizeRequirements instead of passing
+    // null to baselineRequirements. However, this would involve rewriting
+    // the baselineRequirements() method to not use the SizeRequirements
+    // utility method, since they cannot reuse a cached instance.
+    SizeRequirements total = baselineRequirements(axis, null);
+    SizeRequirements.calculateAlignedPositions(targetSpan, total, childReqs,
                                                offsets, spans);
     validateLayout(axis);
   }
@@ -692,6 +620,9 @@ public class BoxView
       layoutChanged(X_AXIS);
     if (this.height != (int) height)
       layoutChanged(Y_AXIS);
+    
+    this.width = (int) width;
+    this.height = (int) height;
 
     Rectangle outside = new Rectangle(0, 0, this.width, this.height);
     Rectangle inside = getInsideAllocation(outside);
@@ -711,4 +642,99 @@ public class BoxView
     if (axis == Y_AXIS)
       yLayoutValid = true;
   }
+
+  /**
+   * Returns the size requirements of this view's children for the major
+   * axis.
+   *
+   * @return the size requirements of this view's children for the major
+   *         axis
+   */
+  SizeRequirements[] getChildRequirements(int axis)
+  {
+    // Allocate SizeRequirements for each child view.
+    int count = getViewCount();
+    SizeRequirements[] childReqs = new SizeRequirements[count];
+    for (int i = 0; i < count; ++i)
+      {
+        View view = getView(i);
+        childReqs[i] = new SizeRequirements((int) view.getMinimumSpan(axis),
+                                            (int) view.getPreferredSpan(axis),
+                                            (int) view.getMaximumSpan(axis),
+                                            view.getAlignment(axis));
+      }
+    return childReqs;
+  }
+
+  /**
+   * Returns the span for the child view with the given index for the specified
+   * axis.
+   *
+   * @param axis the axis to examine, either <code>X_AXIS</code> or
+   *        <code>Y_AXIS</code>
+   * @param childIndex the index of the child for for which to return the span
+   *
+   * @return the span for the child view with the given index for the specified
+   *         axis
+   */
+  protected int getSpan(int axis, int childIndex)
+  {
+    if (axis == X_AXIS)
+      return spansX[childIndex];
+    else
+      return spansY[childIndex];
+  }
+
+  /**
+   * Returns the offset for the child view with the given index for the
+   * specified axis.
+   *
+   * @param axis the axis to examine, either <code>X_AXIS</code> or
+   *        <code>Y_AXIS</code>
+   * @param childIndex the index of the child for for which to return the span
+   *
+   * @return the offset for the child view with the given index for the
+   *         specified axis
+   */
+  protected int getOffset(int axis, int childIndex)
+  {
+    if (axis == X_AXIS)
+      return offsetsX[childIndex];
+    else
+      return offsetsY[childIndex];
+  }
+
+  /**
+   * Returns the alignment for this box view for the specified axis. The
+   * axis that is tiled (the major axis) will be requested to be aligned
+   * centered (0.5F). The minor axis alignment depends on the child view's
+   * total alignment.
+   *
+   * @param axis the axis which is examined
+   *
+   * @return the alignment for this box view for the specified axis
+   */
+  public float getAlignment(int axis)
+  {
+    if (axis == myAxis)
+      return 0.5F;
+    else
+      return baselineRequirements(axis, null).alignment;
+  }
+  
+  /**
+   * Called by a child View when its preferred span has changed.
+   * 
+   * @param width indicates that the preferred width of the child changed.
+   * @param height indicates that the preferred height of the child changed.
+   * @param child the child View. 
+   */
+  public void preferenceChanged (View child, boolean width, boolean height)
+  {
+    if (width)
+      xLayoutValid = false;
+    if (height)
+      yLayoutValid = false;
+    super.preferenceChanged(child, width, height);
+  }
 }
diff --git a/libjava/classpath/javax/swing/text/ComponentView.java b/libjava/classpath/javax/swing/text/ComponentView.java
index f6feda2..16112c8 100644
--- a/libjava/classpath/javax/swing/text/ComponentView.java
+++ b/libjava/classpath/javax/swing/text/ComponentView.java
@@ -1,5 +1,5 @@
 /* ComponentView.java -- 
-   Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+   Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -41,65 +41,125 @@ import java.awt.Component;
 import java.awt.Graphics;
 import java.awt.Shape;
 
+import javax.swing.SwingConstants;
+
+/**
+ * A {@link View} implementation that is able to render arbitrary
+ * {@link Component}s. This uses the attribute
+ * {@link StyleConstants#ComponentAttribute} to determine the
+ * <code>Component</code> that should be rendered. This <code>Component</code>
+ * becomes a direct child of the <code>JTextComponent</code> that contains
+ * this <code>ComponentView</code>, so this view must not be shared between
+ * multiple <code>JTextComponent</code>s.
+ *
+ * @author original author unknown
+ * @author Roman Kennke (roman@kennke.org)
+ */
+// FIXME: This class is a complete stub and needs to be implemented properly.
 public class ComponentView extends View
 {
-    public ComponentView(Element elem)
-    {
-	super(elem);
-    }
- 
-    protected  Component createComponent()
-    {
-	return null;
-    }
-    
-    public float getAlignment(int axis)
-    {
-	return 0;
-    }
-
-    public final Component getComponent()
-    {
-	return null;
-    }
-    
-    public float getMaximumSpan(int axis)
-    {
-	return 0;
-    }
-
-    public float getMinimumSpan(int axis)
-    {
-	return 0;
-    }
-
-    public float getPreferredSpan(int axis)
-    {
-	return 0;
-    }
-
-    public Shape modelToView(int pos, Shape a, Position.Bias b)
-      throws BadLocationException
-    {
-	return null;
-    }
-    
-    public void paint(Graphics g, Shape a)
-    {
-    }
+  /**
+   * Creates a new instance of <code>ComponentView</code> for the specified
+   * <code>Element</code>.
+   *
+   * @param elem the element that this <code>View</code> is rendering
+   */
+  public ComponentView(Element elem)
+  {
+    super(elem);
+  }
+
+  /**
+   * Creates the <code>Component</code> that this <code>View</code> is
+   * rendering. The <code>Component</code> is determined using
+   * the {@link StyleConstants#ComponentAttribute} of the associated
+   * <code>Element</code>.
+   *
+   * @return the component that is rendered
+   */
+  protected  Component createComponent()
+  {
+    return StyleConstants.getComponent(getElement().getAttributes());
+  }
+
+  /**
+   * Returns the alignment of this <code>View</code> along the specified axis.
+   *
+   * @param axis either {@link View#X_AXIS} or {@link View#Y_AXIS}
+   *
+   * @return the alignment of this <code>View</code> along the specified axis
+   */
+  public float getAlignment(int axis)
+  {
+    return 0;
+  }
+
+  /**
+   * Returns the <code>Component</code> that is rendered by this
+   * <code>ComponentView</code>.
+   *
+   * @return the <code>Component</code> that is rendered by this
+   *         <code>ComponentView</code>
+   */
+  public final Component getComponent()
+  {
+    return null;
+  }
+
+  /**
+   * Returns the maximum span of this <code>View</code> along the specified
+   * axis.
+   *
+   * This will return {@link Component#getMaximumSize()} for the specified
+   * axis.
+   *
+   * @return the maximum span of this <code>View</code> along the specified
+   *         axis
+   */
+  public float getMaximumSpan(int axis)
+  {
+    return 0;
+  }
+
+  public float getMinimumSpan(int axis)
+  {
+    // TODO: Implement this properly.
+    return 0;
+  }
+
+  public float getPreferredSpan(int axis)
+  {
+    // TODO: Implement this properly.
+    return 0;
+  }
+
+  public Shape modelToView(int pos, Shape a, Position.Bias b)
+    throws BadLocationException
+  {
+    // TODO: Implement this properly.
+    return null;
+  }
     
-    public void setParent(View p)
-    {
-    }
+  public void paint(Graphics g, Shape a)
+  {
+    // TODO: Implement this properly.
+  }
+  
+  public void setParent(View p)
+  {
+    // TODO: Implement this properly.
+  }
     
-    public void setSize(float width, float height)
-    {
-    }
+  public void setSize(float width, float height)
+  {
+    // TODO: Implement this properly.
+  }
     
-    public int viewToModel(float x, float y, Shape a, Position.Bias[] bias)
-    {
-	return 0;
-    }
+  public int viewToModel(float x, float y, Shape a, Position.Bias[] bias)
+  {
+    // TODO: Implement this properly.
+    return 0;
+  }
 
   /**
    * Maps coordinates from the <code>View</code>'s space into a position
@@ -118,4 +178,34 @@ public class ComponentView extends View
     // FIXME: Implement this properly.
     return 0;
   }
+
+  /**
+   * Returns the document position that is (visually) nearest to the given
+   * document position <code>pos</code> in the given direction <code>d</code>.
+   *
+   * @param c the text component
+   * @param pos the document position
+   * @param b the bias for <code>pos</code>
+   * @param d the direction, must be either {@link SwingConstants#NORTH},
+   *        {@link SwingConstants#SOUTH}, {@link SwingConstants#WEST} or
+   *        {@link SwingConstants#EAST}
+   * @param biasRet an array of {@link Position.Bias} that can hold at least
+   *        one element, which is filled with the bias of the return position
+   *        on method exit
+   *
+   * @return the document position that is (visually) nearest to the given
+   *         document position <code>pos</code> in the given direction
+   *         <code>d</code>
+   *
+   * @throws BadLocationException if <code>pos</code> is not a valid offset in
+   *         the document model
+   */
+  public int getNextVisualPositionFrom(JTextComponent c, int pos,
+                                       Position.Bias b, int d,
+                                       Position.Bias[] biasRet)
+    throws BadLocationException
+  {
+    // TODO: Implement this properly.
+    throw new AssertionError("Not implemented yet.");
+  }
 }
diff --git a/libjava/classpath/javax/swing/text/CompositeView.java b/libjava/classpath/javax/swing/text/CompositeView.java
index 6776c95..bc626a4 100644
--- a/libjava/classpath/javax/swing/text/CompositeView.java
+++ b/libjava/classpath/javax/swing/text/CompositeView.java
@@ -62,7 +62,7 @@ public abstract class CompositeView
   /**
    * The allocation of this <code>View</code> minus its insets. This is
    * initialized in {@link #getInsideAllocation} and reused and modified in
-   * {@link childAllocation}.
+   * {@link #childAllocation(int, Rectangle)}.
    */
   Rectangle insideAllocation;
 
@@ -221,20 +221,17 @@ public abstract class CompositeView
     if (childIndex != -1)
       {
         View child = getView(childIndex);
-        Shape result = child.modelToView(pos, a, bias);
+        Rectangle r = a.getBounds();
+        childAllocation(childIndex, r);
+        Shape result = child.modelToView(pos, r, bias);
         if (result == null)
           throw new AssertionError("" + child.getClass().getName()
                                    + ".modelToView() must not return null");
         return result;
       }
     else
-      {
-        // FIXME: Handle the case when we have no child view for the given
-        // position.
-        throw new AssertionError("No child views found where child views are "
-                                 + "expected. pos = " + pos + ", bias = "
-                                 + bias);
-      }
+      throw new BadLocationException("No child view for the specified location",
+                                     pos);
   }
 
   /**
@@ -314,6 +311,7 @@ public abstract class CompositeView
    */
   public int getNextVisualPositionFrom(int pos, Position.Bias b, Shape a,
                                        int direction, Position.Bias[] biasRet)
+    throws BadLocationException
   {
     int retVal = -1;
     switch (direction)
@@ -433,10 +431,16 @@ public abstract class CompositeView
    */
   protected int getViewIndexAtPosition(int pos)
   {
-    // We have one child view allocated for each child element in
-    // loadChildren(), so this should work.
-    Element el = getElement();
-    int index = el.getElementIndex(pos);
+    int index = -1;
+    for (int i = 0; i < children.length; i++)
+      {
+        if (children[i].getStartOffset() <= pos
+            && children[i].getEndOffset() > pos)
+          {
+            index = i;
+            break;
+          }
+      }
     return index;
   }
 
@@ -473,8 +477,8 @@ public abstract class CompositeView
             insideAllocation = inside;
           }
       }
-    inside.x = alloc.x - insets.left;
-    inside.y = alloc.y - insets.top;
+    inside.x = alloc.x + insets.left;
+    inside.y = alloc.y + insets.top;
     inside.width = alloc.width - insets.left - insets.right;
     inside.height = alloc.height - insets.top - insets.bottom;
     return inside;
@@ -594,6 +598,7 @@ public abstract class CompositeView
   protected int getNextNorthSouthVisualPositionFrom(int pos, Position.Bias b,
                                                     Shape a, int direction,
                                                     Position.Bias[] biasRet)
+    throws BadLocationException
   {
     // FIXME: Implement this correctly.
     return pos;
@@ -627,6 +632,7 @@ public abstract class CompositeView
   protected int getNextEastWestVisualPositionFrom(int pos, Position.Bias b,
                                                   Shape a, int direction,
                                                   Position.Bias[] biasRet)
+    throws BadLocationException
   {
     // FIXME: Implement this correctly.
     return pos;
@@ -649,4 +655,34 @@ public abstract class CompositeView
   {
     return false;
   }
+
+  /**
+   * Returns the document position that is (visually) nearest to the given
+   * document position <code>pos</code> in the given direction <code>d</code>.
+   *
+   * @param c the text component
+   * @param pos the document position
+   * @param b the bias for <code>pos</code>
+   * @param d the direction, must be either {@link SwingConstants#NORTH},
+   *        {@link SwingConstants#SOUTH}, {@link SwingConstants#WEST} or
+   *        {@link SwingConstants#EAST}
+   * @param biasRet an array of {@link Position.Bias} that can hold at least
+   *        one element, which is filled with the bias of the return position
+   *        on method exit
+   *
+   * @return the document position that is (visually) nearest to the given
+   *         document position <code>pos</code> in the given direction
+   *         <code>d</code>
+   *
+   * @throws BadLocationException if <code>pos</code> is not a valid offset in
+   *         the document model
+   */
+  public int getNextVisualPositionFrom(JTextComponent c, int pos,
+                                       Position.Bias b, int d,
+                                       Position.Bias[] biasRet)
+    throws BadLocationException
+  {
+    // TODO: Implement this properly.
+    throw new AssertionError("Not implemented yet.");
+  }
 }
diff --git a/libjava/classpath/javax/swing/text/DefaultCaret.java b/libjava/classpath/javax/swing/text/DefaultCaret.java
index 33c3ae3..66e2f47 100644
--- a/libjava/classpath/javax/swing/text/DefaultCaret.java
+++ b/libjava/classpath/javax/swing/text/DefaultCaret.java
@@ -40,15 +40,24 @@ package javax.swing.text;
 import java.awt.Graphics;
 import java.awt.Point;
 import java.awt.Rectangle;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
 import java.awt.event.FocusEvent;
 import java.awt.event.FocusListener;
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseListener;
 import java.awt.event.MouseMotionListener;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
 import java.util.EventListener;
 
+import javax.swing.JComponent;
+import javax.swing.SwingUtilities;
+import javax.swing.Timer;
 import javax.swing.event.ChangeEvent;
 import javax.swing.event.ChangeListener;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
 import javax.swing.event.EventListenerList;
 
 /**
@@ -60,12 +69,164 @@ import javax.swing.event.EventListenerList;
 public class DefaultCaret extends Rectangle
   implements Caret, FocusListener, MouseListener, MouseMotionListener
 {
+
+  /**
+   * Controls the blinking of the caret.
+   *
+   * @author Roman Kennke (kennke@aicas.com)
+   * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+   */
+  private class BlinkTimerListener implements ActionListener
+  {
+    /**
+     * Forces the next event to be ignored. The next event should be ignored
+     * if we force the caret to appear. We do not know how long will it take
+     * to fire the comming event; this may be near immediately. Better to leave
+     * the caret visible one iteration longer.
+     */
+    boolean ignoreNextEvent;
+    
+    /**
+     * Receives notification when the blink timer fires and updates the visible
+     * state of the caret.
+     * 
+     * @param event the action event
+     */
+    public void actionPerformed(ActionEvent event)
+    {
+      if (ignoreNextEvent)
+        ignoreNextEvent = false;
+      else
+        {
+          visible = !visible;
+          repaint();
+        }
+    }
+  }
+
+  /**
+   * Listens for changes in the text component's document and updates the
+   * caret accordingly.
+   * 
+   * @author Roman Kennke (kennke@aicas.com)
+   */
+  private class DocumentHandler implements DocumentListener
+  {
+    /**
+     * Receives notification that some text attributes have changed. No action
+     * is taken here.
+     *
+     * @param event the document event
+     */
+    public void changedUpdate(DocumentEvent event)
+    {
+      // Nothing to do here.
+    }
+
+    /**
+     * Receives notification that some text has been inserted from the text
+     * component. The caret is moved forward accordingly.
+     *
+     * @param event the document event
+     */
+    public void insertUpdate(DocumentEvent event)
+    {
+      if (policy == ALWAYS_UPDATE || 
+          (SwingUtilities.isEventDispatchThread() && 
+           policy == UPDATE_WHEN_ON_EDT))
+        {        
+          int dot = getDot();
+          setDot(dot + event.getLength());
+        }
+    }
+
+    /**
+     * Receives notification that some text has been removed into the text
+     * component. The caret is moved backwards accordingly.
+     *
+     * @param event the document event
+     */
+    public void removeUpdate(DocumentEvent event)
+    {
+      if (policy == ALWAYS_UPDATE || 
+          (SwingUtilities.isEventDispatchThread() && 
+           policy == UPDATE_WHEN_ON_EDT))
+        {
+          int dot = getDot();
+          setDot(dot - event.getLength());
+        }
+      else if (policy == NEVER_UPDATE)
+        {
+          int docLength = event.getDocument().getLength();
+          if (getDot() > docLength)
+            setDot(docLength);
+        }
+    }
+  }
+
+  /**
+   * Listens for property changes on the text document. This is used to add and
+   * remove our document listener, if the document of the text component has
+   * changed.
+   *
+   * @author Roman Kennke (kennke@aicas.com)
+   */
+  private class PropertyChangeHandler implements PropertyChangeListener
+  {
+
+    /**
+     * Receives notification when a property has changed on the text component.
+     * This adds/removes our document listener from the text component's
+     * document when the document changes.
+     *
+     * @param e the property change event
+     */
+    public void propertyChange(PropertyChangeEvent e)
+    {
+      if (e.getPropertyName().equals("document"))
+        {
+          Document oldDoc = (Document) e.getOldValue();
+          oldDoc.removeDocumentListener(documentListener);
+          Document newDoc = (Document) e.getNewValue();
+          newDoc.addDocumentListener(documentListener);
+        }
+    }
+    
+  }
+
+  /** The serialization UID (compatible with JDK1.5). */
+  private static final long serialVersionUID = 4325555698756477346L;
+  
   /**
-   * The serial version UID for DefaultCaret.
+   * Indicates the Caret position should always be updated after Document
+   * changes even if the updates are not performed on the Event Dispatching
+   * thread.
+   * 
+   * @since 1.5
    */
-  private static final long serialVersionUID = 228155774675466193L;
+  public static final int ALWAYS_UPDATE = 2;
 
   /**
+   * Indicates the Caret position should not be changed unless the Document
+   * length becomes less than the Caret position, in which case the Caret
+   * is moved to the end of the Document.
+   * 
+   * @since 1.5
+   */
+  public static final int NEVER_UPDATE = 1;
+  
+  /** 
+   * Indicates the Caret position should be updated only if Document changes
+   * are made on the Event Dispatcher thread.
+   *  
+   * @since 1.5
+   */
+  public static final int UPDATE_WHEN_ON_EDT = 0;
+  
+  /** Keeps track of the current update policy **/
+  int policy = UPDATE_WHEN_ON_EDT;
+    
+  /**
    * The <code>ChangeEvent</code> that is fired by {@link #fireStateChanged()}.
    */
   protected ChangeEvent changeEvent = new ChangeEvent(this);
@@ -76,6 +237,16 @@ public class DefaultCaret extends Rectangle
   protected EventListenerList listenerList = new EventListenerList();
 
   /**
+   * Our document listener.
+   */
+  DocumentListener documentListener;
+
+  /**
+   * Our property listener.
+   */
+  PropertyChangeListener propertyChangeListener;
+
+  /**
    * The text component in which this caret is installed.
    */
   private JTextComponent textComponent;
@@ -106,15 +277,65 @@ public class DefaultCaret extends Rectangle
   private Point magicCaretPosition = null;
 
   /**
-   * Indicates if this <code>Caret</code> is currently visible or not.
+   * Indicates if this <code>Caret</code> is currently visible or not. This is
+   * package private to avoid an accessor method.
    */
-  private boolean visible = true;
+  boolean visible = false;
 
   /**
    * The current highlight entry.
    */
   private Object highlightEntry;
 
+  private Timer blinkTimer;
+  
+  private BlinkTimerListener blinkListener;
+
+  /**
+   * Creates a new <code>DefaultCaret</code> instance.
+   */
+  public DefaultCaret()
+  {
+    // Nothing to do here.
+  }
+
+  /**
+   * Sets the Caret update policy.
+   *    
+   * @param policy the new policy.  Valid values are:
+   * ALWAYS_UPDATE: always update the Caret position, even when Document
+   * updates don't occur on the Event Dispatcher thread.
+   * NEVER_UPDATE: don't update the Caret position unless the Document
+   * length becomes less than the Caret position (then update the
+   * Caret to the end of the Document).
+   * UPDATE_WHEN_ON_EDT: update the Caret position when the 
+   * Document updates occur on the Event Dispatcher thread.  This is the 
+   * default.
+   * 
+   * @since 1.5
+   * @throws IllegalArgumentException if policy is not one of the above.
+   */
+  public void setUpdatePolicy (int policy)
+  {
+    if (policy != ALWAYS_UPDATE && policy != NEVER_UPDATE
+        && policy != UPDATE_WHEN_ON_EDT)
+      throw new 
+        IllegalArgumentException
+        ("policy must be ALWAYS_UPDATE, NEVER__UPDATE, or UPDATE_WHEN_ON_EDT");
+    this.policy = policy;
+  }
+  
+  /**
+   * Gets the caret update policy.
+   * 
+   * @return the caret update policy.
+   * @since 1.5
+   */
+  public int getUpdatePolicy ()
+  {
+    return policy;
+  }
+  
   /**
    * Moves the caret position when the mouse is dragged over the text
    * component, modifying the selection accordingly.
@@ -123,7 +344,7 @@ public class DefaultCaret extends Rectangle
    */
   public void mouseDragged(MouseEvent event)
   {
-    // FIXME: Implement this properly.
+    moveCaret(event);
   }
 
   /**
@@ -153,7 +374,7 @@ public class DefaultCaret extends Rectangle
    */
   public void mouseClicked(MouseEvent event)
   {
-    // FIXME: Implement this properly.
+    // TODO: Implement double- and triple-click behaviour here.
   }
 
   /**
@@ -175,6 +396,7 @@ public class DefaultCaret extends Rectangle
    */
   public void mouseExited(MouseEvent event)
   {
+    // Nothing to do here.
   }
 
   /**
@@ -187,7 +409,7 @@ public class DefaultCaret extends Rectangle
    */
   public void mousePressed(MouseEvent event)
   {
-    // FIXME: Implement this properly.
+    positionCaret(event);
   }
 
   /**
@@ -208,6 +430,7 @@ public class DefaultCaret extends Rectangle
    */
   public void focusGained(FocusEvent event)
   {
+    setVisible(true);
   }
 
   /**
@@ -217,6 +440,8 @@ public class DefaultCaret extends Rectangle
    */
   public void focusLost(FocusEvent event)
   {
+    if (event.isTemporary() == false)
+      setVisible(false);
   }
 
   /**
@@ -227,7 +452,8 @@ public class DefaultCaret extends Rectangle
    */
   protected void moveCaret(MouseEvent event)
   {
-    // FIXME: Implement this properly.
+    int newDot = getComponent().viewToModel(event.getPoint());
+    moveDot(newDot);
   }
 
   /**
@@ -238,7 +464,8 @@ public class DefaultCaret extends Rectangle
    */
   protected void positionCaret(MouseEvent event)
   {
-    // FIXME: Implement this properly.
+    int newDot = getComponent().viewToModel(event.getPoint());
+    setDot(newDot);
   }
 
   /**
@@ -253,7 +480,16 @@ public class DefaultCaret extends Rectangle
     textComponent.removeFocusListener(this);
     textComponent.removeMouseListener(this);
     textComponent.removeMouseMotionListener(this);
+    textComponent.getDocument().removeDocumentListener(documentListener);
+    documentListener = null;
+    textComponent.removePropertyChangeListener(propertyChangeListener);
+    propertyChangeListener = null;
     textComponent = null;
+
+    // Deinstall blink timer if present.
+    if (blinkTimer != null)
+      blinkTimer.stop();
+    blinkTimer = null;
   }
 
   /**
@@ -269,6 +505,11 @@ public class DefaultCaret extends Rectangle
     textComponent.addFocusListener(this);
     textComponent.addMouseListener(this);
     textComponent.addMouseMotionListener(this);
+    propertyChangeListener = new PropertyChangeHandler();
+    textComponent.addPropertyChangeListener(propertyChangeListener);
+    documentListener = new DocumentHandler();
+    textComponent.getDocument().addDocumentListener(documentListener);
+
     repaint();
   }
 
@@ -376,10 +617,7 @@ public class DefaultCaret extends Rectangle
    */
   protected final void repaint()
   {
-    // FIXME: Is this good? This possibly causes alot of the component
-    // hierarchy to be repainted on every caret blink.
-    if (textComponent != null)
-      textComponent.repaint();
+    getComponent().repaint(x, y, width, height);
   }
 
   /**
@@ -390,7 +628,8 @@ public class DefaultCaret extends Rectangle
    */
   public void paint(Graphics g)
   {
-    if (textComponent == null)
+    JTextComponent comp = getComponent();
+    if (comp == null)
       return;
 
     int dot = getDot();
@@ -398,25 +637,33 @@ public class DefaultCaret extends Rectangle
 
     try
       {
-	rect = textComponent.modelToView(dot);
+        rect = textComponent.modelToView(dot);
       }
     catch (BadLocationException e)
       {
-	// This should never happen as dot should be always valid.
-	return;
+        assert false : "Unexpected bad caret location: " + dot;
+        return;
       }
 
     if (rect == null)
       return;
-    
-    // First we need to delete the old caret.
-    // FIXME: Implement deleting of old caret.
-    
+
+    // Check if paint has possibly been called directly, without a previous
+    // call to damage(). In this case we need to do some cleanup first.
+    if ((x != rect.x) || (y != rect.y))
+      {
+        repaint(); // Erase previous location of caret.
+        x = rect.x;
+        y = rect.y;
+        width = 1;
+        height = rect.height;
+      }
+
     // Now draw the caret on the new position if visible.
     if (visible)
       {
-	g.setColor(textComponent.getCaretColor());
-	g.drawLine(rect.x, rect.y, rect.x, rect.y + rect.height);
+        g.setColor(textComponent.getCaretColor());
+        g.drawLine(rect.x, rect.y, rect.x, rect.y + rect.height);
       }
   }
 
@@ -507,6 +754,8 @@ public class DefaultCaret extends Rectangle
    */
   public void setBlinkRate(int rate)
   {
+    if (blinkTimer != null)
+      blinkTimer.setDelay(rate);
     blinkRate = rate;
   }
 
@@ -534,7 +783,8 @@ public class DefaultCaret extends Rectangle
   {
     this.dot = dot;
     handleHighlight();
-    repaint();
+    adjustVisibility(this);
+    appear();
   }
 
   /**
@@ -551,8 +801,45 @@ public class DefaultCaret extends Rectangle
     this.dot = dot;
     this.mark = dot;
     handleHighlight();
-    repaint();
+    adjustVisibility(this);
+    appear();
   }
+  
+  /**
+   * Show the caret (may be hidden due blinking) and adjust the timer not to
+   * hide it (possibly immediately).
+   * 
+   * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+   */
+  void appear()
+  {
+    // All machinery is only required if the carret is blinking.
+    if (blinkListener != null)
+      {
+        blinkListener.ignoreNextEvent = true;
+
+        // If the caret is visible, erase the current position by repainting
+        // over.
+        if (visible)
+          repaint();
+
+        // Draw the caret in the new position.
+        visible = true;
+
+        Rectangle area = null;
+        try
+          {
+            area = getComponent().modelToView(getDot());
+          }
+        catch (BadLocationException ex)
+          {
+            assert false : "Unexpected bad caret location: " + getDot();
+          }
+        if (area != null)
+          damage(area);
+      }
+    repaint();
+  }  
 
   /**
    * Returns <code>true</code> if this <code>Caret</code> is currently visible,
@@ -574,8 +861,33 @@ public class DefaultCaret extends Rectangle
    */  
   public void setVisible(boolean v)
   {
-    visible = v;
-    repaint();
+    if (v != visible)
+      {
+        visible = v;
+        if (visible)
+          if (textComponent.isEnabled() && textComponent.isEditable())
+            {
+              if (blinkTimer == null)
+                initBlinkTimer();
+              blinkTimer.start();
+            }
+        else
+          {
+            if (blinkTimer != null)
+              blinkTimer.stop();
+          }
+        Rectangle area = null;
+        try
+          {
+            area = getComponent().modelToView(getDot());
+          }
+        catch (BadLocationException ex)
+          {
+            assert false: "Unexpected bad caret location: " + getDot();
+          }
+        if (area != null)
+          damage(area);
+      }
   }
 
   /**
@@ -589,4 +901,47 @@ public class DefaultCaret extends Rectangle
   {
     return DefaultHighlighter.DefaultPainter;
   }
+
+  /**
+   * Updates the carets rectangle properties to the specified rectangle and
+   * repaints the caret.
+   *
+   * @param r the rectangle to set as the caret rectangle
+   */
+  protected void damage(Rectangle r)
+  {
+    if (r == null)
+      return;
+    x = r.x;
+    y = r.y;
+    width = 1;
+    // height is normally set in paint and we leave it untouched. However, we
+    // must set a valid value here, since otherwise the painting mechanism
+    // sets a zero clip and never calls paint.
+    if (height <= 0)
+      height = getComponent().getHeight();
+    repaint();
+  }
+
+  /**
+   * Adjusts the text component so that the caret is visible. This default
+   * implementation simply calls
+   * {@link JComponent#scrollRectToVisible(Rectangle)} on the text component.
+   * Subclasses may wish to change this.
+   */
+  protected void adjustVisibility(Rectangle rect)
+  {
+    getComponent().scrollRectToVisible(rect);
+  }
+
+  /**
+   * Initializes the blink timer.
+   */
+  private void initBlinkTimer()
+  {
+    // Setup the blink timer.
+    blinkListener = new BlinkTimerListener();
+    blinkTimer = new Timer(getBlinkRate(), blinkListener);
+    blinkTimer.setRepeats(true);
+  }
 }
diff --git a/libjava/classpath/javax/swing/text/DefaultEditorKit.java b/libjava/classpath/javax/swing/text/DefaultEditorKit.java
index a14f3ff..3b3fc1f 100644
--- a/libjava/classpath/javax/swing/text/DefaultEditorKit.java
+++ b/libjava/classpath/javax/swing/text/DefaultEditorKit.java
@@ -66,8 +66,7 @@ public class DefaultEditorKit extends EditorKit
    *
    * @see Toolkit#beep()
    */
-  public static class BeepAction
-    extends TextAction
+  public static class BeepAction extends TextAction
   {
     /**
      * Creates a new <code>BeepAction</code>.
@@ -95,8 +94,7 @@ public class DefaultEditorKit extends EditorKit
    * @see CutAction
    * @see PasteAction
    */
-  public static class CopyAction 
-    extends TextAction
+  public static class CopyAction extends TextAction
   {
 
     /**
@@ -128,8 +126,7 @@ public class DefaultEditorKit extends EditorKit
    * @see CopyAction
    * @see PasteAction
    */
-  public static class CutAction 
-    extends TextAction
+  public static class CutAction extends TextAction
   {
 
     /**
@@ -159,8 +156,7 @@ public class DefaultEditorKit extends EditorKit
    * @see CopyAction
    * @see CutAction
    */
-  public static class PasteAction 
-    extends TextAction
+  public static class PasteAction extends TextAction
   {
 
     /**
@@ -226,9 +222,6 @@ public class DefaultEditorKit extends EditorKit
             {
               t.getDocument().insertString(t.getCaret().getDot(),
                                            event.getActionCommand(), null);
-              t.getCaret().setDot(Math.min(t.getCaret().getDot() + 1,
-                                           t.getDocument().getEndPosition()
-                                           .getOffset()));
             }
           catch (BadLocationException be)
             {
@@ -243,8 +236,7 @@ public class DefaultEditorKit extends EditorKit
    * of the text component. This is typically triggered by hitting
    * ENTER on the keyboard.
    */
-  public static class InsertBreakAction 
-    extends TextAction
+  public static class InsertBreakAction extends TextAction
   {
 
     /**
@@ -273,8 +265,7 @@ public class DefaultEditorKit extends EditorKit
    */
   // FIXME: Figure out what this Action is supposed to do. Obviously text
   // that is entered by the user is inserted through DefaultKeyTypedAction.
-  public static class InsertContentAction 
-    extends TextAction
+  public static class InsertContentAction extends TextAction
   {
 
     /**
@@ -292,14 +283,15 @@ public class DefaultEditorKit extends EditorKit
      */
     public void actionPerformed(ActionEvent event)
     {
+      // FIXME: Figure out what this Action is supposed to do. Obviously text
+      // that is entered by the user is inserted through DefaultKeyTypedAction.
     }
   }
 
   /**
    * Inserts a TAB character into the text editor.
    */
-  public static class InsertTabAction 
-    extends TextAction
+  public static class InsertTabAction extends TextAction
   {
 
     /**
@@ -699,6 +691,7 @@ public class DefaultEditorKit extends EditorKit
    */
   public DefaultEditorKit()
   {
+    // Nothing to do here.
   }
 
   /**
@@ -954,15 +947,23 @@ public class DefaultEditorKit extends EditorKit
    * @param offset the beginning offset from where to write
    * @param len the length of the fragment to write
    *
-   * @throws BadLocationException if <code>offset</code> or
-   *         <code>offset + len</code>is an invalid location inside
-   *         <code>document</code>
+   * @throws BadLocationException if <code>offset</code> is an 
+   * invalid location inside <code>document</code>.
    * @throws IOException if something goes wrong while writing to
    *        <code>out</code>
    */
   public void write(Writer out, Document document, int offset, int len)
-    throws BadLocationException, IOException
+      throws BadLocationException, IOException
   {
-    // TODO: Implement this properly.
+    // Throw a BLE if offset is invalid
+    if (offset < 0 || offset > document.getLength())
+      throw new BadLocationException("Tried to write to invalid location",
+                                     offset);
+
+    // If they gave an overly large len, just adjust it
+    if (offset + len > document.getLength())
+      len = document.getLength() - offset;
+
+    out.write(document.getText(offset, len));
   }
 }
diff --git a/libjava/classpath/javax/swing/text/DefaultFormatter.java b/libjava/classpath/javax/swing/text/DefaultFormatter.java
index c97d907..f9e0f10 100644
--- a/libjava/classpath/javax/swing/text/DefaultFormatter.java
+++ b/libjava/classpath/javax/swing/text/DefaultFormatter.java
@@ -57,8 +57,7 @@ import javax.swing.JFormattedTextField;
  *  
  * @author Roman Kennke (roman@kennke.org)
  */
-public class DefaultFormatter
-  extends JFormattedTextField.AbstractFormatter
+public class DefaultFormatter extends JFormattedTextField.AbstractFormatter
   implements Cloneable, Serializable
 {
 
@@ -156,9 +155,6 @@ public class DefaultFormatter
      * Checks if the value in the input field is valid. If the
      * property allowsInvalid is set to <code>false</code>, then
      * the string in the input field is not allowed to be entered.
-     *
-     * @param doc the document of the input field
-     * @param value the current (old) value of the input field
      */
     private void checkValidInput()
     {
@@ -179,15 +175,18 @@ public class DefaultFormatter
               catch (ParseException pe)
                 {
                   // if that happens, something serious must be wrong
-                  throw new AssertionError("values must be parseable");
+                  AssertionError ae;
+		  ae = new AssertionError("values must be parseable");
+		  ae.initCause(pe);
+		  throw ae;
                 }
             }
         }
     }
   }
 
-  /** The serialVersoinUID. */
-  private static final long serialVersionUID = -7369196326612908900L;
+  /** The serialization UID (compatible with JDK1.5). */
+  private static final long serialVersionUID = -355018354457785329L;
 
   /**
    * Indicates if the value should be committed after every
diff --git a/libjava/classpath/javax/swing/text/DefaultHighlighter.java b/libjava/classpath/javax/swing/text/DefaultHighlighter.java
index c8d874c..40ea4f8 100644
--- a/libjava/classpath/javax/swing/text/DefaultHighlighter.java
+++ b/libjava/classpath/javax/swing/text/DefaultHighlighter.java
@@ -168,6 +168,7 @@ public class DefaultHighlighter extends LayeredHighlighter
   
   public DefaultHighlighter()
   {
+    // Nothing to do here.
   }
 
   public boolean getDrawsLayeredHighlights()
@@ -238,6 +239,7 @@ public class DefaultHighlighter extends LayeredHighlighter
                                      Shape viewBounds, JTextComponent editor,
                                      View view)
   {
+    // TODO: Implement this properly.
   }
 
   public void paint(Graphics g)
diff --git a/libjava/classpath/javax/swing/text/DefaultStyledDocument.java b/libjava/classpath/javax/swing/text/DefaultStyledDocument.java
index 3545e52..eb56bb0 100644
--- a/libjava/classpath/javax/swing/text/DefaultStyledDocument.java
+++ b/libjava/classpath/javax/swing/text/DefaultStyledDocument.java
@@ -1,5 +1,5 @@
 /* DefaultStyledDocument.java --
-   Copyright (C) 2004 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2005 Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -41,8 +41,14 @@ package javax.swing.text;
 import java.awt.Color;
 import java.awt.Font;
 import java.io.Serializable;
+import java.util.Enumeration;
+import java.util.Vector;
 
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
 import javax.swing.event.DocumentEvent;
+import javax.swing.undo.AbstractUndoableEdit;
+import javax.swing.undo.UndoableEdit;
 
 /**
  * The default implementation of {@link StyledDocument}.
@@ -60,12 +66,359 @@ public class DefaultStyledDocument extends AbstractDocument
   implements StyledDocument
 {
   /**
+   * An {@link UndoableEdit} that can undo attribute changes to an element.
+   *
+   * @author Roman Kennke (kennke@aicas.com)
+   */
+  public static class AttributeUndoableEdit
+    extends AbstractUndoableEdit
+  {
+    /**
+     * A copy of the old attributes.
+     */
+    protected AttributeSet copy;
+
+    /**
+     * The new attributes.
+     */
+    protected AttributeSet newAttributes;
+
+    /**
+     * If the new attributes replaced the old attributes or if they only were
+     * added to them.
+     */
+    protected boolean isReplacing;
+
+    /**
+     * The element that has changed.
+     */
+    protected Element element;
+
+    /**
+     * Creates a new <code>AttributeUndoableEdit</code>.
+     *
+     * @param el the element that changes attributes
+     * @param newAtts the new attributes
+     * @param replacing if the new attributes replace the old or only append to
+     *        them
+     */
+    public AttributeUndoableEdit(Element el, AttributeSet newAtts,
+                                 boolean replacing)
+    {
+      element = el;
+      newAttributes = newAtts;
+      isReplacing = replacing;
+      copy = el.getAttributes().copyAttributes();
+    }
+
+    /**
+     * Undos the attribute change. The <code>copy</code> field is set as
+     * attributes on <code>element</code>.
+     */
+    public void undo()
+    {
+      super.undo();
+      AttributeSet atts = element.getAttributes();
+      if (atts instanceof MutableAttributeSet)
+        {
+          MutableAttributeSet mutable = (MutableAttributeSet) atts;
+          mutable.removeAttributes(atts);
+          mutable.addAttributes(copy);
+        }
+    }
+
+    /**
+     * Redos an attribute change. This adds <code>newAttributes</code> to the
+     * <code>element</code>'s attribute set, possibly clearing all attributes
+     * if <code>isReplacing</code> is true.
+     */
+    public void redo()
+    {
+      super.undo();
+      AttributeSet atts = element.getAttributes();
+      if (atts instanceof MutableAttributeSet)
+        {
+          MutableAttributeSet mutable = (MutableAttributeSet) atts;
+          if (isReplacing)
+            mutable.removeAttributes(atts);
+          mutable.addAttributes(newAttributes);
+        }
+    }
+  }
+
+  /**
+   * Carries specification information for new {@link Element}s that should
+   * be created in {@link ElementBuffer}. This allows the parsing process
+   * to be decoupled from the <code>Element</code> creation process.
+   */
+  public static class ElementSpec
+  {
+    /**
+     * This indicates a start tag. This is a possible value for
+     * {@link #getType}.
+     */
+    public static final short StartTagType = 1;
+
+    /**
+     * This indicates an end tag. This is a possible value for
+     * {@link #getType}.
+     */
+    public static final short EndTagType = 2;
+
+    /**
+     * This indicates a content element. This is a possible value for
+     * {@link #getType}.
+     */
+    public static final short ContentType = 3;
+
+    /**
+     * This indicates that the data associated with this spec should be joined
+     * with what precedes it. This is a possible value for
+     * {@link #getDirection}.
+     */
+    public static final short JoinPreviousDirection = 4;
+
+    /**
+     * This indicates that the data associated with this spec should be joined
+     * with what follows it. This is a possible value for
+     * {@link #getDirection}.
+     */
+    public static final short JoinNextDirection = 5;
+
+    /**
+     * This indicates that the data associated with this spec should be used
+     * to create a new element. This is a possible value for
+     * {@link #getDirection}.
+     */
+    public static final short OriginateDirection = 6;
+
+    /**
+     * This indicates that the data associated with this spec should be joined
+     * to the fractured element. This is a possible value for
+     * {@link #getDirection}.
+     */
+    public static final short JoinFractureDirection = 7;
+
+    /**
+     * The type of the tag.
+     */
+    short type;
+
+    /**
+     * The direction of the tag.
+     */
+    short direction;
+
+    /**
+     * The offset of the content.
+     */
+    int offset;
+
+    /**
+     * The length of the content.
+     */
+    int length;
+
+    /**
+     * The actual content.
+     */
+    char[] content;
+
+    /**
+     * The attributes for the tag.
+     */
+    AttributeSet attributes;
+
+    /**
+     * Creates a new <code>ElementSpec</code> with no content, length or
+     * offset. This is most useful for start and end tags.
+     *
+     * @param a the attributes for the element to be created
+     * @param type the type of the tag
+     */
+    public ElementSpec(AttributeSet a, short type)
+    {
+      this(a, type, 0);
+    }
+
+    /**
+     * Creates a new <code>ElementSpec</code> that specifies the length but
+     * not the offset of an element. Such <code>ElementSpec</code>s are
+     * processed sequentially from a known starting point.
+     *
+     * @param a the attributes for the element to be created
+     * @param type the type of the tag
+     * @param len the length of the element
+     */
+    public ElementSpec(AttributeSet a, short type, int len)
+    {
+      this(a, type, null, 0, len);
+    }
+ 
+    /**
+     * Creates a new <code>ElementSpec</code> with document content.
+     *
+     * @param a the attributes for the element to be created
+     * @param type the type of the tag
+     * @param txt the actual content
+     * @param offs the offset into the <code>txt</code> array
+     * @param len the length of the element
+     */
+    public ElementSpec(AttributeSet a, short type, char[] txt, int offs,
+                       int len)
+    {
+      attributes = a;
+      this.type = type;
+      offset = offs;
+      length = len;
+      content = txt;
+      direction = OriginateDirection;
+    }
+
+    /**
+     * Sets the type of the element.
+     *
+     * @param type the type of the element to be set
+     */
+    public void setType(short type)
+    {
+      this.type = type;
+    }
+
+    /**
+     * Returns the type of the element.
+     *
+     * @return the type of the element
+     */
+    public short getType()
+    {
+      return type;
+    }
+
+    /**
+     * Sets the direction of the element.
+     *
+     * @param dir the direction of the element to be set
+     */
+    public void setDirection(short dir)
+    {
+      direction = dir;
+    }
+
+    /**
+     * Returns the direction of the element.
+     *
+     * @return the direction of the element
+     */
+    public short getDirection()
+    {
+      return direction;
+    }
+
+    /**
+     * Returns the attributes of the element.
+     *
+     * @return the attributes of the element
+     */
+    public AttributeSet getAttributes()
+    {
+      return attributes;
+    }
+
+    /**
+     * Returns the actual content of the element.
+     *
+     * @return the actual content of the element
+     */
+    public char[] getArray()
+    {
+      return content;
+    }
+
+    /**
+     * Returns the offset of the content.
+     *
+     * @return the offset of the content
+     */
+    public int getOffset()
+    {
+      return offset;
+    }
+
+    /**
+     * Returns the length of the content.
+     *
+     * @return the length of the content
+     */
+    public int getLength()
+    {
+      return length;
+    }
+
+    /**
+     * Returns a String representation of this <code>ElementSpec</code>
+     * describing the type, direction and length of this
+     * <code>ElementSpec</code>.
+     *
+     * @return a String representation of this <code>ElementSpec</code>
+     */
+    public String toString()
+    {
+      StringBuilder b = new StringBuilder();
+      b.append('<');
+      switch (type)
+        {
+        case StartTagType:
+          b.append("StartTag");
+          break;
+        case EndTagType:
+          b.append("EndTag");
+          break;
+        case ContentType:
+          b.append("Content");
+          break;
+        default:
+          b.append("??");
+          break;
+        }
+
+      b.append(':');
+
+      switch (direction)
+        {
+        case JoinPreviousDirection:
+          b.append("JoinPrevious");
+          break;
+        case JoinNextDirection:
+          b.append("JoinNext");
+          break;
+        case OriginateDirection:
+          b.append("Originate");
+          break;
+        case JoinFractureDirection:
+          b.append("Fracture");
+          break;
+        default:
+          b.append("??");
+          break;
+        }
+
+      b.append(':');
+      b.append(length);
+
+      return b.toString();
+    }
+  }
+
+  /**
    * Performs all <em>structural</code> changes to the <code>Element</code>
    * hierarchy.
    */
-  public class ElementBuffer
-    implements Serializable
+  public class ElementBuffer implements Serializable
   {
+    /** The serialization UID (compatible with JDK1.5). */
+    private static final long serialVersionUID = 1688745877691146623L;
+
     /** The root element of the hierarchy. */
     private Element root;
 
@@ -76,6 +429,19 @@ public class DefaultStyledDocument extends AbstractDocument
     private int length;
 
     /**
+     * Holds fractured elements during insertion of end and start tags.
+     * Inserting an end tag may lead to fracturing of the current paragraph
+     * element. The elements that have been cut off may be added to the
+     * next paragraph that is created in the next start tag.
+     */
+    Element[] fracture;
+
+    /**
+     * The ElementChange that describes the latest changes.
+     */
+    DefaultDocumentEvent documentEvent;
+
+    /**
      * Creates a new <code>ElementBuffer</code> for the specified
      * <code>root</code> element.
      *
@@ -114,6 +480,7 @@ public class DefaultStyledDocument extends AbstractDocument
     {
       this.offset = offset;
       this.length = length;
+      documentEvent = ev;
       changeUpdate();
     }
 
@@ -142,38 +509,352 @@ public class DefaultStyledDocument extends AbstractDocument
     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 });
-		}
+        {
+          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);
+                  Element[] add = new Element[]{ child1, child2 };
+                  par.replace(index, 1, add);
+                  documentEvent.addEdit(new ElementEdit(par, index,
+                                                        new Element[]{ el },
+                                                        add));
+                }
               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 "
+        throw new AssertionError("content elements are expected to be "
+                                 + "instances of "
 			+ "javax.swing.text.AbstractDocument.AbstractElement");
     }
+
+    /**
+     * Inserts new <code>Element</code> in the document at the specified
+     * position.
+     *
+     * Most of the work is done by {@link #insertUpdate}, after some fields
+     * have been prepared for it.
+     *
+     * @param offset the location in the document at which the content is
+     *        inserted
+     * @param length the length of the inserted content
+     * @param data the element specifications for the content to be inserted
+     * @param ev the document event that is updated to reflect the structural
+     *        changes
+     */
+    public void insert(int offset, int length, ElementSpec[] data,
+                       DefaultDocumentEvent ev)
+    {
+      this.offset = offset;
+      this.length = length;
+      documentEvent = ev;
+      insertUpdate(data);
+    }
+
+    /**
+     * Performs the actual structural change for {@link #insert}. This
+     * creates a bunch of {@link Element}s as specified by <code>data</code>
+     * and inserts it into the document as specified in the arguments to
+     * {@link #insert}.
+     *
+     * @param data the element specifications for the elements to be inserte
+     */
+    protected void insertUpdate(ElementSpec[] data)
+    {
+      for (int i = 0; i < data.length; i++)
+        {
+          switch (data[i].getType())
+            {
+            case ElementSpec.StartTagType:
+              insertStartTag(data[i]);
+              break;
+            case ElementSpec.EndTagType:
+              insertEndTag(data[i]);
+              break;
+            default:
+              insertContentTag(data[i]);
+              break;
+            }
+        }
+    }
+
+    /**
+     * Insert a new paragraph after the paragraph at the current position.
+     *
+     * @param tag the element spec that describes the element to be inserted
+     */
+    void insertStartTag(ElementSpec tag)
+    {
+      BranchElement root = (BranchElement) getDefaultRootElement();
+      int index = root.getElementIndex(offset);
+      if (index == -1)
+        index = 0;
+
+      BranchElement newParagraph =
+        (BranchElement) createBranchElement(root, tag.getAttributes());
+      newParagraph.setResolveParent(getStyle(StyleContext.DEFAULT_STYLE));
+
+      // Add new paragraph into document structure.
+      Element[] added = new Element[]{newParagraph};
+      root.replace(index + 1, 0, added);
+      ElementEdit edit = new ElementEdit(root, index + 1, new Element[0],
+                                         added);
+      documentEvent.addEdit(edit);
+
+      // Maybe add fractured elements.
+      if (tag.getDirection() == ElementSpec.JoinFractureDirection)
+        {
+          Element[] newFracture = new Element[fracture.length];
+          for (int i = 0; i < fracture.length; i++)
+            {
+              Element oldLeaf = fracture[i];
+              Element newLeaf = createLeafElement(newParagraph,
+                                                  oldLeaf.getAttributes(),
+                                                  oldLeaf.getStartOffset(),
+                                                  oldLeaf.getEndOffset());
+              newFracture[i] = newLeaf;
+            }
+          newParagraph.replace(0, 0, newFracture);
+          edit = new ElementEdit(newParagraph, 0, new Element[0],
+                                 fracture);
+          documentEvent.addEdit(edit);
+          fracture = new Element[0];
+        }
+    }
+
+    /**
+     * Inserts an end tag into the document structure. This cuts of the
+     * current paragraph element, possibly fracturing it's child elements.
+     * The fractured elements are saved so that they can be joined later
+     * with a new paragraph element.
+     */
+    void insertEndTag(ElementSpec tag)
+    {
+      BranchElement root = (BranchElement) getDefaultRootElement();
+      int parIndex = root.getElementIndex(offset);
+      BranchElement paragraph = (BranchElement) root.getElement(parIndex);
+
+      int index = paragraph.getElementIndex(offset);
+      LeafElement content = (LeafElement) paragraph.getElement(index);
+      // We might have to split the element at offset.
+      split(content, offset);
+      index = paragraph.getElementIndex(offset);
+
+      int count = paragraph.getElementCount();
+      // Store fractured elements.
+      fracture = new Element[count - index];
+      for (int i = index; i < count; ++i)
+        fracture[i - index] = paragraph.getElement(i);
+
+      // Delete fractured elements.
+      paragraph.replace(index, count - index, new Element[0]);
+
+      // Add this action to the document event.
+      ElementEdit edit = new ElementEdit(paragraph, index, fracture,
+                                         new Element[0]);
+      documentEvent.addEdit(edit);
+    }
+
+    /**
+     * Inserts a content element into the document structure.
+     *
+     * @param tag the element spec
+     */
+    void insertContentTag(ElementSpec tag)
+    {
+      int len = tag.getLength();
+      int dir = tag.getDirection();
+      if (dir == ElementSpec.JoinPreviousDirection)
+        {
+          Element prev = getCharacterElement(offset);
+          BranchElement prevParent = (BranchElement) prev.getParentElement();
+          Element join = createLeafElement(prevParent, tag.getAttributes(),
+                                           prev.getStartOffset(),
+                                           Math.max(prev.getEndOffset(),
+                                                    offset + len));
+          int ind = prevParent.getElementIndex(offset);
+          if (ind == -1)
+            ind = 0;
+          Element[] add = new Element[]{join};
+          prevParent.replace(ind, 1, add);
+
+          // Add this action to the document event.
+          ElementEdit edit = new ElementEdit(prevParent, ind,
+                                             new Element[]{prev}, add);
+          documentEvent.addEdit(edit);
+        }
+      else if (dir == ElementSpec.JoinNextDirection)
+        {
+          Element next = getCharacterElement(offset + len);
+          BranchElement nextParent = (BranchElement) next.getParentElement();
+          Element join = createLeafElement(nextParent, tag.getAttributes(),
+                                           offset,
+                                           next.getEndOffset());
+          int ind = nextParent.getElementIndex(offset + len);
+          if (ind == -1)
+            ind = 0;
+          Element[] add = new Element[]{join};
+          nextParent.replace(ind, 1, add);
+
+          // Add this action to the document event.
+          ElementEdit edit = new ElementEdit(nextParent, ind,
+                                             new Element[]{next}, add);
+          documentEvent.addEdit(edit);
+        }
+      else
+        {
+          BranchElement par = (BranchElement) getParagraphElement(offset);
+
+          int ind = par.getElementIndex(offset);
+
+          // Make room for the element.
+          // Cut previous element.
+          Element prev = par.getElement(ind);
+          if (prev != null && prev.getStartOffset() < offset)
+            {
+              Element cutPrev = createLeafElement(par, prev.getAttributes(),
+                                                  prev.getStartOffset(),
+                                                  offset);
+              Element[] remove = new Element[]{prev};
+              Element[] add = new Element[]{cutPrev};
+              if (prev.getEndOffset() > offset + len)
+                {
+                  Element rem = createLeafElement(par, prev.getAttributes(),
+                                                  offset + len,
+                                                  prev.getEndOffset());
+                  add = new Element[]{cutPrev, rem};
+                }
+
+              par.replace(ind, 1, add);
+              documentEvent.addEdit(new ElementEdit(par, ind, remove, add));
+              ind++;
+            }
+          // ind now points to the next element.
+
+          // Cut next element if necessary.
+          Element next = par.getElement(ind);
+          if (next != null && next.getStartOffset() < offset + len)
+            {
+              Element cutNext = createLeafElement(par, next.getAttributes(),
+                                                  offset + len,
+                                                  next.getEndOffset());
+              Element[] remove = new Element[]{next};
+              Element[] add = new Element[]{cutNext};
+              par.replace(ind, 1, add);
+              documentEvent.addEdit(new ElementEdit(par, ind, remove,
+                                                    add));
+            }
+
+          // Insert new element.
+          Element newEl = createLeafElement(par, tag.getAttributes(),
+                                            offset, offset + len);
+          Element[] added = new Element[]{newEl};
+          par.replace(ind, 0, added);
+          // Add this action to the document event.
+          ElementEdit edit = new ElementEdit(par, ind, new Element[0],
+                                             added);
+          documentEvent.addEdit(edit);
+        }
+      offset += len;
+    }
+    
+    /**
+     * Creates a copy of the element <code>clonee</code> that has the parent
+     * <code>parent</code>.
+     * @param parent the parent of the newly created Element
+     * @param clonee the Element to clone
+     * @return the cloned Element
+     */
+    public Element clone (Element parent, Element clonee)
+    {
+      // If the Element we want to clone is a leaf, then simply copy it
+      if (clonee.isLeaf())
+        return createLeafElement(parent, clonee.getAttributes(),
+                                 clonee.getStartOffset(), clonee.getEndOffset());
+      
+      // Otherwise create a new BranchElement with the desired parent and 
+      // the clonee's attributes
+      BranchElement result = (BranchElement) createBranchElement(parent, clonee.getAttributes());
+      
+      // And clone all the of clonee's children
+      Element[] children = new Element[clonee.getElementCount()];
+      for (int i = 0; i < children.length; i++)
+        children[i] = clone(result, clonee.getElement(i));
+      
+      // Make the cloned children the children of the BranchElement
+      result.replace(0, 0, children);
+      return result;
+    }
   }
 
   /**
+   * An element type for sections. This is a simple BranchElement with
+   * a unique name.
+   */
+  protected class SectionElement extends BranchElement
+  {
+    /**
+     * Creates a new SectionElement.
+     */
+    public SectionElement()
+    {
+      super(null, null);
+    }
+
+    /**
+     * Returns the name of the element. This method always returns
+     * &quot;section&quot;.
+     *
+     * @return the name of the element
+     */
+    public String getName()
+    {
+      return "section";
+    }
+  }
+
+  /**
+   * Receives notification when any of the document's style changes and calls
+   * {@link DefaultStyledDocument#styleChanged(Style)}.
+   *
+   * @author Roman Kennke (kennke@aicas.com)
+   */
+  private class StyleChangeListener
+    implements ChangeListener
+  {
+
+    /**
+     * Receives notification when any of the document's style changes and calls
+     * {@link DefaultStyledDocument#styleChanged(Style)}.
+     *
+     * @param event the change event
+     */
+    public void stateChanged(ChangeEvent event)
+    {
+      Style style = (Style) event.getSource();
+      styleChanged(style);
+    }
+  }
+
+  /** The serialization UID (compatible with JDK1.5). */
+  private static final long serialVersionUID = 940485415728614849L;
+
+  /**
    * The default size to use for new content buffers.
    */
   public static final int BUFFER_SIZE_DEFAULT = 4096;
@@ -185,6 +866,11 @@ public class DefaultStyledDocument extends AbstractDocument
   protected DefaultStyledDocument.ElementBuffer buffer;
 
   /**
+   * Listens for changes on this document's styles and notifies styleChanged().
+   */
+  private StyleChangeListener styleChangeListener;
+
+  /**
    * Creates a new <code>DefaultStyledDocument</code>.
    */
   public DefaultStyledDocument()
@@ -237,7 +923,14 @@ public class DefaultStyledDocument extends AbstractDocument
   public Style addStyle(String nm, Style parent)
   {
     StyleContext context = (StyleContext) getAttributeContext();
-    return context.addStyle(nm, parent);
+    Style newStyle = context.addStyle(nm, parent);
+
+    // Register change listener.
+    if (styleChangeListener == null)
+      styleChangeListener = new StyleChangeListener();
+    newStyle.addChangeListener(styleChangeListener);
+
+    return newStyle;
   }
 
   /**
@@ -250,9 +943,11 @@ public class DefaultStyledDocument extends AbstractDocument
     Element[] tmp;
     // FIXME: Create a SecionElement here instead of a BranchElement.
     // Use createBranchElement() and createLeafElement instead.
-    BranchElement section = new BranchElement(null, null);
-    
-    BranchElement paragraph = new BranchElement(section, null);
+    SectionElement section = new SectionElement();
+
+    BranchElement paragraph =
+      (BranchElement) createBranchElement(section, null);
+    paragraph.setResolveParent(getStyle(StyleContext.DEFAULT_STYLE));
     tmp = new Element[1];
     tmp[0] = paragraph;
     section.replace(0, 0, tmp);
@@ -261,7 +956,7 @@ public class DefaultStyledDocument extends AbstractDocument
     tmp = new Element[1];
     tmp[0] = leaf;
     paragraph.replace(0, 0, tmp);
-    
+
     return section;
   }
 
@@ -279,10 +974,10 @@ public class DefaultStyledDocument extends AbstractDocument
   {
     Element element = getDefaultRootElement();
 
-    while (! element.isLeaf())
+    while (!element.isLeaf())
       {
-	int index = element.getElementIndex(position);
-	element = element.getElement(index);
+        int index = element.getElementIndex(position);
+        element = element.getElement(index);
       }
     
     return element;
@@ -353,6 +1048,10 @@ public class DefaultStyledDocument extends AbstractDocument
 
   /**
    * Returns the paragraph element for the specified position.
+   * If the position is outside the bounds of the document's root element,
+   * then the closest element is returned. That is the last paragraph if
+   * <code>position >= endIndex</code> or the first paragraph if
+   * <code>position < startIndex</code>.
    *
    * @param position the position for which to query the paragraph element
    *
@@ -360,8 +1059,18 @@ public class DefaultStyledDocument extends AbstractDocument
    */
   public Element getParagraphElement(int position)
   {
-    Element element = getCharacterElement(position);
-    return element.getParentElement();
+    BranchElement root = (BranchElement) getDefaultRootElement();
+    int start = root.getStartOffset();
+    int end = root.getEndOffset();
+    if (position >= end)
+      position = end - 1;
+    else if (position < start)
+      position = start;
+
+    Element par = root.positionToElement(position);
+
+    assert par != null : "The paragraph element must not be null";
+    return par;
   }
 
   /**
@@ -416,35 +1125,37 @@ public class DefaultStyledDocument extends AbstractDocument
     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 "
+        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");
-	  }
+          }
       }
+
+    fireChangedUpdate(ev);
   }
   
   /**
@@ -476,10 +1187,199 @@ public class DefaultStyledDocument extends AbstractDocument
    *     selection are overridden, otherwise they are merged
    */
   public void setParagraphAttributes(int offset, int length,
-				     AttributeSet attributes,
-				     boolean replace)
+                                     AttributeSet attributes,
+                                     boolean replace)
+  {
+    int index = offset;
+    while (index < offset + length)
+      {
+        AbstractElement par = (AbstractElement) getParagraphElement(index);
+        AttributeContext ctx = getAttributeContext();
+        if (replace)
+          par.removeAttributes(par);
+        par.addAttributes(attributes);
+        index = par.getElementCount();
+      }
+  }
+
+  /**
+   * Called in response to content insert actions. This is used to
+   * update the element structure.
+   *
+   * @param ev the <code>DocumentEvent</code> describing the change
+   * @param attr the attributes for the change
+   */
+  protected void insertUpdate(DefaultDocumentEvent ev, AttributeSet attr)
+  {
+    super.insertUpdate(ev, attr);
+    int offset = ev.getOffset();
+    int length = ev.getLength();
+    int endOffset = offset + length;
+    Segment txt = new Segment();
+    try
+      {
+        getText(offset, length, txt);
+      }
+    catch (BadLocationException ex)
+      {
+        AssertionError ae = new AssertionError("Unexpected bad location");
+        ae.initCause(ex);
+        throw ae;
+      }
+
+    int len = 0;
+    Vector specs = new Vector();
+
+    Element prev = getCharacterElement(offset);
+    Element next = getCharacterElement(endOffset);
+
+    for (int i = offset; i < endOffset; ++i)
+      {
+        len++;
+        if (txt.array[i] == '\n')
+          {
+            ElementSpec spec = new ElementSpec(attr, ElementSpec.ContentType,
+                                               len);
+
+            // If we are at the last index, then check if we could probably be
+            // joined with the next element.
+            if (i == endOffset - 1)
+              {
+                if (next.getAttributes().isEqual(attr))
+                  spec.setDirection(ElementSpec.JoinNextDirection);
+              }
+            // If we are at the first new element, then check if it could be
+            // joined with the previous element.
+            else if (specs.size() == 0)
+              {
+                if (prev.getAttributes().isEqual(attr))
+                    spec.setDirection(ElementSpec.JoinPreviousDirection);
+              }
+
+            specs.add(spec);
+
+            // Add ElementSpecs for the newline.
+            ElementSpec endTag = new ElementSpec(null, ElementSpec.EndTagType);
+            specs.add(endTag);
+            ElementSpec startTag = new ElementSpec(null,
+                                                   ElementSpec.StartTagType);
+            startTag.setDirection(ElementSpec.JoinFractureDirection);
+            specs.add(startTag);
+
+            len = 0;
+            offset += len;
+          }
+      }
+
+    // Create last element if last character hasn't been a newline.
+    if (len > 0)
+      {
+        ElementSpec spec = new ElementSpec(attr, ElementSpec.ContentType, len);
+        // If we are at the first new element, then check if it could be
+        // joined with the previous element.
+        if (specs.size() == 0)
+          {
+            if (prev.getAttributes().isEqual(attr))
+              spec.setDirection(ElementSpec.JoinPreviousDirection);
+          }
+        // Check if we could probably be joined with the next element.
+        else if (next.getAttributes().isEqual(attr))
+          spec.setDirection(ElementSpec.JoinNextDirection);
+
+        specs.add(spec);
+      }
+
+    ElementSpec[] elSpecs =
+      (ElementSpec[]) specs.toArray(new ElementSpec[specs.size()]);
+
+    buffer.insert(offset, length, elSpecs, ev);
+  }
+
+  /**
+   * Returns an enumeration of all style names.
+   *
+   * @return an enumeration of all style names
+   */
+  public Enumeration getStyleNames()
+  {
+    StyleContext context = (StyleContext) getAttributeContext();
+    return context.getStyleNames();
+  }
+
+  /**
+   * Called when any of this document's styles changes.
+   *
+   * @param style the style that changed
+   */
+  protected void styleChanged(Style style)
   {
-    // FIXME: Implement me.
-    throw new Error("not implemented");
+    // Nothing to do here. This is intended to be overridden by subclasses.
+  }
+
+  /**
+   * Inserts a bulk of structured content at once.
+   *
+   * @param offset the offset at which the content should be inserted
+   * @param data the actual content spec to be inserted
+   */
+  protected void insert(int offset, ElementSpec[] data)
+    throws BadLocationException
+  {
+    writeLock();
+    // First we insert the content.
+    int index = offset;
+    for (int i = 0; i < data.length; i++)
+      {
+        ElementSpec spec = data[i];
+        if (spec.getArray() != null && spec.getLength() > 0)
+          {
+            String insertString = new String(spec.getArray(), spec.getOffset(),
+                                             spec.getLength());
+            content.insertString(index, insertString);
+          }
+        index += spec.getLength();
+      }
+    // Update the view structure.
+    DefaultDocumentEvent ev = new DefaultDocumentEvent(offset, index - offset,
+                                               DocumentEvent.EventType.INSERT);
+    for (int i = 0; i < data.length; i++)
+      {
+        ElementSpec spec = data[i];
+        AttributeSet atts = spec.getAttributes();
+        if (atts != null)
+          insertUpdate(ev, atts);
+      }
+
+    // Finally we must update the document structure and fire the insert update
+    // event.
+    buffer.insert(offset, index - offset, data, ev);
+    fireInsertUpdate(ev);
+    writeUnlock();
+  }
+
+  /**
+   * Initializes the <code>DefaultStyledDocument</code> with the specified
+   * data.
+   *
+   * @param data the specification of the content with which the document is
+   *        initialized
+   */
+  protected void create(ElementSpec[] data)
+  {
+    try
+      {
+        // Clear content.
+        content.remove(0, content.length());
+        // Clear buffer and root element.
+        buffer = new ElementBuffer(createDefaultRoot());
+        // Insert the data.
+        insert(0, data);
+      }
+    catch (BadLocationException ex)
+      {
+        AssertionError err = new AssertionError("Unexpected bad location");
+        err.initCause(ex);
+        throw err;
+      }
   }
 }
diff --git a/libjava/classpath/javax/swing/text/DefaultTextUI.java b/libjava/classpath/javax/swing/text/DefaultTextUI.java
new file mode 100644
index 0000000..e7ff018
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/DefaultTextUI.java
@@ -0,0 +1,61 @@
+/* DefaultTextUI.java -- Deprecated base UI for text components
+   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;
+
+import javax.swing.plaf.basic.BasicTextUI;
+
+/**
+ * This class is deprecated and should not be used anymore. The base UI for
+ * all text components is now {@link BasicTextUI}.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+public abstract class DefaultTextUI extends BasicTextUI
+{
+  /**
+   * This class is deprecated and should not be used anymore. The base UI for
+   * all text components is now {@link BasicTextUI}.
+   *
+   * @deprecated use {@link BasicTextUI} instead
+   */
+  public DefaultTextUI()
+  {
+    // Nothing to do here.
+  }
+}
diff --git a/libjava/classpath/javax/swing/text/EditorKit.java b/libjava/classpath/javax/swing/text/EditorKit.java
index bd51a86..8719aee 100644
--- a/libjava/classpath/javax/swing/text/EditorKit.java
+++ b/libjava/classpath/javax/swing/text/EditorKit.java
@@ -48,24 +48,24 @@ import java.io.Writer;
 import javax.swing.Action;
 import javax.swing.JEditorPane;
 
-public abstract class EditorKit
-  implements Cloneable, Serializable
+public abstract class EditorKit implements Cloneable, Serializable
 {
   private static final long serialVersionUID = -5044124649345887822L;
   
   public EditorKit()
   {
+    // Nothing to do here.
   }
 
   public Object clone()
   {
     try
       {
-	return super.clone();
+        return super.clone();
       }
     catch (CloneNotSupportedException e)
       {
-	return null;
+        return null;
       }
   }
 
@@ -74,10 +74,12 @@ public abstract class EditorKit
    */
   public void deinstall(JEditorPane c)
   {
+    // This default implementation does nothing.
   }
 
   public void install(JEditorPane c)
   {
+    // This default implementation does nothing.
   }
 
   public abstract Caret createCaret();
diff --git a/libjava/classpath/javax/swing/text/FieldView.java b/libjava/classpath/javax/swing/text/FieldView.java
index e2e04d7..2496418 100644
--- a/libjava/classpath/javax/swing/text/FieldView.java
+++ b/libjava/classpath/javax/swing/text/FieldView.java
@@ -118,22 +118,24 @@ public class FieldView extends PlainView
     FontMetrics fm = getFontMetrics();
 
     if (axis == Y_AXIS)
-      return fm.getHeight();
+      return super.getPreferredSpan(axis);
 
     String text;
     Element elem = getElement();
 
     try
       {
-	text = elem.getDocument().getText(elem.getStartOffset(),
-					  elem.getEndOffset());
+        text = elem.getDocument().getText(elem.getStartOffset(),
+                                          elem.getEndOffset());
       }
     catch (BadLocationException e)
       {
-	// This should never happen.
-	text = "";
+	// Should never happen
+	AssertionError ae = new AssertionError();
+	ae.initCause(e);
+	throw ae;
       }
-    
+
     return fm.stringWidth(text);
   }
 
@@ -159,18 +161,21 @@ public class FieldView extends PlainView
   {
     Shape newAlloc = adjustAllocation(shape);
     super.insertUpdate(ev, newAlloc, vf);
+    getContainer().repaint();
   }
 
   public void removeUpdate(DocumentEvent ev, Shape shape, ViewFactory vf)
   {
     Shape newAlloc = adjustAllocation(shape);
     super.removeUpdate(ev, newAlloc, vf);
+    getContainer().repaint();
   }
 
   public void changedUpdate(DocumentEvent ev, Shape shape, ViewFactory vf)
   {
     Shape newAlloc = adjustAllocation(shape);
     super.removeUpdate(ev, newAlloc, vf);
+    getContainer().repaint();
   }
 
   public int viewToModel(float fx, float fy, Shape a, Position.Bias[] bias)
diff --git a/libjava/classpath/javax/swing/text/FlowView.java b/libjava/classpath/javax/swing/text/FlowView.java
index a6ef89e..fd6785b 100644
--- a/libjava/classpath/javax/swing/text/FlowView.java
+++ b/libjava/classpath/javax/swing/text/FlowView.java
@@ -42,8 +42,10 @@ import java.awt.Container;
 import java.awt.Graphics;
 import java.awt.Rectangle;
 import java.awt.Shape;
+import java.util.Iterator;
 import java.util.Vector;
 
+import javax.swing.SwingConstants;
 import javax.swing.event.DocumentEvent;
 
 /**
@@ -71,6 +73,7 @@ public abstract class FlowView extends BoxView
      */
     public FlowStrategy()
     {
+      // Nothing to do here.
     }
 
     /**
@@ -137,7 +140,7 @@ public abstract class FlowView extends BoxView
      * Performs the layout for the whole view. By default this rebuilds
      * all the physical views from the logical views of the managed FlowView.
      *
-     * This is called by {@link FlowLayout#layout} to update the layout of
+     * This is called by {@link FlowView#layout} to update the layout of
      * the view.
      *
      * @param fv the flow view for which we perform the layout
@@ -183,11 +186,17 @@ public abstract class FlowView extends BoxView
         {
           View child = createView(fv, offset, spanLeft, rowIndex);
           if (child == null)
-            break;
+            {
+              offset = -1;
+              break;
+            }
 
           int span = (int) child.getPreferredSpan(flowAxis);
           if (span > spanLeft)
-            break;
+            {
+              offset = -1;
+              break;
+            }
 
           row.append(child);
           spanLeft -= span;
@@ -204,7 +213,7 @@ public abstract class FlowView extends BoxView
      * not fit in the available span and also cannot be broken down).
      *
      * @param fv the flow view
-     * @param startOffset the start offset for the view to be created
+     * @param offset the start offset for the view to be created
      * @param spanLeft the available span
      * @param rowIndex the index of the row
      *
@@ -218,13 +227,15 @@ public abstract class FlowView extends BoxView
       View logicalView = getLogicalView(fv);
 
       int viewIndex = logicalView.getViewIndex(offset, Position.Bias.Forward);
+      if (viewIndex == -1)
+        return null;
+
       View child = logicalView.getView(viewIndex);
       int flowAxis = fv.getFlowAxis();
       int span = (int) child.getPreferredSpan(flowAxis);
 
       if (span <= spanLeft)
         return child;
-
       else if (child.getBreakWeight(flowAxis, offset, spanLeft)
                > BadBreakWeight)
         // FIXME: What to do with the pos parameter here?
@@ -326,7 +337,19 @@ public abstract class FlowView extends BoxView
      */
     public int getViewIndex(int pos, Position.Bias b)
     {
-      return getElement().getElementIndex(pos);
+      int index = -1;
+      int i = 0;
+      for (Iterator it = children.iterator(); it.hasNext(); i++)
+        {
+          View child = (View) it.next();
+          if (child.getStartOffset() >= pos
+              && child.getEndOffset() < pos)
+            {
+              index = i;
+              break;
+            }
+        }
+      return index;
     }
 
     /**
@@ -373,6 +396,37 @@ public abstract class FlowView extends BoxView
       throw new AssertionError("This method must not be called in "
                                + "LogicalView.");
     }
+
+    /**
+     * Returns the document position that is (visually) nearest to the given
+     * document position <code>pos</code> in the given direction <code>d</code>.
+     *
+     * @param c the text component
+     * @param pos the document position
+     * @param b the bias for <code>pos</code>
+     * @param d the direction, must be either {@link SwingConstants#NORTH},
+     *        {@link SwingConstants#SOUTH}, {@link SwingConstants#WEST} or
+     *        {@link SwingConstants#EAST}
+     * @param biasRet an array of {@link Position.Bias} that can hold at least
+     *        one element, which is filled with the bias of the return position
+     *        on method exit
+     *
+     * @return the document position that is (visually) nearest to the given
+     *         document position <code>pos</code> in the given direction
+     *         <code>d</code>
+     *
+     * @throws BadLocationException if <code>pos</code> is not a valid offset in
+     *         the document model
+     */
+    public int getNextVisualPositionFrom(JTextComponent c, int pos,
+                                         Position.Bias b, int d,
+                                         Position.Bias[] biasRet)
+      throws BadLocationException
+    {
+      assert false : "getNextVisualPositionFrom() must not be called in "
+        + "LogicalView";
+      return 0;
+    }
   }
 
   /**
@@ -478,7 +532,7 @@ public abstract class FlowView extends BoxView
    * The real children are created at layout time and each represent one
    * row.
    *
-   * This method is called by {@link #setParent} in order to initialize
+   * This method is called by {@link View#setParent} in order to initialize
    * the view.
    *
    * @param vf the view factory to use for creating the child views
@@ -502,7 +556,7 @@ public abstract class FlowView extends BoxView
 
   /**
    * Performs the layout of this view. If the span along the flow axis changed,
-   * this first calls {@link FlowStrategy.layout} in order to rebuild the
+   * this first calls {@link FlowStrategy#layout} in order to rebuild the
    * rows of this view. Then the superclass's behaviour is called to arrange
    * the rows within the box.
    *
diff --git a/libjava/classpath/javax/swing/text/GapContent.java b/libjava/classpath/javax/swing/text/GapContent.java
index 1dd46c4..4c65de0 100644
--- a/libjava/classpath/javax/swing/text/GapContent.java
+++ b/libjava/classpath/javax/swing/text/GapContent.java
@@ -39,10 +39,15 @@ exception statement from your version. */
 package javax.swing.text;
 
 import java.io.Serializable;
+import java.util.ArrayList;
 import java.util.Collections;
-import java.util.LinkedList;
+import java.util.Iterator;
 import java.util.ListIterator;
+import java.util.Vector;
 
+import javax.swing.undo.AbstractUndoableEdit;
+import javax.swing.undo.CannotRedoException;
+import javax.swing.undo.CannotUndoException;
 import javax.swing.undo.UndoableEdit;
 
 /**
@@ -59,7 +64,6 @@ import javax.swing.undo.UndoableEdit;
 public class GapContent
     implements AbstractDocument.Content, Serializable
 {
-
   /**
    * A {@link Position} implementation for <code>GapContent</code>.
    */
@@ -114,6 +118,11 @@ public class GapContent
      */
     public int getOffset()
     {
+      // Check precondition.
+      assert mark <= gapStart || mark >= gapEnd : "mark: " + mark
+                                               + ", gapStart: " + gapStart
+                                               + ", gapEnd: " + gapEnd;
+
       if (mark <= gapStart)
         return mark;
       else
@@ -121,13 +130,91 @@ public class GapContent
     }
   }
 
-  private static final long serialVersionUID = 8374645204155842629L;
+  class UndoInsertString extends AbstractUndoableEdit
+  {
+    public int where, length;
+    String text;
+    public UndoInsertString(int start, int len)
+    {
+      where = start;
+      length = len;
+    }
+
+    public void undo () throws CannotUndoException
+    {
+      super.undo();
+      try
+      {
+        text = getString(where, length);
+        remove(where, length);
+      }
+      catch (BadLocationException ble)
+      {
+        throw new CannotUndoException();
+      }
+    }
+    
+    public void redo () throws CannotUndoException
+    {
+      super.redo();
+      try
+      {
+        insertString(where, text);
+      }
+      catch (BadLocationException ble)
+      {
+        throw new CannotRedoException();
+      }
+    }
+    
+  }
+  
+  class UndoRemove extends AbstractUndoableEdit
+  {
+    public int where;
+    String text;
+    public UndoRemove(int start, String removedText)
+    {
+      where = start;
+      text = removedText;
+    }
+
+    public void undo () throws CannotUndoException
+    {
+      super.undo();
+      try
+      {
+        insertString(where, text);
+      }
+      catch (BadLocationException ble)
+      {
+        throw new CannotUndoException();
+      }
+    }
+    
+    public void redo () throws CannotUndoException
+    {
+      super.redo();
+      try
+      {
+        remove(where, text.length());
+      }
+      catch (BadLocationException ble)
+      {
+        throw new CannotRedoException();
+      }
+    }
+    
+  }
+  
+  /** The serialization UID (compatible with JDK1.5). */
+  private static final long serialVersionUID = -6226052713477823730L;
 
   /**
    * This is the default buffer size and the amount of bytes that a buffer is
    * extended if it is full.
    */
-  static final int DEFAULT_BUFSIZE = 64;
+  static final int DEFAULT_BUFSIZE = 10;
 
   /**
    * The text buffer.
@@ -148,7 +235,7 @@ public class GapContent
    * The positions generated by this GapContent. They are kept in an ordered
    * fashion, so they can be looked up easily.
    */
-  LinkedList positions;
+  ArrayList positions;
 
   /**
    * Creates a new GapContent object.
@@ -166,10 +253,10 @@ public class GapContent
   public GapContent(int size)
   {
     buffer = (char[]) allocateArray(size);
-    gapStart = 0;
-    gapEnd = size - 1;
-    buffer[size - 1] = '\n';
-    positions = new LinkedList();
+    gapStart = 1;
+    gapEnd = size;
+    buffer[0] = '\n';
+    positions = new ArrayList();
   }
 
   /**
@@ -211,8 +298,7 @@ public class GapContent
    * @param where the position where the string is inserted
    * @param str the string that is to be inserted
    * 
-   * @return an UndoableEdit object (currently not supported, so
-   *         <code>null</code> is returned)
+   * @return an UndoableEdit object
    * 
    * @throws BadLocationException if <code>where</code> is not a valid
    *         location in the buffer
@@ -228,9 +314,9 @@ public class GapContent
       throw new BadLocationException("the where argument cannot be greater"
           + " than the content length", where);
 
-    replace(where, 0, str.toCharArray(), str.length());
+    replace(where, 0, str.toCharArray(), strLen);
 
-    return null;
+    return new UndoInsertString(where, strLen);
   }
 
   /**
@@ -239,8 +325,7 @@ public class GapContent
    * @param where the position where the content is to be removed
    * @param nitems number of characters to be removed
    * 
-   * @return an UndoableEdit object (currently not supported, so
-   *         <code>null</code> is returned)
+   * @return an UndoableEdit object
    * 
    * @throws BadLocationException if <code>where</code> is not a valid
    *         location in the buffer
@@ -257,9 +342,10 @@ public class GapContent
       throw new BadLocationException("where + nitems cannot be greater"
           + " than the content length", where + nitems);
 
+    String removedText = getString(where, nitems);
     replace(where, nitems, null, 0);
 
-    return null;
+    return new UndoRemove(where, removedText);
   }
 
   /**
@@ -372,7 +458,6 @@ public class GapContent
     if (index < 0)
       index = -(index + 1);
     positions.add(index, pos);
-
     return pos;
   }
 
@@ -386,7 +471,14 @@ public class GapContent
    */
   protected void shiftEnd(int newSize)
   {
-    int delta = (gapEnd - gapStart) - newSize;
+    assert newSize > (gapEnd - gapStart) : "The new gap size must be greater "
+                                           + "than the old gap size";
+
+    int delta = newSize - gapEnd + gapStart;
+    // Update the marks after the gapEnd.
+    adjustPositionsInRange(gapEnd, buffer.length - gapEnd, delta);
+
+    // Copy the data around.
     char[] newBuf = (char[]) allocateArray(length() + newSize);
     System.arraycopy(buffer, 0, newBuf, 0, gapStart);
     System.arraycopy(buffer, gapEnd, newBuf, gapStart + newSize, buffer.length
@@ -394,18 +486,6 @@ public class GapContent
     gapEnd = gapStart + newSize;
     buffer = newBuf;
 
-    // Update the marks after the gapEnd.
-    int index = Collections.binarySearch(positions, new GapContentPosition(
-        gapEnd));
-    if (index < 0)
-    {
-      index = -(index + 1);
-    }
-    for (ListIterator i = positions.listIterator(index); i.hasNext();)
-    {
-      GapContentPosition p = (GapContentPosition) i.next();
-      p.mark += delta;
-    }
   }
 
   /**
@@ -415,32 +495,15 @@ public class GapContent
    */
   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 GapContentPosition(gapEnd));
-    int index2 = Collections.binarySearch(positions,
-                                          new GapContentPosition(newGapEnd));
-    if (index1 > 0 && index2 > 0)
-      {
-        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;
-    else if (newGapStart < gapStart)
+
+    int newGapEnd = newGapStart + gapEnd - gapStart;
+    if (newGapStart < gapStart)
       {
+        // Update the positions between newGapStart and (old) gapStart. The marks
+        // must be shifted by (gapEnd - gapStart).
+        adjustPositionsInRange(newGapStart, gapStart - newGapStart, gapEnd - gapStart);
         System.arraycopy(buffer, newGapStart, buffer, newGapEnd, gapStart
                          - newGapStart);
         gapStart = newGapStart;
@@ -448,11 +511,54 @@ public class GapContent
       }
     else
       {
+        // Update the positions between newGapEnd and (old) gapEnd. The marks
+        // must be shifted by (gapEnd - gapStart).
+        adjustPositionsInRange(gapEnd, newGapEnd - gapEnd, -(gapEnd - gapStart));
         System.arraycopy(buffer, gapEnd, buffer, gapStart, newGapStart
                          - gapStart);
         gapStart = newGapStart;
         gapEnd = newGapEnd;
       }
+    if (gapStart == 0)
+      resetMarksAtZero();
+  }
+
+  /**
+   * Shifts the gap start downwards. This does not affect the content of the
+   * buffer. This only updates the gap start and all the marks that are between
+   * the old gap start and the new gap start. They all are squeezed to the start
+   * of the gap, because their location has been removed.
+   *
+   * @param newGapStart the new gap start
+   */
+  protected void shiftGapStartDown(int newGapStart)
+  {
+    if (newGapStart == gapStart)
+      return;
+
+    assert newGapStart < gapStart : "The new gap start must be less than the "
+                                    + "old gap start.";
+    setPositionsInRange(newGapStart, gapStart - newGapStart, gapStart);
+    gapStart = newGapStart;
+  }
+
+  /**
+   * Shifts the gap end upwards. This does not affect the content of the
+   * buffer. This only updates the gap end and all the marks that are between
+   * the old gap end and the new end start. They all are squeezed to the end
+   * of the gap, because their location has been removed.
+   *
+   * @param newGapEnd the new gap start
+   */
+  protected void shiftGapEndUp(int newGapEnd)
+  {
+    if (newGapEnd == gapEnd)
+      return;
+
+    assert newGapEnd > gapEnd : "The new gap end must be greater than the "
+                                + "old gap end.";
+    setPositionsInRange(gapEnd, newGapEnd - gapEnd, newGapEnd + 1);
+    gapEnd = newGapEnd;
   }
 
   /**
@@ -476,13 +582,15 @@ public class GapContent
   protected void replace(int position, int rmSize, Object addItems,
                          int addSize)
   {
+    if (gapStart != position)
+      shiftGap(position);
     // Remove content
-    shiftGap(position);
-    gapEnd += rmSize;
+    if (rmSize > 0)
+      shiftGapEndUp(gapEnd + rmSize);
 
     // If gap is too small, enlarge the gap.
-    if ((gapEnd - gapStart) < addSize)
-      shiftEnd(addSize);
+    if ((gapEnd - gapStart) <= addSize)
+      shiftEnd((addSize - gapEnd + gapStart + 1) * 2 + gapEnd + DEFAULT_BUFSIZE);
 
     // Add new items to the buffer.
     if (addItems != null)
@@ -491,4 +599,164 @@ public class GapContent
         gapStart += addSize;
       }
   }
+
+  /**
+   * Returns the start index of the gap within the buffer array.
+   *
+   * @return the start index of the gap within the buffer array
+   */
+  protected final int getGapStart()
+  {
+    return gapStart;
+  }
+
+  /**
+   * Returns the end index of the gap within the buffer array.
+   *
+   * @return the end index of the gap within the buffer array
+   */
+  protected final int getGapEnd()
+  {
+    return gapEnd;
+  }
+
+  /**
+   * Returns all <code>Position</code>s that are in the range specified by
+   * <code>offset</code> and </code>length</code> within the buffer array.
+   *
+   * @param v the vector to use; if <code>null</code>, a new Vector is allocated
+   * @param offset the start offset of the range to search
+   * @param length the length of the range to search
+   *
+   * @return the positions within the specified range
+   */
+  protected Vector getPositionsInRange(Vector v, int offset, int length)
+  {
+    Vector res = v;
+    if (res == null)
+      res = new Vector();
+    else
+      res.clear();
+
+    int endOffset = offset + length;
+
+    int index1 = Collections.binarySearch(positions,
+                                          new GapContentPosition(offset));
+    if (index1 < 0)
+      index1 = -(index1 + 1);
+    for (ListIterator i = positions.listIterator(index1); i.hasNext();)
+      {
+        GapContentPosition p = (GapContentPosition) i.next();
+        if (p.mark > endOffset)
+          break;
+        if (p.mark >= offset && p.mark <= endOffset)
+          res.add(p);
+      }
+    return res;
+  }
+  
+  /**
+   * Sets the mark of all <code>Position</code>s that are in the range 
+   * specified by <code>offset</code> and </code>length</code> within 
+   * the buffer array to <code>value</code>
+   *
+   * @param offset the start offset of the range to search
+   * @param length the length of the range to search
+   * @param value the new value for each mark
+   */
+  void setPositionsInRange(int offset, int length, int value)
+  {
+    int endOffset = offset + length;
+
+    int index1 = Collections.binarySearch(positions,
+                                          new GapContentPosition(offset));
+    if (index1 < 0)
+      index1 = -(index1 + 1);
+    for (ListIterator i = positions.listIterator(index1); i.hasNext();)
+      {
+        GapContentPosition p = (GapContentPosition) i.next();
+        if (p.mark > endOffset)
+          break;
+        
+        if (p.mark >= offset && p.mark <= endOffset)
+          p.mark = value;
+      }
+  }
+  
+  /**
+   * Adjusts the mark of all <code>Position</code>s that are in the range 
+   * specified by <code>offset</code> and </code>length</code> within 
+   * the buffer array by <code>increment</code>
+   *
+   * @param offset the start offset of the range to search
+   * @param length the length of the range to search
+   * @param incr the increment
+   */
+  void adjustPositionsInRange(int offset, int length, int incr)
+  {
+    int endOffset = offset + length;
+
+    int index1 = Collections.binarySearch(positions,
+                                          new GapContentPosition(offset));
+    if (index1 < 0)
+      index1 = -(index1 + 1);
+    for (ListIterator i = positions.listIterator(index1); i.hasNext();)
+      {
+        GapContentPosition p = (GapContentPosition) i.next();
+        if (p.mark > endOffset)
+          break;
+
+        if (p.mark >= offset && p.mark <= endOffset)
+          p.mark += incr;
+      }
+  }
+
+  /**
+   * Resets all <code>Position</code> that have an offset of <code>0</code>,
+   * to also have an array index of <code>0</code>. This might be necessary
+   * after a call to <code>shiftGap(0)</code>, since then the marks at offset
+   * <code>0</code> get shifted to <code>gapEnd</code>.
+   */
+  protected void resetMarksAtZero()
+  {
+    if (gapStart != 0)
+      return;
+
+    setPositionsInRange(gapEnd, 0, 0);
+  }
+
+  /**
+   * Outputs debugging info to System.err. It prints out the buffer array,
+   * the gapStart is marked by a &lt; sign, the gapEnd is marked by a &gt;
+   * sign and each position is marked by a # sign.
+   */
+  private void dump()
+  {
+    System.err.println("GapContent debug information");
+    System.err.println("buffer length: " + buffer.length);
+    System.err.println("gap start: " + gapStart);
+    System.err.println("gap end: " + gapEnd);
+    for (int i = 0; i < buffer.length; i++)
+      {
+        if (i == gapStart)
+          System.err.print('<');
+        if (i == gapEnd)
+          System.err.print('>');
+
+        if (!Character.isISOControl(buffer[i]))
+          System.err.print(buffer[i]);
+        else
+          System.err.print('.');
+      }
+    System.err.println();
+  }
+
+  private void dumpPositions()
+  {
+    for (Iterator i = positions.iterator(); i.hasNext();)
+      {
+        GapContentPosition pos = (GapContentPosition) i.next();
+        System.err.println("position at: " + pos.mark);
+      }
+  }
 }
diff --git a/libjava/classpath/javax/swing/text/GlyphView.java b/libjava/classpath/javax/swing/text/GlyphView.java
index f9e6097..eb1fadd 100644
--- a/libjava/classpath/javax/swing/text/GlyphView.java
+++ b/libjava/classpath/javax/swing/text/GlyphView.java
@@ -44,6 +44,12 @@ import java.awt.FontMetrics;
 import java.awt.Graphics;
 import java.awt.Rectangle;
 import java.awt.Shape;
+import java.awt.Toolkit;
+import java.text.BreakIterator;
+
+import javax.swing.SwingConstants;
+import javax.swing.event.DocumentEvent;
+import javax.swing.text.Position.Bias;
 
 /**
  * Renders a run of styled text. This {@link View} subclass paints the
@@ -52,9 +58,7 @@ import java.awt.Shape;
  *
  * @author Roman Kennke (roman@kennke.org)
  */
-public class GlyphView
-  extends View
-  implements TabableView, Cloneable
+public class GlyphView extends View implements TabableView, Cloneable
 {
 
   /**
@@ -68,15 +72,47 @@ public class GlyphView
      */
     public GlyphPainter()
     {
+      // Nothing to do here.
     }
 
     /**
+     * Returns the ascent of the font that is used by this glyph painter.
+     *
+     * @param v the glyph view
+     *
+     * @return the ascent of the font that is used by this glyph painter
+     */
+    public abstract float getAscent(GlyphView v);
+
+    /**
+     * Returns the descent of the font that is used by this glyph painter.
+     *
+     * @param v the glyph view
+     *
+     * @return the descent of the font that is used by this glyph painter
+     */
+    public abstract float getDescent(GlyphView v);
+
+    /**
      * Returns the full height of the rendered text.
      *
      * @return the full height of the rendered text
      */
     public abstract float getHeight(GlyphView view);
-    
+
+    /**
+     * Determines the model offset, so that the text between <code>p0</code>
+     * and this offset fits within the span starting at <code>x</code> with
+     * the length of <code>len</code>. 
+     *
+     * @param v the glyph view
+     * @param p0 the starting offset in the model
+     * @param x the start location in the view
+     * @param len the length of the span in the view
+     */
+    public abstract int getBoundedPosition(GlyphView v, int p0, float x,
+                                           float len);
+
     /**
      * Paints the glyphs.
      *
@@ -97,8 +133,8 @@ public class GlyphView
      * @param view the glyph view
      * @param pos the position of the character in the model
      * @param a the area that is occupied by the view
-     * @param bias either {@link Position.Bias.Forward} or
-     *        {@link Position.Bias.Backward} depending on the preferred
+     * @param b either {@link Position.Bias#Forward} or
+     *        {@link Position.Bias#Backward} depending on the preferred
      *        direction bias. If <code>null</code> this defaults to
      *        <code>Position.Bias.Forward</code>
      *
@@ -114,6 +150,20 @@ public class GlyphView
       throws BadLocationException;
 
     /**
+     * Maps a visual position into a document location.
+     *
+     * @param v the glyph view
+     * @param x the X coordinate of the visual position
+     * @param y the Y coordinate of the visual position
+     * @param a the allocated region
+     * @param biasRet filled with the bias of the model location on method exit
+     *
+     * @return the model location that represents the specified view location
+     */
+    public abstract int viewToModel(GlyphView v, float x, float y, Shape a,
+                                    Position.Bias[] biasRet);
+
+    /**
      * Determine the span of the glyphs from location <code>p0</code> to
      * location <code>p1</code>. If <code>te</code> is not <code>null</code>,
      * then TABs are expanded using this <code>TabExpander</code>.
@@ -122,7 +172,7 @@ public class GlyphView
      *
      * @param view the glyph view
      * @param p0 the starting location in the document model
-     * @param p0 the end location in the document model
+     * @param p1 the end location in the document model
      * @param te the tab expander to use
      * @param x the location at which the view is located
      *
@@ -132,6 +182,69 @@ public class GlyphView
     public abstract float getSpan(GlyphView view, int p0, int p1,
                                   TabExpander te, float x);
 
+
+    /**
+     * Returns the model location that should be used to place a caret when
+     * moving the caret through the document.
+     *
+     * @param v the glyph view
+     * @param pos the current model location
+     * @param b the bias for <code>p</code>
+     * @param a the allocated region for the glyph view
+     * @param direction the direction from the current position; Must be one of
+     *        {@link SwingConstants#EAST}, {@link SwingConstants#WEST},
+     *        {@link SwingConstants#NORTH} or {@link SwingConstants#SOUTH}
+     * @param biasRet filled with the bias of the resulting location when method
+     *        returns
+     *
+     * @return the location within the document that should be used to place the
+     *         caret when moving the caret around the document
+     *
+     * @throws BadLocationException if <code>pos</code> is an invalid model
+     *         location
+     * @throws IllegalArgumentException if <code>d</code> is invalid
+     */
+    public int getNextVisualPositionFrom(GlyphView v, int pos, Position.Bias b,
+                                         Shape a, int direction,
+                                         Position.Bias[] biasRet)
+      throws BadLocationException
+
+    {
+      int result = pos;
+      switch (direction)
+      {
+        case SwingConstants.EAST:
+          result = pos + 1;
+          break;
+        case SwingConstants.WEST:
+          result = pos - 1;
+          break;
+        case SwingConstants.NORTH:
+        case SwingConstants.SOUTH:
+        default:
+          // This should be handled in enclosing view, since the glyph view
+          // does not layout vertically.
+          break;
+      }
+      return result;
+    }
+
+    /**
+     * Returns a painter that can be used to render the specified glyph view.
+     * If this glyph painter is stateful, then it should return a new instance.
+     * However, if this painter is stateless it should return itself. The
+     * default behaviour is to return itself.
+     *
+     * @param v the glyph view for which to create a painter
+     * @param p0 the start offset of the rendered area
+     * @param p1 the end offset of the rendered area
+     *
+     * @return a painter that can be used to render the specified glyph view
+     */
+    public GlyphPainter getPainter(GlyphView v, int p0, int p1)
+    {
+      return this;
+    }
   }
 
   /**
@@ -147,7 +260,7 @@ public class GlyphView
     public float getHeight(GlyphView view)
     {
       Font font = view.getFont();
-      FontMetrics metrics = view.getContainer().getFontMetrics(font);
+      FontMetrics metrics = Toolkit.getDefaultToolkit().getFontMetrics(font);
       float height = metrics.getHeight();
       return height;
     }
@@ -173,11 +286,40 @@ public class GlyphView
       if (parent instanceof TabExpander)
         tabEx = (TabExpander) parent;
 
-      // FIXME: Set character attributes like font-family, font-size, colors.
-      Color foreground = view.getForeground();
-      g.setColor(foreground);
-      Utilities.drawTabbedText(txt, bounds.x, bounds.y, g, tabEx,
-                               txt.offset);
+      // Fill the background of the text run.
+      Color background = view.getBackground();
+      g.setColor(background);
+      int width = Utilities.getTabbedTextWidth(txt, g.getFontMetrics(),
+                                               bounds.x, tabEx, txt.offset);
+      g.fillRect(bounds.x, bounds.y, width, height);
+
+      // Draw the actual text.
+      g.setColor(view.getForeground());
+      g.setFont(view.getFont());
+      if (view.isSuperscript())
+        // TODO: Adjust font for superscripting.
+        Utilities.drawTabbedText(txt, bounds.x, bounds.y - height / 2, g, tabEx,
+                                   txt.offset);
+      else if (view.isSubscript())
+        // TODO: Adjust font for subscripting.
+        Utilities.drawTabbedText(txt, bounds.x, bounds.y + height / 2, g, tabEx,
+                                 txt.offset);
+      else
+        Utilities.drawTabbedText(txt, bounds.x, bounds.y, g, tabEx,
+                                 txt.offset);
+
+      if (view.isStikeThrough())
+        {
+          int strikeHeight = (int) (getAscent(view) / 2);
+          g.drawLine(bounds.x, bounds.y + strikeHeight, bounds.height + width,
+                     bounds.y + strikeHeight);
+        }
+      if (view.isUnderline())
+        {
+          int lineHeight = (int) getAscent(view);
+          g.drawLine(bounds.x, bounds.y + lineHeight, bounds.height + width,
+                     bounds.y + lineHeight);
+        }
     }
 
     /**
@@ -188,8 +330,8 @@ public class GlyphView
      * @param view the glyph view
      * @param pos the position of the character in the model
      * @param a the area that is occupied by the view
-     * @param bias either {@link Position.Bias.Forward} or
-     *        {@link Position.Bias.Backward} depending on the preferred
+     * @param b either {@link Position.Bias#Forward} or
+     *        {@link Position.Bias#Backward} depending on the preferred
      *        direction bias. If <code>null</code> this defaults to
      *        <code>Position.Bias.Forward</code>
      *
@@ -225,7 +367,7 @@ public class GlyphView
      *
      * @param view the glyph view
      * @param p0 the starting location in the document model
-     * @param p0 the end location in the document model
+     * @param p1 the end location in the document model
      * @param te the tab expander to use
      * @param x the location at which the view is located
      *
@@ -237,11 +379,90 @@ public class GlyphView
     {
       Element el = view.getElement();
       Font font = view.getFont();
-      FontMetrics fm = view.getContainer().getFontMetrics(font);
+      FontMetrics fm = Toolkit.getDefaultToolkit().getFontMetrics(font);
       Segment txt = view.getText(p0, p1);
       int span = Utilities.getTabbedTextWidth(txt, fm, (int) x, te, p0);
       return span;
     }
+
+    /**
+     * Returns the ascent of the text run that is rendered by this
+     * <code>GlyphPainter</code>.
+     *
+     * @param v the glyph view
+     *
+     * @return the ascent of the text run that is rendered by this
+     *         <code>GlyphPainter</code>
+     *
+     * @see FontMetrics#getAscent()
+     */
+    public float getAscent(GlyphView v)
+    {
+      Font font = v.getFont();
+      FontMetrics fm = v.getContainer().getFontMetrics(font);
+      return fm.getAscent();
+    }
+
+    /**
+     * Returns the descent of the text run that is rendered by this
+     * <code>GlyphPainter</code>.
+     *
+     * @param v the glyph view
+     *
+     * @return the descent of the text run that is rendered by this
+     *         <code>GlyphPainter</code>
+     *
+     * @see FontMetrics#getDescent()
+     */
+    public float getDescent(GlyphView v)
+    {
+      Font font = v.getFont();
+      FontMetrics fm = v.getContainer().getFontMetrics(font);
+      return fm.getDescent();
+    }
+
+    /**
+     * Determines the model offset, so that the text between <code>p0</code>
+     * and this offset fits within the span starting at <code>x</code> with
+     * the length of <code>len</code>. 
+     *
+     * @param v the glyph view
+     * @param p0 the starting offset in the model
+     * @param x the start location in the view
+     * @param len the length of the span in the view
+     */
+    public int getBoundedPosition(GlyphView v, int p0, float x, float len)
+    {
+      TabExpander te = v.getTabExpander();
+      Segment txt = v.getText(p0, v.getEndOffset());
+      Font font = v.getFont();
+      FontMetrics fm = v.getContainer().getFontMetrics(font);
+      int pos = Utilities.getTabbedTextOffset(txt, fm, (int) x,
+                                              (int) (x + len), te, p0, false);
+      return pos;
+    }
+
+    /**
+     * Maps a visual position into a document location.
+     *
+     * @param v the glyph view
+     * @param x the X coordinate of the visual position
+     * @param y the Y coordinate of the visual position
+     * @param a the allocated region
+     * @param biasRet filled with the bias of the model location on method exit
+     *
+     * @return the model location that represents the specified view location
+     */
+    public int viewToModel(GlyphView v, float x, float y, Shape a,
+                           Bias[] biasRet)
+    {
+      Rectangle b = a.getBounds();
+      assert b.contains(x, y) : "The coordinates are expected to be within the "
+                                + "view's bounds: x=" + x + ", y=" + y
+                                + "a=" + a;
+      int pos = getBoundedPosition(v, v.getStartOffset(), b.x, x - b.x);
+      return pos;
+    }
   }
 
   /**
@@ -250,6 +471,16 @@ public class GlyphView
   GlyphPainter glyphPainter;
 
   /**
+   * The start offset within the document for this view.
+   */
+  int startOffset;
+
+  /**
+   * The end offset within the document for this view.
+   */
+  int endOffset;
+
+  /**
    * Creates a new <code>GlyphView</code> for the given <code>Element</code>.
    *
    * @param element the element that is rendered by this GlyphView
@@ -257,6 +488,8 @@ public class GlyphView
   public GlyphView(Element element)
   {
     super(element);
+    startOffset = element.getStartOffset();
+    endOffset = element.getEndOffset();
   }
 
   /**
@@ -319,16 +552,21 @@ public class GlyphView
    */
   public float getPreferredSpan(int axis)
   {
-    Element el = getElement();
+    float span = 0;
     checkPainter();
     GlyphPainter painter = getGlyphPainter();
-    TabExpander tabEx = null;
-    View parent = getParent();
-    if (parent instanceof TabExpander)
-      tabEx = (TabExpander) parent;
-    // FIXME: Figure out how to determine the x parameter.
-    float span = painter.getSpan(this, el.getStartOffset(), el.getEndOffset(),
-                                 tabEx, 0.F);
+    if (axis == X_AXIS)
+      {
+        Element el = getElement();
+        TabExpander tabEx = null;
+        View parent = getParent();
+        if (parent instanceof TabExpander)
+          tabEx = (TabExpander) parent;
+        span = painter.getSpan(this, getStartOffset(), getEndOffset(),
+                               tabEx, 0.F);
+      }
+    else
+      span = painter.getHeight(this); 
     return span;
   }
 
@@ -372,8 +610,9 @@ public class GlyphView
    */
   public int viewToModel(float x, float y, Shape a, Position.Bias[] b)
   {
-    // FIXME: not implemented
-    return 0;
+    checkPainter();
+    GlyphPainter painter = getGlyphPainter();
+    return painter.viewToModel(this, x, y, a, b);
   }
 
   /**
@@ -383,12 +622,11 @@ public class GlyphView
    */
   public TabExpander getTabExpander()
   {
-    // TODO: Figure out if this is correct.
     TabExpander te = null;
     View parent = getParent();
 
-    if (parent instanceof ParagraphView)
-      te = (ParagraphView) parent;
+    if (parent instanceof TabExpander)
+      te = (TabExpander) parent;
     
     return te;
   }
@@ -428,23 +666,26 @@ public class GlyphView
       }
     catch (BadLocationException ex)
       {
-        throw new AssertionError("BadLocationException must not be thrown "
-                                 + "here");
+	AssertionError ae;
+        ae = new AssertionError("BadLocationException must not be thrown "
+				+ "here");
+	ae.initCause(ex);
+	throw ae;
       }
     FontMetrics fm = null; // Fetch font metrics somewhere.
     return Utilities.getTabbedTextWidth(seg, fm, 0, null, p0);
   }
 
   /**
-   * Returns the starting offset in the document model of the portion
+   * Returns the start offset in the document model of the portion
    * of text that this view is responsible for.
    *
-   * @return the starting offset in the document model of the portion
+   * @return the start offset in the document model of the portion
    *         of text that this view is responsible for
    */
-  public int getBeginIndex()
+  public int getStartOffset()
   {
-    return getElement().getStartOffset();
+    return startOffset;
   }
 
   /**
@@ -454,9 +695,9 @@ public class GlyphView
    * @return the end offset in the document model of the portion
    *         of text that this view is responsible for
    */
-  public int getEndIndex()
+  public int getEndOffset()
   {
-    return getElement().getEndOffset();
+    return endOffset;
   }
 
   /**
@@ -476,8 +717,11 @@ public class GlyphView
       }
     catch (BadLocationException ex)
       {
-        throw new AssertionError("BadLocationException should not be "
-                                 + "thrown here. p0 = " + p0 + ", p1 = " + p1);
+	AssertionError ae;
+        ae = new AssertionError("BadLocationException should not be "
+				+ "thrown here. p0 = " + p0 + ", p1 = " + p1);
+	ae.initCause(ex);
+	throw ae;
       }
 
     return txt;
@@ -518,4 +762,332 @@ public class GlyphView
     AttributeSet atts = el.getAttributes();
     return StyleConstants.getForeground(atts);
   }
+
+  /**
+   * Returns the background color which should be used to paint the text.
+   * This is fetched from the associated element's text attributes using
+   * {@link StyleConstants#getBackground}.
+   *
+   * @return the background color which should be used to paint the text
+   */
+  public Color getBackground()
+  {
+    Element el = getElement();
+    AttributeSet atts = el.getAttributes();
+    return StyleConstants.getBackground(atts);
+  }
+
+  /**
+   * Determines whether the text should be rendered strike-through or not. This
+   * is determined using the method
+   * {@link StyleConstants#isStrikeThrough(AttributeSet)} on the element of
+   * this view.
+   *
+   * @return whether the text should be rendered strike-through or not
+   */
+  public boolean isStikeThrough()
+  {
+    Element el = getElement();
+    AttributeSet atts = el.getAttributes();
+    return StyleConstants.isStrikeThrough(atts);
+  }
+
+  /**
+   * Determines whether the text should be rendered as subscript or not. This
+   * is determined using the method
+   * {@link StyleConstants#isSubscript(AttributeSet)} on the element of
+   * this view.
+   *
+   * @return whether the text should be rendered as subscript or not
+   */
+  public boolean isSubscript()
+  {
+    Element el = getElement();
+    AttributeSet atts = el.getAttributes();
+    return StyleConstants.isSubscript(atts);
+  }
+
+  /**
+   * Determines whether the text should be rendered as superscript or not. This
+   * is determined using the method
+   * {@link StyleConstants#isSuperscript(AttributeSet)} on the element of
+   * this view.
+   *
+   * @return whether the text should be rendered as superscript or not
+   */
+  public boolean isSuperscript()
+  {
+    Element el = getElement();
+    AttributeSet atts = el.getAttributes();
+    return StyleConstants.isSuperscript(atts);
+  }
+
+  /**
+   * Determines whether the text should be rendered as underlined or not. This
+   * is determined using the method
+   * {@link StyleConstants#isUnderline(AttributeSet)} on the element of
+   * this view.
+   *
+   * @return whether the text should be rendered as underlined or not
+   */
+  public boolean isUnderline()
+  {
+    Element el = getElement();
+    AttributeSet atts = el.getAttributes();
+    return StyleConstants.isUnderline(atts);
+  }
+
+  /**
+   * Creates and returns a shallow clone of this GlyphView. This is used by
+   * the {@link #createFragment} and {@link #breakView} methods.
+   *
+   * @return a shallow clone of this GlyphView
+   */
+  protected final Object clone()
+  {
+    try
+      {
+        return super.clone();
+      }
+    catch (CloneNotSupportedException ex)
+      {
+        AssertionError err = new AssertionError("CloneNotSupportedException "
+                                                + "must not be thrown here");
+        err.initCause(ex);
+        throw err;
+      }
+  }
+
+  /**
+   * Tries to break the view near the specified view span <code>len</code>.
+   * The glyph view can only be broken in the X direction. For Y direction it
+   * returns itself.
+   *
+   * @param axis the axis for breaking, may be {@link View#X_AXIS} or
+   *        {@link View#Y_AXIS}
+   * @param p0 the model location where the fragment should start
+   * @param pos the view position along the axis where the fragment starts
+   * @param len the desired length of the fragment view
+   *
+   * @return the fragment view, or <code>this</code> if breaking was not
+   *         possible
+   */
+  public View breakView(int axis, int p0, float pos, float len)
+  {
+    if (axis == Y_AXIS)
+      return this;
+
+    checkPainter();
+    GlyphPainter painter = getGlyphPainter();
+    int breakLocation = painter.getBoundedPosition(this, p0, pos, len);
+    // Try to find a suitable line break.
+    BreakIterator lineBreaker = BreakIterator.getLineInstance();
+    Segment txt = new Segment();
+    try
+      {
+        getDocument().getText(getStartOffset(), getEndOffset(), txt);
+      }
+    catch (BadLocationException ex)
+      {
+        AssertionError err = new AssertionError("BadLocationException must not "
+                                                + "be thrown here.");
+        err.initCause(ex);
+        throw err;
+      }
+    lineBreaker.setText(txt);
+    int goodBreakLocation = lineBreaker.previous();
+    if (goodBreakLocation != BreakIterator.DONE)
+      breakLocation = goodBreakLocation;
+
+    View brokenView = createFragment(p0, breakLocation);
+    return brokenView;
+  }
+
+  /**
+   * Determines how well the specified view location is suitable for inserting
+   * a line break. If <code>axis</code> is <code>View.Y_AXIS</code>, then
+   * this method forwards to the superclass, if <code>axis</code> is
+   * <code>View.X_AXIS</code> then this method returns
+   * {@link View#ExcellentBreakWeight} if there is a suitable break location
+   * (usually whitespace) within the specified view span, or
+   * {@link View#GoodBreakWeight} if not.
+   *
+   * @param axis the axis along which the break weight is requested
+   * @param pos the starting view location
+   * @param len the length of the span at which the view should be broken
+   *
+   * @return the break weight
+   */
+  public int getBreakWeight(int axis, float pos, float len)
+  {
+    int weight;
+    if (axis == Y_AXIS)
+      weight = super.getBreakWeight(axis, pos, len);
+    else
+      {
+        // Determine the model locations at pos and pos + len.
+        int spanX = (int) getPreferredSpan(X_AXIS);
+        int spanY = (int) getPreferredSpan(Y_AXIS);
+        Rectangle dummyAlloc = new Rectangle(0, 0, spanX, spanY);
+        Position.Bias[] biasRet = new Position.Bias[1];
+        int offset1 = viewToModel(pos, spanY / 2, dummyAlloc, biasRet);
+        int offset2 = viewToModel(pos, spanY / 2, dummyAlloc, biasRet);
+        Segment txt = getText(offset1, offset2);
+        BreakIterator lineBreaker = BreakIterator.getLineInstance();
+        lineBreaker.setText(txt);
+        int breakLoc = lineBreaker.previous();
+        if (breakLoc == offset1)
+          weight = View.BadBreakWeight;
+        else if(breakLoc ==  BreakIterator.DONE)
+          weight = View.GoodBreakWeight;
+        else
+          weight = View.ExcellentBreakWeight;
+      }
+    return weight;
+  }
+
+  /**
+   * Receives notification that some text attributes have changed within the
+   * text fragment that this view is responsible for. This calls
+   * {@link View#preferenceChanged(View, boolean, boolean)} on the parent for
+   * both width and height.
+   *
+   * @param e the document event describing the change; not used here
+   * @param a the view allocation on screen; not used here
+   * @param vf the view factory; not used here
+   */
+  public void changedUpdate(DocumentEvent e, Shape a, ViewFactory vf)
+  {
+    getParent().preferenceChanged(this, true, true);
+  }
+
+  /**
+   * Receives notification that some text has been inserted within the
+   * text fragment that this view is responsible for. This calls
+   * {@link View#preferenceChanged(View, boolean, boolean)} on the parent for
+   * width.
+   *
+   * @param e the document event describing the change; not used here
+   * @param a the view allocation on screen; not used here
+   * @param vf the view factory; not used here
+   */
+  public void insertUpdate(DocumentEvent e, Shape a, ViewFactory vf)
+  {
+    getParent().preferenceChanged(this, true, false);
+  }
+
+  /**
+   * Receives notification that some text has been removed within the
+   * text fragment that this view is responsible for. This calls
+   * {@link View#preferenceChanged(View, boolean, boolean)} on the parent for
+   * width.
+   *
+   * @param e the document event describing the change; not used here
+   * @param a the view allocation on screen; not used here
+   * @param vf the view factory; not used here
+   */
+  public void removeUpdate(DocumentEvent e, Shape a, ViewFactory vf)
+  {
+    getParent().preferenceChanged(this, true, false);
+  }
+
+  /**
+   * Creates a fragment view of this view that starts at <code>p0</code> and
+   * ends at <code>p1</code>.
+   *
+   * @param p0 the start location for the fragment view
+   * @param p1 the end location for the fragment view
+   *
+   * @return the fragment view
+   */
+  public View createFragment(int p0, int p1)
+  {
+    GlyphView fragment = (GlyphView) clone();
+    fragment.startOffset = p0;
+    fragment.endOffset = p1;
+    return fragment;
+  }
+
+  /**
+   * Returns the alignment of this view along the specified axis. For the Y
+   * axis this is <code>(height - descent) / height</code> for the used font,
+   * so that it is aligned along the baseline.
+   * For the X axis the superclass is called.
+   */
+  public float getAlignment(int axis)
+  {
+    float align;
+    if (axis == Y_AXIS)
+      {
+        checkPainter();
+        GlyphPainter painter = getGlyphPainter();
+        float height = painter.getHeight(this);
+        float descent = painter.getDescent(this);
+        align = (height - descent) / height; 
+      }
+    else
+      align = super.getAlignment(axis);
+
+    return align;
+  }
+
+  /**
+   * Returns the model location that should be used to place a caret when
+   * moving the caret through the document.
+   *
+   * @param pos the current model location
+   * @param bias the bias for <code>p</code>
+   * @param a the allocated region for the glyph view
+   * @param direction the direction from the current position; Must be one of
+   *        {@link SwingConstants#EAST}, {@link SwingConstants#WEST},
+   *        {@link SwingConstants#NORTH} or {@link SwingConstants#SOUTH}
+   * @param biasRet filled with the bias of the resulting location when method
+   *        returns
+   *
+   * @return the location within the document that should be used to place the
+   *         caret when moving the caret around the document
+   *
+   * @throws BadLocationException if <code>pos</code> is an invalid model
+   *         location
+   * @throws IllegalArgumentException if <code>d</code> is invalid
+   */
+  public int getNextVisualPositionFrom(int pos, Position.Bias bias, Shape a,
+                                       int direction, Position.Bias[] biasRet)
+    throws BadLocationException
+  {
+    checkPainter();
+    GlyphPainter painter = getGlyphPainter();
+    return painter.getNextVisualPositionFrom(this, pos, bias, a, direction,
+                                             biasRet);
+  }
+
+  /**
+   * Returns the document position that is (visually) nearest to the given
+   * document position <code>pos</code> in the given direction <code>d</code>.
+   *
+   * @param c the text component
+   * @param pos the document position
+   * @param b the bias for <code>pos</code>
+   * @param d the direction, must be either {@link SwingConstants#NORTH},
+   *        {@link SwingConstants#SOUTH}, {@link SwingConstants#WEST} or
+   *        {@link SwingConstants#EAST}
+   * @param biasRet an array of {@link Position.Bias} that can hold at least
+   *        one element, which is filled with the bias of the return position
+   *        on method exit
+   *
+   * @return the document position that is (visually) nearest to the given
+   *         document position <code>pos</code> in the given direction
+   *         <code>d</code>
+   *
+   * @throws BadLocationException if <code>pos</code> is not a valid offset in
+   *         the document model
+   */
+  public int getNextVisualPositionFrom(JTextComponent c, int pos,
+                                       Position.Bias b, int d,
+                                       Position.Bias[] biasRet)
+    throws BadLocationException
+  {
+    // TODO: Implement this properly.
+    throw new AssertionError("Not implemented yet.");
+  }
 }
diff --git a/libjava/classpath/javax/swing/text/IconView.java b/libjava/classpath/javax/swing/text/IconView.java
index c7e22b6..6dd0f7a 100644
--- a/libjava/classpath/javax/swing/text/IconView.java
+++ b/libjava/classpath/javax/swing/text/IconView.java
@@ -41,6 +41,8 @@ package javax.swing.text;
 import java.awt.Graphics;
 import java.awt.Shape;
 
+import javax.swing.SwingConstants;
+
 // TODO: Implement this class.
 public class IconView
   extends View
@@ -125,4 +127,34 @@ public class IconView
     // FIXME: not implemented
     return 0;
   }
+
+  /**
+   * Returns the document position that is (visually) nearest to the given
+   * document position <code>pos</code> in the given direction <code>d</code>.
+   *
+   * @param c the text component
+   * @param pos the document position
+   * @param b the bias for <code>pos</code>
+   * @param d the direction, must be either {@link SwingConstants#NORTH},
+   *        {@link SwingConstants#SOUTH}, {@link SwingConstants#WEST} or
+   *        {@link SwingConstants#EAST}
+   * @param biasRet an array of {@link Position.Bias} that can hold at least
+   *        one element, which is filled with the bias of the return position
+   *        on method exit
+   *
+   * @return the document position that is (visually) nearest to the given
+   *         document position <code>pos</code> in the given direction
+   *         <code>d</code>
+   *
+   * @throws BadLocationException if <code>pos</code> is not a valid offset in
+   *         the document model
+   */
+  public int getNextVisualPositionFrom(JTextComponent c, int pos,
+                                       Position.Bias b, int d,
+                                       Position.Bias[] biasRet)
+    throws BadLocationException
+  {
+    // TODO: Implement this properly.
+    throw new AssertionError("Not implemented yet.");
+  }
 }
diff --git a/libjava/classpath/javax/swing/text/InternationalFormatter.java b/libjava/classpath/javax/swing/text/InternationalFormatter.java
index cedaf59..86300a7 100644
--- a/libjava/classpath/javax/swing/text/InternationalFormatter.java
+++ b/libjava/classpath/javax/swing/text/InternationalFormatter.java
@@ -57,9 +57,8 @@ import javax.swing.JFormattedTextField;
 public class InternationalFormatter
   extends DefaultFormatter
 {
-
-  /** The serialVersoinUID. */
-  private static final long serialVersionUID = 6941977820906408656L;
+  /** The serialization UID (compatible with JDK1.5). */
+  private static final long serialVersionUID = 2436068675711756856L;
 
   /** The format that handles value to string conversion. */
   Format format;
diff --git a/libjava/classpath/javax/swing/text/JTextComponent.java b/libjava/classpath/javax/swing/text/JTextComponent.java
index b3fad79..83966bb 100644
--- a/libjava/classpath/javax/swing/text/JTextComponent.java
+++ b/libjava/classpath/javax/swing/text/JTextComponent.java
@@ -50,9 +50,9 @@ import java.awt.datatransfer.StringSelection;
 import java.awt.datatransfer.Transferable;
 import java.awt.datatransfer.UnsupportedFlavorException;
 import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
 import java.awt.event.InputMethodListener;
 import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
 import java.io.IOException;
 import java.io.Reader;
 import java.io.Writer;
@@ -72,7 +72,6 @@ import javax.swing.JViewport;
 import javax.swing.KeyStroke;
 import javax.swing.Scrollable;
 import javax.swing.SwingConstants;
-import javax.swing.Timer;
 import javax.swing.TransferHandler;
 import javax.swing.UIManager;
 import javax.swing.event.CaretEvent;
@@ -89,6 +88,7 @@ public abstract class JTextComponent extends JComponent
   /**
    * AccessibleJTextComponent
    */
+  // FIXME: This inner class is a complete stub and needs to be implemented.
   public class AccessibleJTextComponent extends AccessibleJComponent
     implements AccessibleText, CaretListener, DocumentListener
   {
@@ -99,6 +99,7 @@ public abstract class JTextComponent extends JComponent
      */
     public AccessibleJTextComponent()
     {
+      // Nothing to do here.
     }
 
     /**
@@ -301,50 +302,6 @@ public abstract class JTextComponent extends JComponent
   }
 
   /**
-   * The timer that lets the caret blink.
-   */
-  private class CaretBlinkTimer
-    extends Timer
-    implements ActionListener
-  {
-    /**
-     * Creates a new CaretBlinkTimer object with a default delay of 1 second.
-     */
-    public CaretBlinkTimer()
-    {
-      super(1000, null);
-      addActionListener(this);
-    }
-
-    /**
-     * Lets the caret blink.
-     */
-    public void actionPerformed(ActionEvent ev)
-    {
-      Caret c = caret;
-      if (c != null)
-	c.setVisible(!c.isVisible());
-    }
-
-    /**
-     * Updates the blink delay according to the current caret.
-     */
-    public void update()
-    {
-      stop();
-      Caret c = caret;
-      if (c != null)
-	{
-	  setDelay(c.getBlinkRate());
-	  if (editable)
-	    start();
-	  else
-	    c.setVisible(false);
-	}
-    }
-  }
-
-  /**
    * According to <a
    * href="http://java.sun.com/products/jfc/tsc/special_report/kestrel/keybindings.html">this
    * report</a>, a pair of private classes wraps a {@link
@@ -604,8 +561,7 @@ public abstract class JTextComponent extends JComponent
     }
   }
 
-  class DefaultTransferHandler
-    extends TransferHandler
+  class DefaultTransferHandler extends TransferHandler
   {
     public boolean canImport(JComponent component, DataFlavor[] flavors)
     {
@@ -631,23 +587,23 @@ public abstract class JTextComponent extends JComponent
       int end = textComponent.getSelectionEnd();
 
       if (start == end)
-	return;
+        return;
 
       try
-	{
-	  // Copy text to clipboard.
-	  String data = textComponent.getDocument().getText(start, end);
-	  StringSelection selection = new StringSelection(data);
-	  clipboard.setContents(selection, null);
-
-	  // Delete selected text on cut action.
-	  if (action == MOVE)
-	    doc.remove(start, end - start);
-	}
+        {
+          // Copy text to clipboard.
+          String data = textComponent.getDocument().getText(start, end);
+          StringSelection selection = new StringSelection(data);
+          clipboard.setContents(selection, null);
+
+          // Delete selected text on cut action.
+          if (action == MOVE)
+            doc.remove(start, end - start);
+        }
       catch (BadLocationException e)
-	{
-	  // Ignore this and do nothing.
-	}
+        {
+          // Ignore this and do nothing.
+        }
     }
     
     public int getSourceActions()
@@ -661,30 +617,30 @@ public abstract class JTextComponent extends JComponent
       DataFlavor[] flavors = transferable.getTransferDataFlavors();
 
       if (flavors == null)
-	return false;
+        return false;
 
       for (int i = 0; i < flavors.length; ++i)
-	if (flavors[i].equals(DataFlavor.stringFlavor))
-	   flavor = flavors[i];
+        if (flavors[i].equals(DataFlavor.stringFlavor))
+          flavor = flavors[i];
       
       if (flavor == null)
-	return false;
+        return false;
 
       try
-	{
-	  JTextComponent textComponent = (JTextComponent) component;
-	  String data = (String) transferable.getTransferData(flavor);
-	  textComponent.replaceSelection(data);
-	  return true;
-	}
+        {
+          JTextComponent textComponent = (JTextComponent) component;
+          String data = (String) transferable.getTransferData(flavor);
+          textComponent.replaceSelection(data);
+          return true;
+        }
       catch (IOException e)
-	{
-	  // Ignored.
-	}
+        {
+          // Ignored.
+        }
       catch (UnsupportedFlavorException e)
-	{
-	  // Ignored.
-	}
+        {
+          // Ignored.
+        }
 
       return false;
     }
@@ -701,8 +657,6 @@ public abstract class JTextComponent extends JComponent
   private char focusAccelerator = '\0';
   private NavigationFilter navigationFilter;
 
-  private CaretBlinkTimer caretBlinkTimer;
-
   /**
    * Get a Keymap from the global keymap table, by name.
    *
@@ -960,8 +914,6 @@ public abstract class JTextComponent extends JComponent
         creatingKeymap = true;
       }
 
-    caretBlinkTimer = new CaretBlinkTimer();
-
     setFocusable(true);
     setEditable(true);
     enableEvents(AWTEvent.KEY_EVENT_MASK);
@@ -1021,12 +973,17 @@ public abstract class JTextComponent extends JComponent
   {
     try
       {
-	doc.remove(0, doc.getLength());
-	doc.insertString(0, text, null);
+        if (doc instanceof AbstractDocument)
+          ((AbstractDocument) doc).replace(0, doc.getLength(), text, null);
+        else
+          {
+            doc.remove(0, doc.getLength());
+            doc.insertString(0, text, null);
+          }
       }
     catch (BadLocationException e)
       {
-	// This can never happen.
+        // This can never happen.
       }
   }
 
@@ -1044,12 +1001,12 @@ public abstract class JTextComponent extends JComponent
 
     try
       {
-	return doc.getText(0, doc.getLength());
+        return doc.getText(0, doc.getLength());
       }
     catch (BadLocationException e)
       {
-	// This should never happen.
-	return "";
+        // This should never happen.
+        return "";
       }
   }
 
@@ -1080,12 +1037,12 @@ public abstract class JTextComponent extends JComponent
   {
     try
       {
-	return doc.getText(getSelectionStart(), getSelectionEnd());
+        return doc.getText(getSelectionStart(), getSelectionEnd());
       }
     catch (BadLocationException e)
       {
-	// This should never happen.
-	return null;
+        // This should never happen.
+        return null;
       }
   }
 
@@ -1105,7 +1062,8 @@ public abstract class JTextComponent extends JComponent
    */
   protected String paramString()
   {
-    return "JTextComponent";
+    // TODO: Do something useful here.
+    return super.paramString();
   }
 
   /**
@@ -1194,14 +1152,6 @@ public abstract class JTextComponent extends JComponent
     if (editable == newValue)
       return;
 
-    if (newValue == true)
-      caretBlinkTimer.start();
-    else
-      {
-        caretBlinkTimer.stop();
-        caret.setVisible(false);
-      }
-
     boolean oldValue = editable;
     editable = newValue;
     firePropertyChange("editable", oldValue, newValue);
@@ -1230,8 +1180,6 @@ public abstract class JTextComponent extends JComponent
     Caret oldCaret = caret;
     caret = newCaret;
 
-    caretBlinkTimer.update();
-
     if (caret != null)
       caret.install(this);
     
@@ -1399,7 +1347,7 @@ public abstract class JTextComponent extends JComponent
     start = Math.max(start, 0);
     start = Math.min(start, length);
 
-    end = Math.max(end, 0);
+    end = Math.max(end, start);
     end = Math.min(end, length);
 
     setCaretPosition(start);
@@ -1422,28 +1370,28 @@ public abstract class JTextComponent extends JComponent
     // If content is empty delete selection.
     if (content == null)
       {
-	caret.setDot(dot);
-	return;
+        caret.setDot(dot);
+        return;
       }
 
     try
       {
-	int start = getSelectionStart();
-	int end = getSelectionEnd();
-	
-	// Remove selected text.
-	if (dot != mark)
-	  doc.remove(start, end - start);
-
-	// Insert new text.
-	doc.insertString(start, content, null);
-
-	// Set dot to new position.
-	setCaretPosition(start + content.length());
+        int start = getSelectionStart();
+        int end = getSelectionEnd();
+
+        // Remove selected text.
+        if (dot != mark)
+          doc.remove(start, end - start);
+
+        // Insert new text.
+        doc.insertString(start, content, null);
+
+        // Set dot to new position.
+        setCaretPosition(start + content.length());
       }
     catch (BadLocationException e)
       {
-	// This should never happen.
+        // This should never happen.
       }
   }
 
@@ -1577,15 +1525,15 @@ public abstract class JTextComponent extends JComponent
     // Install default TransferHandler if none set.
     if (getTransferHandler() == null)
       {
-	if (defaultTransferHandler == null)
-	  defaultTransferHandler = new DefaultTransferHandler();
-	
-	setTransferHandler(defaultTransferHandler);
+        if (defaultTransferHandler == null)
+          defaultTransferHandler = new DefaultTransferHandler();
+
+        setTransferHandler(defaultTransferHandler);
       }
 
     // Perform action.
     ActionEvent event = new ActionEvent(this, ActionEvent.ACTION_PERFORMED,
-					action.getValue(Action.NAME).toString());
+                                        action.getValue(Action.NAME).toString());
     action.actionPerformed(event);
   }
 
@@ -1669,5 +1617,20 @@ public abstract class JTextComponent extends JComponent
              throws IOException
   {
     output.write(getText());
-  }  
+  }
+
+  /**
+   * Returns the tooltip text for this text component for the given mouse
+   * event. This forwards the call to
+   * {@link TextUI#getToolTipText(JTextComponent, Point)}.
+   *
+   * @param ev the mouse event
+   *
+   * @return the tooltip text for this text component for the given mouse
+   *         event
+   */
+  public String getToolTipText(MouseEvent ev)
+  {
+    return getUI().getToolTipText(this, ev.getPoint());
+  }
 }
diff --git a/libjava/classpath/javax/swing/text/LabelView.java b/libjava/classpath/javax/swing/text/LabelView.java
index a103916..4890735 100644
--- a/libjava/classpath/javax/swing/text/LabelView.java
+++ b/libjava/classpath/javax/swing/text/LabelView.java
@@ -38,10 +38,57 @@ exception statement from your version. */
 
 package javax.swing.text;
 
-// TODO: Implement this class.
-public class LabelView
-  extends GlyphView
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Shape;
+
+import javax.swing.event.DocumentEvent;
+
+/**
+ * A {@link GlyphView} that caches the textattributes for most effective
+ * rendering.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+public class LabelView extends GlyphView
 {
+
+  /**
+   * The background color.
+   */
+  Color background;
+
+  /**
+   * The foreground color.
+   */
+  Color foreground;
+
+  /**
+   * The background color.
+   */
+  Font font;
+
+  /**
+   * The strikethrough flag.
+   */
+  boolean strikeThrough;
+
+  /**
+   * The underline flag.
+   */
+  boolean underline;
+
+  /**
+   * The subscript flag.
+   */
+  boolean subscript;
+
+  /**
+   * The superscript flag.
+   */
+  boolean superscript;
+
   /**
    * Creates a new <code>GlyphView</code> for the given <code>Element</code>.
    *
@@ -50,5 +97,194 @@ public class LabelView
   public LabelView(Element element)
   {
     super(element);
+    setPropertiesFromAttributes();
+  }
+
+  /**
+   * Loads the properties of this label view from the element's text
+   * attributes. This method is called from the constructor and the
+   * {@link #changedUpdate} method
+   */
+  protected void setPropertiesFromAttributes()
+  {
+    Element el = getElement();
+    AttributeSet atts = el.getAttributes();
+    background = StyleConstants.getBackground(atts);
+    foreground = StyleConstants.getForeground(atts);
+    strikeThrough = StyleConstants.isStrikeThrough(atts);
+    subscript = StyleConstants.isSubscript(atts);
+    superscript = StyleConstants.isSuperscript(atts);
+    underline = StyleConstants.isUnderline(atts);
+
+    // Determine the font.
+    String family = StyleConstants.getFontFamily(atts);
+    int size = StyleConstants.getFontSize(atts);
+    int style = Font.PLAIN;
+    if (StyleConstants.isBold(atts))
+        style |= Font.BOLD;
+    if (StyleConstants.isItalic(atts))
+      style |= Font.ITALIC;
+    font = new Font(family, style, size);
+  }
+
+  /**
+   * Receives notification when text attributes change in the chunk of
+   * text that this view is responsible for. This simply calls
+   * {@link #setPropertiesFromAttributes()}.
+   *
+   * @param e the document event
+   * @param a the allocation of this view
+   * @param vf the view factory to use for creating new views
+   */
+  public void changedUpdate(DocumentEvent e, Shape a, ViewFactory vf)
+  {
+    setPropertiesFromAttributes();
+  }
+
+  /**
+   * Returns the background color for the glyphs.
+   *
+   * @return the background color for the glyphs
+   */
+  public Color getBackground()
+  {
+    return background;
+  }
+
+  /**
+   * Sets the background color for the glyphs. A value of <code>null</code>
+   * means the background of the parent view should shine through.
+   *
+   * @param bg the background to set or <code>null</code>
+   *
+   * @since 1.5
+   */
+  protected void setBackground(Color bg)
+  {
+    background = bg;
+  }
+
+  /**
+   * Returns the foreground color for the glyphs.
+   *
+   * @return the foreground color for the glyphs
+   */
+  public Color getForeground()
+  {
+    return foreground;
+  }
+
+  /**
+   * Returns the font for the glyphs.
+   *
+   * @return the font for the glyphs
+   */
+  public Font getFont()
+  {
+    return font;
+  }
+
+  /**
+   * Returns the font metrics of the current font.
+   *
+   * @return the font metrics of the current font
+   *
+   * @deprecated this is not used anymore
+   */
+  protected FontMetrics getFontMetrics()
+  {
+    return getContainer().getGraphics().getFontMetrics(font);
+  }
+
+  /**
+   * Returns <code>true</code> if the glyphs are rendered underlined,
+   * <code>false</code> otherwise.
+   *
+   * @return <code>true</code> if the glyphs are rendered underlined,
+   *         <code>false</code> otherwise
+   */
+  public boolean isUnderline()
+  {
+    return underline;
+  }
+
+  /**
+   * Sets the underline flag.
+   *
+   * @param flag <code>true</code> if the glyphs are rendered underlined,
+   *             <code>false</code> otherwise
+   */
+  protected void setUnderline(boolean flag)
+  {
+    underline = flag;
+  }
+
+  /**
+   * Returns <code>true</code> if the glyphs are rendered as subscript,
+   * <code>false</code> otherwise.
+   *
+   * @return <code>true</code> if the glyphs are rendered as subscript,
+   *         <code>false</code> otherwise
+   */
+  public boolean isSubscript()
+  {
+    return subscript;
+  }
+
+  /**
+   * Sets the subscript flag.
+   *
+   * @param flag <code>true</code> if the glyphs are rendered as subscript,
+   *             <code>false</code> otherwise
+   */
+  protected void setSubscript(boolean flag)
+  {
+    subscript = flag;
+  }
+
+  /**
+   * Returns <code>true</code> if the glyphs are rendered as superscript,
+   * <code>false</code> otherwise.
+   *
+   * @return <code>true</code> if the glyphs are rendered as superscript,
+   *         <code>false</code> otherwise
+   */
+  public boolean isSuperscript()
+  {
+    return superscript;
+  }
+
+  /**
+   * Sets the superscript flag.
+   *
+   * @param flag <code>true</code> if the glyphs are rendered as superscript,
+   *             <code>false</code> otherwise
+   */
+  protected void setSuperscript(boolean flag)
+  {
+    superscript = flag;
+  }
+
+  /**
+   * Returns <code>true</code> if the glyphs are rendered strike-through,
+   * <code>false</code> otherwise.
+   *
+   * @return <code>true</code> if the glyphs are rendered strike-through,
+   *         <code>false</code> otherwise
+   */
+  public boolean isStrikeThrough()
+  {
+    return strikeThrough;
+  }
+
+  /**
+   * Sets the strike-through flag.
+   *
+   * @param flag <code>true</code> if the glyphs are rendered strike-through,
+   *             <code>false</code> otherwise
+   */
+  protected void setStrikeThrough(boolean flag)
+  {
+    strikeThrough = flag;
   }
 }
diff --git a/libjava/classpath/javax/swing/text/LayoutQueue.java b/libjava/classpath/javax/swing/text/LayoutQueue.java
index 83433b6..b0c84b9 100644
--- a/libjava/classpath/javax/swing/text/LayoutQueue.java
+++ b/libjava/classpath/javax/swing/text/LayoutQueue.java
@@ -57,6 +57,7 @@ public class LayoutQueue
    */
   public LayoutQueue()
   {
+    // Nothing to do here.
   }
 
   /**
diff --git a/libjava/classpath/javax/swing/text/ParagraphView.java b/libjava/classpath/javax/swing/text/ParagraphView.java
index 6c6006a..6fb121f 100644
--- a/libjava/classpath/javax/swing/text/ParagraphView.java
+++ b/libjava/classpath/javax/swing/text/ParagraphView.java
@@ -59,6 +59,11 @@ public class ParagraphView extends FlowView implements TabExpander
     {
       super(el, X_AXIS);
     }
+    public float getAlignment(int axis)
+    {
+      // FIXME: This is very likely not 100% correct. Work this out.
+      return 0.0F;
+    }
   }
 
   /**
@@ -86,4 +91,29 @@ public class ParagraphView extends FlowView implements TabExpander
   {
     return new Row(getElement());
   }
+
+  /**
+   * Returns the alignment for this paragraph view for the specified axis.
+   * For the X_AXIS the paragraph view will be aligned at it's left edge
+   * (0.0F). For the Y_AXIS the paragraph view will be aligned at the
+   * center of it's first row.
+   *
+   * @param axis the axis which is examined
+   *
+   * @return the alignment for this paragraph view for the specified axis
+   */
+  public float getAlignment(int axis)
+  {
+    if (axis == X_AXIS)
+      return 0.0F;
+    else if (getViewCount() > 0)
+      {
+
+        float prefHeight = getPreferredSpan(Y_AXIS);
+        float firstRowHeight = getView(0).getPreferredSpan(Y_AXIS);
+        return (firstRowHeight / 2.F) / prefHeight;
+      }
+    else
+      return 0.0F;
+  }
 }
diff --git a/libjava/classpath/javax/swing/text/PlainDocument.java b/libjava/classpath/javax/swing/text/PlainDocument.java
index 71070e9..9e600c4 100644
--- a/libjava/classpath/javax/swing/text/PlainDocument.java
+++ b/libjava/classpath/javax/swing/text/PlainDocument.java
@@ -132,8 +132,8 @@ public class PlainDocument extends AbstractDocument
         // collapse elements if the removal spans more than 1 line
         Element newEl = createLeafElement(rootElement,
                                           SimpleAttributeSet.EMPTY,
-                                          start, end - len);
-        rootElement.replace(i1, i2 - i1, new Element[]{ newEl });
+                                          start, end);
+        rootElement.replace(i1, i2 - i1 + 1, new Element[]{ newEl });
       }
   }
 
@@ -147,4 +147,28 @@ public class PlainDocument extends AbstractDocument
     Element root = getDefaultRootElement();
     return root.getElement(root.getElementIndex(pos));
   }
+
+  /**
+   * Inserts a string into the document. If the document property
+   * '<code>filterNewLines</code>' is set to <code>Boolean.TRUE</code>, then
+   * all newlines in the inserted string are replaced by space characters,
+   * otherwise the superclasses behaviour is executed.
+   *
+   * Inserting content causes a write lock to be acquired during this method
+   * call.
+   *
+   * @param offs the offset at which to insert the string
+   * @param str the string to be inserted
+   * @param atts the text attributes of the string to be inserted
+   *
+   * @throws BadLocationException
+   */
+  public void insertString(int offs, String str, AttributeSet atts)
+    throws BadLocationException
+  {
+    String string = str;
+    if (Boolean.TRUE.equals(getProperty("filterNewlines")))
+      string = str.replaceAll("\n", " ");
+    super.insertString(offs, string, atts);
+  }
 }
diff --git a/libjava/classpath/javax/swing/text/PlainView.java b/libjava/classpath/javax/swing/text/PlainView.java
index 91d7547..9f5ee8ad 100644
--- a/libjava/classpath/javax/swing/text/PlainView.java
+++ b/libjava/classpath/javax/swing/text/PlainView.java
@@ -46,15 +46,35 @@ import java.awt.Graphics;
 import java.awt.Rectangle;
 import java.awt.Shape;
 
-public class PlainView extends View
-  implements TabExpander
+import javax.swing.SwingConstants;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentEvent.ElementChange;
+
+public class PlainView extends View implements TabExpander
 {
   Color selectedColor;
   Color unselectedColor;
+
+  /**
+   * The color that is used to draw disabled text fields.
+   */
+  Color disabledColor;
+
   Font font;
   
+  /** The length of the longest line in the Document **/
+  float maxLineLength = -1;
+  
+  /** The longest line in the Document **/
+  Element longestLine = null;
+  
   protected FontMetrics metrics;
 
+  /**
+   * The instance returned by {@link #getLineBuffer()}.
+   */
+  private transient Segment lineBuffer;
+
   public PlainView(Element elem)
   {
     super(elem);
@@ -104,7 +124,7 @@ public class PlainView extends View
     // Get the rectangle for position.
     Element line = getElement().getElement(lineIndex);
     int lineStart = line.getStartOffset();
-    Segment segment = new Segment();
+    Segment segment = getLineBuffer();
     document.getText(lineStart, position - lineStart, segment);
     int xoffset = Utilities.getTabbedTextWidth(segment, metrics, rect.x,
 					       this, lineStart);
@@ -129,7 +149,9 @@ public class PlainView extends View
       }
     catch (BadLocationException e)
       {
-	// This should never happen.
+	AssertionError ae = new AssertionError("Unexpected bad location");
+	ae.initCause(e);
+	throw ae;
       }
   }
 
@@ -137,7 +159,7 @@ public class PlainView extends View
     throws BadLocationException
   {
     g.setColor(selectedColor);
-    Segment segment = new Segment();
+    Segment segment = getLineBuffer();
     getDocument().getText(p0, p1 - p0, segment);
     return Utilities.drawTabbedText(segment, x, y, g, this, 0);
   }
@@ -145,8 +167,13 @@ public class PlainView extends View
   protected int drawUnselectedText(Graphics g, int x, int y, int p0, int p1)
     throws BadLocationException
   {
-    g.setColor(unselectedColor);
-    Segment segment = new Segment();
+    JTextComponent textComponent = (JTextComponent) getContainer();
+    if (textComponent.isEnabled())
+      g.setColor(unselectedColor);
+    else
+      g.setColor(disabledColor);
+
+    Segment segment = getLineBuffer();
     getDocument().getText(p0, p1 - p0, segment);
     return Utilities.drawTabbedText(segment, x, y, g, this, segment.offset);
   }
@@ -161,7 +188,8 @@ public class PlainView extends View
     g.setFont(textComponent.getFont());
     selectedColor = textComponent.getSelectedTextColor();
     unselectedColor = textComponent.getForeground();
-    
+    disabledColor = textComponent.getDisabledTextColor();
+
     Rectangle rect = s.getBounds();
 
     // FIXME: Text may be scrolled.
@@ -176,9 +204,19 @@ public class PlainView extends View
       }
   }
 
+  /**
+   * Returns the tab size of a tab.  Checks the Document's
+   * properties for PlainDocument.tabSizeAttribute and returns it if it is
+   * defined, otherwise returns 8.
+   * 
+   * @return the tab size.
+   */
   protected int getTabSize()
   {
-    return 8;
+    Object tabSize = getDocument().getProperty(PlainDocument.tabSizeAttribute);
+    if (tabSize == null)
+      return 8;
+    return ((Integer)tabSize).intValue();
   }
 
   /**
@@ -191,10 +229,54 @@ public class PlainView extends View
    */
   public float nextTabStop(float x, int tabStop)
   {
-    float tabSizePixels = getTabSize() + metrics.charWidth('m');
+    float tabSizePixels = getTabSize() * metrics.charWidth('m');
     return (float) (Math.floor(x / tabSizePixels) + 1) * tabSizePixels;
   }
 
+  /**
+   * Returns the length of the longest line, used for getting the span
+   * @return the length of the longest line
+   */
+  float determineMaxLineLength()
+  {
+    // if the longest line is cached, return the cached value
+    if (maxLineLength != -1)
+      return maxLineLength;
+    
+    // otherwise we have to go through all the lines and find it
+    Element el = getElement();
+    Segment seg = getLineBuffer();
+    float span = 0;
+    for (int i = 0; i < el.getElementCount(); i++)
+      {
+        Element child = el.getElement(i);
+        int start = child.getStartOffset();
+        int end = child.getEndOffset();
+        try
+          {
+            el.getDocument().getText(start, end - start, seg);
+          }
+        catch (BadLocationException ex)
+          {
+            AssertionError ae = new AssertionError("Unexpected bad location");
+	    ae.initCause(ex);
+	    throw ae;
+          }
+        
+        if (seg == null || seg.array == null || seg.count == 0)
+          continue;
+        
+        int width = metrics.charsWidth(seg.array, seg.offset, seg.count);
+        if (width > span)
+          {
+            longestLine = child;
+            span = width;
+          }
+      }
+    maxLineLength = span;
+    return maxLineLength;
+  }
+  
   public float getPreferredSpan(int axis)
   {
     if (axis != X_AXIS && axis != Y_AXIS)
@@ -205,36 +287,16 @@ public class PlainView extends View
 
     float span = 0;
     Element el = getElement();
-    Document doc = el.getDocument();
-    Segment seg = new Segment();
 
     switch (axis)
       {
       case X_AXIS:
-        // calculate the maximum of the line's widths
-        for (int i = 0; i < el.getElementCount(); i++)
-          {
-            Element child = el.getElement(i);
-            int start = child.getStartOffset();
-            int end = child.getEndOffset();
-            try {
-              doc.getText(start, start + end, seg);
-            }
-            catch (BadLocationException ex)
-              {
-                // throw new ClasspathAssertionError
-                // ("no BadLocationException should be thrown here");
-              }
-            int width = metrics.charsWidth(seg.array, seg.offset, seg.count);
-            span = Math.max(span, width);
-          }
-        break;
+        span = determineMaxLineLength();
       case Y_AXIS:
       default:
         span = metrics.getHeight() * el.getElementCount();
         break;
       }
-
     return span;
   }
 
@@ -252,8 +314,251 @@ public class PlainView extends View
    */
   public int viewToModel(float x, float y, Shape a, Position.Bias[] b)
   {
-    // FIXME: not implemented
-    return 0;
+    Rectangle rec = a.getBounds();
+    Document doc = getDocument();
+    Element root = doc.getDefaultRootElement();
+    
+    // PlainView doesn't support line-wrapping so we can find out which
+    // Element was clicked on just by the y-position    
+    int lineClicked = (int) (y - rec.y) / metrics.getHeight();
+    if (lineClicked >= root.getElementCount())
+      return getEndOffset() - 1;
+    
+    Element line = root.getElement(lineClicked);
+    Segment s = getLineBuffer();
+    int start = line.getStartOffset();
+    // We don't want the \n at the end of the line.
+    int end = line.getEndOffset() - 1;
+    try
+      {
+        doc.getText(start, end - start, s);
+      }
+    catch (BadLocationException ble)
+      {
+        AssertionError ae = new AssertionError("Unexpected bad location");
+        ae.initCause(ble);
+        throw ae;
+      }
+    
+    int pos = Utilities.getTabbedTextOffset(s, metrics, rec.x, (int)x, this, start);
+    return Math.max (0, pos);
+  }     
+  
+  /**
+   * Since insertUpdate and removeUpdate each deal with children
+   * Elements being both added and removed, they both have to perform
+   * the same checks.  So they both simply call this method.
+   * @param changes the DocumentEvent for the changes to the Document.
+   * @param a the allocation of the View.
+   * @param f the ViewFactory to use for rebuilding.
+   */
+  protected void updateDamage(DocumentEvent changes, Shape a, ViewFactory f)
+  {
+    Element el = getElement();
+    ElementChange ec = changes.getChange(el);
+    
+    // If ec is null then no lines were added or removed, just 
+    // repaint the changed line
+    if (ec == null)
+      {
+        int line = getElement().getElementIndex(changes.getOffset());
+        damageLineRange(line, line, a, getContainer());
+        return;
+      }
+    
+    Element[] removed = ec.getChildrenRemoved();
+    Element[] newElements = ec.getChildrenAdded();
+    
+    // If no Elements were added or removed, we just want to repaint
+    // the area containing the line that was modified
+    if (removed == null && newElements == null)
+      {
+        int line = getElement().getElementIndex(changes.getOffset());
+        damageLineRange(line, line, a, getContainer());
+        return;
+      }
+
+    // Check to see if we removed the longest line, if so we have to
+    // search through all lines and find the longest one again
+    if (removed != null)
+      {
+        for (int i = 0; i < removed.length; i++)
+          if (removed[i].equals(longestLine))
+            {
+              // reset maxLineLength and search through all lines for longest one
+              maxLineLength = -1;
+              determineMaxLineLength();
+              ((JTextComponent)getContainer()).repaint();
+              return;
+            }
+      }
+    
+    // If we've reached here, that means we haven't removed the longest line
+    if (newElements == null)
+      {
+        // No lines were added, just repaint the container and exit
+        ((JTextComponent)getContainer()).repaint();
+        return;
+      }
+
+    //  Make sure we have the metrics
+    updateMetrics();
+       
+    // If we've reached here, that means we haven't removed the longest line
+    // and we have added at least one line, so we have to check if added lines
+    // are longer than the previous longest line        
+    Segment seg = getLineBuffer();
+    float longestNewLength = 0;
+    Element longestNewLine = null;    
+
+    // Loop through the added lines to check their length
+    for (int i = 0; i < newElements.length; i++)
+      {
+        Element child = newElements[i];
+        int start = child.getStartOffset();
+        int end = child.getEndOffset();
+        try
+          {
+            el.getDocument().getText(start, end - start, seg);
+          }
+        catch (BadLocationException ex)
+          {
+            AssertionError ae = new AssertionError("Unexpected bad location");
+	    ae.initCause(ex);
+	    throw ae;
+          }
+                
+        if (seg == null || seg.array == null || seg.count == 0)
+          continue;
+        
+        int width = metrics.charsWidth(seg.array, seg.offset, seg.count);
+        if (width > longestNewLength)
+          {
+            longestNewLine = child;
+            longestNewLength = width;
+          }
+      }
+    
+    // Check if the longest of the new lines is longer than our previous
+    // longest line, and if so update our values
+    if (longestNewLength > maxLineLength)
+      {
+        maxLineLength = longestNewLength;
+        longestLine = longestNewLine;
+      }
+    // Repaint the container
+    ((JTextComponent)getContainer()).repaint();
+  }
+
+  /**
+   * This method is called when something is inserted into the Document
+   * that this View is displaying.
+   * 
+   * @param changes the DocumentEvent for the changes.
+   * @param a the allocation of the View
+   * @param f the ViewFactory used to rebuild
+   */
+  public void insertUpdate(DocumentEvent changes, Shape a, ViewFactory f)
+  {
+    updateDamage(changes, a, f);
+  }
+
+  /**
+   * This method is called when something is removed from the Document
+   * that this View is displaying.
+   * 
+   * @param changes the DocumentEvent for the changes.
+   * @param a the allocation of the View
+   * @param f the ViewFactory used to rebuild
+   */
+  public void removeUpdate(DocumentEvent changes, Shape a, ViewFactory f)
+  {
+    updateDamage(changes, a, f);
+  }
+  
+  /**
+   * This method is called when attributes were changed in the 
+   * Document in a location that this view is responsible for.
+   */
+  public void changedUpdate (DocumentEvent changes, Shape a, ViewFactory f)
+  {
+    updateDamage(changes, a, f);
+  }
+  
+  /**
+   * Repaint the given line range.  This is called from insertUpdate,
+   * changedUpdate, and removeUpdate when no new lines were added 
+   * and no lines were removed, to repaint the line that was 
+   * modified.
+   * 
+   * @param line0 the start of the range
+   * @param line1 the end of the range
+   * @param a the rendering region of the host
+   * @param host the Component that uses this View (used to call repaint
+   * on that Component)
+   * 
+   * @since 1.4
+   */
+  protected void damageLineRange (int line0, int line1, Shape a, Component host)
+  {
+    if (a == null)
+      return;
+
+    Rectangle rec0 = lineToRect(a, line0);
+    Rectangle rec1 = lineToRect(a, line1);
+
+    if (rec0 == null || rec1 == null)
+      // something went wrong, repaint the entire host to be safe
+      host.repaint();
+    else
+      {
+        Rectangle repaintRec = rec0.union(rec1);
+        host.repaint();
+      }    
+  }
+
+  /**
+   * Provides a {@link Segment} object, that can be used to fetch text from
+   * the document.
+   *
+   * @returna {@link Segment} object, that can be used to fetch text from
+   *          the document
+   */
+  protected Segment getLineBuffer()
+  {
+    if (lineBuffer == null)
+      lineBuffer = new Segment();
+    return lineBuffer;
+  }
+
+  /**
+   * Returns the document position that is (visually) nearest to the given
+   * document position <code>pos</code> in the given direction <code>d</code>.
+   *
+   * @param c the text component
+   * @param pos the document position
+   * @param b the bias for <code>pos</code>
+   * @param d the direction, must be either {@link SwingConstants#NORTH},
+   *        {@link SwingConstants#SOUTH}, {@link SwingConstants#WEST} or
+   *        {@link SwingConstants#EAST}
+   * @param biasRet an array of {@link Position.Bias} that can hold at least
+   *        one element, which is filled with the bias of the return position
+   *        on method exit
+   *
+   * @return the document position that is (visually) nearest to the given
+   *         document position <code>pos</code> in the given direction
+   *         <code>d</code>
+   *
+   * @throws BadLocationException if <code>pos</code> is not a valid offset in
+   *         the document model
+   */
+  public int getNextVisualPositionFrom(JTextComponent c, int pos,
+                                       Position.Bias b, int d,
+                                       Position.Bias[] biasRet)
+    throws BadLocationException
+  {
+    // TODO: Implement this properly.
+    throw new AssertionError("Not implemented yet.");
   }
 }
 
diff --git a/libjava/classpath/javax/swing/text/Segment.java b/libjava/classpath/javax/swing/text/Segment.java
index 92d8500..84e0e70 100644
--- a/libjava/classpath/javax/swing/text/Segment.java
+++ b/libjava/classpath/javax/swing/text/Segment.java
@@ -39,8 +39,7 @@ package javax.swing.text;
 
 import java.text.CharacterIterator;
 
-public class Segment
-  implements Cloneable, CharacterIterator
+public class Segment implements Cloneable, CharacterIterator
 {
   private boolean partialReturn;
   private int current;
@@ -51,6 +50,7 @@ public class Segment
 
   public Segment()
   {
+    // Nothing to do here.
   }
 
   public Segment(char[] array, int offset, int count)
diff --git a/libjava/classpath/javax/swing/text/SimpleAttributeSet.java b/libjava/classpath/javax/swing/text/SimpleAttributeSet.java
index 3ef5db6..0c9f607 100644
--- a/libjava/classpath/javax/swing/text/SimpleAttributeSet.java
+++ b/libjava/classpath/javax/swing/text/SimpleAttributeSet.java
@@ -45,6 +45,9 @@ import java.util.Hashtable;
 public class SimpleAttributeSet
   implements MutableAttributeSet, Serializable, Cloneable
 {
+  /** The serialization UID (compatible with JDK1.5). */
+  private static final long serialVersionUID = 8267656273837665219L;
+
   public static final AttributeSet EMPTY = new SimpleAttributeSet();
 
   Hashtable tab;
@@ -84,12 +87,34 @@ public class SimpleAttributeSet
     return s;
   }
 
+  /**
+   * Returns true if the given name and value represent an attribute
+   * found either in this AttributeSet or in its resolve parent hierarchy.
+   * @param name the key for the attribute
+   * @param value the value for the attribute
+   * @return true if the attribute is found here or in this set's resolve
+   * parent hierarchy
+   */
   public boolean containsAttribute(Object name, Object value)
   {
+    return (tab.containsKey(name) && tab.get(name).equals(value)) || 
+      (getResolveParent() != null && getResolveParent().
+       containsAttribute(name, value));
+  }
+  
+  /**
+   * Returns true if the given name and value are found in this AttributeSet.
+   * Does not check the resolve parent.
+   * @param name the key for the attribute
+   * @param value the value for the attribute
+   * @return true if the attribute is found in this AttributeSet
+   */
+  boolean containsAttributeLocally(Object name, Object value)
+  {
     return tab.containsKey(name) 
       && tab.get(name).equals(value);
   }
-    
+
   public boolean containsAttributes(AttributeSet attributes)
   {
     Enumeration e = attributes.getAttributeNames();
@@ -110,9 +135,9 @@ public class SimpleAttributeSet
 
   public boolean equals(Object obj)
   {
-    return (obj != null) 
-      && (obj instanceof SimpleAttributeSet)
-      && ((SimpleAttributeSet)obj).tab.equals(this.tab);
+    return 
+      (obj instanceof AttributeSet)
+      && this.isEqual((AttributeSet) obj);
   }
 
   public Object getAttribute(Object name)
@@ -157,10 +182,16 @@ public class SimpleAttributeSet
   {
     return tab.isEmpty();	
   }
-        
+
+  /**
+   * Returns true if the given set has the same number of attributes
+   * as this set and <code>containsAttributes(attr)</code> returns
+   * true.
+   */
   public boolean isEqual(AttributeSet attr)
   {
-    return this.equals(attr);
+    return getAttributeCount() == attr.getAttributeCount()
+      && this.containsAttributes(attr);
   }
     
   public void removeAttribute(Object name)
@@ -168,9 +199,21 @@ public class SimpleAttributeSet
     tab.remove(name);
   }
 
+  /**
+   * Removes attributes from this set if they are found in the 
+   * given set.  Only attributes whose key AND value are removed.
+   * Removes attributes only from this set, not from the resolving parent.
+   */
   public void removeAttributes(AttributeSet attributes)
   {
-    removeAttributes(attributes.getAttributeNames());
+    Enumeration e = attributes.getAttributeNames();
+    while (e.hasMoreElements())
+      {
+        Object name = e.nextElement();
+        Object val = attributes.getAttribute(name);
+        if (containsAttributeLocally(name, val))
+          removeAttribute(name);     
+      }
   }
 
   public void removeAttributes(Enumeration names)
diff --git a/libjava/classpath/javax/swing/text/StringContent.java b/libjava/classpath/javax/swing/text/StringContent.java
index bedf480..7db377a 100644
--- a/libjava/classpath/javax/swing/text/StringContent.java
+++ b/libjava/classpath/javax/swing/text/StringContent.java
@@ -56,6 +56,9 @@ import javax.swing.undo.UndoableEdit;
  */
 public final class StringContent implements AbstractDocument.Content, Serializable
 {
+  /** The serialization UID (compatible with JDK1.5). */
+  private static final long serialVersionUID = 4755994433709540381L;
+
   // This is package-private to avoid an accessor method.
   char[] content;
 
diff --git a/libjava/classpath/javax/swing/text/StyleConstants.java b/libjava/classpath/javax/swing/text/StyleConstants.java
index 3f973f2..598eaf6 100644
--- a/libjava/classpath/javax/swing/text/StyleConstants.java
+++ b/libjava/classpath/javax/swing/text/StyleConstants.java
@@ -54,11 +54,13 @@ public class StyleConstants
   public static final Object BidiLevel = CharacterConstants.BidiLevel;
   public static final Object Bold = CharacterConstants.Bold;
   public static final Object ComponentAttribute = CharacterConstants.ComponentAttribute;
-  public static final Object FontFamily = CharacterConstants.Family;
+  public static final Object Family = CharacterConstants.Family;
+  public static final Object FontFamily = CharacterConstants.Family;  
   public static final Object FontSize = CharacterConstants.Size;
   public static final Object Foreground = CharacterConstants.Foreground;
   public static final Object IconAttribute = CharacterConstants.IconAttribute;
   public static final Object Italic = CharacterConstants.Italic;
+  public static final Object Size = CharacterConstants.Size;
   public static final Object StrikeThrough = CharacterConstants.StrikeThrough;
   public static final Object Subscript = CharacterConstants.Subscript;
   public static final Object Superscript = CharacterConstants.Superscript;
@@ -109,7 +111,7 @@ public class StyleConstants
     if (a.isDefined(Background))
       return (Color) a.getAttribute(Background);
     else
-      return Color.BLACK;
+      return Color.WHITE;
   } 
   
   public static int getBidiLevel(AttributeSet a)
diff --git a/libjava/classpath/javax/swing/text/StyleContext.java b/libjava/classpath/javax/swing/text/StyleContext.java
index ae11622..6c4e2994 100644
--- a/libjava/classpath/javax/swing/text/StyleContext.java
+++ b/libjava/classpath/javax/swing/text/StyleContext.java
@@ -57,9 +57,15 @@ import javax.swing.event.EventListenerList;
 public class StyleContext 
     implements Serializable, AbstractDocument.AttributeContext
 {
+  /** The serialization UID (compatible with JDK1.5). */
+  private static final long serialVersionUID = 8042858831190784241L;
+
   public class NamedStyle
     implements Serializable, Style
   {
+    /** The serialization UID (compatible with JDK1.5). */
+    private static final long serialVersionUID = -6690628971806226374L;
+
     protected ChangeEvent changeEvent;
     protected EventListenerList listenerList;
       
@@ -288,7 +294,7 @@ public class StyleContext
     public boolean equals(Object obj)
     {
       return 
-        (obj instanceof SmallAttributeSet)
+        (obj instanceof AttributeSet)
         && this.isEqual((AttributeSet)obj);
     }
  
@@ -300,9 +306,14 @@ public class StyleContext
             return attrs[i+1];
         }
             
-      Object p = getResolveParent();
-      if (p != null && p instanceof AttributeSet)
-        return (((AttributeSet)p).getAttribute(key));
+      // Check the resolve parent, unless we're looking for the 
+      // ResolveAttribute, which would cause an infinite loop
+      if (!(key.equals(ResolveAttribute)))
+          {
+            Object p = getResolveParent();
+            if (p != null && p instanceof AttributeSet)
+              return (((AttributeSet)p).getAttribute(key));
+          }
       
       return null;
     }
diff --git a/libjava/classpath/javax/swing/text/StyledDocument.java b/libjava/classpath/javax/swing/text/StyledDocument.java
index ea27754..168e1b1 100644
--- a/libjava/classpath/javax/swing/text/StyledDocument.java
+++ b/libjava/classpath/javax/swing/text/StyledDocument.java
@@ -45,101 +45,96 @@ import java.awt.Font;
  * @author	Andrew Selkirk
  * @version	1.0
  */
-public interface StyledDocument extends Document {
-
-	//-------------------------------------------------------------
-	// Methods ----------------------------------------------------
-	//-------------------------------------------------------------
-
-	/**
-	 * addStyle
-	 * @param nm TODO
-	 * @param rent TODO
-	 * @returns Style
-	 */
-	Style addStyle(String nm, Style parent);
-
-	/**
-	 * removeStyle
-	 * @param nm TODO
-	 */
-	void removeStyle(String nm);
-
-	/**
-	 * getStyle
-	 * @param nm TODO
-	 * @returns Style
-	 */
-	Style getStyle(String nm);
-
-	/**
-	 * setCharacterAttributes
-	 * @param offset TODO
-	 * @param length TODO
-	 * @param set TODO
-	 * @param replace TODO
-	 */
-	void setCharacterAttributes(int offset, int length,
-		AttributeSet set, boolean replace);
-
-	/**
-	 * setParagraphAttributes
-	 * @param offset TODO
-	 * @param length TODO
-	 * @param set TODO
-	 * @param replace TODO
-	 */
-	void setParagraphAttributes(int offset, int length,
-		AttributeSet set, boolean replace);
-
-	/**
-	 * getLogicalStyle
-	 * @param position TODO
-	 * @returns Style
-	 */
-	Style getLogicalStyle(int position);
-
-	/**
-	 * setLogicalStyle
-	 * @param position TODO
-	 * @param style TODO
-	 */
-	void setLogicalStyle(int position, Style style);
-
-	/**
-	 * getParagraphElement
-	 * @param position TODO
-	 * @returns Element
-	 */
-	Element getParagraphElement(int position);
-
-	/**
-	 * getCharacterElement
-	 * @param position TODO
-	 * @returns Element
-	 */
-	Element getCharacterElement(int position);
-
-	/**
-	 * getForeground
-	 * @param set TODO
-	 * @returns Color
-	 */
-	Color getForeground(AttributeSet set);
-
-	/**
-	 * getBackground
-	 * @param set TODO
-	 * @returns Color
-	 */
-	Color getBackground(AttributeSet set);
-
-	/**
-	 * getFont
-	 * @param set TODO
-	 * @returns Font
-	 */
-	Font getFont(AttributeSet set);
-
-
-} // StyledDocument
+public interface StyledDocument extends Document
+{
+  /**
+   * addStyle
+   * @param nm TODO
+   * @param parent TODO
+   * @returns Style
+   */
+  Style addStyle(String nm, Style parent);
+
+  /**
+   * removeStyle
+   * @param nm TODO
+   */
+  void removeStyle(String nm);
+
+  /**
+   * getStyle
+   * @param nm TODO
+   * @returns Style
+   */
+  Style getStyle(String nm);
+
+  /**
+   * setCharacterAttributes
+   * @param offset TODO
+   * @param length TODO
+   * @param set TODO
+   * @param replace TODO
+   */
+  void setCharacterAttributes(int offset, int length, AttributeSet set,
+                              boolean replace);
+
+  /**
+   * setParagraphAttributes
+   * @param offset TODO
+   * @param length TODO
+   * @param set TODO
+   * @param replace TODO
+   */
+  void setParagraphAttributes(int offset, int length, AttributeSet set,
+                              boolean replace);
+
+  /**
+   * getLogicalStyle
+   * @param position TODO
+   * @returns Style
+   */
+  Style getLogicalStyle(int position);
+
+  /**
+   * setLogicalStyle
+   * @param position TODO
+   * @param style TODO
+   */
+  void setLogicalStyle(int position, Style style);
+
+  /**
+   * getParagraphElement
+   * @param position TODO
+   * @returns Element
+   */
+  Element getParagraphElement(int position);
+
+  /**
+   * getCharacterElement
+   * @param position TODO
+   * @returns Element
+   */
+  Element getCharacterElement(int position);
+
+  /**
+   * getForeground
+   * @param set TODO
+   * @returns Color
+   */
+  Color getForeground(AttributeSet set);
+
+  /**
+   * getBackground
+   * @param set TODO
+   * @returns Color
+   */
+  Color getBackground(AttributeSet set);
+
+  /**
+   * getFont
+   * @param set TODO
+   * @returns Font
+   */
+  Font getFont(AttributeSet set);
+
+}
diff --git a/libjava/classpath/javax/swing/text/StyledEditorKit.java b/libjava/classpath/javax/swing/text/StyledEditorKit.java
index 89c4cf1..e71f992 100644
--- a/libjava/classpath/javax/swing/text/StyledEditorKit.java
+++ b/libjava/classpath/javax/swing/text/StyledEditorKit.java
@@ -40,13 +40,9 @@ package javax.swing.text;
 
 import java.awt.Color;
 import java.awt.event.ActionEvent;
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
-import java.io.Serializable;
 
 import javax.swing.Action;
 import javax.swing.JEditorPane;
-import javax.swing.JTextPane;
 import javax.swing.event.CaretEvent;
 import javax.swing.event.CaretListener;
 
@@ -460,11 +456,11 @@ public class StyledEditorKit extends DefaultEditorKit
    * <code>StyledEditorKit</code>, namely the following types of Elements:
    *
    * <ul>
-   * <li>{@link AbstractDocument.ContentElementName}</li>
-   * <li>{@link AbstractDocument.ParagraphElementName}</li>
-   * <li>{@link AbstractDocument.SectionElementName}</li>
-   * <li>{@link StyleContext.ComponentElementName}</li>
-   * <li>{@link StyleContext.IconElementName}</li>
+   * <li>{@link AbstractDocument#ContentElementName}</li>
+   * <li>{@link AbstractDocument#ParagraphElementName}</li>
+   * <li>{@link AbstractDocument#SectionElementName}</li>
+   * <li>{@link StyleConstants#ComponentElementName}</li>
+   * <li>{@link StyleConstants#IconElementName}</li>
    * </ul>
    */
   static class StyledViewFactory
@@ -667,11 +663,11 @@ public class StyledEditorKit extends DefaultEditorKit
    * namely the following types of <code>Element</code>s:
    *
    * <ul>
-   * <li>{@link AbstractDocument.ContentElementName}</li>
-   * <li>{@link AbstractDocument.ParagraphElementName}</li>
-   * <li>{@link AbstractDocument.SectionElementName}</li>
-   * <li>{@link StyleContext.ComponentElementName}</li>
-   * <li>{@link StyleContext.IconElementName}</li>
+   * <li>{@link AbstractDocument#ContentElementName}</li>
+   * <li>{@link AbstractDocument#ParagraphElementName}</li>
+   * <li>{@link AbstractDocument#SectionElementName}</li>
+   * <li>{@link StyleConstants#ComponentElementName}</li>
+   * <li>{@link StyleConstants#IconElementName}</li>
    * </ul>
    *
    * @return a {@link ViewFactory} that is able to create {@link View}s
diff --git a/libjava/classpath/javax/swing/text/TabSet.java b/libjava/classpath/javax/swing/text/TabSet.java
index 146f545..ecad944 100644
--- a/libjava/classpath/javax/swing/text/TabSet.java
+++ b/libjava/classpath/javax/swing/text/TabSet.java
@@ -41,6 +41,9 @@ import java.io.Serializable;
 
 public class TabSet implements Serializable
 {
+  /** The serialization UID (compatible with JDK1.5). */
+  private static final long serialVersionUID = 2367703481999080593L;
+
   TabStop[] tabs;
 
   public TabSet(TabStop[] t) 
diff --git a/libjava/classpath/javax/swing/text/TabStop.java b/libjava/classpath/javax/swing/text/TabStop.java
index 032da8b..56f862f 100644
--- a/libjava/classpath/javax/swing/text/TabStop.java
+++ b/libjava/classpath/javax/swing/text/TabStop.java
@@ -41,6 +41,9 @@ import java.io.Serializable;
 
 public class TabStop implements Serializable
 {
+  /** The serialization UID (compatible with JDK1.5). */
+  private static final long serialVersionUID = -5381995917363605058L;
+
   public static final int ALIGN_LEFT = 0;
   public static final int ALIGN_RIGHT = 1;
   public static final int ALIGN_CENTER = 2;
diff --git a/libjava/classpath/javax/swing/text/Utilities.java b/libjava/classpath/javax/swing/text/Utilities.java
index d40408d..7830b2f 100644
--- a/libjava/classpath/javax/swing/text/Utilities.java
+++ b/libjava/classpath/javax/swing/text/Utilities.java
@@ -40,6 +40,11 @@ package javax.swing.text;
 
 import java.awt.FontMetrics;
 import java.awt.Graphics;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.text.BreakIterator;
+
+import javax.swing.SwingConstants;
 
 /**
  * A set of utilities to deal with text. This is used by several other classes
@@ -195,4 +200,409 @@ public class Utilities
 
     return maxWidth;
   }
+
+  /**
+   * Provides a facility to map screen coordinates into a model location. For a
+   * given text fragment and start location within this fragment, this method
+   * determines the model location so that the resulting fragment fits best
+   * into the span <code>[x0, x]</code>.
+   *
+   * The parameter <code>round</code> controls which model location is returned
+   * if the view coordinates are on a character: If <code>round</code> is
+   * <code>true</code>, then the result is rounded up to the next character, so
+   * that the resulting fragment is the smallest fragment that is larger than
+   * the specified span. If <code>round</code> is <code>false</code>, then the
+   * resulting fragment is the largest fragment that is smaller than the
+   * specified span.
+   *
+   * @param s the text segment
+   * @param fm the font metrics to use
+   * @param x0 the starting screen location
+   * @param x the target screen location at which the requested fragment should
+   *        end
+   * @param te the tab expander to use; if this is <code>null</code>, TABs are
+   *        expanded to one space character
+   * @param p0 the starting model location
+   * @param round if <code>true</code> round up to the next location, otherwise
+   *        round down to the current location
+   *
+   * @return the model location, so that the resulting fragment fits within the
+   *         specified span
+   */
+  public static final int getTabbedTextOffset(Segment s, FontMetrics fm, int x0,
+                                              int x, TabExpander te, int p0,
+                                              boolean round)
+  {
+    // At the end of the for loop, this holds the requested model location
+    int pos;
+    int currentX = x0;
+
+    for (pos = p0; pos < s.count; pos++)
+      {
+        char nextChar = s.array[s.offset+pos];
+        if (nextChar == 0)
+          {
+            if (! round)
+              pos--;
+            break;
+          }
+        if (nextChar != '\t')
+          currentX += fm.charWidth(nextChar);
+        else
+          {
+            if (te == null)
+              currentX += fm.charWidth(' ');
+            else
+              currentX = (int) te.nextTabStop(currentX, pos);
+          }
+        if (currentX > x)
+          {
+            if (! round)
+              pos--;
+            break;
+          }
+      }
+    return pos;
+  }
+
+  /**
+   * Provides a facility to map screen coordinates into a model location. For a
+   * given text fragment and start location within this fragment, this method
+   * determines the model location so that the resulting fragment fits best
+   * into the span <code>[x0, x]</code>.
+   *
+   * This method rounds up to the next location, so that the resulting fragment
+   * will be the smallest fragment of the text, that is greater than the
+   * specified span.
+   *
+   * @param s the text segment
+   * @param fm the font metrics to use
+   * @param x0 the starting screen location
+   * @param x the target screen location at which the requested fragment should
+   *        end
+   * @param te the tab expander to use; if this is <code>null</code>, TABs are
+   *        expanded to one space character
+   * @param p0 the starting model location
+   *
+   * @return the model location, so that the resulting fragment fits within the
+   *         specified span
+   */
+  public static final int getTabbedTextOffset(Segment s, FontMetrics fm, int x0,
+                                              int x, TabExpander te, int p0)
+  {
+    return getTabbedTextOffset(s, fm, x0, x, te, p0, true);
+  }
+  
+  /**
+   * Finds the start of the next word for the given offset.
+   * 
+   * @param c
+   *          the text component
+   * @param offs
+   *          the offset in the document
+   * @return the location in the model of the start of the next word.
+   * @throws BadLocationException
+   *           if the offset is invalid.
+   */
+  public static final int getNextWord(JTextComponent c, int offs)
+      throws BadLocationException
+  {
+    if (offs < 0 || offs > (c.getText().length() - 1))
+      throw new BadLocationException("invalid offset specified", offs);
+    String text = c.getText();
+    BreakIterator wb = BreakIterator.getWordInstance();
+    wb.setText(text);
+    int last = wb.following(offs);
+    int current = wb.next();
+    while (current != BreakIterator.DONE)
+      {
+        for (int i = last; i < current; i++)
+          {
+            // FIXME: Should use isLetter(int) and text.codePointAt(int)
+            // instead, but isLetter(int) isn't implemented yet
+            if (Character.isLetter(text.charAt(i)))
+              return last;
+          }
+        last = current;
+        current = wb.next();
+      }
+    return BreakIterator.DONE;
+  }
+
+  /**
+   * Finds the start of the previous word for the given offset.
+   * 
+   * @param c
+   *          the text component
+   * @param offs
+   *          the offset in the document
+   * @return the location in the model of the start of the previous word.
+   * @throws BadLocationException
+   *           if the offset is invalid.
+   */
+  public static final int getPreviousWord(JTextComponent c, int offs)
+      throws BadLocationException
+  {
+    if (offs < 0 || offs > (c.getText().length() - 1))
+      throw new BadLocationException("invalid offset specified", offs);
+    String text = c.getText();
+    BreakIterator wb = BreakIterator.getWordInstance();
+    wb.setText(text);
+    int last = wb.preceding(offs);
+    int current = wb.previous();
+
+    while (current != BreakIterator.DONE)
+      {
+        for (int i = last; i < offs; i++)
+          {
+            // FIXME: Should use isLetter(int) and text.codePointAt(int)
+            // instead, but isLetter(int) isn't implemented yet
+            if (Character.isLetter(text.charAt(i)))
+              return last;
+          }
+        last = current;
+        current = wb.previous();
+      }
+    return 0;
+  }
+  
+  /**
+   * Finds the start of a word for the given location.
+   * @param c the text component
+   * @param offs the offset location
+   * @return the location of the word beginning
+   * @throws BadLocationException if the offset location is invalid
+   */
+  public static final int getWordStart(JTextComponent c, int offs)
+      throws BadLocationException
+  {
+    if (offs < 0 || offs >= c.getText().length())
+      throw new BadLocationException("invalid offset specified", offs);
+    
+    String text = c.getText();
+    BreakIterator wb = BreakIterator.getWordInstance();
+    wb.setText(text);
+    if (wb.isBoundary(offs))
+      return offs;
+    return wb.preceding(offs);
+  }
+  
+  /**
+   * Finds the end of a word for the given location.
+   * @param c the text component
+   * @param offs the offset location
+   * @return the location of the word end
+   * @throws BadLocationException if the offset location is invalid
+   */
+  public static final int getWordEnd(JTextComponent c, int offs)
+      throws BadLocationException
+  {
+    if (offs < 0 || offs >= c.getText().length())
+      throw new BadLocationException("invalid offset specified", offs);
+    
+    String text = c.getText();
+    BreakIterator wb = BreakIterator.getWordInstance();
+    wb.setText(text);
+    return wb.following(offs);
+  }
+  
+  /**
+   * Get the model position of the end of the row that contains the 
+   * specified model position.  Return null if the given JTextComponent
+   * does not have a size.
+   * @param c the JTextComponent
+   * @param offs the model position
+   * @return the model position of the end of the row containing the given 
+   * offset
+   * @throws BadLocationException if the offset is invalid
+   */
+  public static final int getRowEnd(JTextComponent c, int offs)
+      throws BadLocationException
+  {
+    String text = c.getText();
+    if (text == null)
+      return -1;
+
+    // Do a binary search for the smallest position X > offs
+    // such that that character at positino X is not on the same
+    // line as the character at position offs
+    int high = offs + ((text.length() - 1 - offs) / 2);
+    int low = offs;
+    int oldHigh = text.length() + 1;
+    while (true)
+      {
+        if (c.modelToView(high).y != c.modelToView(offs).y)
+          {
+            oldHigh = high;
+            high = low + ((high + 1 - low) / 2);
+            if (oldHigh == high)
+              return high - 1;
+          }
+        else
+          {
+            low = high;
+            high += ((oldHigh - high) / 2);
+            if (low == high)
+              return low;
+          }
+      }
+  }
+      
+  /**
+   * Get the model position of the start of the row that contains the specified
+   * model position. Return null if the given JTextComponent does not have a
+   * size.
+   * 
+   * @param c the JTextComponent
+   * @param offs the model position
+   * @return the model position of the start of the row containing the given
+   *         offset
+   * @throws BadLocationException if the offset is invalid
+   */
+  public static final int getRowStart(JTextComponent c, int offs)
+      throws BadLocationException
+  {
+    String text = c.getText();
+    if (text == null)
+      return -1;
+
+    // Do a binary search for the greatest position X < offs
+    // such that the character at position X is not on the same
+    // row as the character at position offs
+    int high = offs;
+    int low = 0;
+    int oldLow = 0;
+    while (true)
+      {
+        if (c.modelToView(low).y != c.modelToView(offs).y)
+          {
+            oldLow = low;
+            low = high - ((high + 1 - low) / 2);
+            if (oldLow == low)
+              return low + 1;
+          }
+        else
+          {
+            high = low;
+            low -= ((low - oldLow) / 2);
+            if (low == high)
+              return low;
+          }
+      }
+  }
+  
+  /**
+   * Determine where to break the text in the given Segment, attempting to find
+   * a word boundary.
+   * @param s the Segment that holds the text
+   * @param metrics the font metrics used for calculating the break point
+   * @param x0 starting view location representing the start of the text
+   * @param x the target view location
+   * @param e the TabExpander used for expanding tabs (if this is null tabs
+   * are expanded to 1 space)
+   * @param startOffset the offset in the Document of the start of the text
+   * @return the offset at which we should break the text
+   */
+  public static final int getBreakLocation(Segment s, FontMetrics metrics,
+                                           int x0, int x, TabExpander e,
+                                           int startOffset)
+  {
+    int mark = Utilities.getTabbedTextOffset(s, metrics, x0, x, e, startOffset);
+    BreakIterator breaker = BreakIterator.getWordInstance();
+    breaker.setText(s.toString());
+    
+    // If mark is equal to the end of the string, just use that position
+    if (mark == s.count)
+      return mark;
+    
+    // Try to find a word boundary previous to the mark at which we 
+    // can break the text
+    int preceding = breaker.preceding(mark + 1);
+    
+    if (preceding != 0)
+      return preceding;
+    else
+      // If preceding is 0 we couldn't find a suitable word-boundary so
+      // just break it on the character boundary
+      return mark;
+  }
+
+  /**
+   * Returns the paragraph element in the text component <code>c</code> at
+   * the specified location <code>offset</code>.
+   *
+   * @param c the text component
+   * @param offset the offset of the paragraph element to return
+   *
+   * @return the paragraph element at <code>offset</code>
+   */
+  public static final Element getParagraphElement(JTextComponent c, int offset)
+  {
+    Document doc = c.getDocument();
+    Element par = null;
+    if (doc instanceof StyledDocument)
+      {
+        StyledDocument styledDoc = (StyledDocument) doc;
+        par = styledDoc.getParagraphElement(offset);
+      }
+    else
+      {
+        Element root = c.getDocument().getDefaultRootElement();
+        int parIndex = root.getElementIndex(offset);
+        par = root.getElement(parIndex);
+      }
+    return par;
+  }
+
+  /**
+   * Returns the document position that is closest above to the specified x
+   * coordinate in the row containing <code>offset</code>.
+   *
+   * @param c the text component
+   * @param offset the offset
+   * @param x the x coordinate
+   *
+   * @return  the document position that is closest above to the specified x
+   *          coordinate in the row containing <code>offset</code>
+   *
+   * @throws BadLocationException if <code>offset</code> is not a valid offset
+   */
+  public static final int getPositionAbove(JTextComponent c, int offset, int x)
+    throws BadLocationException
+  {
+    View rootView = c.getUI().getRootView(c);
+    Rectangle r = c.modelToView(offset);
+    int offs = c.viewToModel(new Point(x, r.y));
+    int pos = rootView.getNextVisualPositionFrom(c, offs,
+                                                 Position.Bias.Forward,
+                                                 SwingConstants.NORTH,
+                                                 new Position.Bias[1]);
+    return pos;
+  }
+
+  /**
+   * Returns the document position that is closest below to the specified x
+   * coordinate in the row containing <code>offset</code>.
+   *
+   * @param c the text component
+   * @param offset the offset
+   * @param x the x coordinate
+   *
+   * @return  the document position that is closest above to the specified x
+   *          coordinate in the row containing <code>offset</code>
+   *
+   * @throws BadLocationException if <code>offset</code> is not a valid offset
+   */
+  public static final int getPositionBelow(JTextComponent c, int offset, int x)
+    throws BadLocationException
+  {
+    View rootView = c.getUI().getRootView(c);
+    Rectangle r = c.modelToView(offset);
+    int offs = c.viewToModel(new Point(x, r.y));
+    int pos = rootView.getNextVisualPositionFrom(c, offs,
+                                                 Position.Bias.Forward,
+                                                 SwingConstants.SOUTH,
+                                                 new Position.Bias[1]);
+    return pos;
+  }
 }
diff --git a/libjava/classpath/javax/swing/text/View.java b/libjava/classpath/javax/swing/text/View.java
index 24efba9..daab347 100644
--- a/libjava/classpath/javax/swing/text/View.java
+++ b/libjava/classpath/javax/swing/text/View.java
@@ -43,7 +43,6 @@ import java.awt.Graphics;
 import java.awt.Rectangle;
 import java.awt.Shape;
 
-import javax.swing.JComponent;
 import javax.swing.SwingConstants;
 import javax.swing.event.DocumentEvent;
 
@@ -87,9 +86,9 @@ public abstract class View implements SwingConstants
   {
     View parent = getParent();
     if (parent == null)
-      throw new AssertionError("The parent of a View must not be null.");
-
-    return parent.getContainer();
+      return null;
+    else
+      return parent.getContainer();
   }
   
   public Document getDocument()
@@ -508,6 +507,30 @@ public abstract class View implements SwingConstants
   }
 
   /**
+   * Maps a position in the document into the coordinate space of the View.
+   * The output rectangle usually reflects the font height but has a width
+   * of zero.
+   *
+   * This method is deprecated and calls
+   * {@link #modelToView(int, Position.Bias, int, Position.Bias, Shape)} with
+   * a bias of {@link Position.Bias#Forward}.
+   *
+   * @param pos the position of the character in the model
+   * @param a the area that is occupied by the view
+   *
+   * @return a rectangle that gives the location of the document position
+   *         inside the view coordinate space
+   *
+   * @throws BadLocationException if <code>pos</code> is invalid
+   *
+   * @deprecated Use {@link #modelToView(int, Shape, Position.Bias)} instead.
+   */
+  public Shape modelToView(int pos, Shape a) throws BadLocationException
+  {
+    return modelToView(pos, a, Position.Bias.Forward);
+  }
+
+  /**
    * Maps coordinates from the <code>View</code>'s space into a position
    * in the document model.
    *
@@ -521,6 +544,25 @@ public abstract class View implements SwingConstants
    */
   public abstract int viewToModel(float x, float y, Shape a, Position.Bias[] b);
 
+  /**
+   * Maps coordinates from the <code>View</code>'s space into a position
+   * in the document model. This method is deprecated and only there for
+   * compatibility.
+   *
+   * @param x the x coordinate in the view space
+   * @param y the y coordinate in the view space
+   * @param a the allocation of this <code>View</code>
+   *
+   * @return the position in the document that corresponds to the screen
+   *         coordinates <code>x, y</code>
+   *
+   * @deprecated Use {@link #viewToModel(float, float, Shape, Position.Bias[])}
+   *             instead.
+   */
+  public int viewToModel(float x, float y, Shape a)
+  {
+    return viewToModel(x, y, a, new Position.Bias[0]);
+  }
 
   /**
    * Dumps the complete View hierarchy. This method can be used for debugging
@@ -552,4 +594,30 @@ public abstract class View implements SwingConstants
     for (int i = 0; i < count; ++i)
       getView(i).dump(indent + 1);
   }
+
+  /**
+   * Returns the document position that is (visually) nearest to the given
+   * document position <code>pos</code> in the given direction <code>d</code>.
+   *
+   * @param c the text component
+   * @param pos the document position
+   * @param b the bias for <code>pos</code>
+   * @param d the direction, must be either {@link SwingConstants#NORTH},
+   *        {@link SwingConstants#SOUTH}, {@link SwingConstants#WEST} or
+   *        {@link SwingConstants#EAST}
+   * @param biasRet an array of {@link Position.Bias} that can hold at least
+   *        one element, which is filled with the bias of the return position
+   *        on method exit
+   *
+   * @return the document position that is (visually) nearest to the given
+   *         document position <code>pos</code> in the given direction
+   *         <code>d</code>
+   *
+   * @throws BadLocationException if <code>pos</code> is not a valid offset in
+   *         the document model
+   */
+  public abstract int getNextVisualPositionFrom(JTextComponent c, int pos,
+                                                Position.Bias b, int d,
+                                                Position.Bias[] biasRet)
+    throws BadLocationException;
 }
diff --git a/libjava/classpath/javax/swing/text/WrappedPlainView.java b/libjava/classpath/javax/swing/text/WrappedPlainView.java
new file mode 100644
index 0000000..b905190
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/WrappedPlainView.java
@@ -0,0 +1,700 @@
+/* WrappedPlainView.java -- 
+   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;
+
+import java.awt.Color;
+import java.awt.Container;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Rectangle;
+import java.awt.Shape;
+
+import javax.swing.SwingConstants;
+import javax.swing.event.DocumentEvent;
+import javax.swing.text.Position.Bias;
+
+/**
+ * @author abalkiss
+ *
+ */
+public class WrappedPlainView extends BoxView implements TabExpander
+{
+  /** The color for selected text **/
+  Color selectedColor;
+  
+  /** The color for unselected text **/
+  Color unselectedColor;
+  
+  /** The color for disabled components **/
+  Color disabledColor;
+  
+  /** Stores the font metrics **/
+  protected FontMetrics metrics;
+  
+  /** Whether or not to wrap on word boundaries **/
+  boolean wordWrap;
+  
+  /** A ViewFactory that creates WrappedLines **/
+  ViewFactory viewFactory = new WrappedLineCreator();
+  
+  /** The start of the selected text **/
+  int selectionStart;
+  
+  /** The end of the selected text **/
+  int selectionEnd;
+  
+  /**
+   * The instance returned by {@link #getLineBuffer()}.
+   */
+  private transient Segment lineBuffer;
+  
+  public WrappedPlainView (Element elem)
+  {
+    this (elem, false);
+  }
+  
+  public WrappedPlainView (Element elem, boolean wordWrap)
+  {
+    super (elem, Y_AXIS);
+    this.wordWrap = wordWrap;    
+  }  
+  
+  /**
+   * Provides access to the Segment used for retrievals from the Document.
+   * @return the Segment.
+   */
+  protected final Segment getLineBuffer()
+  {
+    if (lineBuffer == null)
+      lineBuffer = new Segment();
+    return lineBuffer;
+  }
+  
+  /**
+   * Returns the next tab stop position after a given reference position.
+   *
+   * This implementation ignores the <code>tabStop</code> argument.
+   * 
+   * @param x the current x position in pixels
+   * @param tabStop the position within the text stream that the tab occured at
+   */
+  public float nextTabStop(float x, int tabStop)
+  {
+    JTextComponent host = (JTextComponent)getContainer();
+    float tabSizePixels = getTabSize()
+                          * host.getFontMetrics(host.getFont()).charWidth('m');
+    return (float) (Math.floor(x / tabSizePixels) + 1) * tabSizePixels;
+  }
+  
+  /**
+   * Returns the tab size for the Document based on 
+   * PlainDocument.tabSizeAttribute, defaulting to 8 if this property is
+   * not defined
+   * 
+   * @return the tab size.
+   */
+  protected int getTabSize()
+  {
+    Object tabSize = getDocument().getProperty(PlainDocument.tabSizeAttribute);
+    if (tabSize == null)
+      return 8;
+    return ((Integer)tabSize).intValue();
+  }
+  
+  /**
+   * Draws a line of text, suppressing white space at the end and expanding
+   * tabs.  Calls drawSelectedText and drawUnselectedText.
+   * @param p0 starting document position to use
+   * @param p1 ending document position to use
+   * @param g graphics context
+   * @param x starting x position
+   * @param y starting y position
+   */
+  protected void drawLine(int p0, int p1, Graphics g, int x, int y)
+  {
+    try
+    {
+      // We have to draw both selected and unselected text.  There are
+      // several cases:
+      //  - entire range is unselected
+      //  - entire range is selected
+      //  - start of range is selected, end of range is unselected
+      //  - start of range is unselected, end of range is selected
+      //  - middle of range is selected, start and end of range is unselected
+      
+      // entire range unselected:      
+      if ((selectionStart == selectionEnd) || 
+          (p0 > selectionEnd || p1 < selectionStart))
+        drawUnselectedText(g, x, y, p0, p1);
+      
+      // entire range selected
+      else if (p0 >= selectionStart && p1 <= selectionEnd)
+        drawSelectedText(g, x, y, p0, p1);
+      
+      // start of range selected, end of range unselected
+      else if (p0 >= selectionStart)
+        {
+          x = drawSelectedText(g, x, y, p0, selectionEnd);
+          drawUnselectedText(g, x, y, selectionEnd, p1);
+        }
+      
+      // start of range unselected, end of range selected
+      else if (selectionStart > p0 && selectionEnd > p1)
+        {
+          x = drawUnselectedText(g, x, y, p0, selectionStart);
+          drawSelectedText(g, x, y, selectionStart, p1);
+        }
+      
+      // middle of range selected
+      else if (selectionStart > p0)
+        {
+          x = drawUnselectedText(g, x, y, p0, selectionStart);
+          x = drawSelectedText(g, x, y, selectionStart, selectionEnd);
+          drawUnselectedText(g, x, y, selectionEnd, p1);
+        }        
+    }
+    catch (BadLocationException ble)
+    {
+      // shouldn't happen
+    }
+  }
+
+  /**
+   * Renders the range of text as selected text.  Just paints the text 
+   * in the color specified by the host component.  Assumes the highlighter
+   * will render the selected background.
+   * @param g the graphics context
+   * @param x the starting X coordinate
+   * @param y the starting Y coordinate
+   * @param p0 the starting model location
+   * @param p1 the ending model location 
+   * @return the X coordinate of the end of the text
+   * @throws BadLocationException if the given range is invalid
+   */
+  protected int drawSelectedText(Graphics g, int x, int y, int p0, int p1)
+      throws BadLocationException
+  {
+    g.setColor(selectedColor);
+    Segment segment = getLineBuffer();
+    getDocument().getText(p0, p1 - p0, segment);
+    return Utilities.drawTabbedText(segment, x, y, g, this, p0);
+  }
+
+  /**
+   * Renders the range of text as normal unhighlighted text.
+   * @param g the graphics context
+   * @param x the starting X coordinate
+   * @param y the starting Y coordinate
+   * @param p0 the starting model location
+   * @param p1 the end model location
+   * @return the X location of the end off the range
+   * @throws BadLocationException if the range given is invalid
+   */
+  protected int drawUnselectedText(Graphics g, int x, int y, int p0, int p1)
+      throws BadLocationException
+  {    
+    JTextComponent textComponent = (JTextComponent) getContainer();
+    if (textComponent.isEnabled())
+      g.setColor(unselectedColor);
+    else
+      g.setColor(disabledColor);
+
+    Segment segment = getLineBuffer();
+    getDocument().getText(p0, p1 - p0, segment);
+    return Utilities.drawTabbedText(segment, x, y, g, this, p0);
+  }  
+  
+  /**
+   * Loads the children to initiate the view.  Called by setParent.
+   * Creates a WrappedLine for each child Element.
+   */
+  protected void loadChildren (ViewFactory f)
+  {
+    Element root = getElement();
+    int numChildren = root.getElementCount();
+    if (numChildren == 0)
+      return;
+    
+    View[] children = new View[numChildren];
+    for (int i = 0; i < numChildren; i++)
+      children[i] = new WrappedLine(root.getElement(i));
+    replace(0, 0, children);
+  }
+  
+  /**
+   * Calculates the break position for the text between model positions
+   * p0 and p1.  Will break on word boundaries or character boundaries
+   * depending on the break argument given in construction of this 
+   * WrappedPlainView.  Used by the nested WrappedLine class to determine
+   * when to start the next logical line.
+   * @param p0 the start model position
+   * @param p1 the end model position
+   * @return the model position at which to break the text
+   */
+  protected int calculateBreakPosition(int p0, int p1)
+  {
+    Container c = getContainer();
+    Rectangle alloc = c.isValid() ? c.getBounds()
+                                 : new Rectangle(c.getPreferredSize());
+    updateMetrics();
+    try
+      {
+        getDocument().getText(p0, p1 - p0, getLineBuffer());
+      }
+    catch (BadLocationException ble)
+      {
+        // this shouldn't happen
+      }
+    // FIXME: Should we account for the insets of the container?
+    if (wordWrap)
+      return p0
+             + Utilities.getBreakLocation(lineBuffer, metrics, alloc.x,
+                                          alloc.x + alloc.width, this, 0);
+    else
+      {
+      return p0
+             + Utilities.getTabbedTextOffset(lineBuffer, metrics, alloc.x,
+                                             alloc.x + alloc.width, this, 0);
+      }
+  }
+  
+  void updateMetrics()
+  {
+    Container component = getContainer();
+    metrics = component.getFontMetrics(component.getFont());
+  }
+  
+  /**
+   * Determines the preferred span along the given axis.  Implemented to 
+   * cache the font metrics and then call the super classes method.
+   */
+  public float getPreferredSpan (int axis)
+  {
+    updateMetrics();
+    return super.getPreferredSpan(axis);
+  }
+  
+  /**
+   * Determines the minimum span along the given axis.  Implemented to 
+   * cache the font metrics and then call the super classes method.
+   */
+  public float getMinimumSpan (int axis)
+  {
+    updateMetrics();
+    return super.getMinimumSpan(axis);
+  }
+  
+  /**
+   * Determines the maximum span along the given axis.  Implemented to 
+   * cache the font metrics and then call the super classes method.
+   */
+  public float getMaximumSpan (int axis)
+  {
+    updateMetrics();
+    return super.getMaximumSpan(axis);
+  }
+  
+  /**
+   * Called when something was inserted.  Overridden so that
+   * the view factory creates WrappedLine views.
+   */
+  public void insertUpdate (DocumentEvent e, Shape a, ViewFactory f)
+  {
+    super.insertUpdate(e, a, viewFactory);
+    // FIXME: could improve performance by repainting only the necessary area
+    getContainer().repaint();
+  }
+  
+  /**
+   * Called when something is removed.  Overridden so that
+   * the view factory creates WrappedLine views.
+   */
+  public void removeUpdate (DocumentEvent e, Shape a, ViewFactory f)
+  {
+    super.removeUpdate(e, a, viewFactory);
+    // FIXME: could improve performance by repainting only the necessary area
+    getContainer().repaint();
+  }
+  
+  /**
+   * Called when the portion of the Document that this View is responsible
+   * for changes.  Overridden so that the view factory creates
+   * WrappedLine views.
+   */
+  public void changedUpdate (DocumentEvent e, Shape a, ViewFactory f)
+  {
+    super.changedUpdate(e, a, viewFactory);
+    // FIXME: could improve performance by repainting only the necessary area
+    getContainer().repaint();
+  }
+    
+  class WrappedLineCreator implements ViewFactory
+  {
+    // Creates a new WrappedLine
+    public View create(Element elem)
+    {
+      return new WrappedLine(elem);
+    }    
+  }
+  
+  /**
+   * Renders the <code>Element</code> that is associated with this
+   * <code>View</code>.  Caches the metrics and then calls
+   * super.paint to paint all the child views.
+   *
+   * @param g the <code>Graphics</code> context to render to
+   * @param a the allocated region for the <code>Element</code>
+   */
+  public void paint(Graphics g, Shape a)
+  {
+    JTextComponent comp = (JTextComponent)getContainer();
+    selectionStart = comp.getSelectionStart();
+    selectionEnd = comp.getSelectionEnd();
+    updateMetrics();
+    super.paint(g, a);
+  }
+  
+  /**
+   * Sets the size of the View.  Implemented to update the metrics
+   * and then call super method.
+   */
+  public void setSize (float width, float height)
+  {
+    updateMetrics();
+    if (width != getWidth())
+      preferenceChanged(null, true, true);
+    super.setSize(width, height);
+  }
+  
+  class WrappedLine extends View
+  { 
+    /** Used to cache the number of lines for this View **/
+    int numLines;
+    
+    public WrappedLine(Element elem)
+    {
+      super(elem);
+      determineNumLines();
+    }
+
+    /**
+     * Renders this (possibly wrapped) line using the given Graphics object
+     * and on the given rendering surface.
+     */
+    public void paint(Graphics g, Shape s)
+    {
+      // Ensure metrics are up-to-date.
+      updateMetrics();
+      JTextComponent textComponent = (JTextComponent) getContainer();
+
+      g.setFont(textComponent.getFont());
+      selectedColor = textComponent.getSelectedTextColor();
+      unselectedColor = textComponent.getForeground();
+      disabledColor = textComponent.getDisabledTextColor();
+
+      // FIXME: this is a hack, for some reason textComponent.getSelectedColor
+      // was returning black, which is not visible against a black background
+      selectedColor = Color.WHITE;
+      
+      Rectangle rect = s.getBounds();
+      int lineHeight = metrics.getHeight();
+
+      int end = getEndOffset();
+      int currStart = getStartOffset();
+      int currEnd;      
+      while (currStart < end)
+        {
+          currEnd = calculateBreakPosition(currStart, end);
+          drawLine(currStart, currEnd, g, rect.x, rect.y);
+          rect.y += lineHeight;          
+          if (currEnd == currStart)
+            currStart ++;
+          else
+            currStart = currEnd;          
+        }
+    }
+    
+    /**
+     * Determines the number of logical lines that the Element
+     * needs to be displayed
+     * @return the number of lines needed to display the Element
+     */
+    int determineNumLines()
+    {      
+      numLines = 0;
+      int end = getEndOffset();
+      if (end == 0)
+        return 0;
+            
+      int breakPoint;
+      for (int i = getStartOffset(); i < end;)
+        {
+          numLines ++;
+          // careful: check that there's no off-by-one problem here
+          // depending on which position calculateBreakPosition returns
+          breakPoint = calculateBreakPosition(i, end);
+          if (breakPoint == i)
+            i ++;
+          else
+            i = breakPoint;
+        }
+      return numLines;
+    }
+    
+    /**
+     * Determines the preferred span for this view along the given axis.
+     * 
+     * @param axis the axis (either X_AXIS or Y_AXIS)
+     * 
+     * @return the preferred span along the given axis.
+     * @throws IllegalArgumentException if axis is not X_AXIS or Y_AXIS
+     */
+    public float getPreferredSpan(int axis)
+    {
+      if (axis == X_AXIS)
+        return getWidth();
+      else if (axis == Y_AXIS)
+        return numLines * metrics.getHeight(); 
+      
+      throw new IllegalArgumentException("Invalid axis for getPreferredSpan: "
+                                         + axis);
+    }
+    
+    /**
+     * Provides a mapping from model space to view space.
+     * 
+     * @param pos the position in the model
+     * @param a the region into which the view is rendered
+     * @param b the position bias (forward or backward)
+     * 
+     * @return a box in view space that represents the given position 
+     * in model space
+     * @throws BadLocationException if the given model position is invalid
+     */
+    public Shape modelToView(int pos, Shape a, Bias b)
+        throws BadLocationException
+    {
+      Segment s = getLineBuffer();
+      int lineHeight = metrics.getHeight();
+      Rectangle rect = a.getBounds();
+      
+      // Return a rectangle with width 1 and height equal to the height 
+      // of the text
+      rect.height = lineHeight;
+      rect.width = 1;
+
+      int currLineStart = getStartOffset();
+      int end = getEndOffset();
+      
+      if (pos < currLineStart || pos >= end)
+        throw new BadLocationException("invalid offset", pos);
+           
+      while (true)
+        {
+          int currLineEnd = calculateBreakPosition(currLineStart, end);
+          // If pos is between currLineStart and currLineEnd then just find
+          // the width of the text from currLineStart to pos and add that
+          // to rect.x
+          if (pos >= currLineStart && pos < currLineEnd || pos == end - 1)
+            {             
+              try
+                {
+                  getDocument().getText(currLineStart, pos - currLineStart, s);
+                }
+              catch (BadLocationException ble)
+                {
+                  // Shouldn't happen
+                }
+              rect.x += Utilities.getTabbedTextWidth(s, metrics, rect.x,
+                                                     WrappedPlainView.this,
+                                                     currLineStart);
+              return rect;
+            }
+          // Increment rect.y so we're checking the next logical line
+          rect.y += lineHeight;
+          
+          // Increment currLineStart to the model position of the start
+          // of the next logical line
+          if (currLineEnd == currLineStart)
+            currLineStart = end;
+          else
+            currLineStart = currLineEnd;
+        }
+
+    }
+
+    /**
+     * Provides a mapping from view space to model space.
+     * 
+     * @param x the x coordinate in view space
+     * @param y the y coordinate in view space
+     * @param a the region into which the view is rendered
+     * @param b the position bias (forward or backward)
+     * 
+     * @return the location in the model that best represents the
+     * given point in view space
+     */
+    public int viewToModel(float x, float y, Shape a, Bias[] b)
+    {
+      Segment s = getLineBuffer();
+      Rectangle rect = a.getBounds();
+      int currLineStart = getStartOffset();
+      int end = getEndOffset();
+      int lineHeight = metrics.getHeight();
+      if (y < rect.y)
+        return currLineStart;
+      if (y > rect.y + rect.height)
+        return end - 1;
+
+      while (true)
+        {
+          int currLineEnd = calculateBreakPosition(currLineStart, end);
+          // If we're at the right y-position that means we're on the right
+          // logical line and we should look for the character
+          if (y >= rect.y && y < rect.y + lineHeight)
+            {
+              // Check if the x position is to the left or right of the text
+              if (x < rect.x)
+                return currLineStart;
+              if (x > rect.x + rect.width)
+                return currLineEnd - 1;
+              
+              try
+                {
+                  getDocument().getText(currLineStart, end - currLineStart, s);
+                }
+              catch (BadLocationException ble)
+                {
+                  // Shouldn't happen
+                }
+              int mark = Utilities.getTabbedTextOffset(s, metrics, rect.x,
+                                                       (int) x,
+                                                       WrappedPlainView.this,
+                                                       currLineStart);
+              return currLineStart + mark;
+            }
+          // Increment rect.y so we're checking the next logical line
+          rect.y += lineHeight;
+          
+          // Increment currLineStart to the model position of the start
+          // of the next logical line
+          if (currLineEnd == currLineStart)
+            currLineStart = end;
+          else
+            currLineStart = currLineEnd;
+        }
+    }    
+
+    /**
+     * Returns the document position that is (visually) nearest to the given
+     * document position <code>pos</code> in the given direction <code>d</code>.
+     *
+     * @param c the text component
+     * @param pos the document position
+     * @param b the bias for <code>pos</code>
+     * @param d the direction, must be either {@link SwingConstants#NORTH},
+     *        {@link SwingConstants#SOUTH}, {@link SwingConstants#WEST} or
+     *        {@link SwingConstants#EAST}
+     * @param biasRet an array of {@link Position.Bias} that can hold at least
+     *        one element, which is filled with the bias of the return position
+     *        on method exit
+     *
+     * @return the document position that is (visually) nearest to the given
+     *         document position <code>pos</code> in the given direction
+     *         <code>d</code>
+     *
+     * @throws BadLocationException if <code>pos</code> is not a valid offset 
+     *         in the document model
+     */
+    public int getNextVisualPositionFrom(JTextComponent c, int pos,
+                                         Position.Bias b, int d,
+                                         Position.Bias[] biasRet)
+      throws BadLocationException
+    {
+      // TODO: Implement this properly.
+      throw new AssertionError("Not implemented yet.");
+    }
+    
+    /**
+     * This method is called from insertUpdate and removeUpdate.
+     * If the number of lines in the document has changed, just repaint
+     * the whole thing (note, could improve performance by not repainting 
+     * anything above the changes).  If the number of lines hasn't changed, 
+     * just repaint the given Rectangle.
+     * @param a the Rectangle to repaint if the number of lines hasn't changed
+     */
+    void updateDamage (Rectangle a)
+    {
+      int newNumLines = determineNumLines();
+      if (numLines != newNumLines)
+        {
+          numLines = newNumLines;
+          getContainer().repaint();
+        }
+      else
+        getContainer().repaint(a.x, a.y, a.width, a.height);
+    }
+    
+    /**
+     * This method is called when something is inserted into the Document
+     * that this View is displaying.
+     * 
+     * @param changes the DocumentEvent for the changes.
+     * @param a the allocation of the View
+     * @param f the ViewFactory used to rebuild
+     */
+    public void insertUpdate (DocumentEvent changes, Shape a, ViewFactory f)
+    {
+      updateDamage((Rectangle)a); 
+    }
+    
+    /**
+     * This method is called when something is removed from the Document
+     * that this View is displaying.
+     * 
+     * @param changes the DocumentEvent for the changes.
+     * @param a the allocation of the View
+     * @param f the ViewFactory used to rebuild
+     */
+    public void removeUpdate (DocumentEvent changes, Shape a, ViewFactory f)
+    {
+      updateDamage((Rectangle)a); 
+    }
+  }
+}
diff --git a/libjava/classpath/javax/swing/text/html/CSS.java b/libjava/classpath/javax/swing/text/html/CSS.java
new file mode 100644
index 0000000..029ad26
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/CSS.java
@@ -0,0 +1,461 @@
+/* CSS.java -- Provides CSS attributes
+   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.html;
+
+import java.util.HashMap;
+
+/**
+ * Provides CSS attributes to be used by the HTML view classes. The constants
+ * defined here are used as keys for text attributes for use in
+ * {@link javax.swing.text.AttributeSet}s of {@link javax.swing.text.Element}s.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+public class CSS
+{
+  /**
+   * Returns an array of all CSS attributes.
+   *
+   * @return All available CSS.Attribute objects.
+   */
+  public static CSS.Attribute[] getAllAttributeKeys()
+  {
+    Object[] src = Attribute.attributeMap.values().toArray();
+    CSS.Attribute[] dst = new CSS.Attribute[ src.length ];
+    System.arraycopy(src, 0, dst, 0, src.length);
+    return dst;
+  }
+
+  /**
+   * Returns an a given CSS attribute.
+   *
+   * @param name - The name of the attribute.
+   * @return The CSS attribute with the given name, or <code>null</code> if
+   * no attribute with that name exists.
+   */
+  public static CSS.Attribute getAttribute(String name)
+  {
+    return (CSS.Attribute)Attribute.attributeMap.get( name );
+  }
+
+  public static final class Attribute
+  {
+    /**
+     * The CSS attribute 'background'.
+     */
+    public static final Attribute BACKGROUND =
+      new Attribute("background", false, null);
+
+    /**
+     * The CSS attribute 'background-attachment'.
+     */
+    public static final Attribute BACKGROUND_ATTACHMENT =
+      new Attribute("background-attachment", false, "scroll");
+
+    /**
+     * The CSS attribute 'background-color'.
+     */
+    public static final Attribute BACKGROUND_COLOR =
+      new Attribute("background-color", false, "transparent");
+
+    /**
+     * The CSS attribute 'background-image'.
+     */
+    public static final Attribute BACKGROUND_IMAGE =
+      new Attribute("background-image", false, "none");
+
+    /**
+     * The CSS attribute 'background-position'.
+     */
+    public static final Attribute BACKGROUND_POSITION =
+      new Attribute("background-position", false, null);
+
+    /**
+     * The CSS attribute 'background-repeat'.
+     */
+    public static final Attribute BACKGROUND_REPEAT =
+      new Attribute("background-repeat", false, "repeat");
+
+    /**
+     * The CSS attribute 'border'.
+     */
+    public static final Attribute BORDER = new Attribute("border", false, null);
+
+    /**
+     * The CSS attribute 'border-bottom'.
+     */
+    public static final Attribute BORDER_BOTTOM =
+      new Attribute("border-bottom", false, null);
+
+    /**
+     * The CSS attribute 'border-bottom-width'.
+     */
+    public static final Attribute BORDER_BOTTOM_WIDTH =
+      new Attribute("border-bottom-width", false, "medium");
+
+    /**
+     * The CSS attribute 'border-color'.
+     */
+    public static final Attribute BORDER_COLOR =
+      new Attribute("border-color", false, "black");
+
+    /**
+     * The CSS attribute 'border-left'.
+     */
+    public static final Attribute BORDER_LEFT =
+      new Attribute("border-left", false, null);
+
+    /**
+     * The CSS attribute 'border-left-width'.
+     */
+    public static final Attribute BORDER_LEFT_WIDTH =
+      new Attribute("border-left-width", false, "medium");
+
+    /**
+     * The CSS attribute 'border-right'.
+     */
+    public static final Attribute BORDER_RIGHT =
+      new Attribute("border-right", false, null);
+
+    /**
+     * The CSS attribute 'border-right-width'.
+     */
+    public static final Attribute BORDER_RIGHT_WIDTH =
+      new Attribute("border-right-width", false, "medium");
+
+    /**
+     * The CSS attribute 'border-style'.
+     */
+    public static final Attribute BORDER_STYLE =
+      new Attribute("border-style", false, "none");
+
+    /**
+     * The CSS attribute 'border-top'.
+     */
+    public static final Attribute BORDER_TOP =
+      new Attribute("border-top", false, null);
+
+    /**
+     * The CSS attribute 'border-top-width'.
+     */
+    public static final Attribute BORDER_TOP_WIDTH =
+      new Attribute("border-top-width", false, "medium");
+
+    /**
+     * The CSS attribute 'border-width'.
+     */
+    public static final Attribute BORDER_WIDTH =
+      new Attribute("border-width", false, "medium");
+
+    /**
+     * The CSS attribute 'clear'.
+     */
+    public static final Attribute CLEAR = new Attribute("clear", false, "none");
+
+    /**
+     * The CSS attribute 'color'.
+     */
+    public static final Attribute COLOR = new Attribute("color", true, "black");
+
+    /**
+     * The CSS attribute 'display'.
+     */
+    public static final Attribute DISPLAY =
+      new Attribute("display", false, "block");
+
+    /**
+     * The CSS attribute 'float'.
+     */
+    public static final Attribute FLOAT = new Attribute("float", false, "none");
+
+    /**
+     * The CSS attribute 'font'.
+     */
+    public static final Attribute FONT = new Attribute("font", true, null);
+
+    /**
+     * The CSS attribute 'font-family'.
+     */
+    public static final Attribute FONT_FAMILY =
+      new Attribute("font-family", true, null);
+
+    /**
+     * The CSS attribute 'font-size'.
+     */
+    public static final Attribute FONT_SIZE =
+      new Attribute("font-size", true, "medium");
+
+    /**
+     * The CSS attribute 'font-style'.
+     */
+    public static final Attribute FONT_STYLE =
+      new Attribute("font-style", true, "normal");
+
+    /**
+     * The CSS attribute 'font-variant'.
+     */
+    public static final Attribute FONT_VARIANT =
+      new Attribute("font-variant", true, "normal");
+
+    /**
+     * The CSS attribute 'font-weight'.
+     */
+    public static final Attribute FONT_WEIGHT =
+      new Attribute("font-weight", true, "normal");
+
+    /**
+     * The CSS attribute 'height'.
+     */
+    public static final Attribute HEIGHT =
+      new Attribute("height", false, "auto");
+
+    /**
+     * The CSS attribute 'letter-spacing'.
+     */
+    public static final Attribute LETTER_SPACING =
+      new Attribute("letter-spacing", true, "normal");
+
+    /**
+     * The CSS attribute 'line-height'.
+     */
+    public static final Attribute LINE_HEIGHT =
+      new Attribute("line-height", true, "normal");
+
+    /**
+     * The CSS attribute 'list-style'.
+     */
+    public static final Attribute LIST_STYLE =
+      new Attribute("list-style", true, null);
+
+    /**
+     * The CSS attribute 'list-style-image'.
+     */
+    public static final Attribute LIST_STYLE_IMAGE =
+      new Attribute("list-style-image", true, "none");
+
+    /**
+     * The CSS attribute 'list-style-position'.
+     */
+    public static final Attribute LIST_STYLE_POSITION =
+      new Attribute("list-style-position", true, "outside");
+
+    /**
+     * The CSS attribute 'list-style-type'.
+     */
+    public static final Attribute LIST_STYLE_TYPE =
+      new Attribute("list-style-type", true, "disc");
+
+    /**
+     * The CSS attribute 'margin'.
+     */
+    public static final Attribute MARGIN = new Attribute("margin", false, null);
+
+    /**
+     * The CSS attribute 'margin-bottom'.
+     */
+    public static final Attribute MARGIN_BOTTOM =
+      new Attribute("margin-bottom", false, "0");
+
+    /**
+     * The CSS attribute 'margin-left'.
+     */
+    public static final Attribute MARGIN_LEFT =
+      new Attribute("margin-left", false, "0");
+
+    /**
+     * The CSS attribute 'margin-right'.
+     */
+    public static final Attribute MARGIN_RIGHT =
+      new Attribute("margin-right", false, "0");
+
+    /**
+     * The CSS attribute 'margin-top'.
+     */
+    public static final Attribute MARGIN_TOP =
+      new Attribute("margin-top", false, "0");
+
+    /**
+     * The CSS attribute 'padding'.
+     */
+    public static final Attribute PADDING =
+      new Attribute("padding", false, null);
+
+    /**
+     * The CSS attribute 'padding-bottom'.
+     */
+    public static final Attribute PADDING_BOTTOM =
+      new Attribute("padding-bottom", false, "0");
+
+    /**
+     * The CSS attribute 'padding-left'.
+     */
+    public static final Attribute PADDING_LEFT =
+      new Attribute("padding-left", false, "0");
+
+    /**
+     * The CSS attribute 'padding-right'.
+     */
+    public static final Attribute PADDING_RIGHT =
+      new Attribute("padding-right", false, "0");
+
+    /**
+     * The CSS attribute 'padding-top'.
+     */
+    public static final Attribute PADDING_TOP =
+      new Attribute("padding-top", false, "0");
+
+    /**
+     * The CSS attribute 'text-align'.
+     */
+    public static final Attribute TEXT_ALIGN =
+      new Attribute("text-align", true, null);
+
+    /**
+     * The CSS attribute 'text-decoration'.
+     */
+    public static final Attribute TEXT_DECORATION =
+      new Attribute("text-decoration", true, "none");
+
+    /**
+     * The CSS attribute 'text-indent'.
+     */
+    public static final Attribute TEXT_INDENT =
+      new Attribute("text-indent", true, "0");
+
+    /**
+     * The CSS attribute 'text-transform'.
+     */
+    public static final Attribute TEXT_TRANSFORM =
+      new Attribute("text-transform", true, "none");
+
+    /**
+     * The CSS attribute 'vertical-align'.
+     */
+    public static final Attribute VERTICAL_ALIGN =
+      new Attribute("vertical-align", false, "baseline");
+
+    /**
+     * The CSS attribute 'white-space'.
+     */
+    public static final Attribute WHITE_SPACE =
+      new Attribute("white-space", true, "normal");
+
+    /**
+     * The CSS attribute 'width'.
+     */
+    public static final Attribute WIDTH =
+      new Attribute("width", false, "auto");
+
+    /**
+     * The CSS attribute 'word-spacing'.
+     */
+    public static final Attribute WORD_SPACING =
+      new Attribute("word-spacing", true, "normal");
+
+    /**
+     * The attribute string.
+     */
+    String attStr;
+
+    /**
+     * Indicates if this attribute should be inherited from it's parent or
+     * not.
+     */
+    boolean isInherited;
+
+    /**
+     * A default value for this attribute if one exists, otherwise null.
+     */
+    String defaultValue;
+
+    /**
+     * A HashMap of all attributes.
+     */
+    static HashMap attributeMap;
+
+    /**
+     * Creates a new Attribute instance with the specified values.
+     *
+     * @param attr the attribute string
+     * @param inherited if the attribute should be inherited or not
+     * @param def a default value; may be <code>null</code> 
+     */
+    Attribute(String attr, boolean inherited, String def)
+    {
+      attStr = attr;
+      isInherited = inherited;
+      defaultValue = def;
+      if( attributeMap == null)
+	attributeMap = new HashMap();
+      attributeMap.put( attr, this );
+    }
+
+    /**
+     * Returns the string representation of this attribute as specified
+     * in the CSS specification.
+     */
+    public String toString()
+    {
+      return attStr;
+    }
+
+    /**
+     * Returns <code>true</code> if the attribute should be inherited from
+     * the parent, <code>false</code> otherwise.
+     *
+     * @return <code>true</code> if the attribute should be inherited from
+     *         the parent, <code>false</code> otherwise
+     */
+    public boolean isInherited()
+    {
+      return isInherited;
+    }
+
+    /**
+     * Returns the default value of this attribute if one exists,
+     * <code>null</code> otherwise.
+     *
+     * @return the default value of this attribute if one exists,
+     *         <code>null</code> otherwise
+     */
+    public String getDefaultValue()
+    {
+      return defaultValue;
+    }
+  }
+}
diff --git a/libjava/classpath/javax/swing/text/html/HTML.java b/libjava/classpath/javax/swing/text/html/HTML.java
index 3c03a63..0b758d2 100644
--- a/libjava/classpath/javax/swing/text/html/HTML.java
+++ b/libjava/classpath/javax/swing/text/html/HTML.java
@@ -945,22 +945,22 @@ public class HTML
      * This tag is not included into the array, returned by getAllTags().
      * toString() returns 'comment'. HTML reader synthesizes this tag.
      */
-    public static final Tag COMMENT = new Tag("comment", SYNTETIC);
+    public static final Tag COMMENT = new Tag("comment", SYNTHETIC);
 
     /**
      *  All text content is labeled with this tag.
      *  This tag is not included into the array, returned by getAllTags().
      *  toString() returns 'content'. HTML reader synthesizes this tag.
      */
-    public static final Tag CONTENT = new Tag("content", SYNTETIC);
+    public static final Tag CONTENT = new Tag("content", SYNTHETIC);
 
     /**
      * All text content must be in a paragraph element.
      * If a paragraph didn't exist when content was encountered,
      * a paragraph is manufactured.
-     * toString() returns 'implied'. HTML reader synthesizes this tag.
+     * toString() returns 'p-implied'. HTML reader synthesizes this tag.
      */
-    public static final Tag IMPLIED = new Tag("implied", SYNTETIC);
+    public static final Tag IMPLIED = new Tag("p-implied", SYNTHETIC);
     final String name;
     final int flags;
 
@@ -1144,7 +1144,7 @@ public class HTML
      */
     boolean isSyntetic()
     {
-      return (flags & SYNTETIC) != 0;
+      return (flags & SYNTHETIC) != 0;
     }
 
     private static void unexpected(Exception ex)
@@ -1185,7 +1185,7 @@ public class HTML
   static final int BREAKS = 1;
   static final int BLOCK = 2;
   static final int PREFORMATTED = 4;
-  static final int SYNTETIC = 8;
+  static final int SYNTHETIC = 8;
   private static Map tagMap;
   private static Map attrMap;
 
@@ -1196,6 +1196,7 @@ public class HTML
    */
   public HTML()
   {
+    // Nothing to do here.
   }
 
   /**
diff --git a/libjava/classpath/javax/swing/text/html/HTMLDocument.java b/libjava/classpath/javax/swing/text/html/HTMLDocument.java
index a95e496..d048a04 100644
--- a/libjava/classpath/javax/swing/text/html/HTMLDocument.java
+++ b/libjava/classpath/javax/swing/text/html/HTMLDocument.java
@@ -38,7 +38,14 @@ exception statement from your version. */
 
 package javax.swing.text.html;
 
+import java.net.URL;
+
+import javax.swing.text.AbstractDocument;
+import javax.swing.text.AttributeSet;
 import javax.swing.text.DefaultStyledDocument;
+import javax.swing.text.Element;
+import javax.swing.text.ElementIterator;
+import javax.swing.text.html.HTML.Tag;
 
 /**
  * TODO: This class is not yet completetely implemented.
@@ -47,7 +54,215 @@ import javax.swing.text.DefaultStyledDocument;
  */
 public class HTMLDocument extends DefaultStyledDocument
 {
+  /** A key for document properies.  The value for the key is
+   * a Vector of Strings of comments not found in the body.
+   */  
+  public static final String AdditionalComments = "AdditionalComments";
+  URL baseURL = null;
+  boolean preservesUnknownTags = true;
+  
+  /**
+   * Returns the location against which to resolve relative URLs.
+   * This is the document's URL if the document was loaded from a URL.
+   * If a <code>base</code> tag is found, it will be used.
+   * @return the base URL
+   */
+  public URL getBase()
+  {
+    return baseURL;
+  }
+  
+  /**
+   * Sets the location against which to resolve relative URLs.
+   * @param u the new base URL
+   */
+  public void setBase(URL u)
+  {
+    baseURL = u;
+    //TODO: also set the base of the StyleSheet
+  }
+  
+  /**
+   * Returns whether or not the parser preserves unknown HTML tags.
+   * @return true if the parser preserves unknown tags
+   */
+  public boolean getPreservesUnknownTags()
+  {
+    return preservesUnknownTags;
+  }
+  
+  /**
+   * Sets the behaviour of the parser when it encounters unknown HTML tags.
+   * @param preservesTags true if the parser should preserve unknown tags.
+   */
+  public void setPreservesUnknownTags(boolean preservesTags)
+  {
+    preservesUnknownTags = preservesTags;
+  }
+  
+  /**
+   * An iterator to iterate through LeafElements in the document.
+   */
+  class LeafIterator extends Iterator
+  {
+    HTML.Tag tag;
+    HTMLDocument doc;
+    ElementIterator it;
+
+    public LeafIterator (HTML.Tag t, HTMLDocument d)
+    {
+      doc = d;
+      tag = t;
+      it = new ElementIterator(doc);
+    }
+    
+    /**
+     * Return the attributes for the tag associated with this iteartor
+     * @return the AttributeSet
+     */
+    public AttributeSet getAttributes()
+    {
+      if (it.current() != null)
+        return it.current().getAttributes();
+      return null;
+    }
+
+    /**
+     * Get the end of the range for the current occurrence of the tag
+     * being defined and having the same attributes.
+     * @return the end of the range
+     */
+    public int getEndOffset()
+    {
+      if (it.current() != null)
+        return it.current().getEndOffset();
+      return -1;
+    }
+
+    /**
+     * Get the start of the range for the current occurrence of the tag
+     * being defined and having the same attributes.
+     * @return the start of the range (-1 if it can't be found).
+     */
+
+    public int getStartOffset()
+    {
+      if (it.current() != null)
+        return it.current().getStartOffset();
+      return -1;
+    }
+
+    /**
+     * Advance the iterator to the next LeafElement .
+     */
+    public void next()
+    {
+      it.next();
+      while (it.current()!= null && !it.current().isLeaf())
+        it.next();
+    }
+
+    /**
+     * Indicates whether or not the iterator currently represents an occurrence
+     * of the tag.
+     * @return true if the iterator currently represents an occurrence of the
+     * tag.
+     */
+    public boolean isValid()
+    {
+      return it.current() != null;
+    }
+
+    /**
+     * Type of tag for this iterator.
+     */
+    public Tag getTag()
+    {
+      return tag;
+    }
+
+  }
+
   public void processHTMLFrameHyperlinkEvent(HTMLFrameHyperlinkEvent event)
   {
+    // TODO: Implement this properly.
+  }
+  
+  /**
+   * Gets an iterator for the given HTML.Tag.
+   * @param t the requested HTML.Tag
+   * @return the Iterator
+   */
+  public HTMLDocument.Iterator getIterator (HTML.Tag t)
+  {
+    return new HTMLDocument.LeafIterator(t, this);
+  }
+  
+  /**
+   * An iterator over a particular type of tag.
+   */
+  public abstract static class Iterator
+  {
+    /**
+     * Return the attribute set for this tag.
+     * @return the <code>AttributeSet</code> (null if none found).
+     */
+    public abstract AttributeSet getAttributes();
+    
+    /**
+     * Get the end of the range for the current occurrence of the tag
+     * being defined and having the same attributes.
+     * @return the end of the range
+     */
+    public abstract int getEndOffset();
+    
+    /**
+     * Get the start of the range for the current occurrence of the tag
+     * being defined and having the same attributes.
+     * @return the start of the range (-1 if it can't be found).
+     */
+    public abstract int getStartOffset();
+    
+    /**
+     * Move the iterator forward.
+     */
+    public abstract void next();
+    
+    /**
+     * Indicates whether or not the iterator currently represents an occurrence
+     * of the tag.
+     * @return true if the iterator currently represents an occurrence of the
+     * tag.
+     */
+    public abstract boolean isValid();
+    
+    /**
+     * Type of tag this iterator represents.
+     * @return the tag.
+     */
+    public abstract HTML.Tag getTag();
+  }
+  
+  public class BlockElement extends AbstractDocument.BranchElement
+  {
+    public BlockElement (Element parent, AttributeSet a)
+    {
+      super (parent, a);
+    }
+    
+    /**
+     * Gets the resolving parent.  Since HTML attributes are not 
+     * inherited at the model level, this returns null.
+     */
+    public AttributeSet getResolveParent()
+    {
+      return null;
+    }
+    
+    public String getName()
+    {
+      //FIXME: this is supposed to do something different from the super class
+      return super.getName();
+    }
   }
 }
diff --git a/libjava/classpath/javax/swing/text/html/HTMLEditorKit.java b/libjava/classpath/javax/swing/text/html/HTMLEditorKit.java
index c0182fe..5189c77 100644
--- a/libjava/classpath/javax/swing/text/html/HTMLEditorKit.java
+++ b/libjava/classpath/javax/swing/text/html/HTMLEditorKit.java
@@ -43,8 +43,10 @@ import java.io.Reader;
 import java.io.Serializable;
 
 import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
 import javax.swing.text.MutableAttributeSet;
 import javax.swing.text.StyledEditorKit;
+import javax.swing.text.html.parser.ParserDelegator;
 
 /**
  * This class is NOT implemented. This file currently holds only
@@ -96,9 +98,9 @@ public class HTMLEditorKit
     /**
      * The parser calls this method after it finishes parsing the document.
      */
-    public void flush()
-               throws BadLocationException
+    public void flush() throws BadLocationException
     {
+      // TODO: What to do here, if anything?
     }
 
     /**
@@ -108,6 +110,7 @@ public class HTMLEditorKit
      */
     public void handleComment(char[] comment, int position)
     {
+      // TODO: What to do here, if anything?
     }
 
     /**
@@ -118,6 +121,7 @@ public class HTMLEditorKit
      */
     public void handleEndOfLineString(String end_of_line)
     {
+      // TODO: What to do here, if anything?
     }
 
     /**
@@ -129,6 +133,7 @@ public class HTMLEditorKit
      */
     public void handleEndTag(HTML.Tag tag, int position)
     {
+      // TODO: What to do here, if anything?
     }
 
     /**
@@ -139,6 +144,7 @@ public class HTMLEditorKit
      */
     public void handleError(String message, int position)
     {
+      // TODO: What to do here, if anything?
     }
 
     /**
@@ -149,9 +155,9 @@ public class HTMLEditorKit
      * @param position The tag position in the text being parsed.
      */
     public void handleSimpleTag(HTML.Tag tag, MutableAttributeSet attributes,
-                                int position
-                               )
+                                int position)
     {
+      // TODO: What to do here, if anything?
     }
 
     /**
@@ -165,6 +171,7 @@ public class HTMLEditorKit
                                int position
                               )
     {
+      // TODO: What to do here, if anything?
     }
 
     /**
@@ -174,6 +181,7 @@ public class HTMLEditorKit
      */
     public void handleText(char[] text, int position)
     {
+      // TODO: What to do here, if anything?
     }
   }
 
@@ -247,4 +255,26 @@ public class HTMLEditorKit
    * The "ident paragraph right" action.
    */
   public static final String PARA_INDENT_RIGHT = "html-para-indent-right";
+
+  /**
+   * Create a text storage model for this type of editor.
+   *
+   * @return the model
+   */
+  public Document createDefaultDocument()
+  {
+    HTMLDocument document = new HTMLDocument();
+    return document;
+  }
+
+  /**
+   * Get the parser that this editor kit uses for reading HTML streams. This
+   * method can be overridden to use the alternative parser.
+   *
+   * @return the HTML parser (by default, {@link ParserDelegator}).
+   */
+  protected Parser getParser()
+  {
+    return new ParserDelegator();
+  }
 }
\ No newline at end of file
diff --git a/libjava/classpath/javax/swing/text/html/HTMLFrameHyperlinkEvent.java b/libjava/classpath/javax/swing/text/html/HTMLFrameHyperlinkEvent.java
index dc0ab10..e146965 100644
--- a/libjava/classpath/javax/swing/text/html/HTMLFrameHyperlinkEvent.java
+++ b/libjava/classpath/javax/swing/text/html/HTMLFrameHyperlinkEvent.java
@@ -41,7 +41,6 @@ package javax.swing.text.html;
 import java.net.URL;
 
 import javax.swing.event.HyperlinkEvent;
-import javax.swing.event.HyperlinkEvent.EventType;
 import javax.swing.text.Element;
 
 /**
@@ -50,8 +49,7 @@ import javax.swing.text.Element;
  *
  * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
  */
-public class HTMLFrameHyperlinkEvent
-  extends HyperlinkEvent
+public class HTMLFrameHyperlinkEvent extends HyperlinkEvent
 {
   private final String target_frame;
 
diff --git a/libjava/classpath/javax/swing/text/html/parser/ContentModel.java b/libjava/classpath/javax/swing/text/html/parser/ContentModel.java
index deb7b16..70e9c2a 100644
--- a/libjava/classpath/javax/swing/text/html/parser/ContentModel.java
+++ b/libjava/classpath/javax/swing/text/html/parser/ContentModel.java
@@ -95,9 +95,12 @@ public final class ContentModel
    */
   public int type;
 
-  /** Create a content model initializing all fields to default values. */
+  /**
+   * Create a content model initializing all fields to default values.
+   */
   public ContentModel()
   {
+    // Nothing to do here.
   }
 
   /**
diff --git a/libjava/classpath/javax/swing/text/html/parser/DTD.java b/libjava/classpath/javax/swing/text/html/parser/DTD.java
index f17ca01..16bc5b0 100644
--- a/libjava/classpath/javax/swing/text/html/parser/DTD.java
+++ b/libjava/classpath/javax/swing/text/html/parser/DTD.java
@@ -81,8 +81,9 @@ public class DTD
 {
   /**
    * The version of the persistent data format.
+   * @specnote This was made <code>final</code> in 1.5.
    */
-  public static int FILE_VERSION = 1;
+  public static final int FILE_VERSION = 1;
 
   /**
    * The table of existing available DTDs.
@@ -590,8 +591,7 @@ public class DTD
    * @param name the name of the entity
    * @param type the type of the entity, a bitwise combination
    * of GENERAL, PARAMETER, SYSTEM and PUBLIC.
-   * @throws an error if the parameter is both GENERAL and PARAMETER
-   * of both PUBLIC and SYSTEM.
+   *
    * @return the created entity
    */
   private Entity newEntity(String name, int type)
diff --git a/libjava/classpath/javax/swing/text/html/parser/DocumentParser.java b/libjava/classpath/javax/swing/text/html/parser/DocumentParser.java
index 164297f..062606d 100644
--- a/libjava/classpath/javax/swing/text/html/parser/DocumentParser.java
+++ b/libjava/classpath/javax/swing/text/html/parser/DocumentParser.java
@@ -168,6 +168,7 @@ public class DocumentParser
    * specific packages, write your own DTD or obtain the working instance
    * of parser in other way, for example, by calling
    * {@link javax.swing.text.html.HTMLEditorKit#getParser()}.
+   *
    * @param a_dtd a DTD to use.
    */
   public DocumentParser(DTD a_dtd)
@@ -212,6 +213,7 @@ public class DocumentParser
    */
   protected void handleComment(char[] comment)
   {
+    // This default implementation does nothing.
   }
 
   /**
@@ -224,6 +226,7 @@ public class DocumentParser
   protected void handleEmptyTag(TagElement tag)
                          throws javax.swing.text.ChangedCharSetException
   {
+    // This default implementation does nothing.
   }
 
   /**
@@ -234,11 +237,13 @@ public class DocumentParser
    */
   protected void handleEndTag(TagElement tag)
   {
+    // This default implementation does nothing.
   }
 
   /* Handle error that has occured in the given line. */
   protected void handleError(int line, String message)
   {
+    // This default implementation does nothing.
   }
 
   /**
@@ -249,6 +254,7 @@ public class DocumentParser
    */
   protected void handleStartTag(TagElement tag)
   {
+    // This default implementation does nothing.
   }
 
   /**
@@ -257,5 +263,6 @@ public class DocumentParser
    */
   protected void handleText(char[] text)
   {
+    // This default implementation does nothing.
   }
 }
diff --git a/libjava/classpath/javax/swing/text/html/parser/Element.java b/libjava/classpath/javax/swing/text/html/parser/Element.java
index 098983c..c07c07f 100644
--- a/libjava/classpath/javax/swing/text/html/parser/Element.java
+++ b/libjava/classpath/javax/swing/text/html/parser/Element.java
@@ -148,10 +148,10 @@ public final class Element
   /**
    * The default constructor must have package level access in this
    * class. Use DTD.defineElement(..) to create an element when required.
-   * @todo MAKE THIS PACKAGE in the final version. Now the Parser needs it!
    */
   Element()
   {
+    // Nothing to do here.
   }
 
   /**
diff --git a/libjava/classpath/javax/swing/text/html/parser/Parser.java b/libjava/classpath/javax/swing/text/html/parser/Parser.java
index 7ff6853..a88e9ce 100644
--- a/libjava/classpath/javax/swing/text/html/parser/Parser.java
+++ b/libjava/classpath/javax/swing/text/html/parser/Parser.java
@@ -256,6 +256,7 @@ public class Parser
    */
   protected void endTag(boolean omitted)
   {
+    // This default implementation does nothing.
   }
 
   /**
@@ -310,6 +311,7 @@ public class Parser
    */
   protected void handleComment(char[] comment)
   {
+    // This default implementation does nothing.
   }
 
   /**
@@ -333,6 +335,7 @@ public class Parser
   protected void handleEmptyTag(TagElement tag)
     throws ChangedCharSetException
   {
+    // This default implementation does nothing.
   }
 
   /**
@@ -343,11 +346,13 @@ public class Parser
    */
   protected void handleEndTag(TagElement tag)
   {
+    // This default implementation does nothing.
   }
 
   /* Handle error that has occured in the given line. */
   protected void handleError(int line, String message)
   {
+    // This default implementation does nothing.
   }
 
   /**
@@ -358,6 +363,7 @@ public class Parser
    */
   protected void handleStartTag(TagElement tag)
   {
+    // This default implementation does nothing.
   }
 
   /**
@@ -376,6 +382,7 @@ public class Parser
    */
   protected void handleText(char[] text)
   {
+    // This default implementation does nothing.
   }
 
   /**
@@ -387,6 +394,7 @@ public class Parser
    */
   protected void handleTitle(char[] title)
   {
+    // This default implementation does nothing.
   }
 
   /**
@@ -420,6 +428,7 @@ public class Parser
    */
   protected void markFirstTime(Element element)
   {
+    // This default implementation does nothing.
   }
 
   /**
@@ -432,5 +441,6 @@ public class Parser
   protected void startTag(TagElement tag)
     throws ChangedCharSetException
   {
+    // This default implementation does nothing.
   }
 }
-- 
cgit v1.1