[snow-cvs] r75 - trunk/src/java/snow/swing

Alessio Stalla astalla at common-lisp.net
Thu Apr 15 20:50:45 UTC 2010


Author: astalla
Date: Thu Apr 15 16:50:45 2010
New Revision: 75

Log:
ConsoleDocument should now be thread-safe: the user input buffer is always kept at the end
of the document, so multiple threads cannot accidentally cause the buffer position to be miscalculated.


Modified:
   trunk/src/java/snow/swing/ConsoleDocument.java

Modified: trunk/src/java/snow/swing/ConsoleDocument.java
==============================================================================
--- trunk/src/java/snow/swing/ConsoleDocument.java	(original)
+++ trunk/src/java/snow/swing/ConsoleDocument.java	Thu Apr 15 16:50:45 2010
@@ -59,32 +59,28 @@
 
 public class ConsoleDocument extends DefaultStyledDocument {
 
-	private int lastEditableOffset = 0;
-	private StringBuffer inputBuffer = new StringBuffer();
+    private StringBuffer inputBuffer = new StringBuffer();
 	
-	private Reader reader = new Reader() {
+    private Reader reader = new Reader() {
 
-		@Override
-		public void close() throws IOException {
-		}
+	    @Override
+	    public void close() throws IOException {}
 
-		@Override
-		public synchronized int read(char[] cbuf, int off, int len) throws IOException {
-			try {
-				int length = Math.min(inputBuffer.length(), len);
-				while(length <= 0) {
-					wait();
-					length = Math.min(inputBuffer.length(), len);
-				}
-				inputBuffer.getChars(0, length, cbuf, off);
-				inputBuffer.delete(0, length);
-				lastEditableOffset += length;
-				return length;
-			} catch (InterruptedException e) {
-				throw new IOException(e);
-			}
-			
+	    @Override
+	    public synchronized int read(char[] cbuf, int off, int len) throws IOException {
+		try {
+		    int length = Math.min(inputBuffer.length(), len);
+		    while(length <= 0) {
+			wait();
+			length = Math.min(inputBuffer.length(), len);
+		    }
+		    inputBuffer.getChars(0, length, cbuf, off);
+		    inputBuffer.delete(0, length);
+		    return length;
+		} catch (InterruptedException e) {
+		    throw new IOException(e);
 		}
+	    }
 	};
 	
     private Writer writer = new Writer() {
@@ -97,27 +93,32 @@
 
 	    @Override
 	    public void write(final char[] cbuf, final int off, final int len) throws IOException {
-		synchronized(reader) {
-		    try {
+		try {
+		    final int insertOffs;
+		    synchronized(reader) {
 			if(inputBuffer.toString().trim().isEmpty()) {
 			    int length = inputBuffer.length();
 			    inputBuffer.delete(0, length);
-			    lastEditableOffset -= length;
 			}
-			SwingUtilities.invokeAndWait(new Runnable() {
-				public void run() {
+			insertOffs = getLength() - inputBuffer.length();
+			reader.notifyAll();
+		    }
+		    Runnable r = new Runnable() {
+			    public void run() {
+				synchronized(reader) {
 				    try {
-					superInsertString(getLength(), new String(cbuf, off, len), null);
+					superInsertString(insertOffs,
+							  new String(cbuf, off, len),
+							  null);
 				    } catch(Exception e) {
 					assert(false); //BadLocationException should not happen here
 				    }
 				}
-			    });
-			lastEditableOffset = getLength();
-			reader.notifyAll();
-		    }  catch (Exception e) {
-			throw new RuntimeException(e);
-		    }
+			    }
+			};
+		    SwingUtilities.invokeAndWait(r);
+		}  catch (Exception e) {
+		    throw new RuntimeException(e);
 		}
 	    }
 	};
@@ -139,26 +140,27 @@
 	    };
 	replThread.start();
     }
-	
-	@Override
-	public void insertString(int offs, String str, AttributeSet a)
-			throws BadLocationException {
-		if(offs < lastEditableOffset) {
-			throw new BadLocationException("Can only insert after " + lastEditableOffset, offs);
-		}
-		synchronized(reader) {
-			superInsertString(offs, str, a);
-			inputBuffer.insert(offs - lastEditableOffset, str);
-			if(processInputP(inputBuffer, str)) {
-				reader.notifyAll();
-			}
-		}
+
+    @Override
+    public void insertString(int offs, String str, AttributeSet a)
+	throws BadLocationException {
+	synchronized(reader) {
+	    int bufferStart = getLength() - inputBuffer.length();
+	    if(offs < bufferStart) {
+		throw new BadLocationException("Can only insert after " + bufferStart, offs);
+	    }
+	    superInsertString(offs, str, a);
+	    inputBuffer.insert(offs - bufferStart, str);
+	    if(processInputP(inputBuffer, str)) {
+		reader.notifyAll();
+	    }
 	}
+    }
 	
-	protected void superInsertString(int offs, String str, AttributeSet a)
+    protected void superInsertString(int offs, String str, AttributeSet a)
 	throws BadLocationException {
-		super.insertString(offs, str, a);
-	}
+	super.insertString(offs, str, a);
+    }
 	
 	/**
 	 * Guaranteed to run with exclusive access to the buffer.
@@ -185,16 +187,17 @@
 		return parenCount <= 0;
 	}
 	
-	@Override
-	public void remove(int offs, int len) throws BadLocationException {
-		if(offs < lastEditableOffset) {
-			throw new BadLocationException("Can only remove after " + lastEditableOffset, offs);
-		}
-		super.remove(offs, len);
-		synchronized(reader) {
-			inputBuffer.delete(offs - lastEditableOffset, offs - lastEditableOffset + len);
-		}
+    @Override
+    public void remove(int offs, int len) throws BadLocationException {
+	synchronized(reader) {
+	    int bufferStart = getLength() - inputBuffer.length();
+	    if(offs < bufferStart) {
+		throw new BadLocationException("Can only remove after " + bufferStart, offs);
+	    }
+	    super.remove(offs, len);
+	    inputBuffer.delete(offs - bufferStart, offs - bufferStart + len);
 	}
+    }
 	
 	public Reader getReader() {
 		return reader;




More information about the snow-cvs mailing list