From 9dc83af902a99a589dfb8c05c0f16e1a5bdf812d Mon Sep 17 00:00:00 2001 From: Roman Kennke Date: Fri, 6 May 2005 06:03:17 +0000 Subject: [PATCH] 2005-05-06 Roman Kennke * javax/swing/text/PlainView.java (drawUnselectedText): Call Utilities.drawTabbedText() with correct offset parameter. * javax/swing/text/Utilities.java (drawTabbedText): Initilialize local variable pos correctly. 2005-05-06 Roman Kennke * javax/swing/text/AbstractDocument.java (LeafElement): Made start and end package private fields for effective reindexing. * javax/swing/text/PlainDocument.java (constructor): The field rootElement is always BranchElement, so we handle it as such. (removeUpdate): Rewritten reindexing for removeUpdate so that the actual removal is taken into account. 2005-05-06 Roman Kennke * javax/swing/text/GapContent.java: Removed debugging output stuff, which I accidentally left in. 2005-05-06 Roman Kennke * javax/swing/text/GapContent.java: Implemented a real GapContent. Only the public methods have been implemented so far and still no UndoableEdit support. From-SVN: r99300 --- libjava/ChangeLog | 30 ++ .../javax/swing/text/AbstractDocument.java | 4 +- libjava/javax/swing/text/GapContent.java | 311 ++++++++++++++---- libjava/javax/swing/text/PlainDocument.java | 42 ++- libjava/javax/swing/text/PlainView.java | 2 +- libjava/javax/swing/text/Utilities.java | 2 +- 6 files changed, 312 insertions(+), 79 deletions(-) diff --git a/libjava/ChangeLog b/libjava/ChangeLog index cdd5f060a6f..e47919920eb 100644 --- a/libjava/ChangeLog +++ b/libjava/ChangeLog @@ -1,3 +1,33 @@ +2005-05-06 Roman Kennke + + * javax/swing/text/PlainView.java + (drawUnselectedText): Call Utilities.drawTabbedText() with correct + offset parameter. + * javax/swing/text/Utilities.java + (drawTabbedText): Initilialize local variable pos correctly. + +2005-05-06 Roman Kennke + + * javax/swing/text/AbstractDocument.java + (LeafElement): Made start and end package private fields for + effective reindexing. + * javax/swing/text/PlainDocument.java + (constructor): The field rootElement is always BranchElement, + so we handle it as such. + (removeUpdate): Rewritten reindexing for removeUpdate so that + the actual removal is taken into account. + +2005-05-06 Roman Kennke + + * javax/swing/text/GapContent.java: + Removed debugging output stuff, which I accidentally left in. + +2005-05-06 Roman Kennke + + * javax/swing/text/GapContent.java: + Implemented a real GapContent. Only the public methods have + been implemented so far and still no UndoableEdit support. + 2005-05-04 H.J. Lu * java/awt/BufferCapabilities.java (BufferCapabilities): Fix diff --git a/libjava/javax/swing/text/AbstractDocument.java b/libjava/javax/swing/text/AbstractDocument.java index 29be0ad065e..efeb85db67f 100644 --- a/libjava/javax/swing/text/AbstractDocument.java +++ b/libjava/javax/swing/text/AbstractDocument.java @@ -847,8 +847,8 @@ public abstract class AbstractDocument public class LeafElement extends AbstractElement { private static final long serialVersionUID = 5115368706941283802L; - private int start; - private int end; + int start; + int end; public LeafElement(Element parent, AttributeSet attributes, int start, int end) diff --git a/libjava/javax/swing/text/GapContent.java b/libjava/javax/swing/text/GapContent.java index a22aeed51a7..111617e94a9 100644 --- a/libjava/javax/swing/text/GapContent.java +++ b/libjava/javax/swing/text/GapContent.java @@ -40,8 +40,6 @@ package javax.swing.text; import java.io.Serializable; -// too lazy to make a real gapcontent. -// lets just use a stringbuffer instead. import javax.swing.undo.UndoableEdit; /** @@ -53,20 +51,41 @@ import javax.swing.undo.UndoableEdit; * has to be shifted around when the insertion point moves (then the gap also * moves and one array copy is necessary) or when the gap is filled up and * the buffer has to be enlarged. + * + * TODO: Implement UndoableEdit support stuff */ public class GapContent implements AbstractDocument.Content, Serializable { private static final long serialVersionUID = 8374645204155842629L; - - StringBuffer buf = new StringBuffer(); + + /** + * This is the default buffer size and the amount of bytes that + * a buffer is extended if it is full. + */ + static final int DEFAULT_BUFSIZE = 64; + + /** + * The text buffer. + */ + char[] buffer; + + /** + * The index of the first character of the gap. + */ + int gapStart; + + /** + * The index of the character after the last character of the gap. + */ + int gapEnd; /** * Creates a new GapContent object. */ public GapContent() { - this(10); + this(DEFAULT_BUFSIZE); } /** @@ -76,7 +95,185 @@ public class GapContent */ public GapContent(int size) { - buf.append("\n"); + buffer = (char[]) allocateArray(size); + gapStart = 0; + gapEnd = size - 1; + buffer[size - 1] = '\n'; + } + + /** + * Allocates an array of the specified length that can then be used as + * buffer. + * + * @param size the size of the array to be allocated + * + * @return the allocated array + */ + protected Object allocateArray(int size) + { + return new char[size]; + } + + /** + * Returns the length of the allocated buffer array. + * + * @return the length of the allocated buffer array + */ + protected int getArrayLength() + { + return buffer.length; + } + + /** + * Returns the length of the content. + * + * @return the length of the content + */ + public int length() + { + return buffer.length - (gapEnd - gapStart); + } + + /** + * Inserts a string at the specified position. + * + * @param where the position where the string is inserted + * @param str the string that is to be inserted + * + * @return an UndoableEdit object (currently not supported, so + * null is returned) + * + * @throws BadLocationException if where is not a valid location + * in the buffer + */ + public UndoableEdit insertString(int where, String str) + throws BadLocationException + { + // check arguments + int length = length(); + int strLen = str.length(); + + if (where >= length) + throw new BadLocationException("the where argument cannot be greater" + + " than the content length", where); + + // check if the gap is big enough to hold the string + if ((gapEnd - gapStart) < strLen) + // make room for this string and some more + shiftEnd(strLen + DEFAULT_BUFSIZE); + + // are we at the gap boundary? + if (where != gapStart) + shiftGap(where); + + // now we can simple copy the string into the gap and adjust the + // gap boundaries + System.arraycopy(str.toCharArray(), 0, buffer, gapStart, strLen); + gapStart += strLen; + return null; + } + + /** + * Removes a piece of content at th specified position. + * + * @param where the position where the content is to be removed + * @param nitems number of characters to be removed + * + * @return an UndoableEdit object (currently not supported, so + * null is returned) + * + * @throws BadLocationException if where is not a valid location + * in the buffer + */ + public UndoableEdit remove(int where, int nitems) + throws BadLocationException + { + // check arguments + int length = length(); + + if (where >= length) + throw new BadLocationException("the where argument cannot be greater" + + " than the content length", where); + if ((where + nitems) > length) + throw new BadLocationException("where + nitems cannot be greater" + + " than the content length", + where + nitems); + + // check if we are at the gap boundary + if (where != gapStart) + shiftGap(where); + + // now we simply have to enlarge the gap + gapEnd += nitems; + return null; + } + + /** + * Returns a piece of content as String. + * + * @param where the start location of the fragment + * @param len the length of the fragment + * + * @throws BadLocationException if where or + * where + len are no valid locations in the buffer + */ + public String getString(int where, int len) throws BadLocationException + { + Segment seg = new Segment(); + getChars(where, len, seg); + return new String(seg.array, seg.offset, seg.count); + } + + /** + * Fetches a piece of content and stores it in a {@link Segment} object. + * + * If the requested piece of text spans the gap, the content is copied + * into a new array. If it doesn't then it is contiguous and the + * actual content store is returned. + * + * @param where the start location of the fragment + * @param len the length of the fragment + * @param txt the Segment object to store the fragment in + * + * @throws BadLocationException if where or + * where + len are no valid locations in the buffer + */ + public void getChars(int where, int len, Segment txt) + throws BadLocationException + { + // check arguments + int length = length(); + if (where >= length) + throw new BadLocationException("the where argument cannot be greater" + + " than the content length", where); + if ((where + len) > length) + throw new BadLocationException("len plus where cannot be greater" + + " than the content length", + len + where); + + // check if requested segment is contiguous + if ((where < gapStart) && ((gapStart - where) < len)) + { + // requested segment is not contiguous -> copy the pieces together + char[] copy = new char[len]; + int lenFirst = gapStart - where; // the length of the first segment + System.arraycopy(buffer, where, copy, 0, lenFirst); + System.arraycopy(buffer, gapEnd, copy, lenFirst, len - lenFirst); + txt.array = copy; + txt.offset = 0; + txt.count = len; + } + else + { + // requested segment is contiguous -> we can simply return the + // actual content + txt.array = buffer; + if (where < gapStart) + txt.offset = where; + else + txt.offset = where + (gapEnd - gapStart); + txt.count = len; + } } /** @@ -103,85 +300,57 @@ public class GapContent } /** - * Returns the length of the content. + * Enlarges the gap. This allocates a new bigger buffer array, copy the + * segment before the gap as it is and the segment after the gap at + * the end of the new buffer array. This does change the gapEnd mark + * but not the gapStart mark. * - * @return the length of the content + * @param newSize the new size of the gap */ - public int length() + protected void shiftEnd(int newSize) { - return buf.length(); + char[] newBuf = (char[]) allocateArray(length() + newSize); + System.arraycopy(buffer, 0, newBuf, 0, gapStart); + System.arraycopy(buffer, gapEnd, newBuf, gapStart + newSize, + buffer.length - gapEnd); + gapEnd = gapStart + newSize; + buffer = newBuf; } /** - * Inserts a string at the specified position. + * Shifts the gap to the specified position. * - * @param where the position where the string is inserted - * @param str the string that is to be inserted - * - * @return an UndoableEdit object (currently not supported, so - * null is returned) - * - * @throws BadLocationException if where is not a valid location - * in the buffer + * @param newGapStart the new start position of the gap */ - public UndoableEdit insertString(int where, String str) - throws BadLocationException + protected void shiftGap(int newGapStart) { - buf.insert(where, str); - return null; + int newGapEnd = newGapStart + (gapEnd - gapStart); + + if (newGapStart == gapStart) + return; + else if (newGapStart < gapStart) + { + System.arraycopy(buffer, newGapStart, buffer, newGapEnd, + gapStart - newGapStart); + gapStart = newGapStart; + gapEnd = newGapEnd; + } + else + { + System.arraycopy(buffer, gapEnd, buffer, gapStart, + newGapStart - gapStart); + gapStart = newGapStart; + gapEnd = newGapEnd; + } } /** - * Removes a piece of content at th specified position. + * Returns the allocated buffer array. * - * @param where the position where the content is to be removed - * @param nitems number of characters to be removed - * - * @return an UndoableEdit object (currently not supported, so - * null is returned) - * - * @throws BadLocationException if where is not a valid location - * in the buffer + * @return the allocated buffer array */ - public UndoableEdit remove(int where, int nitems) - throws BadLocationException + protected Object getArray() { - buf.delete(where, where + nitems); - return null; - } - - /** - * Returns a piece of content as String. - * - * @param where the start location of the fragment - * @param len the length of the fragment - * - * @throws BadLocationException if where or - * where + len are no valid locations in the buffer - */ - public String getString(int where, int len) throws BadLocationException - { - return buf.substring(where, where+len); - } - - /** - * Fetches a piece of content and stores it in a {@link Segment} object. - * - * @param where the start location of the fragment - * @param len the length of the fragment - * @param txt the Segment object to store the fragment in - * - * @throws BadLocationException if where or - * where + len are no valid locations in the buffer - */ - public void getChars(int where, int len, Segment txt) - throws BadLocationException - { - txt.array = new char[len]; - - System.arraycopy(buf.toString().toCharArray(), where, txt.array, 0, len); - - txt.count = len; - txt.offset = 0; + return buffer; } } diff --git a/libjava/javax/swing/text/PlainDocument.java b/libjava/javax/swing/text/PlainDocument.java index 64e9c8ab3f4..3a44725fc1d 100644 --- a/libjava/javax/swing/text/PlainDocument.java +++ b/libjava/javax/swing/text/PlainDocument.java @@ -47,7 +47,7 @@ public class PlainDocument extends AbstractDocument public static final String lineLimitAttribute = "lineLimit"; public static final String tabSizeAttribute = "tabSize"; - private Element rootElement; + private BranchElement rootElement; private int tabSize; public PlainDocument() @@ -59,7 +59,7 @@ public class PlainDocument extends AbstractDocument { super(content); tabSize = 8; - rootElement = createDefaultRoot(); + rootElement = (BranchElement) createDefaultRoot(); } private void reindex() @@ -114,9 +114,43 @@ public class PlainDocument extends AbstractDocument protected void removeUpdate(DefaultDocumentEvent event) { - reindex(); - super.removeUpdate(event); + + int p0 = event.getOffset(); + int p1 = event.getLength() + p0; + int len = event.getLength(); + + // check if we must collapse some elements + int i1 = rootElement.getElementIndex(p0); + int i2 = rootElement.getElementIndex(p1); + if (i1 != i2) + { + Element el1 = rootElement.getElement(i1); + Element el2 = rootElement.getElement(i2); + int start = el1.getStartOffset(); + int end = el2.getEndOffset(); + // collapse elements if the removal spans more than 1 line + Element newEl = createLeafElement(rootElement, + SimpleAttributeSet.EMPTY, + start, end - len); + rootElement.replace(start, end - start, new Element[]{ newEl }); + } + else + { + // otherwise only adjust indices of the element + LeafElement el1 = (LeafElement) rootElement.getElement(i1); + el1.end -= len; + } + + // reindex remaining elements + for (int i = rootElement.getElementIndex(p0) + 1; + i < rootElement.getElementCount(); i++) + { + LeafElement el = (LeafElement) rootElement.getElement(i); + el.start -= len; + el.end -= len; + } + } public Element getDefaultRootElement() diff --git a/libjava/javax/swing/text/PlainView.java b/libjava/javax/swing/text/PlainView.java index c852c1d69b4..fb6af4eecad 100644 --- a/libjava/javax/swing/text/PlainView.java +++ b/libjava/javax/swing/text/PlainView.java @@ -148,7 +148,7 @@ public class PlainView extends View g.setColor(unselectedColor); Segment segment = new Segment(); getDocument().getText(p0, p1 - p0, segment); - return Utilities.drawTabbedText(segment, x, y, g, this, 0); + return Utilities.drawTabbedText(segment, x, y, g, this, segment.offset); } public void paint(Graphics g, Shape s) diff --git a/libjava/javax/swing/text/Utilities.java b/libjava/javax/swing/text/Utilities.java index c55f48e0a5f..79047014d46 100644 --- a/libjava/javax/swing/text/Utilities.java +++ b/libjava/javax/swing/text/Utilities.java @@ -92,7 +92,7 @@ public class Utilities int ascent = metrics.getAscent(); int pixelWidth = 0; - int pos = 0; + int pos = s.offset; int len = 0; for (int offset = s.offset; offset < (s.offset + s.count); ++offset)