summaryrefslogtreecommitdiff
path: root/javax
diff options
context:
space:
mode:
authorRoman Kennke <roman@kennke.org>2006-11-19 19:37:36 +0000
committerRoman Kennke <roman@kennke.org>2006-11-19 19:37:36 +0000
commitcbf4afe9bb3f1617c04612b18fce873e7ca725c7 (patch)
tree6b981e458b5f76492c481f69fe2f42a68c02880b /javax
parentb1d0c928622637949dfb9158cdc3f75851850992 (diff)
downloadclasspath-cbf4afe9bb3f1617c04612b18fce873e7ca725c7.tar.gz
2006-11-19 Roman Kennke <kennke@aicas.com>
* 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.
Diffstat (limited to 'javax')
-rw-r--r--javax/swing/JEditorPane.java182
-rw-r--r--javax/swing/text/DefaultStyledDocument.java96
-rw-r--r--javax/swing/text/html/HTMLDocument.java39
-rw-r--r--javax/swing/text/html/HTMLEditorKit.java9
-rw-r--r--javax/swing/text/html/TableView.java27
5 files changed, 302 insertions, 51 deletions
diff --git a/javax/swing/JEditorPane.java b/javax/swing/JEditorPane.java
index a503bb6e8..cb1fc3f0e 100644
--- a/javax/swing/JEditorPane.java
+++ b/javax/swing/JEditorPane.java
@@ -40,6 +40,8 @@ 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;
@@ -58,6 +60,7 @@ 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;
@@ -507,6 +510,121 @@ public class JEditorPane extends JTextComponent
}
}
+ /**
+ * 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;
@@ -519,6 +637,11 @@ public class JEditorPane extends JTextComponent
// A mapping between content types and used EditorKits
HashMap editorMap;
+ /**
+ * The currently loading stream, if any.
+ */
+ private PageStream loading;
+
public JEditorPane()
{
init();
@@ -936,16 +1059,59 @@ public class JEditorPane extends JTextComponent
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);
}
/**
diff --git a/javax/swing/text/DefaultStyledDocument.java b/javax/swing/text/DefaultStyledDocument.java
index a88b663c1..e97ee1dc1 100644
--- a/javax/swing/text/DefaultStyledDocument.java
+++ b/javax/swing/text/DefaultStyledDocument.java
@@ -683,6 +683,58 @@ public class DefaultStyledDocument extends AbstractDocument implements
return ret;
}
+ /**
+ * Creates a document in response to a call to
+ * {@link 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;
@@ -2379,18 +2431,24 @@ public class DefaultStyledDocument extends AbstractDocument implements
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));
}
@@ -2410,14 +2468,16 @@ public class DefaultStyledDocument extends AbstractDocument implements
*/
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)
@@ -2429,38 +2489,18 @@ public class DefaultStyledDocument extends AbstractDocument implements
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);
+ buffer.create(len, data, ev);
- // 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));
+ // For the bidi update.
+ super.insertUpdate(ev, null);
+ ev.end();
fireInsertUpdate(ev);
fireUndoableEditUpdate(new UndoableEditEvent(this, ev));
}
diff --git a/javax/swing/text/html/HTMLDocument.java b/javax/swing/text/html/HTMLDocument.java
index bbc2368c3..3ff40b437 100644
--- a/javax/swing/text/html/HTMLDocument.java
+++ b/javax/swing/text/html/HTMLDocument.java
@@ -1293,18 +1293,28 @@ public class HTMLDocument extends DefaultStyledDocument
*/
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.
@@ -1535,9 +1545,10 @@ public class HTMLDocument extends DefaultStyledDocument
// 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);
}
@@ -1603,7 +1614,7 @@ public class HTMLDocument extends DefaultStyledDocument
{
try
{
- flush();
+ flushImpl();
}
catch (BadLocationException ble)
{
diff --git a/javax/swing/text/html/HTMLEditorKit.java b/javax/swing/text/html/HTMLEditorKit.java
index df6be5a4b..cc47b6dd5 100644
--- a/javax/swing/text/html/HTMLEditorKit.java
+++ b/javax/swing/text/html/HTMLEditorKit.java
@@ -1094,8 +1094,15 @@ public class HTMLEditorKit
*/
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;
}
diff --git a/javax/swing/text/html/TableView.java b/javax/swing/text/html/TableView.java
index fb62c1b1a..0bdbccd44 100644
--- a/javax/swing/text/html/TableView.java
+++ b/javax/swing/text/html/TableView.java
@@ -38,9 +38,12 @@ 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;
@@ -745,4 +748,28 @@ class TableView
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);
+ }
}