diff options
author | Roman Kennke <roman@kennke.org> | 2006-11-19 19:37:36 +0000 |
---|---|---|
committer | Roman Kennke <roman@kennke.org> | 2006-11-19 19:37:36 +0000 |
commit | cbf4afe9bb3f1617c04612b18fce873e7ca725c7 (patch) | |
tree | 6b981e458b5f76492c481f69fe2f42a68c02880b /javax | |
parent | b1d0c928622637949dfb9158cdc3f75851850992 (diff) | |
download | classpath-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.java | 182 | ||||
-rw-r--r-- | javax/swing/text/DefaultStyledDocument.java | 96 | ||||
-rw-r--r-- | javax/swing/text/html/HTMLDocument.java | 39 | ||||
-rw-r--r-- | javax/swing/text/html/HTMLEditorKit.java | 9 | ||||
-rw-r--r-- | javax/swing/text/html/TableView.java | 27 |
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); + } } |