This implements the asynchronous/incremental loading facility for the
JEditorPane. Asynchronous means that loading is performed in a seperate
thread, thus freeing the event queue and keeping the GUI responsive.
Incremental loading means that the HTML is parsed in chunks, pushing the
partial HTML to the views for quick rendering. This way, even huge
documents like:

http://www.kaffe.org/~stuart/japi/htmlout/h-jdk15-classpath.html

can be rendered quite snappy:

http://kennke.org/~roman/japi6.png

2006-11-19  Roman Kennke  <[EMAIL PROTECTED]>

        * javax/swing/JEditorPane.java
        (PageStream): New inner class.
        (PageLoader): New inner class.
        (loading): New field.
        (setPage): Implemented asynchronous loading.
        * javax/swing/text/DefaultStyledDocument.java
        (ElementBuffer.create): New helper method.
        (create): Use new ElementBuffer method instead of hack.
        * javax/swing/text/html/HTMLDocument.java
        (HTMLReader.flushImpl): New helper method.
        (HTMLReader.addContent): Use flushImpl().
        (HTMLReader.blockClose): Added null check.
        (HTMLReader.flush): Use flushImpl().
        * javax/swing/text/html/HTMLEditorKit.java
        (createDefaultDocument): Set load priority to 4 and token
threshold
        to 100.
        * javax/swing/text/html/TableView.java
        (insertUpdate): Overridden to provide correct view factory.
        (removeUpdate): Overridden to provide correct view factory.
        (changedUpdate): Overridden to provide correct view factory.

/Roman
Index: javax/swing/JEditorPane.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/JEditorPane.java,v
retrieving revision 1.38
diff -u -1 -5 -r1.38 JEditorPane.java
--- javax/swing/JEditorPane.java	2 Nov 2006 14:00:45 -0000	1.38
+++ javax/swing/JEditorPane.java	19 Nov 2006 19:36:40 -0000
@@ -28,48 +28,51 @@
 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;
 
 import java.awt.Container;
 import java.awt.Dimension;
+import java.awt.Rectangle;
+import java.io.FilterInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.Reader;
 import java.io.StringReader;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URLConnection;
 import java.util.HashMap;
 
 import javax.accessibility.AccessibleContext;
 import javax.accessibility.AccessibleHyperlink;
 import javax.accessibility.AccessibleHypertext;
 import javax.accessibility.AccessibleStateSet;
 import javax.accessibility.AccessibleText;
 import javax.swing.event.HyperlinkEvent;
 import javax.swing.event.HyperlinkListener;
 import javax.swing.plaf.TextUI;
+import javax.swing.text.AbstractDocument;
 import javax.swing.text.BadLocationException;
 import javax.swing.text.DefaultEditorKit;
 import javax.swing.text.Document;
 import javax.swing.text.EditorKit;
 import javax.swing.text.Element;
 import javax.swing.text.JTextComponent;
 import javax.swing.text.View;
 import javax.swing.text.ViewFactory;
 import javax.swing.text.WrappedPlainView;
 import javax.swing.text.html.HTML;
 import javax.swing.text.html.HTMLDocument;
 import javax.swing.text.html.HTMLEditorKit;
 
 /**
  * A powerful text editor component that can handle different types of
@@ -495,42 +498,162 @@
     /**
      * Returns a ViewFactory that supplies WrappedPlainViews.
      */
     public ViewFactory getViewFactory()
     {
       return new ViewFactory()
       {
         public View create(Element el)
         {
           return new WrappedPlainView(el);
         }
       };
     }
   }
 
+  /**
+   * A special stream that can be cancelled.
+   */
+  private class PageStream
+    extends FilterInputStream
+  {
+    /**
+     * True when the stream has been cancelled, false otherwise.
+     */
+    private boolean cancelled;
+
+    protected PageStream(InputStream in)
+    {
+      super(in);
+      cancelled = false;
+    }
+
+    private void checkCancelled()
+      throws IOException
+    {
+      if (cancelled)
+        throw new IOException("Stream has been cancelled");
+    }
+
+    void cancel()
+    {
+      cancelled = true;
+    }
+
+    public int read()
+      throws IOException
+    {
+      checkCancelled();
+      return super.read();
+    }
+
+    public int read(byte[] b, int off, int len)
+      throws IOException
+    {
+      checkCancelled();
+      return super.read(b, off, len);
+    }
+
+    public long skip(long n)
+      throws IOException
+    {
+      checkCancelled();
+      return super.skip(n);
+    }
+
+    public int available()
+      throws IOException
+    {
+      checkCancelled();
+      return super.available();
+    }
+
+    public void reset()
+      throws IOException
+    {
+      checkCancelled();
+      super.reset();
+    }
+  }
+
+  /**
+   * The thread that loads documents asynchronously.
+   */
+  private class PageLoader
+    implements Runnable
+  {
+    private Document doc;
+    private InputStream in;
+    private URL old;
+    private URL page;
+    PageLoader(Document doc, InputStream in, int prio, URL old, URL page)
+    {
+      this.doc = doc;
+      this.in = in;
+      this.old = old;
+      this.page = page;
+    }
+
+    public void run()
+    {
+      try
+        {
+          read(in, doc);
+          synchronized (JEditorPane.this)
+          {
+            loading = null;
+          }
+        }
+      catch (IOException ex)
+        {
+          UIManager.getLookAndFeel().provideErrorFeedback(JEditorPane.this);
+        }
+      finally
+        {
+          if (SwingUtilities.isEventDispatchThread())
+            firePropertyChange("page", old, page);
+          else
+            {
+              SwingUtilities.invokeLater(new Runnable()
+              {
+                public void run()
+                {
+                  firePropertyChange("page", old, page);
+                }
+              });
+            }
+      }
+     }
+  }
+
   private static final long serialVersionUID = 3140472492599046285L;
   
   private EditorKit editorKit;
   
   boolean focus_root;
   
   // A mapping between content types and registered EditorKit types
   static HashMap registerMap;
   
   // A mapping between content types and used EditorKits
   HashMap editorMap;  
 
+  /**
+   * The currently loading stream, if any.
+   */
+  private PageStream loading;
+
   public JEditorPane()
   {
     init();
     setEditorKit(createDefaultEditorKit());
   }
 
   public JEditorPane(String url) throws IOException
   {
     this(new URL(url));
   }
 
   public JEditorPane(String type, String text)
   {
     init();
     setEditorKit(createEditorKitForContentType(type));
@@ -924,40 +1047,83 @@
    * Sets the current URL being displayed.  
    */
   public void setPage(String url) throws IOException
   {
     setPage(new URL(url));
   }
 
   /**
    * Sets the current URL being displayed.  
    */
   public void setPage(URL page) throws IOException
   {
     if (page == null)
       throw new IOException("invalid url");
 
-    URL old = getPage();;
-    InputStream in = getStream(page);
-    if (editorKit != null)
+    URL old = getPage();
+    // Reset scrollbar when URL actually changes.
+    if (! page.equals(old) && page.getRef() == null)
+      scrollRectToVisible(new Rectangle(0, 0, 1, 1));
+
+    // Only reload if the URL doesn't point to the same file.
+    // This is not the same as equals because there might be different
+    // URLs on the same file with different anchors.
+    if (old == null || ! old.sameFile(page))
       {
-        Document doc = editorKit.createDefaultDocument();
-        doc.putProperty(Document.StreamDescriptionProperty, page);
-        read(in, doc);
-        setDocument(doc);
+        InputStream in = getStream(page);
+        if (editorKit != null)
+          {
+            Document doc = editorKit.createDefaultDocument();
+            doc.putProperty(Document.StreamDescriptionProperty, page);
+
+            // Cancel loading stream, if there is any.
+            synchronized (this)
+              {
+                if (loading != null)
+                  {
+                    loading.cancel();
+                    loading = null;
+                  }
+              }
+            int prio = -1;
+            if (doc instanceof AbstractDocument)
+              {
+                AbstractDocument aDoc = (AbstractDocument) doc;
+                prio = aDoc.getAsynchronousLoadPriority();
+              }
+            if (prio >= 0)
+              {
+                // Load asynchronously.
+                setDocument(doc);
+                synchronized (this)
+                  {
+                    loading = new PageStream(in);
+                  }
+                PageLoader loader = new PageLoader(doc, loading, prio, old,
+                                                   page);
+                Thread loadThread = new Thread(loader);
+                loadThread.start();
+              }
+            else
+              {
+                // Load synchronously.
+                PageLoader loader = new PageLoader(doc, in, prio, old, page);
+                loader.run();
+                setDocument(doc);
+              }
+          }
       }
-    firePropertyChange("page", old, page);
   }
 
   /**
    * Sets the text of the JEditorPane.  The argument <code>t</code>
    * is expected to be in the format of the current EditorKit.  This removes
    * the content of the current document and uses the EditorKit to read in the
    * new text.  This allows the EditorKit to handle the String rather than just
    * inserting in plain text.
    * 
    * @param t the text to display in this JEditorPane
    */
   public void setText(String t)
   {
     try
     {
Index: javax/swing/text/DefaultStyledDocument.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/DefaultStyledDocument.java,v
retrieving revision 1.68
diff -u -1 -5 -r1.68 DefaultStyledDocument.java
--- javax/swing/text/DefaultStyledDocument.java	25 Aug 2006 13:15:35 -0000	1.68
+++ javax/swing/text/DefaultStyledDocument.java	19 Nov 2006 19:36:41 -0000
@@ -671,30 +671,82 @@
                     }
                 }
             }
             }
 
           // Perform changes.
           pop();
 
           // Return true if we no longer have any children.
           if(elem.getElementCount() == (ec.removed.size() - ec.added.size()))
             ret = true;
         }
       return ret;
     }
 
+    /**
+     * Creates a document in response to a call to
+     * [EMAIL PROTECTED] DefaultStyledDocument#create(ElementSpec[])}.
+     *
+     * @param len the length of the inserted text
+     * @param data the specs for the elements
+     * @param ev the document event
+     */
+    void create(int len, ElementSpec[] data, DefaultDocumentEvent ev)
+    {
+      prepareEdit(offset, len);
+      Element el = root;
+      int index = el.getElementIndex(0);
+      while (! el.isLeaf())
+        {
+          Element child = el.getElement(index);
+          Edit edit = new Edit(el, index, false);
+          elementStack.push(edit);
+          el = child;
+          index = el.getElementIndex(0);
+        }
+      Edit ed = (Edit) elementStack.peek();
+      Element child = ed.e.getElement(ed.index);
+      ed.added.add(createLeafElement(ed.e, child.getAttributes(), getLength(),
+                                     child.getEndOffset()));
+      ed.removed.add(child);
+      while (elementStack.size() > 1)
+        pop();
+      int n = data.length;
+
+      // Reset root element's attributes.
+      AttributeSet newAtts = null;
+      if (n > 0 && data[0].getType() == ElementSpec.StartTagType)
+        newAtts = data[0].getAttributes();
+      if (newAtts == null)
+        newAtts = SimpleAttributeSet.EMPTY;
+      MutableAttributeSet mAtts = (MutableAttributeSet) root.getAttributes();
+      ev.addEdit(new AttributeUndoableEdit(root, newAtts, true));
+      mAtts.removeAttributes(mAtts);
+      mAtts.addAttributes(newAtts);
+
+      // Insert the specified elements.
+      for (int i = 1; i < n; i++)
+        insertElement(data[i]);
+
+      // Pop remaining stack.
+      while (elementStack.size() > 0)
+        pop();
+
+      finishEdit(ev);
+    }
+
     private boolean canJoin(Element e0, Element e1)
     {
       boolean ret = false;
       if ((e0 != null) && (e1 != null))
         {
           // Don't join a leaf to a branch.
           boolean isLeaf0 = e0.isLeaf();
           boolean isLeaf1 = e1.isLeaf();
           if(isLeaf0 == isLeaf1)
             {
               if (isLeaf0)
                 {
                   // Only join leaves if the attributes match, otherwise
                   // style information will be lost.
                   ret = e0.getAttributes().isEqual(e1.getAttributes());
@@ -2367,112 +2419,100 @@
           {
             // Collect all inserts into one so we can get the correct
             // ElementEdit
             ElementSpec spec = data[i];
             if (spec.getArray() != null && spec.getLength() > 0)
               contentBuffer.append(spec.getArray(), spec.getOffset(),
                                    spec.getLength());
           }
 
         int length = contentBuffer.length();
 
         // If there was no content inserted then exit early.
         if (length == 0)
           return;
 
-        UndoableEdit edit = content.insertString(offset,
-                                                 contentBuffer.toString());
+        Content c = getContent();
+        UndoableEdit edit = c.insertString(offset,
+                                           contentBuffer.toString());
 
         // Create the DocumentEvent with the ElementEdit added
         DefaultDocumentEvent ev = new DefaultDocumentEvent(offset,
                                                            length,
                                                            DocumentEvent.EventType.INSERT);
+
         ev.addEdit(edit);
 
         // Finally we must update the document structure and fire the insert
         // update event.
         buffer.insert(offset, length, data, ev);
+
+        super.insertUpdate(ev, null);
+
+        ev.end();
         fireInsertUpdate(ev);
         fireUndoableEditUpdate(new UndoableEditEvent(this, ev));
       }
     finally
       {
         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)
   {
-    writeLock();
     try
       {
+
         // Clear content if there is some.
         int len = getLength();
         if (len > 0)
           remove(0, len);
 
+        writeLock();
+
         // Now we insert the content.
         StringBuilder b = new StringBuilder();
         for (int i = 0; i < data.length; ++i)
           {
             ElementSpec el = data[i];
             if (el.getArray() != null && el.getLength() > 0)
               b.append(el.getArray(), el.getOffset(), el.getLength());
           }
         Content content = getContent();
         UndoableEdit cEdit = content.insertString(0, b.toString());
 
+        len = b.length();
         DefaultDocumentEvent ev =
           new DefaultDocumentEvent(0, b.length(),
                                    DocumentEvent.EventType.INSERT);
         ev.addEdit(cEdit);
 
-        // We do a little trick here to get the new structure: We instantiate
-        // a new ElementBuffer with a new root element, insert into that root
-        // and then reparent the newly created elements to the old root
-        // element.
-        BranchElement createRoot =
-          (BranchElement) createBranchElement(null, null);
-        Element dummyLeaf = createLeafElement(createRoot, null, 0, 1);
-        createRoot.replace(0, 0, new Element[]{ dummyLeaf });
-        ElementBuffer createBuffer = new ElementBuffer(createRoot);
-        createBuffer.insert(0, b.length(), data, new DefaultDocumentEvent(0, b.length(), DocumentEvent.EventType.INSERT));
-        // Now the new root is the first child of the createRoot.
-        Element newRoot = createRoot.getElement(0);
-        BranchElement root = (BranchElement) getDefaultRootElement();
-        Element[] added = new Element[newRoot.getElementCount()];
-        for (int i = 0; i < added.length; ++i)
-          {
-            added[i] = newRoot.getElement(i);
-            ((AbstractElement) added[i]).element_parent = root;
-          }
-        Element[] removed = new Element[root.getElementCount()];
-        for (int i = 0; i < removed.length; ++i)
-          removed[i] = root.getElement(i);
-
-        // Replace the old elements in root with the new and update the event.
-        root.replace(0, removed.length, added);
-        ev.addEdit(new ElementEdit(root, 0, removed, added));
+        buffer.create(len, data, ev);
+
+        // For the bidi update.
+        super.insertUpdate(ev, null);
 
+        ev.end();
         fireInsertUpdate(ev);
         fireUndoableEditUpdate(new UndoableEditEvent(this, ev));
       }
     catch (BadLocationException ex)
       {
         AssertionError err = new AssertionError("Unexpected bad location");
         err.initCause(ex);
         throw err;
       }
     finally
       {
         writeUnlock();
       }
   }
 }
Index: javax/swing/text/html/HTMLDocument.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/html/HTMLDocument.java,v
retrieving revision 1.50
diff -u -1 -5 -r1.50 HTMLDocument.java
--- javax/swing/text/html/HTMLDocument.java	15 Nov 2006 13:35:05 -0000	1.50
+++ javax/swing/text/html/HTMLDocument.java	19 Nov 2006 19:36:41 -0000
@@ -1281,42 +1281,52 @@
      * 
      * @param t the Tag to register
      * @param a the Action for the Tag
      */
     protected void registerTag(HTML.Tag t, HTMLDocument.HTMLReader.TagAction a)
     {
       tagToAction.put (t, a);
     }
     
     /**
      * This is the last method called on the HTMLReader, allowing any pending
      * changes to be flushed to the HTMLDocument.
      */
     public void flush() throws BadLocationException
     {
-      DefaultStyledDocument.ElementSpec[] elements;
-      elements = new DefaultStyledDocument.ElementSpec[parseBuffer.size()];
-      parseBuffer.copyInto(elements);
-      parseBuffer.removeAllElements();
-      if (offset == 0)
-        create(elements);
-      else
-        insert(offset, elements);
+      flushImpl();
+    }
 
-      offset += HTMLDocument.this.getLength() - offset;
+    /**
+     * Flushes the buffer and handle partial inserts.
+     *
+     */
+    private void flushImpl()
+      throws BadLocationException
+    {
+      int oldLen = getLength();
+      int size = parseBuffer.size();
+      ElementSpec[] elems = new ElementSpec[size];
+      parseBuffer.copyInto(elems);
+      if (oldLen == 0)
+        create(elems);
+      else
+        insert(offset, elems);
+      parseBuffer.removeAllElements();
+      offset += getLength() - oldLen;
     }
-    
+
     /**
      * This method is called by the parser to indicate a block of 
      * text was encountered.  Should insert the text appropriately.
      * 
      * @param data the text that was inserted
      * @param pos the position at which the text was inserted
      */
     public void handleText(char[] data, int pos)
     {
       if (shouldInsert() && data != null && data.length > 0)
         {
           if (inTextArea)
             textAreaContent(data);
           else if (inPreTag)
             preContent(data);
@@ -1523,33 +1533,34 @@
     protected void blockClose(HTML.Tag t)
     {
       DefaultStyledDocument.ElementSpec element;
 
       if (inImpliedParagraph)
         {
           inImpliedParagraph = false;
           inParagraph = false;
           if (t != HTML.Tag.IMPLIED)
             blockClose(HTML.Tag.IMPLIED);
         }
 
       // If the previous tag is a start tag then we insert a synthetic
       // content tag.
       DefaultStyledDocument.ElementSpec prev;
-      prev = (DefaultStyledDocument.ElementSpec)
-	      parseBuffer.get(parseBuffer.size() - 1);
-      if (prev.getType() == DefaultStyledDocument.ElementSpec.StartTagType)
+      prev = parseBuffer.size() > 0 ? (DefaultStyledDocument.ElementSpec)
+                                parseBuffer.get(parseBuffer.size() - 1) : null;
+      if (prev != null &&
+          prev.getType() == DefaultStyledDocument.ElementSpec.StartTagType)
         {
           addContent(new char[]{' '}, 0, 1);
         }
 
       element = new DefaultStyledDocument.ElementSpec(null,
 				DefaultStyledDocument.ElementSpec.EndTagType);
       parseBuffer.addElement(element);
     }
     
     /**
      * Adds text to the appropriate context using the current character
      * attribute set.
      * 
      * @param data the text to add
      * @param offs the offset at which to add it
@@ -1591,31 +1602,31 @@
       else
         attributes = ctx.getEmptySet();
       attributes = ctx.addAttribute(attributes, StyleConstants.NameAttribute,
                                     HTML.Tag.CONTENT);
       element = new DefaultStyledDocument.ElementSpec(attributes,
                                 DefaultStyledDocument.ElementSpec.ContentType,
                                 data, offs, length);
       
       // Add the element to the buffer
       parseBuffer.addElement(element);
 
       if (parseBuffer.size() > HTMLDocument.this.getTokenThreshold())
         {
           try
             {
-              flush();
+              flushImpl();
             }
           catch (BadLocationException ble)
             {
               // TODO: what to do here?
             }
         }
     }
     
     /**
      * Adds content that is specified in the attribute set.
      * 
      * @param t the HTML.Tag
      * @param a the attribute set specifying the special content
      */
     protected void addSpecialElement(HTML.Tag t, MutableAttributeSet a)
Index: javax/swing/text/html/HTMLEditorKit.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/html/HTMLEditorKit.java,v
retrieving revision 1.41
diff -u -1 -5 -r1.41 HTMLEditorKit.java
--- javax/swing/text/html/HTMLEditorKit.java	15 Nov 2006 23:11:02 -0000	1.41
+++ javax/swing/text/html/HTMLEditorKit.java	19 Nov 2006 19:36:42 -0000
@@ -1082,32 +1082,39 @@
    */
   public ViewFactory getViewFactory()
   {
     if (viewFactory == null)
       viewFactory = new HTMLFactory();
     return viewFactory;
   }
   
   /**
    * Create a text storage model for this type of editor.
    *
    * @return the model
    */
   public Document createDefaultDocument()
   {
-    HTMLDocument document = new HTMLDocument(getStyleSheet());
+    // Protect the shared stylesheet.
+    StyleSheet styleSheet = getStyleSheet();
+    StyleSheet ss = new StyleSheet();
+    ss.addStyleSheet(styleSheet);
+
+    HTMLDocument document = new HTMLDocument(ss);
     document.setParser(getParser());
+    document.setAsynchronousLoadPriority(4);
+    document.setTokenThreshold(100);
     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, [EMAIL PROTECTED] ParserDelegator}).
    */
   protected Parser getParser()
   {
     if (parser == null)
       {
         parser = new GnuParserDelegator(HTML_401F.getInstance());
       }
Index: javax/swing/text/html/TableView.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/html/TableView.java,v
retrieving revision 1.7
diff -u -1 -5 -r1.7 TableView.java
--- javax/swing/text/html/TableView.java	15 Nov 2006 11:03:00 -0000	1.7
+++ javax/swing/text/html/TableView.java	19 Nov 2006 19:36:42 -0000
@@ -26,33 +26,36 @@
 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.awt.Shape;
+
 import gnu.javax.swing.text.html.css.Length;
 
 import javax.swing.SizeRequirements;
+import javax.swing.event.DocumentEvent;
 import javax.swing.text.AttributeSet;
 import javax.swing.text.BoxView;
 import javax.swing.text.Element;
 import javax.swing.text.StyleConstants;
 import javax.swing.text.View;
 import javax.swing.text.ViewFactory;
 
 /**
  * A view implementation that renders HTML tables.
  *
  * This is basically a vertical BoxView that contains the rows of the table
  * and the rows are horizontal BoxViews that contain the actual columns.
  */
 class TableView
   extends BoxView
@@ -733,16 +736,40 @@
   }
 
   /**
    * Overridden to adjust for cellSpacing.
    */
   protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets,
                                  int spans[])
   {
     int adjust = (getViewCount() + 1) * cellSpacing;
     super.layoutMajorAxis(targetSpan - adjust, axis, offsets, spans);
     for (int i = 0; i < offsets.length; i++)
       {
         offsets[i] += (i + 1) * cellSpacing;
       }
   }
+
+  /**
+   * Overridden to replace view factory with this one.
+   */
+  public void insertUpdate(DocumentEvent e, Shape a, ViewFactory f)
+  {
+    super.insertUpdate(e, a, this);
+  }
+
+  /**
+   * Overridden to replace view factory with this one.
+   */
+  public void removeUpdate(DocumentEvent e, Shape a, ViewFactory f)
+  {
+    super.removeUpdate(e, a, this);
+  }
+
+  /**
+   * Overridden to replace view factory with this one.
+   */
+  public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f)
+  {
+    super.changedUpdate(e, a, this);
+  }
 }

Reply via email to