This fixes an ugly issue in PlainDocument.insertUpdate(). This method didn't handle the special case of inserting text after a newline correctly. I basically rewrote this piece, it has been such a mess before. And luckily, we now pass all Mauve and Harmony tests for that class :-) !
2006-06-22 Roman Kennke <[EMAIL PROTECTED]>
* javax/swing/text/PlainDocument.java
(rootElement): Changed type to Element.
(tabSize): Removed field. This is stored in the document
properties
instead.
(PlainDocument): Set tabSize property. Init rootElement without
cast.
(insertUpdate): Rewritten. The previous implementation did not
handle some corner cases properly and was a mess.
(removeUpdate): Cast rootElement to BranchElement.
/Roman
--
“Improvement makes straight roads, but the crooked roads, without
Improvement, are roads of Genius.” - William Blake
Index: javax/swing/text/PlainDocument.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/PlainDocument.java,v
retrieving revision 1.22
diff -u -2 -0 -r1.22 PlainDocument.java
--- javax/swing/text/PlainDocument.java 21 Jun 2006 17:04:41 -0000 1.22
+++ javax/swing/text/PlainDocument.java 22 Jun 2006 15:00:41 -0000
@@ -22,70 +22,72 @@
making a combined work based on this library. Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.
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;
import java.util.ArrayList;
+import java.util.List;
/**
* A simple document class which maps lines to [EMAIL PROTECTED] Element}s.
*
* @author Anthony Balkissoon ([EMAIL PROTECTED])
* @author Graydon Hoare ([EMAIL PROTECTED])
* @author Roman Kennke ([EMAIL PROTECTED])
* @author Michael Koch ([EMAIL PROTECTED])
* @author Robert Schuster ([EMAIL PROTECTED])
*/
public class PlainDocument extends AbstractDocument
{
private static final long serialVersionUID = 4758290289196893664L;
public static final String lineLimitAttribute = "lineLimit";
public static final String tabSizeAttribute = "tabSize";
- private BranchElement rootElement;
- private int tabSize;
+ private Element rootElement;
public PlainDocument()
{
this(new GapContent());
}
public PlainDocument(AbstractDocument.Content content)
{
super(content);
- tabSize = 8;
- rootElement = (BranchElement) createDefaultRoot();
+ rootElement = createDefaultRoot();
+
+ // This property has been determined using a Mauve test.
+ putProperty("tabSize", new Integer(8));
}
private void reindex()
{
Element[] lines;
try
{
String str = content.getString(0, content.length());
ArrayList elts = new ArrayList();
int j = 0;
for (int i = str.indexOf('\n', 0); i != -1; i = str.indexOf('\n', i + 1))
{
elts.add(createLeafElement(rootElement, SimpleAttributeSet.EMPTY, j, i + 1));
j = i + 1;
}
if (j < content.length())
elts.add(createLeafElement(rootElement, SimpleAttributeSet.EMPTY, j, content.length()));
@@ -100,188 +102,169 @@
}
((BranchElement) rootElement).replace(0, rootElement.getElementCount(), lines);
}
protected AbstractDocument.AbstractElement createDefaultRoot()
{
BranchElement root =
(BranchElement) createBranchElement(null, null);
Element[] array = new Element[1];
array[0] = createLeafElement(root, null, 0, 1);
root.replace(0, 0, array);
return root;
}
protected void insertUpdate(DefaultDocumentEvent event,
AttributeSet attributes)
{
+
+ String text = null;
int offset = event.getOffset();
- int eventLength = event.getLength();
- int end = offset + event.getLength();
- int oldElementIndex, elementIndex = rootElement.getElementIndex(offset);
- Element firstElement = rootElement.getElement(elementIndex);
- oldElementIndex = elementIndex;
-
- // If we're inserting immediately after a newline we have to fix the
- // Element structure (but only if we are dealing with a line which
- // has not existed as Element before).
- if (offset > 0 && firstElement.getStartOffset() != offset)
+ int length = event.getLength();
+ try
{
- try
- {
- String s = getText(offset - 1, 1);
- if (s.equals("\n") )
- {
- int newEl2EndOffset = end;
- boolean replaceNext = false;
- if (rootElement.getElementCount() > elementIndex + 1)
- {
- replaceNext = true;
- newEl2EndOffset =
- rootElement.getElement(elementIndex + 1).getEndOffset();
- }
- Element newEl1 =
- createLeafElement(rootElement, firstElement.getAttributes(),
- firstElement.getStartOffset(), offset);
- Element newEl2 =
- createLeafElement (rootElement, firstElement.getAttributes(),
- offset, newEl2EndOffset);
- if (replaceNext)
- rootElement.replace(elementIndex, 2, new Element[] { newEl1, newEl2 });
- else
- rootElement.replace(elementIndex, 1, new Element[] { newEl1, newEl2 });
- firstElement = newEl2;
- elementIndex ++;
- }
- }
- catch (BadLocationException ble)
- {
- // This shouldn't happen.
- AssertionError ae = new AssertionError();
- ae.initCause(ble);
- throw ae;
- }
+ text = getText(offset, length);
+ }
+ catch (BadLocationException ex)
+ {
+ AssertionError err = new AssertionError();
+ err.initCause(ex);
+ throw err;
}
- // added and removed are Element arrays used to add an ElementEdit
- // to the DocumentEvent if there were entire lines added or removed.
- Element[] removed = new Element[1];
- Element[] added;
- try
+ boolean hasLineBreak = text.indexOf('\n') != -1;
+ boolean prevCharIsLineBreak = false;
+ try
{
- String str = content.getString(offset, eventLength);
- ArrayList elts = new ArrayList();
+ prevCharIsLineBreak =
+ offset > 0 && getText(offset - 1, 1).charAt(0) == '\n';
+ }
+ catch (BadLocationException ex)
+ {
+ AssertionError err = new AssertionError();
+ err.initCause(ex);
+ throw err;
+ }
+ boolean lastCharIsLineBreak = text.charAt(text.length() - 1) == '\n';
+ int lineIndex = -1;
+ int lineStart = -1;
+ int lineEnd = -1;
+ Element[] removed = null;
+ BranchElement root = (BranchElement) rootElement;
+ boolean updateStructure = true;
- // Determine how many NEW lines were added by finding the newline
- // characters within the newly inserted text
- int j = firstElement.getStartOffset();
- int i = str.indexOf('\n', 0);
- int contentLength = content.length();
-
- while (i != -1 && i <= eventLength)
- {
- // For each new line, create a new element
- elts.add(createLeafElement(rootElement, SimpleAttributeSet.EMPTY,
- j, offset + i + 1));
-
- j = offset + i + 1;
- if (j >= contentLength)
- break;
- i = str.indexOf('\n', i + 1);
- }
+ if (prevCharIsLineBreak && ! lastCharIsLineBreak)
+ {
+ // We must fix the structure a little if the previous char
+ // is a linebreak and the last char isn't.
+ lineIndex = root.getElementIndex(offset - 1);
+ Element prevLine = root.getElement(lineIndex);
+ Element nextLine = root.getElement(lineIndex + 1);
+ lineStart = prevLine.getStartOffset();
+ lineEnd = nextLine.getEndOffset();
+ removed = new Element[]{ prevLine, nextLine };
+ }
+ else if (hasLineBreak)
+ {
+ lineIndex = root.getElementIndex(offset);
+ Element line = root.getElement(lineIndex);
+ lineStart = line.getStartOffset();
+ lineEnd = line.getEndOffset();
+ removed = new Element[]{ line };
+ }
+ else
+ {
+ updateStructure = false;
+ }
- // If there were new lines added we have to add an ElementEdit to
- // the DocumentEvent and we have to call rootElement.replace to
- // insert the new lines
- if (elts.size() != 0)
+ if (updateStructure)
+ {
+ // Break the lines between lineStart and lineEnd.
+ ArrayList lines = new ArrayList();
+ int len = lineEnd - lineStart;
+ try
{
- // If we have created new lines test whether there are remaining
- // characters in firstElement after the inserted text and if so
- // create a new element for them.
- if (j < firstElement.getEndOffset())
- elts.add(createLeafElement(rootElement, SimpleAttributeSet.EMPTY, j, firstElement.getEndOffset()));
-
- // Set up the ElementEdit by filling the added and removed
- // arrays with the proper Elements
- added = new Element[elts.size()];
- elts.toArray(added);
-
- removed[0] = firstElement;
-
- // Now create and add the ElementEdit
- ElementEdit e = new ElementEdit(rootElement, elementIndex, removed,
- added);
- event.addEdit(e);
-
- // And call replace to actually make the changes
- ((BranchElement) rootElement).replace(elementIndex, 1, added);
+ text = getText(lineStart, len);
}
+ catch (BadLocationException ex)
+ {
+ AssertionError err = new AssertionError();
+ err.initCause(ex);
+ throw err;
+ }
+ int prevLineBreak = 0;
+ int lineBreak = text.indexOf('\n');
+ do
+ {
+ lineBreak++;
+ lines.add(createLeafElement(root, null, lineStart + prevLineBreak,
+ lineStart + lineBreak));
+ prevLineBreak = lineBreak;
+ lineBreak = text.indexOf('\n', prevLineBreak);
+ } while (prevLineBreak < len);
+
+ // Update the element structure and prepare document event.
+ Element[] added = (Element[]) lines.toArray(new Element[lines.size()]);
+ event.addEdit(new ElementEdit(root, lineIndex, removed, added));
+ root.replace(lineIndex, removed.length, added);
}
- catch (BadLocationException e)
- {
- // This shouldn't happen so we throw an AssertionError
- AssertionError ae = new AssertionError();
- ae.initCause(e);
- throw ae;
- }
-
super.insertUpdate(event, attributes);
}
protected void removeUpdate(DefaultDocumentEvent event)
{
super.removeUpdate(event);
// added and removed are Element arrays used to add an ElementEdit
// to the DocumentEvent if there were entire lines added or removed
// from the Document
Element[] added = new Element[1];
Element[] removed;
int p0 = event.getOffset();
// check if we must collapse some elements
int i1 = rootElement.getElementIndex(p0);
int i2 = rootElement.getElementIndex(p0 + event.getLength());
if (i1 != i2)
{
// If there were lines removed then we have to add an ElementEdit
// to the DocumentEvent so we set it up now by filling the Element
// arrays "removed" and "added" appropriately
removed = new Element [i2 - i1 + 1];
for (int i = i1; i <= i2; i++)
removed[i-i1] = rootElement.getElement(i);
int start = rootElement.getElement(i1).getStartOffset();
int end = rootElement.getElement(i2).getEndOffset();
added[0] = createLeafElement(rootElement,
SimpleAttributeSet.EMPTY,
start, end);
// Now create and add the ElementEdit
ElementEdit e = new ElementEdit(rootElement, i1, removed, added);
event.addEdit(e);
// collapse elements if the removal spans more than 1 line
- rootElement.replace(i1, i2 - i1 + 1, added);
+ ((BranchElement) rootElement).replace(i1, i2 - i1 + 1, added);
}
}
public Element getDefaultRootElement()
{
return rootElement;
}
public Element getParagraphElement(int pos)
{
Element root = getDefaultRootElement();
return root.getElement(root.getElementIndex(pos));
}
/**
* Inserts a string into the document. If the document property
* '<code>filterNewLines</code>' is set to <code>Boolean.TRUE</code>, then
* all newlines in the inserted string are replaced by space characters,
* otherwise the superclasses behaviour is executed.
*
signature.asc
Description: Dies ist ein digital signierter Nachrichtenteil
