diff options
author | Mark Wielaard <mark@gcc.gnu.org> | 2005-11-15 23:20:01 +0000 |
---|---|---|
committer | Mark Wielaard <mark@gcc.gnu.org> | 2005-11-15 23:20:01 +0000 |
commit | 8f523f3a1047919d3563daf1ef47ba87336ebe89 (patch) | |
tree | a5eb7cf42a51869cc8aa1fad7ad6a90cca47fdd8 /libjava/classpath/javax/swing/text/AbstractDocument.java | |
parent | 02e549bfaaec38f68307e7f34e46ea57ea1809af (diff) | |
download | gcc-8f523f3a1047919d3563daf1ef47ba87336ebe89.zip gcc-8f523f3a1047919d3563daf1ef47ba87336ebe89.tar.gz gcc-8f523f3a1047919d3563daf1ef47ba87336ebe89.tar.bz2 |
Imported GNU Classpath 0.19 + gcj-import-20051115.
* sources.am: Regenerated.
* Makefile.in: Likewise.
* scripts/makemake.tcl: Use glob -nocomplain.
From-SVN: r107049
Diffstat (limited to 'libjava/classpath/javax/swing/text/AbstractDocument.java')
-rw-r--r-- | libjava/classpath/javax/swing/text/AbstractDocument.java | 326 |
1 files changed, 249 insertions, 77 deletions
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; |