A couple of fixes for javax.swing.text that have been lying around on my HD for too long now...
2006-06-21 Roman Kennke <[EMAIL PROTECTED]>
* javax/swing/text/AbstractDocument.java
(BranchElement.numChildren): New field.
(BranchElement.BranchElement): Initialize children array with
one element (that's the least number of elements that makes sense).
Initialize numChildren.
(BranchElement.children): Use numChildren as boundary.
(BranchElement.getElement): Use numChildren as boundary.
(BranchElement.getElementCount): Use numChildren as boundary.
(BranchElement.getElementIndex): Use numChildren as boundary.
(BranchElement.getEndOffset): Use numChildren as boundary.
(BranchElement.getStartOffset): Use numChildren as boundary.
(BranchElement.positionToElement): Use numChildren as boundary.
(BranchElement.replace): Handle the children array more efficiently
by growing in blocks > 1, and reusing space from removed elements.
(LeafElement.startDelta): Removed.
(LeafElement.endDelta): Removed.
(LeafElement.LeafElement): Removed handling of deltas.
(LeafElement.getEndOffset): Likewise.
(LeafElement.getStartOffset): Likewise.
* javax/swing/text/JTextComponent.java
(setDocument): Added locking of the old document to avoid dangling
notification beeing delivered while the document is beeing
disconnected.
(getScrollableTracksViewportWidth): Fixed condition.
* javax/swing/text/PlainDocument.java
(createDefaultRoot): Create elements without AttributeSet.
* javax/swing/text/rtf/RTFParser.java
(parseFile): Handle slightly incorrect RTF gracefully.
* javax/swing/text/rtf/RTFScanner.java
(lastToken): New field.
(readTokenImpl): New method.
(peekToken): New method.
(readToken): Changed to call readTokenImpl or return the lastToken
if there's one present.
--
“Improvement makes straight roads, but the crooked roads, without
Improvement, are roads of Genius.” - William Blake
Index: javax/swing/text/AbstractDocument.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/AbstractDocument.java,v
retrieving revision 1.57
diff -u -1 -0 -r1.57 AbstractDocument.java
--- javax/swing/text/AbstractDocument.java 13 May 2006 23:11:13 -0000 1.57
+++ javax/swing/text/AbstractDocument.java 21 Jun 2006 17:02:57 -0000
@@ -1667,22 +1667,29 @@
/**
* An implementation of [EMAIL PROTECTED] Element} to represent composite
* <code>Element</code>s that contain other <code>Element</code>s.
*/
public class BranchElement extends AbstractElement
{
/** 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];
+ /**
+ * The child elements of this BranchElement.
+ */
+ private Element[] children;;
+
+ /**
+ * The number of children in the branch element.
+ */
+ private int numChildren;
/**
* The cached startOffset value. This is used in the case when a
* BranchElement (temporarily) has no child elements.
*/
private int startOffset;
/**
* The cached endOffset value. This is used in the case when a
* BranchElement (temporarily) has no child elements.
@@ -1693,38 +1700,40 @@
* Creates a new <code>BranchElement</code> with the specified
* parent and attributes.
*
* @param parent the parent element of this <code>BranchElement</code>
* @param attributes the attributes to set on this
* <code>BranchElement</code>
*/
public BranchElement(Element parent, AttributeSet attributes)
{
super(parent, attributes);
+ children = new Element[1];
+ numChildren = 0;
startOffset = -1;
endOffset = -1;
}
/**
* Returns the children of this <code>BranchElement</code>.
*
* @return the children of this <code>BranchElement</code>
*/
public Enumeration children()
{
if (children.length == 0)
return null;
Vector tmp = new Vector();
- for (int index = 0; index < children.length; ++index)
- tmp.add(children[index]);
+ for (int index = 0; index < numChildren; ++index)
+ tmp.add(children[index]);
return tmp.elements();
}
/**
* Returns <code>true</code> since <code>BranchElements</code> allow
* child elements.
*
* @return <code>true</code> since <code>BranchElements</code> allow
* child elements
@@ -1736,55 +1745,55 @@
/**
* Returns the child element at the specified <code>index</code>.
*
* @param index the index of the requested child element
*
* @return the requested element
*/
public Element getElement(int index)
{
- if (index < 0 || index >= children.length)
- return null;
+ if (index < 0 || index >= numChildren)
+ return null;
return children[index];
}
/**
* Returns the number of child elements of this element.
*
* @return the number of child elements of this element
*/
public int getElementCount()
{
- return children.length;
+ return numChildren;
}
/**
* Returns the index of the child element that spans the specified
* offset in the document model.
*
* @param offset the offset for which the responsible element is searched
*
* @return the index of the child element that spans the specified
* offset in the document model
*/
public int getElementIndex(int offset)
{
// 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 - 1; ++index)
+ for (int index = 0; index < numChildren - 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)
@@ -1807,27 +1816,27 @@
* This is the end offset of the last child element. If this element
* has no children, this method throws a <code>NullPointerException</code>.
*
* @return the offset inside the document model that is after the last
* character of this element
*
* @throws NullPointerException if this branch element has no children
*/
public int getEndOffset()
{
- if (children.length == 0)
+ if (numChildren == 0)
{
if (endOffset == -1)
throw new NullPointerException("BranchElement has no children.");
}
else
- endOffset = children[children.length - 1].getEndOffset();
+ endOffset = children[numChildren - 1].getEndOffset();
return endOffset;
}
/**
* Returns the name of this element. This is [EMAIL PROTECTED] #ParagraphElementName}
* in this case.
*
* @return the name of this element
*/
@@ -1841,21 +1850,21 @@
* This is the start offset of the first child element. If this element
* has no children, this method throws a <code>NullPointerException</code>.
*
* @return the start offset of this element inside the document model
*
* @throws NullPointerException if this branch element has no children and
* no startOffset value has been cached
*/
public int getStartOffset()
{
- if (children.length == 0)
+ if (numChildren == 0)
{
if (startOffset == -1)
throw new NullPointerException("BranchElement has no children.");
}
else
startOffset = children[0].getStartOffset();
return startOffset;
}
@@ -1877,49 +1886,62 @@
*
* @return the <code>Element</code> at the specified <code>Document</code>
* offset
*
* @see #getElementIndex(int)
*/
public Element positionToElement(int position)
{
// 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 < numChildren; ++index)
{
Element elem = children[index];
if ((elem.getStartOffset() <= position)
&& (position < elem.getEndOffset()))
return elem;
}
return null;
}
/**
* Replaces a set of child elements with a new set of child elemens.
*
* @param offset the start index of the elements to be removed
* @param length the number of elements to be removed
* @param elements the new elements to be inserted
*/
public void replace(int offset, int length, Element[] elements)
{
- Element[] target = new Element[children.length - length
- + elements.length];
- System.arraycopy(children, 0, target, 0, offset);
- System.arraycopy(elements, 0, target, offset, elements.length);
- System.arraycopy(children, offset + length, target,
- offset + elements.length,
- children.length - offset - length);
- children = target;
+ if (numChildren + elements.length - length > children.length)
+ {
+ // Gotta grow the array.
+ int newSize = Math.max(2 * children.length,
+ numChildren + elements.length - length);
+ Element[] target = new Element[newSize];
+ System.arraycopy(children, 0, target, 0, offset);
+ System.arraycopy(elements, 0, target, offset, elements.length);
+ System.arraycopy(children, offset + length, target,
+ offset + elements.length,
+ numChildren - offset - length);
+ children = target;
+ }
+ else
+ {
+ System.arraycopy(children, offset + length, children,
+ offset + elements.length,
+ numChildren - offset - length);
+ System.arraycopy(elements, 0, children, offset, elements.length);
+ }
+ numChildren += elements.length - length;
}
/**
* Returns a string representation of this element.
*
* @return a string representation of this element
*/
public String toString()
{
return ("BranchElement(" + getName() + ") "
@@ -2158,65 +2180,46 @@
* Manages the start offset of this element.
*/
private Position startPos;
/**
* Manages the end offset of this element.
*/
private Position endPos;
/**
- * This gets possible added to the startOffset when a startOffset
- * outside the document range is requested.
- */
- private int startDelta;
-
- /**
- * This gets possible added to the endOffset when a endOffset
- * outside the document range is requested.
- */
- private int endDelta;
-
- /**
* Creates a new <code>LeafElement</code>.
*
* @param parent the parent of this <code>LeafElement</code>
* @param attributes the attributes to be set
* @param start the start index of this element inside the document model
* @param end the end index of this element inside the document model
*/
public LeafElement(Element parent, AttributeSet attributes, int start,
int end)
{
super(parent, attributes);
- int len = content.length();
- startDelta = 0;
- if (start > len)
- startDelta = start - len;
- endDelta = 0;
- if (end > len)
- endDelta = end - len;
try
- {
- startPos = createPosition(start - startDelta);
- endPos = createPosition(end - endDelta);
- }
- catch (BadLocationException ex)
- {
- AssertionError as;
- as = new AssertionError("BadLocationException thrown "
- + "here. start=" + start
- + ", end=" + end
- + ", length=" + getLength());
- as.initCause(ex);
- throw as;
- }
+ {
+ startPos = createPosition(start);
+ endPos = createPosition(end);
+ }
+ catch (BadLocationException ex)
+ {
+ AssertionError as;
+ as = new AssertionError("BadLocationException thrown "
+ + "here. start=" + start
+ + ", end=" + end
+ + ", length=" + getLength());
+ as.initCause(ex);
+ throw as;
+ }
}
/**
* Returns <code>null</code> since <code>LeafElement</code>s cannot have
* children.
*
* @return <code>null</code> since <code>LeafElement</code>s cannot have
* children
*/
public Enumeration children()
@@ -2274,21 +2277,21 @@
/**
* Returns the end offset of this <code>Element</code> inside the
* document.
*
* @return the end offset of this <code>Element</code> inside the
* document
*/
public int getEndOffset()
{
- return endPos.getOffset() + endDelta;
+ return endPos.getOffset();
}
/**
* Returns the name of this <code>Element</code>. This is
* [EMAIL PROTECTED] #ContentElementName} in this case.
*
* @return the name of this <code>Element</code>
*/
public String getName()
{
@@ -2300,21 +2303,21 @@
/**
* Returns the start offset of this <code>Element</code> inside the
* document.
*
* @return the start offset of this <code>Element</code> inside the
* document
*/
public int getStartOffset()
{
- return startPos.getOffset() + startDelta;
+ return startPos.getOffset();
}
/**
* Returns <code>true</code>.
*
* @return <code>true</code>
*/
public boolean isLeaf()
{
return true;
Index: javax/swing/text/JTextComponent.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/JTextComponent.java,v
retrieving revision 1.59
diff -u -1 -0 -r1.59 JTextComponent.java
--- javax/swing/text/JTextComponent.java 20 Jun 2006 18:24:14 -0000 1.59
+++ javax/swing/text/JTextComponent.java 21 Jun 2006 17:02:58 -0000
@@ -35,20 +35,21 @@
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
package javax.swing.text;
import gnu.classpath.NotImplementedException;
import java.awt.AWTEvent;
import java.awt.Color;
+import java.awt.Container;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.ActionEvent;
@@ -1172,22 +1173,33 @@
setFocusable(true);
setEditable(true);
enableEvents(AWTEvent.KEY_EVENT_MASK);
setOpaque(true);
updateUI();
}
public void setDocument(Document newDoc)
{
Document oldDoc = doc;
- doc = newDoc;
- firePropertyChange("document", oldDoc, newDoc);
+ try
+ {
+ if (oldDoc instanceof AbstractDocument)
+ ((AbstractDocument) oldDoc).readLock();
+
+ doc = newDoc;
+ firePropertyChange("document", oldDoc, newDoc);
+ }
+ finally
+ {
+ if (oldDoc instanceof AbstractDocument)
+ ((AbstractDocument) oldDoc).readUnlock();
+ }
revalidate();
repaint();
}
public Document getDocument()
{
return doc;
}
/**
@@ -1650,24 +1662,26 @@
public boolean getScrollableTracksViewportHeight()
{
if (getParent() instanceof JViewport)
return getParent().getHeight() > getPreferredSize().height;
return false;
}
public boolean getScrollableTracksViewportWidth()
{
- if (getParent() instanceof JViewport)
- return getParent().getWidth() > getPreferredSize().width;
+ boolean res = false;;
+ Container c = getParent();
+ if (c instanceof JViewport)
+ res = ((JViewport) c).getExtentSize().width > getPreferredSize().width;
- return false;
+ return res;
}
/**
* Adds a <code>CaretListener</code> object to this text component.
*
* @param listener the listener to add
*/
public void addCaretListener(CaretListener listener)
{
listenerList.add(CaretListener.class, listener);
Index: javax/swing/text/PlainDocument.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/PlainDocument.java,v
retrieving revision 1.21
diff -u -1 -0 -r1.21 PlainDocument.java
--- javax/swing/text/PlainDocument.java 6 Mar 2006 10:51:19 -0000 1.21
+++ javax/swing/text/PlainDocument.java 21 Jun 2006 17:02:58 -0000
@@ -98,24 +98,24 @@
lines = new Element[1];
lines[0] = createLeafElement(rootElement, SimpleAttributeSet.EMPTY, 0, 1);
}
((BranchElement) rootElement).replace(0, rootElement.getElementCount(), lines);
}
protected AbstractDocument.AbstractElement createDefaultRoot()
{
BranchElement root =
- (BranchElement) createBranchElement(null, SimpleAttributeSet.EMPTY);
+ (BranchElement) createBranchElement(null, null);
Element[] array = new Element[1];
- array[0] = createLeafElement(root, SimpleAttributeSet.EMPTY, 0, 1);
+ array[0] = createLeafElement(root, null, 0, 1);
root.replace(0, 0, array);
return root;
}
protected void insertUpdate(DefaultDocumentEvent event,
AttributeSet attributes)
{
int offset = event.getOffset();
int eventLength = event.getLength();
Index: javax/swing/text/rtf/RTFParser.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/rtf/RTFParser.java,v
retrieving revision 1.3
diff -u -1 -0 -r1.3 RTFParser.java
--- javax/swing/text/rtf/RTFParser.java 2 Jul 2005 20:32:51 -0000 1.3
+++ javax/swing/text/rtf/RTFParser.java 21 Jun 2006 17:02:58 -0000
@@ -133,23 +133,31 @@
private void parseFile()
throws IOException, BadLocationException
{
Token t1 = scanner.readToken();
if (t1.type != Token.LCURLY)
throw new RTFParseException("expected left curly braces");
parseHeader();
parseDocument();
- Token t2 = scanner.readToken();
- if (t2.type != Token.RCURLY)
- throw new RTFParseException("expected right curly braces");
+ Token t2 = scanner.peekToken();
+ if (t2.type == Token.RCURLY)
+ {
+ // Eat the token.
+ scanner.readToken();
+ }
+ else
+ {
+ // Ignore this for maximum robustness when file is broken.
+ System.err.println("RTF warning: expected right curly braces");
+ }
}
/**
* The parse rules for <header>.
*
* TODO: implement this properly
*/
private void parseHeader()
//throws IOException, BadLocationException
Index: javax/swing/text/rtf/RTFScanner.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/rtf/RTFScanner.java,v
retrieving revision 1.3
diff -u -1 -0 -r1.3 RTFScanner.java
--- javax/swing/text/rtf/RTFScanner.java 2 Jul 2005 20:32:51 -0000 1.3
+++ javax/swing/text/rtf/RTFScanner.java 21 Jun 2006 17:02:58 -0000
@@ -64,20 +64,25 @@
* The reader from which we read the RTF data.
*/
private Reader in;
/**
* This is used to constuct strings from the read in chars.
*/
private StringBuffer buffer;
/**
+ * Lookahead token.
+ */
+ private Token lastToken;
+
+ /**
* Constructs a new RTFScanner without initializing the [EMAIL PROTECTED] Reader}.
*/
private RTFScanner()
{
buffer = new StringBuffer();
}
/**
* Constructs a new RTFScanner for the given [EMAIL PROTECTED] InputStream}.
* The stream is wrapped into an [EMAIL PROTECTED] InputStreamReader} and if it's
@@ -113,21 +118,21 @@
}
}
/**
* Reads in the next [EMAIL PROTECTED] Token} from the stream.
*
* @return the read [EMAIL PROTECTED] Token}
*
* @throws IOException if the underlying stream has problems
*/
- public Token readToken()
+ private Token readTokenImpl()
throws IOException
{
Token token = null;
int c = in.read();
switch(c)
{
case -1:
token = new Token(Token.EOF);
break;
@@ -149,20 +154,41 @@
default:
buffer.delete(0, buffer.length());
buffer.append((char) c);
token = readText();
break;
}
return token;
}
+ Token peekToken()
+ throws IOException
+ {
+ lastToken = readTokenImpl();
+ return lastToken;
+ }
+
+ Token readToken()
+ throws IOException
+ {
+ Token token;
+ if (lastToken != null)
+ {
+ token = lastToken;
+ lastToken = null;
+ }
+ else
+ token = readTokenImpl();
+ return token;
+ }
+
/**
* Reads in a control word and optional parameter.
*
* @return the read in control word as [EMAIL PROTECTED] ControlWordToken}
*
* @throws IOException if the underlying stream has problems
*/
private Token readControlWord()
throws IOException
{
signature.asc
Description: Dies ist ein digital signierter Nachrichtenteil
