summaryrefslogtreecommitdiffstats
path: root/libjava/classpath/javax/swing/text
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/classpath/javax/swing/text')
-rw-r--r--libjava/classpath/javax/swing/text/AbstractDocument.java208
-rw-r--r--libjava/classpath/javax/swing/text/BoxView.java264
-rw-r--r--libjava/classpath/javax/swing/text/CompositeView.java82
-rw-r--r--libjava/classpath/javax/swing/text/DefaultCaret.java86
-rw-r--r--libjava/classpath/javax/swing/text/EmptyAttributeSet.java153
-rw-r--r--libjava/classpath/javax/swing/text/FlowView.java75
-rw-r--r--libjava/classpath/javax/swing/text/GapContent.java371
-rw-r--r--libjava/classpath/javax/swing/text/IconView.java18
-rw-r--r--libjava/classpath/javax/swing/text/JTextComponent.java302
-rw-r--r--libjava/classpath/javax/swing/text/ParagraphView.java37
-rw-r--r--libjava/classpath/javax/swing/text/PlainDocument.java201
-rw-r--r--libjava/classpath/javax/swing/text/Segment.java10
-rw-r--r--libjava/classpath/javax/swing/text/SimpleAttributeSet.java6
-rw-r--r--libjava/classpath/javax/swing/text/StringContent.java6
-rw-r--r--libjava/classpath/javax/swing/text/TabSet.java121
-rw-r--r--libjava/classpath/javax/swing/text/TabStop.java68
-rw-r--r--libjava/classpath/javax/swing/text/View.java113
-rw-r--r--libjava/classpath/javax/swing/text/html/BRView.java (renamed from libjava/classpath/javax/swing/text/html/HTMLTableView.java)47
-rw-r--r--libjava/classpath/javax/swing/text/html/HRuleView.java189
-rw-r--r--libjava/classpath/javax/swing/text/html/HTMLDocument.java370
-rw-r--r--libjava/classpath/javax/swing/text/html/HTMLEditorKit.java20
-rw-r--r--libjava/classpath/javax/swing/text/html/StyleSheet.java52
-rw-r--r--libjava/classpath/javax/swing/text/html/TableView.java137
-rw-r--r--libjava/classpath/javax/swing/text/html/parser/ParserDelegator.java3
-rw-r--r--libjava/classpath/javax/swing/text/rtf/RTFParser.java14
-rw-r--r--libjava/classpath/javax/swing/text/rtf/RTFScanner.java28
26 files changed, 1991 insertions, 990 deletions
diff --git a/libjava/classpath/javax/swing/text/AbstractDocument.java b/libjava/classpath/javax/swing/text/AbstractDocument.java
index 1ef81732fed..eb46a8c42f6 100644
--- a/libjava/classpath/javax/swing/text/AbstractDocument.java
+++ b/libjava/classpath/javax/swing/text/AbstractDocument.java
@@ -147,14 +147,19 @@ public abstract class AbstractDocument implements Document, Serializable
/**
* A condition variable that readers and writers wait on.
*/
- Object documentCV = new Object();
+ private Object documentCV = new Object();
/** An instance of a DocumentFilter.FilterBypass which allows calling
* the insert, remove and replace method without checking for an installed
* document filter.
*/
- DocumentFilter.FilterBypass bypass;
-
+ private DocumentFilter.FilterBypass bypass;
+
+ /**
+ * The bidi root element.
+ */
+ private Element bidiRoot;
+
/**
* Creates a new <code>AbstractDocument</code> with the specified
* {@link Content} model.
@@ -185,6 +190,13 @@ public abstract class AbstractDocument implements Document, Serializable
{
content = doc;
context = ctx;
+
+ // FIXME: This is determined using a Mauve test. Make the document
+ // actually use this.
+ putProperty("i18n", Boolean.FALSE);
+
+ // FIXME: Fully implement bidi.
+ bidiRoot = new BranchElement(null, null);
}
/** Returns the DocumentFilter.FilterBypass instance for this
@@ -360,7 +372,7 @@ public abstract class AbstractDocument implements Document, Serializable
*/
public Element getBidiRootElement()
{
- return null;
+ return bidiRoot;
}
/**
@@ -477,8 +489,9 @@ public abstract class AbstractDocument implements Document, Serializable
*/
public Element[] getRootElements()
{
- Element[] elements = new Element[1];
+ Element[] elements = new Element[2];
elements[0] = getDefaultRootElement();
+ elements[1] = getBidiRootElement();
return elements;
}
@@ -739,29 +752,36 @@ public abstract class AbstractDocument implements Document, Serializable
void removeImpl(int offset, int length) throws BadLocationException
{
- // Prevent some unneccessary method invocation (observed in the RI).
- if (length <= 0)
- return;
-
- DefaultDocumentEvent event =
- new DefaultDocumentEvent(offset, length,
- DocumentEvent.EventType.REMOVE);
-
- try
+ // The RI silently ignores all requests that have a negative length.
+ // Don't ask my why, but that's how it is.
+ if (length > 0)
{
- writeLock();
+ if (offset < 0 || offset > getLength())
+ throw new BadLocationException("Invalid remove position", offset);
+
+ if (offset + length > getLength())
+ throw new BadLocationException("Invalid remove length", offset);
+
+ DefaultDocumentEvent event =
+ new DefaultDocumentEvent(offset, length,
+ DocumentEvent.EventType.REMOVE);
+
+ try
+ {
+ writeLock();
- // The order of the operations below is critical!
- removeUpdate(event);
- UndoableEdit temp = content.remove(offset, length);
+ // The order of the operations below is critical!
+ removeUpdate(event);
+ UndoableEdit temp = content.remove(offset, length);
- postRemoveUpdate(event);
- fireRemoveUpdate(event);
+ postRemoveUpdate(event);
+ fireRemoveUpdate(event);
+ }
+ finally
+ {
+ writeUnlock();
+ }
}
- finally
- {
- writeUnlock();
- }
}
/**
@@ -1674,20 +1694,15 @@ public abstract class AbstractDocument implements Document, Serializable
/** 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 cached startOffset value. This is used in the case when a
- * BranchElement (temporarily) has no child elements.
+ * The child elements of this BranchElement.
*/
- private int startOffset;
+ private Element[] children;;
/**
- * The cached endOffset value. This is used in the case when a
- * BranchElement (temporarily) has no child elements.
+ * The number of children in the branch element.
*/
- private int endOffset;
+ private int numChildren;
/**
* Creates a new <code>BranchElement</code> with the specified
@@ -1700,8 +1715,8 @@ public abstract class AbstractDocument implements Document, Serializable
public BranchElement(Element parent, AttributeSet attributes)
{
super(parent, attributes);
- startOffset = -1;
- endOffset = -1;
+ children = new Element[1];
+ numChildren = 0;
}
/**
@@ -1716,8 +1731,8 @@ public abstract class AbstractDocument implements Document, Serializable
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();
}
@@ -1743,8 +1758,8 @@ public abstract class AbstractDocument implements Document, Serializable
*/
public Element getElement(int index)
{
- if (index < 0 || index >= children.length)
- return null;
+ if (index < 0 || index >= numChildren)
+ return null;
return children[index];
}
@@ -1756,7 +1771,7 @@ public abstract class AbstractDocument implements Document, Serializable
*/
public int getElementCount()
{
- return children.length;
+ return numChildren;
}
/**
@@ -1777,7 +1792,7 @@ public abstract class AbstractDocument implements Document, Serializable
// 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];
@@ -1814,15 +1829,11 @@ public abstract class AbstractDocument implements Document, Serializable
*/
public int getEndOffset()
{
- if (children.length == 0)
- {
- if (endOffset == -1)
- throw new NullPointerException("BranchElement has no children.");
- }
- else
- endOffset = children[children.length - 1].getEndOffset();
-
- return endOffset;
+ // This might accss one cached element or trigger an NPE for
+ // numChildren == 0. This is checked by a Mauve test.
+ Element child = numChildren > 0 ? children[numChildren - 1]
+ : children[0];
+ return child.getEndOffset();
}
/**
@@ -1848,15 +1859,13 @@ public abstract class AbstractDocument implements Document, Serializable
*/
public int getStartOffset()
{
- if (children.length == 0)
- {
- if (startOffset == -1)
- throw new NullPointerException("BranchElement has no children.");
- }
- else
- startOffset = children[0].getStartOffset();
-
- return startOffset;
+ // Do not explicitly throw an NPE here. If the first element is null
+ // then the NPE gets thrown anyway. If it isn't, then it either
+ // holds a real value (for numChildren > 0) or a cached value
+ // (for numChildren == 0) as we don't fully remove elements in replace()
+ // when removing single elements.
+ // This is checked by a Mauve test.
+ return children[0].getStartOffset();
}
/**
@@ -1884,7 +1893,7 @@ public abstract class AbstractDocument implements Document, Serializable
{
// 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];
@@ -1905,14 +1914,26 @@ public abstract class AbstractDocument implements Document, Serializable
*/
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;
+ int delta = elements.length - length;
+ int copyFrom = offset + length; // From where to copy.
+ int copyTo = copyFrom + delta; // Where to copy to.
+ int numMove = numChildren - copyFrom; // How many elements are moved.
+ if (numChildren + delta > children.length)
+ {
+ // Gotta grow the array.
+ int newSize = Math.max(2 * children.length, numChildren + delta);
+ Element[] target = new Element[newSize];
+ System.arraycopy(children, 0, target, 0, offset);
+ System.arraycopy(elements, 0, target, offset, elements.length);
+ System.arraycopy(children, copyFrom, target, copyTo, numMove);
+ children = target;
+ }
+ else
+ {
+ System.arraycopy(children, copyFrom, children, copyTo, numMove);
+ System.arraycopy(elements, 0, children, offset, elements.length);
+ }
+ numChildren += delta;
}
/**
@@ -2165,18 +2186,6 @@ public abstract class AbstractDocument implements Document, Serializable
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>
@@ -2188,28 +2197,21 @@ public abstract class AbstractDocument implements Document, Serializable
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;
+ }
}
/**
@@ -2281,7 +2283,7 @@ public abstract class AbstractDocument implements Document, Serializable
*/
public int getEndOffset()
{
- return endPos.getOffset() + endDelta;
+ return endPos.getOffset();
}
/**
@@ -2307,7 +2309,7 @@ public abstract class AbstractDocument implements Document, Serializable
*/
public int getStartOffset()
{
- return startPos.getOffset() + startDelta;
+ return startPos.getOffset();
}
/**
diff --git a/libjava/classpath/javax/swing/text/BoxView.java b/libjava/classpath/javax/swing/text/BoxView.java
index a184a813152..27e3c0f9a1b 100644
--- a/libjava/classpath/javax/swing/text/BoxView.java
+++ b/libjava/classpath/javax/swing/text/BoxView.java
@@ -67,6 +67,11 @@ public class BoxView
private boolean[] layoutValid = new boolean[2];
/**
+ * Indicates if the requirements for an axis are valid.
+ */
+ private boolean[] requirementsValid = new boolean[2];
+
+ /**
* The spans along the X_AXIS and Y_AXIS.
*/
private int[][] spans = new int[2][];
@@ -265,8 +270,10 @@ public class BoxView
super.replace(offset, length, views);
// Invalidate layout information.
- layoutChanged(X_AXIS);
- layoutChanged(Y_AXIS);
+ layoutValid[X_AXIS] = false;
+ requirementsValid[X_AXIS] = false;
+ layoutValid[Y_AXIS] = false;
+ requirementsValid[Y_AXIS] = false;
}
/**
@@ -278,19 +285,26 @@ public class BoxView
*/
public void paint(Graphics g, Shape a)
{
- Rectangle inside = getInsideAllocation(a);
- // TODO: Used for debugging.
- //g.drawRect(inside.x, inside.y, inside.width, inside.height);
+ Rectangle alloc;
+ if (a instanceof Rectangle)
+ alloc = (Rectangle) a;
+ else
+ alloc = a.getBounds();
+
+ int x = alloc.x + getLeftInset();
+ int y = alloc.y + getTopInset();
- Rectangle copy = new Rectangle(inside);
+ Rectangle clip = g.getClipBounds();
+ Rectangle tmp = new Rectangle();
int count = getViewCount();
for (int i = 0; i < count; ++i)
{
- copy.setBounds(inside);
- childAllocation(i, copy);
- if (!copy.isEmpty()
- && g.hitClip(copy.x, copy.y, copy.width, copy.height))
- paintChild(g, copy, i);
+ tmp.x = x + getOffset(X_AXIS, i);
+ tmp.y = y + getOffset(Y_AXIS, i);
+ tmp.width = getSpan(X_AXIS, i);
+ tmp.height = getSpan(Y_AXIS, i);
+ if (tmp.intersects(clip))
+ paintChild(g, tmp, i);
}
}
@@ -305,7 +319,13 @@ public class BoxView
public float getPreferredSpan(int axis)
{
updateRequirements(axis);
- return requirements[axis].preferred;
+ // Add margin.
+ float margin;
+ if (axis == X_AXIS)
+ margin = getLeftInset() + getRightInset();
+ else
+ margin = getTopInset() + getBottomInset();
+ return requirements[axis].preferred + margin;
}
/**
@@ -319,12 +339,14 @@ public class BoxView
*/
public float getMaximumSpan(int axis)
{
- float max;
- if (axis == myAxis)
- max = getPreferredSpan(axis);
+ updateRequirements(axis);
+ // Add margin.
+ float margin;
+ if (axis == X_AXIS)
+ margin = getLeftInset() + getRightInset();
else
- max = Integer.MAX_VALUE;
- return max;
+ margin = getTopInset() + getBottomInset();
+ return requirements[axis].maximum + margin;
}
/**
@@ -341,7 +363,13 @@ public class BoxView
public float getMinimumSpan(int axis)
{
updateRequirements(axis);
- return requirements[axis].minimum;
+ // Add margin.
+ float margin;
+ if (axis == X_AXIS)
+ margin = getLeftInset() + getRightInset();
+ else
+ margin = getTopInset() + getBottomInset();
+ return requirements[axis].minimum + margin;
}
/**
@@ -435,34 +463,29 @@ public class BoxView
protected SizeRequirements calculateMajorAxisRequirements(int axis,
SizeRequirements sr)
{
- updateChildRequirements(axis);
+ SizeRequirements res = sr;
+ if (res == null)
+ res = new SizeRequirements();
- SizeRequirements result = sr;
- if (result == null)
- result = new SizeRequirements();
+ float min = 0;
+ float pref = 0;
+ float max = 0;
- long minimum = 0;
- long preferred = 0;
- long maximum = 0;
- for (int i = 0; i < children.length; i++)
+ int n = getViewCount();
+ for (int i = 0; i < n; i++)
{
- minimum += childReqs[axis][i].minimum;
- preferred += childReqs[axis][i].preferred;
- maximum += childReqs[axis][i].maximum;
+ View child = getView(i);
+ min += child.getMinimumSpan(axis);
+ pref = child.getPreferredSpan(axis);
+ max = child.getMaximumSpan(axis);
}
- // Overflow check.
- if (minimum > Integer.MAX_VALUE)
- minimum = Integer.MAX_VALUE;
- if (preferred > Integer.MAX_VALUE)
- preferred = Integer.MAX_VALUE;
- if (maximum > Integer.MAX_VALUE)
- maximum = Integer.MAX_VALUE;
-
- result.minimum = (int) minimum;
- result.preferred = (int) preferred;
- result.maximum = (int) maximum;
- result.alignment = 0.5F;
- return result;
+
+ res.minimum = (int) min;
+ res.preferred = (int) pref;
+ res.maximum = (int) max;
+ res.alignment = 0.5F;
+
+ return res;
}
/**
@@ -480,44 +503,24 @@ public class BoxView
protected SizeRequirements calculateMinorAxisRequirements(int axis,
SizeRequirements sr)
{
- updateChildRequirements(axis);
-
SizeRequirements res = sr;
if (res == null)
res = new SizeRequirements();
- float minLeft = 0;
- float minRight = 0;
- float prefLeft = 0;
- float prefRight = 0;
- float maxLeft = 0;
- float maxRight = 0;
- for (int i = 0; i < childReqs[axis].length; i++)
+ res.minimum = 0;
+ res.preferred = 0;
+ res.maximum = 0;
+ res.alignment = 0.5F;
+ int n = getViewCount();
+ for (int i = 0; i < n; i++)
{
- float myMinLeft = childReqs[axis][i].minimum * childReqs[axis][i].alignment;
- float myMinRight = childReqs[axis][i].minimum - myMinLeft;
- minLeft = Math.max(myMinLeft, minLeft);
- minRight = Math.max(myMinRight, minRight);
- float myPrefLeft = childReqs[axis][i].preferred * childReqs[axis][i].alignment;
- float myPrefRight = childReqs[axis][i].preferred - myPrefLeft;
- prefLeft = Math.max(myPrefLeft, prefLeft);
- prefRight = Math.max(myPrefRight, prefRight);
- float myMaxLeft = childReqs[axis][i].maximum * childReqs[axis][i].alignment;
- float myMaxRight = childReqs[axis][i].maximum - myMaxLeft;
- maxLeft = Math.max(myMaxLeft, maxLeft);
- maxRight = Math.max(myMaxRight, maxRight);
+ View child = getView(i);
+ res.minimum = Math.max((int) child.getMinimumSpan(axis), res.minimum);
+ res.preferred = Math.max((int) child.getPreferredSpan(axis),
+ res.preferred);
+ res.maximum = Math.max((int) child.getMaximumSpan(axis), res.maximum);
}
- int minSize = (int) (minLeft + minRight);
- int prefSize = (int) (prefLeft + prefRight);
- int maxSize = (int) (maxLeft + maxRight);
- float align = prefLeft / (prefRight + prefLeft);
- if (Float.isNaN(align))
- align = 0;
- res.alignment = align;
- res.maximum = maxSize;
- res.preferred = prefSize;
- res.minimum = minSize;
return res;
}
@@ -697,15 +700,62 @@ public class BoxView
protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets,
int[] spans)
{
- updateChildRequirements(axis);
- updateRequirements(axis);
+ // Set the spans to the preferred sizes. Determine the space
+ // that we have to adjust the sizes afterwards.
+ long sumPref = 0;
+ int n = getViewCount();
+ for (int i = 0; i < n; i++)
+ {
+ View child = getView(i);
+ spans[i] = (int) child.getPreferredSpan(axis);
+ sumPref = spans[i];
+ }
- // Calculate the spans and offsets using the SizeRequirements uility
- // methods.
- SizeRequirements.calculateTiledPositions(targetSpan, requirements[axis],
- childReqs[axis],
- offsets, spans);
+ // Try to adjust the spans so that we fill the targetSpan.
+ long diff = targetSpan - sumPref;
+ float factor = 0.0F;
+ int[] diffs = null;
+ if (diff != 0)
+ {
+ long total = 0;
+ diffs = new int[n];
+ for (int i = 0; i < n; i++)
+ {
+ View child = getView(i);
+ int span;
+ if (diff < 0)
+ {
+ span = (int) child.getMinimumSpan(axis);
+ diffs[i] = spans[i] - span;
+ }
+ else
+ {
+ span = (int) child.getMaximumSpan(axis);
+ diffs[i] = span - spans[i];
+ }
+ total += span;
+ }
+ float maxAdjust = Math.abs(total - sumPref);
+ factor = diff / maxAdjust;
+ factor = Math.min(factor, 1.0F);
+ factor = Math.max(factor, -1.0F);
+ }
+
+ // Actually perform adjustments.
+ int totalOffs = 0;
+ for (int i = 0; i < n; i++)
+ {
+ offsets[i] = totalOffs;
+ if (diff != 0)
+ {
+ float adjust = factor * diffs[i];
+ spans[i] += Math.round(adjust);
+ }
+ // Avoid overflow here.
+ totalOffs = (int) Math.min((long) totalOffs + (long) spans[i],
+ Integer.MAX_VALUE);
+ }
}
/**
@@ -720,14 +770,26 @@ public class BoxView
protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets,
int[] spans)
{
- updateChildRequirements(axis);
- updateRequirements(axis);
-
- // Calculate the spans and offsets using the SizeRequirements uility
- // methods.
- SizeRequirements.calculateAlignedPositions(targetSpan, requirements[axis],
- childReqs[axis], offsets,
- spans);
+ int count = getViewCount();
+ for (int i = 0; i < count; i++)
+ {
+ View child = getView(i);
+ int max = (int) child.getMaximumSpan(axis);
+ if (max < targetSpan)
+ {System.err.println("align: " + child);
+ // Align child when it can't be made as wide as the target span.
+ float align = child.getAlignment(axis);
+ offsets[i] = (int) ((targetSpan - max) * align);
+ spans[i] = max;
+ }
+ else
+ {
+ // Expand child to target width if possible.
+ int min = (int) child.getMinimumSpan(axis);
+ offsets[i] = 0;
+ spans[i] = Math.max(min, targetSpan);
+ }
+ }
}
/**
@@ -822,15 +884,8 @@ public class BoxView
*/
public float getAlignment(int axis)
{
- float align;
- if (axis == myAxis)
- align = 0.5F;
- else
- {
- updateRequirements(axis);
- align = requirements[axis].alignment;
- }
- return align;
+ updateRequirements(axis);
+ return requirements[axis].alignment;
}
/**
@@ -843,9 +898,15 @@ public class BoxView
public void preferenceChanged(View child, boolean width, boolean height)
{
if (width)
- layoutValid[X_AXIS] = false;
+ {
+ layoutValid[X_AXIS] = false;
+ requirementsValid[X_AXIS] = false;
+ }
if (height)
- layoutValid[Y_AXIS] = false;
+ {
+ layoutValid[Y_AXIS] = false;
+ requirementsValid[Y_AXIS] = false;
+ }
super.preferenceChanged(child, width, height);
}
@@ -862,7 +923,7 @@ public class BoxView
if (! isAllocationValid())
{
Rectangle bounds = a.getBounds();
- layout(bounds.width, bounds.height);
+ setSize(bounds.width, bounds.height);
}
return super.modelToView(pos, a, bias);
}
@@ -963,7 +1024,7 @@ public class BoxView
*/
private void updateRequirements(int axis)
{
- if (! layoutValid[axis])
+ if (! requirementsValid[axis])
{
if (axis == myAxis)
requirements[axis] = calculateMajorAxisRequirements(axis,
@@ -971,6 +1032,7 @@ public class BoxView
else
requirements[axis] = calculateMinorAxisRequirements(axis,
requirements[axis]);
+ requirementsValid[axis] = true;
}
}
}
diff --git a/libjava/classpath/javax/swing/text/CompositeView.java b/libjava/classpath/javax/swing/text/CompositeView.java
index 17f13dbedd6..6f487b8981e 100644
--- a/libjava/classpath/javax/swing/text/CompositeView.java
+++ b/libjava/classpath/javax/swing/text/CompositeView.java
@@ -217,25 +217,43 @@ public abstract class CompositeView
public Shape modelToView(int pos, Shape a, Position.Bias bias)
throws BadLocationException
{
- int childIndex = getViewIndex(pos, bias);
- if (childIndex == -1)
- throw new BadLocationException("Position " + pos + " is not represented by view.", pos);
-
- Shape ret = null;
-
- View child = getView(childIndex);
- Shape childAlloc = getChildAllocation(childIndex, a);
-
- if (childAlloc == null)
- ret = createDefaultLocation(a, bias);
-
- Shape result = child.modelToView(pos, childAlloc, bias);
-
- if (result != null)
- ret = result;
- else
- ret = createDefaultLocation(a, bias);
+ boolean backward = bias == Position.Bias.Backward;
+ int testpos = backward ? Math.max(0, pos - 1) : pos;
+ Shape ret = null;
+ if (! backward || testpos >= getStartOffset())
+ {
+ int childIndex = getViewIndexAtPosition(testpos);
+ if (childIndex != -1 && childIndex < getViewCount())
+ {
+ View child = getView(childIndex);
+ if (child != null && testpos >= child.getStartOffset()
+ && testpos < child.getEndOffset())
+ {
+ Shape childAlloc = getChildAllocation(childIndex, a);
+ if (childAlloc != null)
+ {
+ ret = child.modelToView(pos, childAlloc, bias);
+ // Handle corner case.
+ if (ret == null && child.getEndOffset() == pos)
+ {
+ childIndex++;
+ if (childIndex < getViewCount())
+ {
+ child = getView(childIndex);
+ childAlloc = getChildAllocation(childIndex, a);
+ ret = child.modelToView(pos, childAlloc, bias);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ throw new BadLocationException("Position " + pos
+ + " is not represented by view.", pos);
+ }
+ }
return ret;
}
@@ -378,7 +396,10 @@ public abstract class CompositeView
{
if (b == Position.Bias.Backward && pos != 0)
pos -= 1;
- return getViewIndexAtPosition(pos);
+ int i = -1;
+ if (pos >= getStartOffset() && pos < getEndOffset())
+ i = getViewIndexAtPosition(pos);
+ return i;
}
/**
@@ -446,9 +467,13 @@ public abstract class CompositeView
*/
protected View getViewAtPosition(int pos, Rectangle a)
{
+ View view = null;
int i = getViewIndexAtPosition(pos);
- View view = children[i];
- childAllocation(i, a);
+ if (i >= 0 && i < getViewCount() && a != null)
+ {
+ view = getView(i);
+ childAllocation(i, a);
+ }
return view;
}
@@ -464,17 +489,10 @@ public abstract class CompositeView
*/
protected int getViewIndexAtPosition(int pos)
{
- int index = -1;
- for (int i = 0; i < children.length; i++)
- {
- if (children[i].getStartOffset() <= pos
- && children[i].getEndOffset() > pos)
- {
- index = i;
- break;
- }
- }
- return index;
+ // We have a 1:1 mapping of elements to views here, so we forward
+ // this to the element.
+ Element el = getElement();
+ return el.getElementIndex(pos);
}
/**
diff --git a/libjava/classpath/javax/swing/text/DefaultCaret.java b/libjava/classpath/javax/swing/text/DefaultCaret.java
index 4ad204c00c9..84f47f120de 100644
--- a/libjava/classpath/javax/swing/text/DefaultCaret.java
+++ b/libjava/classpath/javax/swing/text/DefaultCaret.java
@@ -221,9 +221,12 @@ public class DefaultCaret extends Rectangle
if (name.equals("document"))
{
Document oldDoc = (Document) e.getOldValue();
- oldDoc.removeDocumentListener(documentListener);
+ if (oldDoc != null)
+ oldDoc.removeDocumentListener(documentListener);
+
Document newDoc = (Document) e.getNewValue();
- newDoc.addDocumentListener(documentListener);
+ if (newDoc != null)
+ newDoc.addDocumentListener(documentListener);
}
else if (name.equals("editable"))
{
@@ -549,7 +552,6 @@ public class DefaultCaret extends Rectangle
*/
public void mousePressed(MouseEvent event)
{
- int button = event.getButton();
// The implementation assumes that consuming the event makes the AWT event
// mechanism forget about this event instance and not transfer focus.
@@ -562,23 +564,37 @@ public class DefaultCaret extends Rectangle
// - a middle-click positions the caret and pastes the clipboard
// contents.
// - a middle-click when shift is held down is ignored
-
- if (button == MouseEvent.BUTTON1)
- if (event.isShiftDown())
- moveCaret(event);
- else
- positionCaret(event);
- else if(button == MouseEvent.BUTTON2)
- if (event.isShiftDown())
- event.consume();
+
+ if (SwingUtilities.isLeftMouseButton(event))
+ {
+ // Handle the caret.
+ if (event.isShiftDown() && getDot() != -1)
+ {
+ moveCaret(event);
+ }
else
{
positionCaret(event);
-
+ }
+
+ // Handle the focus.
+ if (textComponent != null && textComponent.isEnabled()
+ && textComponent.isRequestFocusEnabled())
+ {
+ textComponent.requestFocus();
+ }
+
+ // TODO: Handle double click for selecting words.
+ }
+ else if(event.getButton() == MouseEvent.BUTTON2)
+ {
+ // Special handling for X11-style pasting.
+ if (! event.isShiftDown())
+ {
+ positionCaret(event);
textComponent.paste();
}
- else
- event.consume();
+ }
}
/**
@@ -708,7 +724,11 @@ public class DefaultCaret extends Rectangle
propertyChangeListener = new PropertyChangeHandler();
textComponent.addPropertyChangeListener(propertyChangeListener);
documentListener = new DocumentHandler();
- textComponent.getDocument().addDocumentListener(documentListener);
+
+ Document doc = textComponent.getDocument();
+ if (doc != null)
+ doc.addDocumentListener(documentListener);
+
active = textComponent.isEditable() && textComponent.isEnabled();
repaint();
@@ -891,10 +911,10 @@ public class DefaultCaret extends Rectangle
}
catch (BadLocationException e)
{
- AssertionError ae;
- ae = new AssertionError("Unexpected bad caret location: " + dot);
- ae.initCause(e);
- throw ae;
+ // Let's ignore that. This shouldn't really occur. But if it
+ // does (it seems that this happens when the model is mutating),
+ // it causes no real damage. Uncomment this for debugging.
+ // e.printStackTrace();
}
if (rect == null)
@@ -1128,10 +1148,10 @@ public class DefaultCaret extends Rectangle
}
catch (BadLocationException e)
{
- AssertionError ae;
- ae = new AssertionError("Unexpected bad caret location: " + dot);
- ae.initCause(e);
- throw ae;
+ // Let's ignore that. This shouldn't really occur. But if it
+ // does (it seems that this happens when the model is mutating),
+ // it causes no real damage. Uncomment this for debugging.
+ // e.printStackTrace();
}
if (area != null)
damage(area);
@@ -1140,6 +1160,24 @@ public class DefaultCaret extends Rectangle
}
/**
+ * Returns <code>true</code> if this <code>Caret</code> is blinking,
+ * and <code>false</code> if not. The returned value is independent of
+ * the visiblity of this <code>Caret</code> as returned by {@link #isVisible()}.
+ *
+ * @return <code>true</code> if this <code>Caret</code> is blinking,
+ * and <code>false</code> if not.
+ * @see #isVisible()
+ * @since 1.5
+ */
+ public boolean isActive()
+ {
+ if (blinkTimer != null)
+ return blinkTimer.isRunning();
+
+ return false;
+ }
+
+ /**
* Returns <code>true</code> if this <code>Caret</code> is currently visible,
* and <code>false</code> if it is not.
*
diff --git a/libjava/classpath/javax/swing/text/EmptyAttributeSet.java b/libjava/classpath/javax/swing/text/EmptyAttributeSet.java
new file mode 100644
index 00000000000..98fb8828c89
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/EmptyAttributeSet.java
@@ -0,0 +1,153 @@
+/* EmptyAttributeSet.java -- An empty attribute set
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+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.Enumeration;
+import java.util.NoSuchElementException;
+
+/**
+ * An immutable, empty attribute set.
+ *
+ * @see SimpleAttributeSet#EMPTY
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+final class EmptyAttributeSet
+ implements AttributeSet
+{
+
+ /**
+ * Always return false as this AttributeSet doesn't contain any attributes.
+ */
+ public boolean containsAttribute(Object name, Object value)
+ {
+ return false;
+ }
+
+ /**
+ * Return true only if the attributes argument also contains no attributes.
+ */
+ public boolean containsAttributes(AttributeSet attributes)
+ {
+ return attributes.getAttributeCount() == 0;
+ }
+
+ /**
+ * Return this, as this is immutable.
+ */
+ public AttributeSet copyAttributes()
+ {
+ return this;
+ }
+
+ /**
+ * Always return null as this AttributeSet doesn't contain any attributes.
+ */
+ public Object getAttribute(Object key)
+ {
+ return null;
+ }
+
+ /**
+ * Always return 0.
+ */
+ public int getAttributeCount()
+ {
+ return 0;
+ }
+
+ /**
+ * Returns an empty Enumeration.
+ */
+ public Enumeration getAttributeNames()
+ {
+ return new Enumeration()
+ {
+ public boolean hasMoreElements()
+ {
+ return false;
+ }
+
+ public Object nextElement()
+ {
+ throw new NoSuchElementException("No more elements");
+ }
+
+ };
+ }
+
+ /**
+ * Always return null as this has no resolve parent.
+ */
+ public AttributeSet getResolveParent()
+ {
+ return null;
+ }
+
+ /**
+ * Always return false as this AttributeSet doesn't contain any attributes.
+ */
+ public boolean isDefined(Object attrName)
+ {
+ return false;
+ }
+
+ /**
+ * Other attribute sets are equal if they are empty too.
+ */
+ public boolean isEqual(AttributeSet attr)
+ {
+ return attr.getAttributeCount() == 0;
+ }
+
+ /**
+ * Other objects are equal if it's the same instance as this, or if
+ * it's another attribute set without attributes.
+ */
+ public boolean equals(Object o)
+ {
+ boolean eq = o == this;
+ if (! eq)
+ {
+ eq = (o instanceof AttributeSet)
+ && ((AttributeSet) o).getAttributeCount() == 0;
+ }
+ return eq;
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/FlowView.java b/libjava/classpath/javax/swing/text/FlowView.java
index 8ca55d8347a..3de95ed7f8d 100644
--- a/libjava/classpath/javax/swing/text/FlowView.java
+++ b/libjava/classpath/javax/swing/text/FlowView.java
@@ -159,20 +159,18 @@ public abstract class FlowView extends BoxView
}
/**
- * Lays out one row of the flow view. This is called by {@link #layout}
- * to fill one row with child views until the available span is exhausted.
- *
- * The default implementation fills the row by calling
- * {@link #createView(FlowView, int, int, int)} until the available space
- * is exhausted, a forced break is encountered or there are no more views
- * in the logical view. If the available space is exhausted,
- * {@link #adjustRow(FlowView, int, int, int)} is called to fit the row
- * into the available span.
- *
+ * Lays out one row of the flow view. This is called by {@link #layout} to
+ * fill one row with child views until the available span is exhausted. The
+ * default implementation fills the row by calling
+ * {@link #createView(FlowView, int, int, int)} until the available space is
+ * exhausted, a forced break is encountered or there are no more views in
+ * the logical view. If the available space is exhausted,
+ * {@link #adjustRow(FlowView, int, int, int)} is called to fit the row into
+ * the available span.
+ *
* @param fv the flow view for which we perform the layout
* @param rowIndex the index of the row
* @param pos the model position for the beginning of the row
- *
* @return the start position of the next row
*/
protected int layoutRow(FlowView fv, int rowIndex, int pos)
@@ -188,34 +186,39 @@ public abstract class FlowView extends BoxView
if (span == 0)
span = Integer.MAX_VALUE;
- while (span > 0)
+ Row: while (span > 0)
{
- if (logicalView.getViewIndex(offset, Position.Bias.Forward) == -1)
+ if (logicalView.getViewIndex(offset, Position.Bias.Forward) == - 1)
break;
View view = createView(fv, offset, span, rowIndex);
if (view == null)
break;
+
int viewSpan = (int) view.getPreferredSpan(axis);
- row.append(view);
int breakWeight = view.getBreakWeight(axis, x, span);
- if (breakWeight >= View.ForcedBreakWeight)
- break;
+
+ row.append(view);
+ offset += (view.getEndOffset() - view.getStartOffset());
x += viewSpan;
span -= viewSpan;
- offset += (view.getEndOffset() - view.getStartOffset());
- }
- if (span < 0)
- {
- int flowStart = fv.getFlowStart(axis);
- int flowSpan = fv.getFlowSpan(axis);
- adjustRow(fv, rowIndex, flowSpan, flowStart);
- int rowViewCount = row.getViewCount();
- if (rowViewCount > 0)
- offset = row.getView(rowViewCount - 1).getEndOffset();
- else
- offset = -1;
+
+ // Break if the line if the view does not fit in this row or the
+ // line just must be broken.
+ if (span < 0 || breakWeight >= View.ForcedBreakWeight)
+ {
+ int flowStart = fv.getFlowStart(axis);
+ int flowSpan = fv.getFlowSpan(axis);
+ adjustRow(fv, rowIndex, flowSpan, flowStart);
+ int rowViewCount = row.getViewCount();
+ if (rowViewCount > 0)
+ offset = row.getView(rowViewCount - 1).getEndOffset();
+ else
+ offset = - 1;
+ break Row;
+ }
}
- return offset != pos ? offset : -1;
+
+ return offset != pos ? offset : - 1;
}
/**
@@ -521,6 +524,7 @@ public abstract class FlowView extends BoxView
*/
public void removeUpdate(DocumentEvent changes, Shape a, ViewFactory vf)
{
+ layoutPool.removeUpdate(changes, a, vf);
strategy.removeUpdate(this, changes, getInsideAllocation(a));
layoutDirty = true;
}
@@ -536,6 +540,7 @@ public abstract class FlowView extends BoxView
*/
public void changedUpdate(DocumentEvent changes, Shape a, ViewFactory vf)
{
+ layoutPool.changedUpdate(changes, a, vf);
strategy.changedUpdate(this, changes, getInsideAllocation(a));
layoutDirty = true;
}
@@ -594,12 +599,14 @@ public abstract class FlowView extends BoxView
protected SizeRequirements calculateMinorAxisRequirements(int axis,
SizeRequirements r)
{
- // We need to call super here so that the alignment is properly
- // calculated.
- SizeRequirements res = super.calculateMinorAxisRequirements(axis, r);
+ SizeRequirements res = r;
+ if (res == null)
+ res = new SizeRequirements();
res.minimum = (int) layoutPool.getMinimumSpan(axis);
- res.preferred = (int) layoutPool.getPreferredSpan(axis);
- res.maximum = (int) layoutPool.getMaximumSpan(axis);
+ res.preferred = Math.max(res.minimum,
+ (int) layoutPool.getMinimumSpan(axis));
+ res.maximum = Integer.MAX_VALUE;
+ res.alignment = 0.5F;
return res;
}
}
diff --git a/libjava/classpath/javax/swing/text/GapContent.java b/libjava/classpath/javax/swing/text/GapContent.java
index 4f06003b458..760e396a223 100644
--- a/libjava/classpath/javax/swing/text/GapContent.java
+++ b/libjava/classpath/javax/swing/text/GapContent.java
@@ -39,7 +39,13 @@ exception statement from your version. */
package javax.swing.text;
import java.io.Serializable;
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.Iterator;
+import java.util.List;
import java.util.Set;
import java.util.Vector;
import java.util.WeakHashMap;
@@ -73,30 +79,39 @@ public class GapContent
* The index to the positionMarks array entry, which in turn holds the
* mark into the buffer array.
*/
- int index;
+ Mark mark;
/**
* Creates a new GapContentPosition object.
*
- * @param mark the mark of this Position
+ * @param offset the offset of this Position
*/
- GapContentPosition(int mark)
+ GapContentPosition(int offset)
{
// Try to find the mark in the positionMarks array, and store the index
// to it.
synchronized (GapContent.this)
{
- int i = binarySearch(positionMarks, mark, numMarks);
+ // Try to make space.
+ garbageCollect();
+ Mark m = new Mark(offset);
+ int i = search(marks, m);
if (i >= 0) // mark found
{
- index = i;
+ m = (Mark) marks.get(i);
}
else
{
- index = -i - 1;
- insertMark(index, mark);
+ i = -i - 1;
+ marks.add(i, m);
}
+ m.refCount++;
+ mark = m;
}
+
+ // Register this position in the death queue, so we can cleanup the marks
+ // when this position object gets GC'ed.
+ new WeakReference(this, queueOfDeath);
}
/**
@@ -106,19 +121,77 @@ public class GapContent
*/
public int getOffset()
{
- synchronized (GapContent.this)
- {
- // Fetch the actual mark.
- int mark = positionMarks[index];
- // Check precondition.
- assert mark <= gapStart || mark >= gapEnd : "mark: " + mark
- + ", gapStart: " + gapStart
- + ", gapEnd: " + gapEnd;
- int res = mark;
- if (mark > gapStart)
- res -= (gapEnd - gapStart);
- return res;
- }
+ return mark.getOffset();
+ }
+ }
+
+ /**
+ * Holds a mark into the buffer that is used by GapContentPosition to find
+ * the actual offset of the position. This is pulled out of the
+ * GapContentPosition object so that the mark and position can be handled
+ * independently, and most important, so that the GapContentPosition can
+ * be garbage collected while we still hold a reference to the Mark object.
+ */
+ private class Mark
+ implements Comparable
+ {
+ /**
+ * The actual mark into the buffer.
+ */
+ int mark;
+
+ /**
+ * The number of GapContentPosition object that reference this mark. If
+ * it reaches zero, it get's deleted by {@link GapContent#garbageCollect()}.
+ */
+ int refCount;
+
+ /**
+ * Creates a new Mark object for the specified offset.
+ *
+ * @param offset the offset
+ */
+ Mark(int offset)
+ {
+ mark = offset;
+ if (mark >= gapStart && mark != 0)
+ mark += (gapEnd - gapStart);
+ }
+
+ /**
+ * Returns the offset of the mark.
+ *
+ * @return the offset of the mark
+ */
+ int getOffset()
+ {
+ assert mark == 0 || mark < gapStart || mark >= gapEnd :
+ "Invalid mark: " + mark + ", gapStart: " + gapStart
+ + ", gapEnd: " + gapEnd;
+
+ int res = mark;
+ if (mark >= gapEnd)
+ res -= (gapEnd - gapStart);
+ return res;
+ }
+
+ /**
+ * Implementation of Comparable.
+ */
+ public int compareTo(Object o)
+ {
+ Mark other = (Mark) o;
+ return mark - other.mark;
+ }
+ /**
+ * Adjustment for equals().
+ */
+ public boolean equals(Object o)
+ {
+ if (o == null || !(o instanceof Mark))
+ return false;
+ else
+ return ((Mark) o).mark == mark;
}
}
@@ -230,19 +303,21 @@ public class GapContent
/**
* Holds the marks for positions. These marks are referenced by the
* GapContentPosition instances by an index into this array.
+ *
+ * This is package private to avoid accessor synthetic methods.
*/
- int[] positionMarks;
+ ArrayList marks;
- /**
- * The number of elements in the positionMarks array. The positionMarks array
- * might be bigger than the actual number of elements.
- */
- int numMarks;
+ WeakHashMap positions;
/**
- * (Weakly) Stores the GapContentPosition instances.
+ * Queues all references to GapContentPositions that are about to be
+ * GC'ed. This is used to remove the corresponding marks from the
+ * positionMarks array if the number of references to that mark reaches zero.
+ *
+ * This is package private to avoid accessor synthetic methods.
*/
- WeakHashMap positions;
+ ReferenceQueue queueOfDeath;
/**
* Creates a new GapContent object.
@@ -265,8 +340,8 @@ public class GapContent
gapEnd = size;
buffer[0] = '\n';
positions = new WeakHashMap();
- positionMarks = new int[10];
- numMarks = 0;
+ marks = new ArrayList();
+ queueOfDeath = new ReferenceQueue();
}
/**
@@ -417,6 +492,8 @@ public class GapContent
if ((where + len) > length)
throw new BadLocationException("len plus where cannot be greater"
+ " than the content length", len + where);
+ if (len < 0)
+ throw new BadLocationException("negative length not allowed: ", len);
// check if requested segment is contiguous
if ((where < gapStart) && ((gapStart - where) < len))
@@ -455,6 +532,11 @@ public class GapContent
*/
public Position createPosition(final int offset) throws BadLocationException
{
+ // Implementation note: We used to perform explicit check on the offset
+ // here. However, this makes some Mauve and Intel/Harmony tests fail
+ // and luckily enough the GapContent can very well deal with offsets
+ // outside the buffer bounds. So I removed that check.
+
// We try to find a GapContentPosition at the specified offset and return
// that. Otherwise we must create a new one.
GapContentPosition pos = null;
@@ -472,10 +554,7 @@ public class GapContent
// If none was found, then create and return a new one.
if (pos == null)
{
- int mark = offset;
- if (mark >= gapStart)
- mark += (gapEnd - gapStart);
- pos = new GapContentPosition(mark);
+ pos = new GapContentPosition(offset);
positions.put(pos, null);
}
@@ -497,7 +576,7 @@ public class GapContent
int delta = newSize - gapEnd + gapStart;
// Update the marks after the gapEnd.
- adjustPositionsInRange(gapEnd, buffer.length - gapEnd, delta);
+ adjustPositionsInRange(gapEnd, -1, delta);
// Copy the data around.
char[] newBuf = (char[]) allocateArray(length() + newSize);
@@ -523,7 +602,7 @@ public class GapContent
{
// Update the positions between newGapStart and (old) gapStart. The marks
// must be shifted by (gapEnd - gapStart).
- adjustPositionsInRange(newGapStart, gapStart - newGapStart, gapEnd - gapStart);
+ adjustPositionsInRange(newGapStart, gapStart, gapEnd - gapStart);
System.arraycopy(buffer, newGapStart, buffer, newGapEnd, gapStart
- newGapStart);
gapStart = newGapStart;
@@ -533,14 +612,13 @@ public class GapContent
{
// Update the positions between newGapEnd and (old) gapEnd. The marks
// must be shifted by (gapEnd - gapStart).
- adjustPositionsInRange(gapEnd, newGapEnd - gapEnd, -(gapEnd - gapStart));
+ adjustPositionsInRange(gapEnd, newGapEnd, -(gapEnd - gapStart));
System.arraycopy(buffer, gapEnd, buffer, gapStart, newGapStart
- gapStart);
gapStart = newGapStart;
gapEnd = newGapEnd;
}
- if (gapStart == 0)
- resetMarksAtZero();
+ resetMarksAtZero();
}
/**
@@ -560,6 +638,7 @@ public class GapContent
+ "old gap start.";
setPositionsInRange(newGapStart, gapStart, false);
gapStart = newGapStart;
+ resetMarksAtZero();
}
/**
@@ -579,6 +658,7 @@ public class GapContent
+ "old gap end.";
setPositionsInRange(gapEnd, newGapEnd, false);
gapEnd = newGapEnd;
+ resetMarksAtZero();
}
/**
@@ -617,10 +697,6 @@ public class GapContent
if (addItems != null)
{
System.arraycopy(addItems, 0, buffer, gapStart, addSize);
-
-
- resetMarksAtZero();
-
gapStart += addSize;
}
}
@@ -689,102 +765,61 @@ public class GapContent
*/
private void setPositionsInRange(int start, int end, boolean toStart)
{
- // We slump together all the GapContentPositions to point to
- // one mark. So this is implemented as follows:
- // 1. Remove all the marks in the specified range.
- // 2. Insert one new mark at the correct location.
- // 3. Adjust all affected GapContentPosition instances to point to
- // this new mark.
-
synchronized (this)
{
- int startIndex = binarySearch(positionMarks, start, numMarks);
+ // Find the start and end indices in the positionMarks array.
+ Mark m = new Mark(0); // For comparison / search only.
+ m.mark = start;
+ int startIndex = search(marks, m);
if (startIndex < 0) // Translate to insertion index, if not found.
startIndex = - startIndex - 1;
- int endIndex = binarySearch(positionMarks, end, numMarks);
+ m.mark = end;
+ int endIndex = search(marks, m);
if (endIndex < 0) // Translate to insertion index - 1, if not found.
endIndex = - endIndex - 2;
- // Update the marks.
- // We have inclusive interval bounds, but let one element over for
- // filling in the new value.
- int removed = endIndex - startIndex;
- if (removed <= 0)
- return;
- System.arraycopy(positionMarks, endIndex + 1, positionMarks,
- startIndex + 1, positionMarks.length - endIndex - 1);
- numMarks -= removed;
- if (toStart)
- {
- positionMarks[startIndex] = start;
- }
- else
- {
- positionMarks[startIndex] = end;
- }
+ // Actually adjust the marks.
+ for (int i = startIndex; i <= endIndex; i++)
+ ((Mark) marks.get(i)).mark = toStart ? start : end;
+ }
- // Update all affected GapContentPositions to point to the new index
- // and all GapContentPositions that come after the interval to
- // have their index moved by -removed.
- Set positionSet = positions.keySet();
- for (Iterator i = positionSet.iterator(); i.hasNext();)
- {
- GapContentPosition p = (GapContentPosition) i.next();
- if (p.index > startIndex || p.index <= endIndex)
- p.index = startIndex;
- else if (p.index > endIndex)
- p.index -= removed;
- }
- }
}
-
+
/**
* Adjusts the mark of all <code>Position</code>s that are in the range
* specified by <code>offset</code> and </code>length</code> within
* the buffer array by <code>increment</code>
*
- * @param offset the start offset of the range to search
- * @param length the length of the range to search
+ * @param startOffs the start offset of the range to search
+ * @param endOffs the length of the range to search, -1 means all to the end
* @param incr the increment
*/
- private void adjustPositionsInRange(int offset, int length, int incr)
+ private void adjustPositionsInRange(int startOffs, int endOffs, int incr)
{
- int endMark = offset + length;
-
synchronized (this)
{
// Find the start and end indices in the positionMarks array.
- int startIndex = binarySearch(positionMarks, offset, numMarks);
+ Mark m = new Mark(0); // For comparison / search only.
+
+ m.mark = startOffs;
+ int startIndex = search(marks, m);
if (startIndex < 0) // Translate to insertion index, if not found.
startIndex = - startIndex - 1;
- int endIndex = binarySearch(positionMarks, endMark, numMarks);
- if (endIndex < 0) // Translate to insertion index - 1, if not found.
- endIndex = - endIndex - 2;
-
- // We must not change the order of the marks, this would have
- // unpredictable results while binary-searching the marks.
- assert (startIndex <= 0
- || positionMarks[startIndex - 1]
- <= positionMarks [startIndex] + incr)
- && (endIndex >= numMarks - 1
- || positionMarks[endIndex + 1]
- >= positionMarks[endIndex] + incr)
- : "Adjusting the marks must not change their order";
-
- // Some debug helper output to determine if the start or end of the
- // should ever be coalesced together with adjecent marks.
- if (startIndex > 0 && positionMarks[startIndex - 1]
- == positionMarks[startIndex] + incr)
- System.err.println("DEBUG: We could coalesce the start of the region"
- + " in GapContent.adjustPositionsInRange()");
- if (endIndex < numMarks - 1 && positionMarks[endIndex + 1]
- == positionMarks[endIndex] + incr)
- System.err.println("DEBUG: We could coalesce the end of the region"
- + " in GapContent.adjustPositionsInRange()");
+ m.mark = endOffs;
+ int endIndex;
+ if (endOffs == -1)
+ endIndex = marks.size() - 1;
+ else
+ {
+ endIndex = search(marks, m);
+ if (endIndex < 0) // Translate to insertion index - 1, if not found.
+ endIndex = - endIndex - 2;
+ }
// Actually adjust the marks.
- for (int i = startIndex; i <= endIndex; i++)
- positionMarks[i] += incr;
+ for (int i = startIndex; i <= endIndex; i++) {
+ ((Mark) marks.get(i)).mark += incr;
+ }
}
}
@@ -800,7 +835,12 @@ public class GapContent
if (gapStart != 0)
return;
- positionMarks[0] = 0;
+ for (int i = 0; i < marks.size(); i++)
+ {
+ Mark m = (Mark) marks.get(i);
+ if (m.mark <= gapEnd)
+ m.mark = 0;
+ }
}
/**
@@ -845,89 +885,60 @@ public class GapContent
*/
private void dumpMarks()
{
- System.err.print("positionMarks: ");
- for (int i = 0; i < numMarks; i++)
- System.err.print(positionMarks[i] + ", ");
- System.err.println();
+ System.out.print("positionMarks: ");
+ for (int i = 0; i < marks.size(); i++)
+ System.out.print(((Mark) marks.get(i)).mark + ", ");
+ System.out.println();
}
/**
- * Inserts a mark into the positionMarks array. This must update all the
- * GapContentPosition instances in positions that come after insertionPoint.
+ * Polls the queue of death for GapContentPositions, updates the
+ * corresponding reference count and removes the corresponding mark
+ * if the refcount reaches zero.
*
- * This is package private to avoid synthetic accessor methods.
- *
- * @param insertionPoint the index at which to insert the mark
- * @param mark the mark to insert
+ * This is package private to avoid accessor synthetic methods.
*/
- void insertMark(int insertionPoint, int mark)
+ void garbageCollect()
{
- synchronized (this)
+ Reference ref = queueOfDeath.poll();
+ while (ref != null)
{
- // Update the positions.
- Set positionSet = positions.keySet();
- for (Iterator i = positionSet.iterator(); i.hasNext();)
- {
- GapContentPosition p = (GapContentPosition) i.next();
- if (p.index >= insertionPoint)
- p.index++;
- }
-
- // Update the position marks.
- if (positionMarks.length <= numMarks)
+ if (ref != null)
{
- int[] newMarks = new int[positionMarks.length + 10];
- System.arraycopy(positionMarks, 0, newMarks, 0, insertionPoint);
- newMarks[insertionPoint] = mark;
- System.arraycopy(positionMarks, insertionPoint, newMarks,
- insertionPoint + 1,
- numMarks - insertionPoint);
- positionMarks = newMarks;
+ GapContentPosition pos = (GapContentPosition) ref.get();
+ Mark m = pos.mark;
+ m.refCount--;
+ if (m.refCount == 0)
+ marks.remove(m);
}
- else
- {
- System.arraycopy(positionMarks, insertionPoint, positionMarks,
- insertionPoint + 1,
- numMarks - insertionPoint);
- positionMarks[insertionPoint] = mark;
- }
- numMarks++;
+ ref = queueOfDeath.poll();
}
}
/**
- * An adaption of {@link java.util.Arrays#binarySearch(int[], int)} to
- * specify a maximum index up to which the array is searched. This allows
- * us to have some trailing entries that we ignore.
- *
- * This is package private to avoid synthetic accessor methods.
- *
- * @param a the array
- * @param key the key to search for
- * @param maxIndex the maximum index up to which the search is performed
+ * Searches the first occurance of object <code>o</code> in list
+ * <code>l</code>. This performs a binary search by calling
+ * {@link Collections#binarySearch(List, Object)} and when an object has been
+ * found, it searches backwards to the first occurance of that object in the
+ * list. The meaning of the return value is the same as in
+ * <code>Collections.binarySearch()</code>.
*
- * @return the index of the found entry, or (-(index)-1) for the
- * insertion point when not found
+ * @param l the list to search through
+ * @param o the object to be searched
*
- * @see java.util.Arrays#binarySearch(int[], int)
+ * @return the index of the first occurance of o in l, or -i + 1 if not found
*/
- int binarySearch(int[] a, int key, int maxIndex)
+ private int search(List l, Object o)
{
- int low = 0;
- int hi = maxIndex - 1;
- int mid = 0;
- while (low <= hi)
+ int i = Collections.binarySearch(l, o);
+ while (i > 0)
{
- mid = (low + hi) >>> 1;
- final int d = a[mid];
- if (d == key)
- return mid;
- else if (d > key)
- hi = mid - 1;
+ Object o2 = l.get(i - 1);
+ if (o2.equals(o))
+ i--;
else
- // This gets the insertion point right on the last loop.
- low = ++mid;
+ break;
}
- return -mid - 1;
+ return i;
}
}
diff --git a/libjava/classpath/javax/swing/text/IconView.java b/libjava/classpath/javax/swing/text/IconView.java
index 699cda90eba..7bb7635b4e7 100644
--- a/libjava/classpath/javax/swing/text/IconView.java
+++ b/libjava/classpath/javax/swing/text/IconView.java
@@ -44,7 +44,6 @@ import java.awt.Shape;
import javax.swing.Icon;
import javax.swing.JTextPane;
-import javax.swing.SwingConstants;
/**
* A View that can render an icon. This view is created by the
@@ -156,4 +155,21 @@ public class IconView
return el.getStartOffset();
}
+ /**
+ * Returns the alignment for this view. This will be 1.0 for the Y_AXIS,
+ * and the super behaviour for the X_AXIS.
+ *
+ * @param axis the axis for which to calculate the alignment
+ *
+ * @return the alignment
+ */
+ public float getAlignment(int axis)
+ {
+ float align;
+ if (axis == Y_AXIS)
+ align = 1.0F;
+ else
+ align = super.getAlignment(axis);
+ return align;
+ }
}
diff --git a/libjava/classpath/javax/swing/text/JTextComponent.java b/libjava/classpath/javax/swing/text/JTextComponent.java
index 9de151dfbac..6da84bfe7d8 100644
--- a/libjava/classpath/javax/swing/text/JTextComponent.java
+++ b/libjava/classpath/javax/swing/text/JTextComponent.java
@@ -42,6 +42,7 @@ 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;
@@ -90,9 +91,10 @@ public abstract class JTextComponent extends JComponent
implements Scrollable, Accessible
{
/**
- * This class implements accessibility support for the JTextComponent class.
- * It provides an implementation of the Java Accessibility API appropriate
- * to menu user-interface elements.
+ * AccessibleJTextComponent implements accessibility hooks for
+ * JTextComponent. It allows an accessibility driver to read and
+ * manipulate the text component's contents as well as update UI
+ * elements such as the caret.
*/
public class AccessibleJTextComponent extends AccessibleJComponent implements
AccessibleText, CaretListener, DocumentListener, AccessibleAction,
@@ -100,15 +102,18 @@ public abstract class JTextComponent extends JComponent
{
private static final long serialVersionUID = 7664188944091413696L;
- /** The caret's offset. */
+ /**
+ * The caret's offset.
+ */
int dot = 0;
-
- /** The current JTextComponent. */
+
+ /**
+ * The current JTextComponent.
+ */
JTextComponent textComp = JTextComponent.this;
-
+
/**
- * Constructs an AccessibleJTextComponent.
- * Adds a listener to track caret change.
+ * Construct an AccessibleJTextComponent.
*/
public AccessibleJTextComponent()
{
@@ -117,11 +122,10 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Returns the zero-based offset of the caret. Note: The character
- * to the right of the caret will have the same index value as the
- * offset (the caret is between two characters).
- *
- * @return offset of caret
+ * Retrieve the current caret position. The index of the first
+ * caret position is 0.
+ *
+ * @return caret position
*/
public int getCaretPosition()
{
@@ -130,9 +134,10 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Returns the portion of the text that is selected.
- *
- * @return null if no text is selected.
+ * Retrieve the current text selection. If no text is selected
+ * this method returns null.
+ *
+ * @return the currently selected text or null
*/
public String getSelectedText()
{
@@ -140,11 +145,14 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Returns the start offset within the selected text. If there is no
- * selection, but there is a caret, the start and end offsets will be
- * the same. Return 0 if the text is empty, or the caret position if no selection.
- *
- * @return index of the start of the text >= 0.
+ * Retrieve the index of the first character in the current text
+ * selection. If there is no text in the text component, this
+ * method returns 0. If there is text in the text component, but
+ * there is no selection, this method returns the current caret
+ * position.
+ *
+ * @return the index of the first character in the selection, the
+ * current caret position or 0
*/
public int getSelectionStart()
{
@@ -154,12 +162,14 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Returns the end offset within the selected text. If there is no
- * selection, but there is a caret, the start and end offsets will
- * be the same. Return 0 if the text is empty, or the caret position
- * if no selection.
- *
- * @return index of the end of the text >= 0.
+ * Retrieve the index of the last character in the current text
+ * selection. If there is no text in the text component, this
+ * method returns 0. If there is text in the text component, but
+ * there is no selection, this method returns the current caret
+ * position.
+ *
+ * @return the index of the last character in the selection, the
+ * current caret position or 0
*/
public int getSelectionEnd()
{
@@ -169,13 +179,10 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Handles caret updates (fire appropriate property change event, which are
- * AccessibleContext.ACCESSIBLE_CARET_PROPERTY and
- * AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY). This keeps track of
- * the dot position internally. When the caret moves, the internal position
- * is updated after firing the event.
- *
- * @param e - caret event
+ * Handle a change in the caret position and fire any applicable
+ * property change events.
+ *
+ * @param e - the caret update event
*/
public void caretUpdate(CaretEvent e)
throws NotImplementedException
@@ -185,7 +192,7 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Returns the accessible state set of this component.
+ * Retreive the accessible state set of this component.
*
* @return the accessible state set of this component
*/
@@ -198,7 +205,7 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Returns the accessible role of this component.
+ * Retrieve the accessible role of this component.
*
* @return the accessible role of this component
*
@@ -210,20 +217,19 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Returns the AccessibleEditableText interface for this text component.
- *
+ * Retrieve an AccessibleEditableText object that controls this
+ * text component.
+ *
* @return this
*/
public AccessibleEditableText getAccessibleEditableText()
{
return this;
}
-
+
/**
- * Get the AccessibleText associated with this object. In the implementation
- * of the Java Accessibility API for this class, return this object,
- * which is responsible for implementing the AccessibleText interface on
- * behalf of itself.
+ * Retrieve an AccessibleText object that controls this text
+ * component.
*
* @return this
*
@@ -235,10 +241,11 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Insert update. Fire appropriate property change event which
- * is AccessibleContext.ACCESSIBLE_TEXT_PROPERTY.
- *
- * @param e - document event
+ * Handle a text insertion event and fire an
+ * AccessibleContext.ACCESSIBLE_TEXT_PROPERTY property change
+ * event.
+ *
+ * @param e - the insertion event
*/
public void insertUpdate(DocumentEvent e)
throws NotImplementedException
@@ -247,10 +254,11 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Remove update. Fire appropriate property change event which
- * is AccessibleContext.ACCESSIBLE_TEXT_PROPERTY.
- *
- * @param e - document event
+ * Handle a text removal event and fire an
+ * AccessibleContext.ACCESSIBLE_TEXT_PROPERTY property change
+ * event.
+ *
+ * @param e - the removal event
*/
public void removeUpdate(DocumentEvent e)
throws NotImplementedException
@@ -259,10 +267,11 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Changed update. Fire appropriate property change event which
- * is AccessibleContext.ACCESSIBLE_TEXT_PROPERTY.
- *
- * @param e - document event
+ * Handle a text change event and fire an
+ * AccessibleContext.ACCESSIBLE_TEXT_PROPERTY property change
+ * event.
+ *
+ * @param e - text change event
*/
public void changedUpdate(DocumentEvent e)
throws NotImplementedException
@@ -271,11 +280,13 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Given a point in the coordinate system of this object, return the
- * 0-based index of the character at that point, or -1 if there is none.
+ * Get the index of the character at the given point, in component
+ * pixel co-ordinates. If the point argument is invalid this
+ * method returns -1.
*
- * @param p the point to look at
- * @return the character index, or -1
+ * @param p - a point in component pixel co-ordinates
+ *
+ * @return a character index, or -1
*/
public int getIndexAtPoint(Point p)
throws NotImplementedException
@@ -284,17 +295,14 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Determines the bounding box of the indexed character. Returns an empty
- * rectangle if the index is out of bounds. The bounds are returned in local coordinates.
- * If the index is invalid a null rectangle is returned. The screen coordinates returned are
- * "unscrolled coordinates" if the JTextComponent is contained in a JScrollPane in which
- * case the resulting rectangle should be composed with the parent coordinates.
- * Note: the JTextComponent must have a valid size (e.g. have been added to a parent
- * container whose ancestor container is a valid top-level window) for this method to
- * be able to return a meaningful (non-null) value.
+ * Calculate the bounding box of the character at the given index.
+ * The returned x and y co-ordinates are relative to this text
+ * component's top-left corner. If the index is invalid this
+ * method returns null.
+ *
+ * @param index - the character index
*
- * @param index the 0-based character index
- * @return the bounding box, may be empty or null.
+ * @return a character's bounding box, or null
*/
public Rectangle getCharacterBounds(int index)
throws NotImplementedException
@@ -303,9 +311,9 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Return the number of characters.
+ * Return the length of the text in this text component.
*
- * @return the character count
+ * @return a character length
*/
public int getCharCount()
{
@@ -313,10 +321,11 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Returns the attributes of a character at an index, or null if the index
- * is out of bounds.
+ * Gets the character attributes of the character at index. If
+ * the index is out of bounds, null is returned.
*
- * @param index the 0-based character index
+ * @param index - index of the character
+ *
* @return the character's attributes
*/
public AttributeSet getCharacterAttribute(int index)
@@ -326,26 +335,28 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Returns the section of text at the index, or null if the index or part
- * is invalid.
- *
- * @param part {@link #CHARACTER}, {@link #WORD}, or {@link #SENTENCE}
- * @param index the 0-based character index
- * @return the selection of text at that index, or null
+ * Gets the text located at index. null is returned if the index
+ * or part is invalid.
+ *
+ * @param part - {@link #CHARACTER}, {@link #WORD}, or {@link #SENTENCE}
+ * @param index - index of the part
+ *
+ * @return the part of text at that index, or null
*/
public String getAtIndex(int part, int index)
throws NotImplementedException
{
return null; // TODO
}
-
+
/**
- * Returns the section of text after the index, or null if the index or part
- * is invalid.
- *
- * @param part {@link #CHARACTER}, {@link #WORD}, or {@link #SENTENCE}
- * @param index the 0-based character index
- * @return the selection of text after that index, or null
+ * Gets the text located after index. null is returned if the index
+ * or part is invalid.
+ *
+ * @param part - {@link #CHARACTER}, {@link #WORD}, or {@link #SENTENCE}
+ * @param index - index after the part
+ *
+ * @return the part of text after that index, or null
*/
public String getAfterIndex(int part, int index)
throws NotImplementedException
@@ -354,12 +365,13 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Returns the section of text before the index, or null if the index or part
- * is invalid.
- *
- * @param part {@link #CHARACTER}, {@link #WORD}, or {@link #SENTENCE}
- * @param index the 0-based character index
- * @return the selection of text before that index, or null
+ * Gets the text located before index. null is returned if the index
+ * or part is invalid.
+ *
+ * @param part - {@link #CHARACTER}, {@link #WORD}, or {@link #SENTENCE}
+ * @param index - index before the part
+ *
+ * @return the part of text before that index, or null
*/
public String getBeforeIndex(int part, int index)
throws NotImplementedException
@@ -368,10 +380,10 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Get the number possible actions for this object, with the zeroth
- * representing the default action.
+ * Returns the number of actions for this object. The zero-th
+ * object represents the default action.
*
- * @return the 0-based number of actions
+ * @return the number of actions (0-based).
*/
public int getAccessibleActionCount()
throws NotImplementedException
@@ -380,11 +392,12 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Get a description for the specified action. Returns null if out of
- * bounds.
+ * Returns the description of the i-th action. Null is returned if
+ * i is out of bounds.
*
- * @param i the action to describe, 0-based
- * @return description of the action
+ * @param i - the action to get the description for
+ *
+ * @return description of the i-th action
*/
public String getAccessibleActionDescription(int i)
throws NotImplementedException
@@ -394,10 +407,12 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Perform the specified action. Does nothing if out of bounds.
+ * Performs the i-th action. Nothing happens if i is
+ * out of bounds.
*
- * @param i the action to perform, 0-based
- * @return true if the action was performed
+ * @param i - the action to perform
+ *
+ * @return true if the action was performed successfully
*/
public boolean doAccessibleAction(int i)
throws NotImplementedException
@@ -406,9 +421,9 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Set the text contents to the given string.
+ * Sets the text contents.
*
- * @param s the new text
+ * @param s - the new text contents.
*/
public void setTextContents(String s)
throws NotImplementedException
@@ -417,10 +432,10 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Inserts the given string at the specified location.
+ * Inserts the text at the given index.
*
- * @param index the index for insertion
- * @param s the new text
+ * @param index - the index to insert the new text at.
+ * @param s - the new text
*/
public void insertTextAtIndex(int index, String s)
throws NotImplementedException
@@ -429,10 +444,10 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Return the text between two points.
+ * Gets the text between two indexes.
*
- * @param start the start position, inclusive
- * @param end the end position, exclusive
+ * @param start - the starting index (inclusive)
+ * @param end - the ending index (exclusive)
*/
public String getTextRange(int start, int end)
{
@@ -447,10 +462,10 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Delete the text between two points.
+ * Deletes the text between two indexes.
*
- * @param start the start position, inclusive
- * @param end the end position, exclusive
+ * @param start - the starting index (inclusive)
+ * @param end - the ending index (exclusive)
*/
public void delete(int start, int end)
{
@@ -458,10 +473,11 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Cut the text between two points to the system clipboard.
+ * Cuts the text between two indexes. The text is put
+ * into the system clipboard.
*
- * @param start the start position, inclusive
- * @param end the end position, exclusive
+ * @param start - the starting index (inclusive)
+ * @param end - the ending index (exclusive)
*/
public void cut(int start, int end)
{
@@ -470,9 +486,9 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Paste the text from the system clipboard at the given index.
+ * Pastes the text from the system clipboard to the given index.
*
- * @param start the start position
+ * @param start - the starting index
*/
public void paste(int start)
{
@@ -481,11 +497,12 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Replace the text between two points with the given string.
+ * Replaces the text between two indexes with the given text.
*
- * @param start the start position, inclusive
- * @param end the end position, exclusive
- * @param s the string to paste
+ *
+ * @param start - the starting index (inclusive)
+ * @param end - the ending index (exclusive)
+ * @param s - the text to paste
*/
public void replaceText(int start, int end, String s)
{
@@ -494,10 +511,10 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Select the text between two points.
+ * Selects the text between two indexes.
*
- * @param start the start position, inclusive
- * @param end the end position, exclusive
+ * @param start - the starting index (inclusive)
+ * @param end - the ending index (exclusive)
*/
public void selectText(int start, int end)
{
@@ -505,11 +522,11 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Set the attributes of text between two points.
+ * Sets the attributes of all the text between two indexes.
*
- * @param start the start position, inclusive
- * @param end the end position, exclusive
- * @param s the new attribute set for the range
+ * @param start - the starting index (inclusive)
+ * @param end - the ending index (exclusive)
+ * @param s - the new attribute set for the text in the range
*/
public void setAttributes(int start, int end, AttributeSet s)
throws NotImplementedException
@@ -1163,8 +1180,19 @@ public abstract class JTextComponent extends JComponent
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();
}
@@ -1641,10 +1669,12 @@ public abstract class JTextComponent extends JComponent
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;
}
/**
diff --git a/libjava/classpath/javax/swing/text/ParagraphView.java b/libjava/classpath/javax/swing/text/ParagraphView.java
index 15bed781825..c4857863d35 100644
--- a/libjava/classpath/javax/swing/text/ParagraphView.java
+++ b/libjava/classpath/javax/swing/text/ParagraphView.java
@@ -74,6 +74,39 @@ public class ParagraphView extends FlowView implements TabExpander
return align;
}
+ /**
+ * Allows rows to span the whole parent view.
+ */
+ public float getMaximumSpan(int axis)
+ {
+ float max;
+ if (axis == X_AXIS)
+ max = Float.MAX_VALUE;
+ else
+ max = super.getMaximumSpan(axis);
+ return max;
+ }
+
+ /**
+ * Overridden because child views are not necessarily laid out in model
+ * order.
+ */
+ protected int getViewIndexAtPosition(int pos)
+ {
+ int index = -1;
+ if (pos >= getStartOffset() && pos < getEndOffset())
+ {
+ int nviews = getViewCount();
+ for (int i = 0; i < nviews && index == -1; i++)
+ {
+ View child = getView(i);
+ if (pos >= child.getStartOffset() && pos < child.getEndOffset())
+ index = i;
+ }
+ }
+ return index;
+ }
+
protected void loadChildren(ViewFactory vf)
{
// Do nothing here. The children are added while layouting.
@@ -140,7 +173,7 @@ public class ParagraphView extends FlowView implements TabExpander
{
float align;
if (axis == X_AXIS)
- align = super.getAlignment(axis);
+ align = 0.5F;
else if (getViewCount() > 0)
{
float prefHeight = getPreferredSpan(Y_AXIS);
@@ -148,7 +181,7 @@ public class ParagraphView extends FlowView implements TabExpander
align = (firstRowHeight / 2.F) / prefHeight;
}
else
- align = 0.0F;
+ align = 0.5F;
return align;
}
diff --git a/libjava/classpath/javax/swing/text/PlainDocument.java b/libjava/classpath/javax/swing/text/PlainDocument.java
index c699dcad2aa..730a619da9f 100644
--- a/libjava/classpath/javax/swing/text/PlainDocument.java
+++ b/libjava/classpath/javax/swing/text/PlainDocument.java
@@ -56,8 +56,12 @@ public class PlainDocument extends AbstractDocument
public static final String lineLimitAttribute = "lineLimit";
public static final String tabSizeAttribute = "tabSize";
- private BranchElement rootElement;
- private int tabSize;
+ /**
+ * The default root element of this document. This is made type Element
+ * because the RI seems to accept other types of elements as well from
+ * createDefaultRoot() (when overridden by a subclass).
+ */
+ private Element rootElement;
public PlainDocument()
{
@@ -67,8 +71,10 @@ public class PlainDocument extends AbstractDocument
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()
@@ -105,10 +111,10 @@ public class PlainDocument extends AbstractDocument
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;
@@ -117,116 +123,97 @@ public class PlainDocument extends AbstractDocument
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);
}
@@ -264,7 +251,7 @@ public class PlainDocument extends AbstractDocument
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);
}
}
diff --git a/libjava/classpath/javax/swing/text/Segment.java b/libjava/classpath/javax/swing/text/Segment.java
index d2364e05a10..63c5fa09dbc 100644
--- a/libjava/classpath/javax/swing/text/Segment.java
+++ b/libjava/classpath/javax/swing/text/Segment.java
@@ -165,8 +165,9 @@ public class Segment implements Cloneable, CharacterIterator
/**
* Sets the current index to point to the last character in the segment and
- * returns that character. If the segment contains zero characters, this
- * method returns {@link #DONE}.
+ * returns that character. If the segment contains zero characters, the
+ * current index is set to {@link #getEndIndex()} and this method returns
+ * {@link #DONE}.
*
* @return The last character in the segment, or {@link #DONE} if the
* segment contains zero characters.
@@ -174,7 +175,10 @@ public class Segment implements Cloneable, CharacterIterator
public char last()
{
if (count == 0)
- return DONE;
+ {
+ current = getEndIndex();
+ return DONE;
+ }
current = getEndIndex() - 1;
return array[current];
diff --git a/libjava/classpath/javax/swing/text/SimpleAttributeSet.java b/libjava/classpath/javax/swing/text/SimpleAttributeSet.java
index 8dbcb0c6a14..8684ef87d34 100644
--- a/libjava/classpath/javax/swing/text/SimpleAttributeSet.java
+++ b/libjava/classpath/javax/swing/text/SimpleAttributeSet.java
@@ -51,8 +51,10 @@ public class SimpleAttributeSet
/** The serialization UID (compatible with JDK1.5). */
private static final long serialVersionUID = 8267656273837665219L;
- /** An empty attribute set. */
- public static final AttributeSet EMPTY = new SimpleAttributeSet();
+ /**
+ * An empty attribute set.
+ */
+ public static final AttributeSet EMPTY = new EmptyAttributeSet();
/** Storage for the attributes. */
Hashtable tab;
diff --git a/libjava/classpath/javax/swing/text/StringContent.java b/libjava/classpath/javax/swing/text/StringContent.java
index 0a31505f3a6..8014dc3bce6 100644
--- a/libjava/classpath/javax/swing/text/StringContent.java
+++ b/libjava/classpath/javax/swing/text/StringContent.java
@@ -178,11 +178,13 @@ public final class StringContent
}
/**
- * Creates a new instance containing the string "\n".
+ * Creates a new instance containing the string "\n". This is equivalent
+ * to calling {@link #StringContent(int)} with an <code>initialLength</code>
+ * of 10.
*/
public StringContent()
{
- this(1);
+ this(10);
}
/**
diff --git a/libjava/classpath/javax/swing/text/TabSet.java b/libjava/classpath/javax/swing/text/TabSet.java
index ecad9444ea5..0f2c8c7c1ee 100644
--- a/libjava/classpath/javax/swing/text/TabSet.java
+++ b/libjava/classpath/javax/swing/text/TabSet.java
@@ -1,5 +1,5 @@
/* TabSet.java --
- Copyright (C) 2004 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2006, Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -39,23 +39,54 @@ package javax.swing.text;
import java.io.Serializable;
+/**
+ * A set of tab stops. Instances of this class are immutable.
+ */
public class TabSet implements Serializable
{
/** The serialization UID (compatible with JDK1.5). */
private static final long serialVersionUID = 2367703481999080593L;
+ /** Storage for the tab stops. */
TabStop[] tabs;
+ /**
+ * Creates a new <code>TabSet</code> containing the specified tab stops.
+ *
+ * @param t the tab stops (<code>null</code> permitted).
+ */
public TabSet(TabStop[] t)
{
- tabs = t;
+ if (t != null)
+ tabs = (TabStop[]) t.clone();
+ else
+ tabs = new TabStop[0];
}
+ /**
+ * Returns the tab stop with the specified index.
+ *
+ * @param i the index.
+ *
+ * @return The tab stop.
+ *
+ * @throws IllegalArgumentException if <code>i</code> is not in the range
+ * <code>0</code> to <code>getTabCount() - 1</code>.
+ */
public TabStop getTab(int i)
{
+ if (i < 0 || i >= tabs.length)
+ throw new IllegalArgumentException("Index out of bounds.");
return tabs[i];
}
+ /**
+ * Returns the tab following the specified location.
+ *
+ * @param location the location.
+ *
+ * @return The tab following the specified location (or <code>null</code>).
+ */
public TabStop getTabAfter(float location)
{
int idx = getTabIndexAfter(location);
@@ -65,11 +96,23 @@ public class TabSet implements Serializable
return tabs[idx];
}
+ /**
+ * Returns the number of tab stops in this tab set.
+ *
+ * @return The number of tab stops in this tab set.
+ */
public int getTabCount()
{
return tabs.length;
}
+ /**
+ * Returns the index of the specified tab, or -1 if the tab is not found.
+ *
+ * @param tab the tab (<code>null</code> permitted).
+ *
+ * @return The index of the specified tab, or -1.
+ */
public int getTabIndex(TabStop tab)
{
for (int i = 0; i < tabs.length; ++i)
@@ -78,28 +121,88 @@ public class TabSet implements Serializable
return -1;
}
+ /**
+ * Returns the index of the tab at or after the specified location.
+ *
+ * @param location the tab location.
+ *
+ * @return The index of the tab stop, or -1.
+ */
public int getTabIndexAfter(float location)
{
- int idx = -1;
- for (int i = 0; i < tabs.length; ++i)
+ for (int i = 0; i < tabs.length; i++)
+ {
+ if (location <= tabs[i].getPosition())
+ return i;
+ }
+ return -1;
+ }
+
+ /**
+ * Tests this <code>TabSet</code> for equality with an arbitrary object.
+ *
+ * @param obj the object (<code>null</code> permitted).
+ *
+ * @return <code>true</code> if this <code>TabSet</code> is equal to
+ * <code>obj</code>, and <code>false</code> otherwise.
+ *
+ * @since 1.5
+ */
+ public boolean equals(Object obj)
+ {
+ if (obj == this)
+ return true;
+ if (!(obj instanceof TabSet))
+ return false;
+ TabSet that = (TabSet) obj;
+ int tabCount = getTabCount();
+ if (tabCount != that.getTabCount())
+ return false;
+ for (int i = 0; i < tabCount; i++)
+ {
+ if (!this.getTab(i).equals(that.getTab(i)))
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Returns a hash code for this <code>TabSet</code>.
+ *
+ * @return A hash code.
+ *
+ * @since 1.5
+ */
+ public int hashCode()
+ {
+ // this hash code won't match Sun's, but that shouldn't matter...
+ int result = 193;
+ int tabs = getTabCount();
+ for (int i = 0; i < tabs; i++)
{
- if (location < tabs[i].getPosition())
- idx = i;
+ TabStop t = getTab(i);
+ if (t != null)
+ result = 37 * result + t.hashCode();
}
- return idx;
+ return result;
}
+ /**
+ * Returns a string representation of this <code>TabSet</code>.
+ *
+ * @return A string representation of this <code>TabSet</code>.
+ */
public String toString()
{
StringBuffer sb = new StringBuffer();
- sb.append("[");
+ sb.append("[ ");
for (int i = 0; i < tabs.length; ++i)
{
if (i != 0)
sb.append(" - ");
sb.append(tabs[i].toString());
}
- sb.append("]");
+ sb.append(" ]");
return sb.toString();
}
}
diff --git a/libjava/classpath/javax/swing/text/TabStop.java b/libjava/classpath/javax/swing/text/TabStop.java
index 56f862fdae4..f4c3f851406 100644
--- a/libjava/classpath/javax/swing/text/TabStop.java
+++ b/libjava/classpath/javax/swing/text/TabStop.java
@@ -1,5 +1,5 @@
-/* TabSet.java --
- Copyright (C) 2004 Free Software Foundation, Inc.
+/* TabStop.java --
+ Copyright (C) 2004, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -39,6 +39,9 @@ package javax.swing.text;
import java.io.Serializable;
+/**
+ * Represents a tab position in some text.
+ */
public class TabStop implements Serializable
{
/** The serialization UID (compatible with JDK1.5). */
@@ -61,18 +64,42 @@ public class TabStop implements Serializable
int align;
int leader;
+ /**
+ * Creates a new <code>TabStop</code> for the specified tab position.
+ *
+ * @param pos the tab position.
+ */
public TabStop(float pos)
{
this(pos, ALIGN_LEFT, LEAD_NONE);
}
+ /**
+ * Creates a new <code>TabStop</code> with the specified attributes.
+ *
+ * @param pos the tab position.
+ * @param align the alignment (one of {@link #ALIGN_LEFT},
+ * {@link #ALIGN_CENTER}, {@link #ALIGN_RIGHT}, {@link #ALIGN_DECIMAL}
+ * or {@link #ALIGN_BAR}).
+ * @param leader the leader (one of {@link #LEAD_NONE}, {@link #LEAD_DOTS},
+ * {@link #LEAD_EQUALS}, {@link #LEAD_HYPHENS}, {@link #LEAD_THICKLINE}
+ * or {@link #LEAD_UNDERLINE}).
+ */
public TabStop(float pos, int align, int leader)
{
this.pos = pos;
this.align = align;
this.leader = leader;
}
-
+
+ /**
+ * Tests this <code>TabStop</code> for equality with an arbitrary object.
+ *
+ * @param other the other object (<code>null</code> permitted).
+ *
+ * @return <code>true</code> if this <code>TabStop</code> is equal to
+ * the specified object, and <code>false</code> otherwise.
+ */
public boolean equals(Object other)
{
return (other != null)
@@ -82,34 +109,60 @@ public class TabStop implements Serializable
&& (((TabStop)other).getAlignment() == this.getAlignment());
}
+ /**
+ * Returns the tab alignment. This should be one of {@link #ALIGN_LEFT},
+ * {@link #ALIGN_CENTER}, {@link #ALIGN_RIGHT}, {@link #ALIGN_DECIMAL} or
+ * {@link #ALIGN_BAR}.
+ *
+ * @return The tab alignment.
+ */
public int getAlignment()
{
return align;
}
+ /**
+ * Returns the leader type. This should be one of {@link #LEAD_NONE},
+ * {@link #LEAD_DOTS}, {@link #LEAD_EQUALS}, {@link #LEAD_HYPHENS},
+ * {@link #LEAD_THICKLINE} or {@link #LEAD_UNDERLINE}.
+ *
+ * @return The leader type.
+ */
public int getLeader()
{
return leader;
}
+ /**
+ * Returns the tab position.
+ *
+ * @return The tab position.
+ */
public float getPosition()
{
return pos;
}
+ /**
+ * Returns a hash code for this <code>TabStop</code>.
+ *
+ * @return A hash code.
+ */
public int hashCode()
{
return (int) pos + (int) leader + (int) align;
}
+ /**
+ * Returns a string describing this <code>TabStop</code>.
+ *
+ * @return A string describing this <code>TabStop</code>.
+ */
public String toString()
{
String prefix = "";
switch (align)
{
- case ALIGN_LEFT:
- prefix = "left ";
- break;
case ALIGN_RIGHT:
prefix = "right ";
break;
@@ -130,7 +183,8 @@ public class TabStop implements Serializable
break;
}
- return (prefix + "tab @" + pos + ((leader == LEAD_NONE) ? "" : "(w/leaders)"));
+ return prefix + "tab @" + pos
+ + ((leader == LEAD_NONE) ? "" : " (w/leaders)");
}
}
diff --git a/libjava/classpath/javax/swing/text/View.java b/libjava/classpath/javax/swing/text/View.java
index d8ad5f5858e..55a63f6b668 100644
--- a/libjava/classpath/javax/swing/text/View.java
+++ b/libjava/classpath/javax/swing/text/View.java
@@ -401,7 +401,10 @@ public abstract class View implements SwingConstants
Element el = getElement();
DocumentEvent.ElementChange ec = ev.getChange(el);
if (ec != null)
- updateChildren(ec, ev, vf);
+ {
+ if (! updateChildren(ec, ev, vf))
+ ec = null;
+ }
forwardUpdate(ec, ev, shape, vf);
updateLayout(ec, ev, shape);
}
@@ -493,27 +496,66 @@ public abstract class View implements SwingConstants
int count = getViewCount();
if (count > 0)
{
+ // Determine start index.
int startOffset = ev.getOffset();
- int endOffset = startOffset + ev.getLength();
int startIndex = getViewIndex(startOffset, Position.Bias.Backward);
- int endIndex = getViewIndex(endOffset, Position.Bias.Forward);
- int index = -1;
- int addLength = -1;
- if (ec != null)
+
+ // For REMOVE events we have to forward the event to the last element,
+ // for the case that an Element has been removed that represente
+ // the offset.
+ if (startIndex == -1 && ev.getType() == DocumentEvent.EventType.REMOVE
+ && startOffset >= getEndOffset())
{
- index = ec.getIndex();
- addLength = ec.getChildrenAdded().length;
+ startIndex = getViewCount() - 1;
}
- if (startIndex >= 0 && endIndex >= 0)
+ // When startIndex is on a view boundary, forward event to the
+ // previous view too.
+ if (startIndex >= 0)
{
- for (int i = startIndex; i <= endIndex; i++)
+ View v = getView(startIndex);
+ if (v != null)
+ {
+ if (v.getStartOffset() == startOffset && startOffset > 0)
+ startIndex = Math.max(0, startIndex - 1);
+ }
+ }
+ startIndex = Math.max(0, startIndex);
+
+ // Determine end index.
+ int endIndex = startIndex;
+ if (ev.getType() != DocumentEvent.EventType.REMOVE)
+ {
+ endIndex = getViewIndex(startOffset + ev.getLength(),
+ Position.Bias.Forward);
+ if (endIndex < 0)
+ endIndex = getViewCount() - 1;
+ }
+
+ // Determine hole that comes from added elements (we don't forward
+ // the event to newly added views.
+ int startAdded = endIndex + 1;
+ int endAdded = startAdded;
+ Element[] added = (ec != null) ? ec.getChildrenAdded() : null;
+ if (added != null && added.length > 0)
+ {
+ startAdded = ec.getIndex();
+ endAdded = startAdded + added.length - 1;
+ }
+
+ // Forward event to all views between startIndex and endIndex,
+ // and leave out all views in the hole.
+ for (int i = startIndex; i <= endIndex; i++)
+ {
+ // Skip newly added child views.
+ if (! (i >= startAdded && i <= endAdded))
{
- // Skip newly added child views.
- if (index >= 0 && i >= index && i < (index+addLength))
- continue;
View child = getView(i);
- forwardUpdateToView(child, ev, shape, vf);
+ if (child != null)
+ {
+ Shape childAlloc = getChildAllocation(i, shape);
+ forwardUpdateToView(child, ev, childAlloc, vf);
+ }
}
}
}
@@ -611,9 +653,46 @@ public abstract class View implements SwingConstants
if (b2 != Position.Bias.Forward && b2 != Position.Bias.Backward)
throw new IllegalArgumentException
("b2 must be either Position.Bias.Forward or Position.Bias.Backward");
- Rectangle s1 = (Rectangle) modelToView(p1, a, b1);
- Rectangle s2 = (Rectangle) modelToView(p2, a, b2);
- return SwingUtilities.computeUnion(s1.x, s1.y, s1.width, s1.height, s2);
+
+ Shape s1 = modelToView(p1, a, b1);
+ // Special case for p2 == end index.
+ Shape s2;
+ if (p2 != getEndOffset())
+ {
+ s2 = modelToView(p2, a, b2);
+ }
+ else
+ {
+ try
+ {
+ s2 = modelToView(p2, a, b2);
+ }
+ catch (BadLocationException ex)
+ {
+ // Assume the end rectangle to be at the right edge of the
+ // view.
+ Rectangle aRect = a instanceof Rectangle ? (Rectangle) a
+ : a.getBounds();
+ s2 = new Rectangle(aRect.x + aRect.width - 1, aRect.y, 1,
+ aRect.height);
+ }
+ }
+
+ // Need to modify the rectangle, so we create a copy in all cases.
+ Rectangle r1 = s1.getBounds();
+ Rectangle r2 = s2 instanceof Rectangle ? (Rectangle) s2
+ : s2.getBounds();
+
+ // For multiline view, let the resulting rectangle span the whole view.
+ if (r1.y != r2.y)
+ {
+ Rectangle aRect = a instanceof Rectangle ? (Rectangle) a
+ : a.getBounds();
+ r1.x = aRect.x;
+ r1.width = aRect.width;
+ }
+
+ return SwingUtilities.computeUnion(r2.x, r2.y, r2.width, r2.height, r1);
}
/**
diff --git a/libjava/classpath/javax/swing/text/html/HTMLTableView.java b/libjava/classpath/javax/swing/text/html/BRView.java
index cac44d8dc27..5521fed8edf 100644
--- a/libjava/classpath/javax/swing/text/html/HTMLTableView.java
+++ b/libjava/classpath/javax/swing/text/html/BRView.java
@@ -1,4 +1,4 @@
-/* HTMLTableView.java -- A table view for HTML tables
+/* BRView.java -- HTML BR tag view
Copyright (C) 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -39,44 +39,33 @@ exception statement from your version. */
package javax.swing.text.html;
import javax.swing.text.Element;
-import javax.swing.text.TableView;
-import javax.swing.text.View;
-import javax.swing.text.ViewFactory;
/**
- * A conrete implementation of TableView that renders HTML tables.
- *
- * @author Roman Kennke (kennke@aicas.com)
+ * Handled the HTML BR tag.
*/
-class HTMLTableView
- extends TableView
-{
+class BRView
+ extends NullView
+{
/**
- * Creates a new HTMLTableView for the specified element.
- *
- * @param el the element for the table view
+ * Creates the new BR view.
+ *
+ * @param elem the HTML element, representing the view.
*/
- public HTMLTableView(Element el)
+ public BRView(Element elem)
{
- super(el);
+ super(elem);
}
-
+
/**
- * Loads the children of the Table. This completely bypasses the ViewFactory
- * and creates instances of TableRow instead.
- *
- * @param vf ignored
+ * Always return ForcedBreakWeight for the X_AXIS, BadBreakWeight for the
+ * Y_AXIS.
*/
- protected void loadChildren(ViewFactory vf)
+ public int getBreakWeight(int axis, float pos, float len)
{
- Element el = getElement();
- int numChildren = el.getElementCount();
- View[] rows = new View[numChildren];
- for (int i = 0; i < numChildren; ++i)
- {
- rows[i] = createTableRow(el.getElement(i));
- }
- replace(0, getViewCount(), rows);
+ if (axis == X_AXIS)
+ return ForcedBreakWeight;
+ else
+ return BadBreakWeight;
}
}
diff --git a/libjava/classpath/javax/swing/text/html/HRuleView.java b/libjava/classpath/javax/swing/text/html/HRuleView.java
new file mode 100644
index 00000000000..3bae5eb8e83
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/HRuleView.java
@@ -0,0 +1,189 @@
+/* HRuleView.java -- Horizontal dash in HTML documents.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+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.html;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Graphics;
+import java.awt.Rectangle;
+import java.awt.Shape;
+
+import javax.swing.text.Element;
+import javax.swing.text.View;
+
+/**
+ * Represents the long horizontal separating dash that can be inserted into the
+ * HTML documents with HR tag.
+ */
+class HRuleView extends InlineView
+{
+ /**
+ * The null view, indicating, that nothing should be painted ahead the
+ * breaking point.
+ */
+ View nullView;
+
+ /**
+ * The height of the horizontal dash area.
+ */
+ static int HEIGHT = 4;
+
+ /**
+ * The imaginary invisible view that stays after end of line after the
+ * breaking procedure. It occupies on character.
+ */
+ class Beginning extends NullView
+ {
+ /**
+ * The break offset that becomes the views start offset.
+ */
+ int breakOffset;
+
+ /**
+ * Return the end offset that is always one char after the break offset.
+ */
+ public int getEndOffset()
+ {
+ return breakOffset + 1;
+ }
+
+ /**
+ * Return the start offset that has been passed in a constructor.
+ */
+ public int getStartOffset()
+ {
+ return breakOffset;
+ }
+
+ /**
+ * Create the new instance of this view.
+ *
+ * @param element the element (inherited from the HR view)
+ * @param offset the position where the HR view has been broken
+ */
+ public Beginning(Element element, int offset)
+ {
+ super(element);
+ breakOffset = offset;
+ }
+ }
+
+ /**
+ * Creates the new HR view.
+ */
+ public HRuleView(Element element)
+ {
+ super(element);
+ }
+
+ /**
+ * Returns the ForcedBreakWeight for the vertical axis, indicating, the the
+ * view must be broken to be displayed correctly. The horizontal dash is
+ * not breakeable along the Y axis.
+ */
+ public int getBreakWeight(int axis, float pos, float len)
+ {
+ if (axis == X_AXIS && ((getEndOffset() - getStartOffset()) > 1))
+ return ForcedBreakWeight;
+ else
+ return BadBreakWeight;
+ }
+
+ /**
+ * Draws the double line, upped black and the lower light gray.
+ */
+ public void paint(Graphics g, Shape a)
+ {
+ Rectangle bounds = a.getBounds();
+
+ int x = bounds.x;
+ int y = bounds.y;
+
+ int w = bounds.x + bounds.width;
+
+ // We move "half pixel up" from the actual horizontal position -
+ // this will be rounded to the closest actual int co-ordinate.
+ int h = bounds.y + (int) Math.round(bounds.height * 0.5 - 0.5);
+
+ g.setColor(Color.black);
+ g.drawLine(x, y++, w, h++);
+ g.setColor(Color.lightGray);
+ g.drawLine(x, y, w, h);
+ }
+
+ /**
+ * Break the view into this view and the invisible imaginary view that
+ * stays on the end of line that is broken by HR dash. The view is broken
+ * only if its length is longer than one (the two characters are expected
+ * in the initial length).
+ */
+ public View breakView(int axis, int offset, float pos, float len)
+ {
+ if (getEndOffset() - getStartOffset() > 1)
+ return new Beginning(getElement(), offset);
+ else
+ return this;
+ }
+
+ /**
+ * Returns the width of the container for the horizontal axis and the
+ * thickness of the dash area for the vertical axis.
+ */
+ public float getMaximumSpan(int axis)
+ {
+ if (axis == X_AXIS)
+ {
+ Component container = getContainer();
+ if (container != null)
+ return getContainer().getWidth();
+ else
+ return 640;
+ }
+ else
+ return HEIGHT;
+ }
+
+ /**
+ * Returns the same values as {@link #getMaximumSpan(int)}
+ */
+ public float getPreferredSpan(int axis)
+ {
+ return getMaximumSpan(axis);
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/html/HTMLDocument.java b/libjava/classpath/javax/swing/text/html/HTMLDocument.java
index e714a857b61..0bfc338df45 100644
--- a/libjava/classpath/javax/swing/text/html/HTMLDocument.java
+++ b/libjava/classpath/javax/swing/text/html/HTMLDocument.java
@@ -40,14 +40,18 @@ package javax.swing.text.html;
import gnu.classpath.NotImplementedException;
import gnu.javax.swing.text.html.CharacterAttributeTranslator;
+import gnu.javax.swing.text.html.parser.htmlAttributeSet;
import java.io.IOException;
+import java.io.StringReader;
import java.net.URL;
import java.util.HashMap;
import java.util.Stack;
import java.util.Vector;
import javax.swing.JEditorPane;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.HyperlinkEvent.EventType;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
@@ -515,19 +519,23 @@ public class HTMLDocument extends DefaultStyledDocument
*/
public class HTMLReader extends HTMLEditorKit.ParserCallback
{
- /** Holds the current character attribute set **/
+ /**
+ * Holds the current character attribute set *
+ */
protected MutableAttributeSet charAttr = new SimpleAttributeSet();
protected Vector parseBuffer = new Vector();
- /** A stack for character attribute sets **/
+ /**
+ * A stack for character attribute sets *
+ */
Stack charAttrStack = new Stack();
/**
* The parse stack. This stack holds HTML.Tag objects that reflect the
* current position in the parsing process.
*/
- private Stack parseStack = new Stack();
+ Stack parseStack = new Stack();
/** A mapping between HTML.Tag objects and the actions that handle them **/
HashMap tagToAction;
@@ -535,10 +543,31 @@ public class HTMLDocument extends DefaultStyledDocument
/** Tells us whether we've received the '</html>' tag yet **/
boolean endHTMLEncountered = false;
- /** Variables related to the constructor with explicit insertTag **/
- int popDepth, pushDepth, offset;
+ /**
+ * Related to the constructor with explicit insertTag
+ */
+ int popDepth;
+
+ /**
+ * Related to the constructor with explicit insertTag
+ */
+ int pushDepth;
+
+ /**
+ * Related to the constructor with explicit insertTag
+ */
+ int offset;
+
+ /**
+ * The tag (inclusve), after that the insertion should start.
+ */
HTML.Tag insertTag;
- boolean insertTagEncountered = false;
+
+ /**
+ * This variable becomes true after the insert tag has been encountered.
+ */
+ boolean insertTagEncountered;
+
/** A temporary variable that helps with the printing out of debug information **/
boolean debug = false;
@@ -1139,8 +1168,21 @@ public class HTMLDocument extends DefaultStyledDocument
}
/**
- * This method is called by the parser and should route the call to
- * the proper handler for the tag.
+ * Checks if the HTML tag should be inserted. The tags before insert tag (if
+ * specified) are not inserted. Also, the tags after the end of the html are
+ * not inserted.
+ *
+ * @return true if the tag should be inserted, false otherwise.
+ */
+ private boolean shouldInsert()
+ {
+ return ! endHTMLEncountered
+ && (insertTagEncountered || insertTag == null);
+ }
+
+ /**
+ * This method is called by the parser and should route the call to the
+ * proper handler for the tag.
*
* @param t the HTML.Tag
* @param a the attribute set
@@ -1148,13 +1190,15 @@ public class HTMLDocument extends DefaultStyledDocument
*/
public void handleStartTag(HTML.Tag t, MutableAttributeSet a, int pos)
{
- // Don't call the Action if we've already seen </html>.
- if (endHTMLEncountered)
- return;
-
- TagAction action = (TagAction) tagToAction.get(t);
- if (action != null)
- action.start(t, a);
+ if (t == insertTag)
+ insertTagEncountered = true;
+
+ if (shouldInsert())
+ {
+ TagAction action = (TagAction) tagToAction.get(t);
+ if (action != null)
+ action.start(t, a);
+ }
}
/**
@@ -1165,42 +1209,41 @@ public class HTMLDocument extends DefaultStyledDocument
*/
public void handleComment(char[] data, int pos)
{
- // Don't call the Action if we've already seen </html>.
- if (endHTMLEncountered)
- return;
-
- TagAction action = (TagAction) tagToAction.get(HTML.Tag.COMMENT);
- if (action != null)
+ if (shouldInsert())
{
- action.start(HTML.Tag.COMMENT, new SimpleAttributeSet());
- action.end (HTML.Tag.COMMENT);
+ TagAction action = (TagAction) tagToAction.get(HTML.Tag.COMMENT);
+ if (action != null)
+ {
+ action.start(HTML.Tag.COMMENT,
+ htmlAttributeSet.EMPTY_HTML_ATTRIBUTE_SET);
+ action.end(HTML.Tag.COMMENT);
+ }
}
}
/**
- * This method is called by the parser and should route the call to
- * the proper handler for the tag.
+ * This method is called by the parser and should route the call to the
+ * proper handler for the tag.
*
* @param t the HTML.Tag
* @param pos the position at which the tag was encountered
*/
public void handleEndTag(HTML.Tag t, int pos)
{
- // Don't call the Action if we've already seen </html>.
- if (endHTMLEncountered)
- return;
-
- // If this is the </html> tag we need to stop calling the Actions
- if (t == HTML.Tag.HTML)
- endHTMLEncountered = true;
-
- TagAction action = (TagAction) tagToAction.get(t);
- if (action != null)
- action.end(t);
+ if (shouldInsert())
+ {
+ // If this is the </html> tag we need to stop calling the Actions
+ if (t == HTML.Tag.HTML)
+ endHTMLEncountered = true;
+
+ TagAction action = (TagAction) tagToAction.get(t);
+ if (action != null)
+ action.end(t);
+ }
}
/**
- * This is a callback from the parser that should be routed to the
+ * This is a callback from the parser that should be routed to the
* appropriate handler for the tag.
*
* @param t the HTML.Tag that was encountered
@@ -1209,15 +1252,17 @@ public class HTMLDocument extends DefaultStyledDocument
*/
public void handleSimpleTag(HTML.Tag t, MutableAttributeSet a, int pos)
{
- // Don't call the Action if we've already seen </html>.
- if (endHTMLEncountered)
- return;
-
- TagAction action = (TagAction) tagToAction.get (t);
- if (action != null)
+ if (t == insertTag)
+ insertTagEncountered = true;
+
+ if (shouldInsert())
{
- action.start(t, a);
- action.end(t);
+ TagAction action = (TagAction) tagToAction.get(t);
+ if (action != null)
+ {
+ action.start(t, a);
+ action.end(t);
+ }
}
}
@@ -1230,7 +1275,6 @@ public class HTMLDocument extends DefaultStyledDocument
* @since 1.3
*/
public void handleEndOfLineString(String eol)
- throws NotImplementedException
{
// FIXME: Implement.
print ("HTMLReader.handleEndOfLineString not implemented yet");
@@ -1273,16 +1317,6 @@ public class HTMLDocument extends DefaultStyledDocument
printBuffer();
DefaultStyledDocument.ElementSpec element;
- // If the previous tag is content and the parent is p-implied, then
- // we must also close the p-implied.
- if (parseStack.size() > 0 && parseStack.peek() == HTML.Tag.IMPLIED)
- {
- element = new DefaultStyledDocument.ElementSpec(null,
- DefaultStyledDocument.ElementSpec.EndTagType);
- parseBuffer.addElement(element);
- parseStack.pop();
- }
-
parseStack.push(t);
AbstractDocument.AttributeContext ctx = getAttributeContext();
AttributeSet copy = attr.copyAttributes();
@@ -1320,16 +1354,6 @@ public class HTMLDocument extends DefaultStyledDocument
new char[0], 0, 0);
parseBuffer.add(element);
}
- // If the previous tag is content and the parent is p-implied, then
- // we must also close the p-implied.
- else if (parseStack.peek() == HTML.Tag.IMPLIED)
- {
- element = new DefaultStyledDocument.ElementSpec(null,
- DefaultStyledDocument.ElementSpec.EndTagType);
- parseBuffer.addElement(element);
- if (parseStack.size() > 0)
- parseStack.pop();
- }
element = new DefaultStyledDocument.ElementSpec(null,
DefaultStyledDocument.ElementSpec.EndTagType);
@@ -1369,27 +1393,6 @@ public class HTMLDocument extends DefaultStyledDocument
DefaultStyledDocument.ElementSpec element;
AttributeSet attributes = null;
- // Content must always be embedded inside a paragraph element,
- // so we create this if the previous element is not one of
- // <p>, <h1> .. <h6>.
- boolean createImpliedParagraph = false;
- HTML.Tag parent = (HTML.Tag) parseStack.peek();
- if (parent != HTML.Tag.P && parent != HTML.Tag.H1
- && parent != HTML.Tag.H2
- && parent != HTML.Tag.H3 && parent != HTML.Tag.H4
- && parent != HTML.Tag.H5 && parent != HTML.Tag.H6
- && parent != HTML.Tag.TD)
- {
- attributes = ctx.getEmptySet();
- attributes = ctx.addAttribute(attributes,
- StyleConstants.NameAttribute,
- HTML.Tag.IMPLIED);
- element = new DefaultStyledDocument.ElementSpec(attributes,
- DefaultStyledDocument.ElementSpec.StartTagType);
- parseBuffer.add(element);
- parseStack.push(HTML.Tag.IMPLIED);
- }
-
// Copy the attribute set, don't use the same object because
// it may change
if (charAttr != null)
@@ -1433,14 +1436,14 @@ public class HTMLDocument extends DefaultStyledDocument
// Migrate from the rather htmlAttributeSet to the faster, lighter and
// unchangeable alternative implementation.
AttributeSet copy = a.copyAttributes();
-
- // TODO: Figure out why we must always insert this single character
- // (otherwise the element does not appear). Either fix or add explaining
- // comment or at least report a normal bug.
- DefaultStyledDocument.ElementSpec spec;
- spec = new DefaultStyledDocument.ElementSpec(copy,
- DefaultStyledDocument.ElementSpec.ContentType,
- new char[] {' '}, 0, 1 );
+
+ // The two spaces are required because some special elements like HR
+ // must be broken. At least two characters are needed to break into the
+ // two parts.
+ DefaultStyledDocument.ElementSpec spec =
+ new DefaultStyledDocument.ElementSpec(copy,
+ DefaultStyledDocument.ElementSpec.ContentType,
+ new char[] {' ', ' '}, 0, 2 );
parseBuffer.add(spec);
}
@@ -1481,7 +1484,61 @@ public class HTMLDocument extends DefaultStyledDocument
HTML.Tag insertTag)
{
return new HTMLReader(pos, popDepth, pushDepth, insertTag);
- }
+ }
+
+ /**
+ * Gets the reader for the parser to use when inserting the HTML fragment into
+ * the document. Checks if the parser is present, sets the parent in the
+ * element stack and removes any actions for BODY (it can be only one body in
+ * a HTMLDocument).
+ *
+ * @param pos - the starting position
+ * @param popDepth - the number of EndTagTypes to generate before inserting
+ * @param pushDepth - the number of StartTagTypes with a direction of
+ * JoinNextDirection that should be generated before inserting, but
+ * after the end tags have been generated.
+ * @param insertTag - the first tag to start inserting into document
+ * @param parent the element that will be the parent in the document. HTML
+ * parsing includes checks for the parent, so it must be available.
+ * @return - the reader
+ * @throws IllegalStateException if the parsert is not set.
+ */
+ public HTMLEditorKit.ParserCallback getInsertingReader(int pos, int popDepth,
+ int pushDepth,
+ HTML.Tag insertTag,
+ final Element parent)
+ throws IllegalStateException
+ {
+ if (parser == null)
+ throw new IllegalStateException("Parser has not been set");
+
+ HTMLReader reader = new HTMLReader(pos, popDepth, pushDepth, insertTag)
+ {
+ /**
+ * Ignore BODY.
+ */
+ public void handleStartTag(HTML.Tag t, MutableAttributeSet a, int pos)
+ {
+ if (t != HTML.Tag.BODY)
+ super.handleStartTag(t, a, pos);
+ }
+
+ /**
+ * Ignore BODY.
+ */
+ public void handleEndTag(HTML.Tag t, int pos)
+ {
+ if (t != HTML.Tag.BODY)
+ super.handleEndTag(t, pos);
+ }
+ };
+
+ // Set the parent HTML tag.
+ reader.parseStack.push(parent.getAttributes().getAttribute(
+ StyleConstants.NameAttribute));
+
+ return reader;
+ }
/**
* Gets the child element that contains the attribute with the value or null.
@@ -1490,8 +1547,8 @@ public class HTMLDocument extends DefaultStyledDocument
* @param e - the element to begin search at
* @param attribute - the desired attribute
* @param value - the desired value
- * @return the element found with the attribute and value specified or null
- * if it is not found.
+ * @return the element found with the attribute and value specified or null if
+ * it is not found.
*/
public Element getElement(Element e, Object attribute, Object value)
{
@@ -1516,16 +1573,17 @@ public class HTMLDocument extends DefaultStyledDocument
}
/**
- * Returns the element that has the given id Attribute. If it is not found,
- * null is returned. This method works on an Attribute, not a character tag.
- * This is not thread-safe.
+ * Returns the element that has the given id Attribute (for instance, &lt;p id
+ * ='my paragraph &gt;'). If it is not found, null is returned. The HTML tag,
+ * having this attribute, is not checked by this method and can be any. The
+ * method is not thread-safe.
*
- * @param attrId - the Attribute id to look for
+ * @param attrId - the value of the attribute id to look for
* @return the element that has the given id.
*/
public Element getElement(String attrId)
{
- return getElement(getDefaultRootElement(), HTML.getAttributeKey(attrId),
+ return getElement(getDefaultRootElement(), HTML.Attribute.ID,
attrId);
}
@@ -1542,22 +1600,30 @@ public class HTMLDocument extends DefaultStyledDocument
* @throws IllegalStateException - if an HTMLEditorKit.Parser has not been set
*/
public void setInnerHTML(Element elem, String htmlText)
- throws BadLocationException, IOException, NotImplementedException
+ throws BadLocationException, IOException
{
if (elem.isLeaf())
throw new IllegalArgumentException("Element is a leaf");
- if (parser == null)
- throw new IllegalStateException("Parser has not been set");
- // FIXME: Not implemented fully, use InsertHTML* in HTMLEditorKit?
- System.out.println("setInnerHTML not implemented");
+
+ int start = elem.getStartOffset();
+ int end = elem.getEndOffset();
+
+ HTMLEditorKit.ParserCallback reader = getInsertingReader(
+ end, 0, 0, HTML.Tag.BODY, elem);
+
+ // TODO charset
+ getParser().parse(new StringReader(htmlText), reader, true);
+
+ // Remove the previous content
+ remove(start, end - start);
}
/**
- * Replaces the given element in the parent with the string. When replacing
- * a leaf, this will attempt to make sure there is a newline present if one is
- * needed. This may result in an additional element being inserted.
- * This will be seen as at least two events, n inserts followed by a remove.
- * The HTMLEditorKit.Parser must be set.
+ * Replaces the given element in the parent with the string. When replacing a
+ * leaf, this will attempt to make sure there is a newline present if one is
+ * needed. This may result in an additional element being inserted. This will
+ * be seen as at least two events, n inserts followed by a remove. The
+ * HTMLEditorKit.Parser must be set.
*
* @param elem - the branch element whose parent will be replaced
* @param htmlText - the string to be parsed and assigned to elem
@@ -1565,18 +1631,25 @@ public class HTMLDocument extends DefaultStyledDocument
* @throws IOException
* @throws IllegalStateException - if parser is not set
*/
- public void setOuterHTML(Element elem, String htmlText)
- throws BadLocationException, IOException, NotImplementedException
- {
- if (parser == null)
- throw new IllegalStateException("Parser has not been set");
- // FIXME: Not implemented fully, use InsertHTML* in HTMLEditorKit?
- System.out.println("setOuterHTML not implemented");
- }
+public void setOuterHTML(Element elem, String htmlText)
+ throws BadLocationException, IOException
+ {
+ // Remove the current element:
+ int start = elem.getStartOffset();
+ int end = elem.getEndOffset();
+
+ remove(start, end-start);
+
+ HTMLEditorKit.ParserCallback reader = getInsertingReader(
+ start, 0, 0, HTML.Tag.BODY, elem);
+
+ // TODO charset
+ getParser().parse(new StringReader(htmlText), reader, true);
+ }
/**
- * Inserts the string before the start of the given element.
- * The parser must be set.
+ * Inserts the string before the start of the given element. The parser must
+ * be set.
*
* @param elem - the element to be the root for the new text.
* @param htmlText - the string to be parsed and assigned to elem
@@ -1585,18 +1658,19 @@ public class HTMLDocument extends DefaultStyledDocument
* @throws IllegalStateException - if parser has not been set
*/
public void insertBeforeStart(Element elem, String htmlText)
- throws BadLocationException, IOException, NotImplementedException
+ throws BadLocationException, IOException
{
- if (parser == null)
- throw new IllegalStateException("Parser has not been set");
- // FIXME: Not implemented fully, use InsertHTML* in HTMLEditorKit?
- System.out.println("insertBeforeStart not implemented");
+ HTMLEditorKit.ParserCallback reader = getInsertingReader(
+ elem.getStartOffset(), 0, 0, HTML.Tag.BODY, elem);
+
+ // TODO charset
+ getParser().parse(new StringReader(htmlText), reader, true);
}
/**
- * Inserts the string at the end of the element. If elem's children
- * are leaves, and the character at elem.getEndOffset() - 1 is a newline,
- * then it will be inserted before the newline. The parser must be set.
+ * Inserts the string at the end of the element. If elem's children are
+ * leaves, and the character at elem.getEndOffset() - 1 is a newline, then it
+ * will be inserted before the newline. The parser must be set.
*
* @param elem - the element to be the root for the new text
* @param htmlText - the text to insert
@@ -1605,12 +1679,14 @@ public class HTMLDocument extends DefaultStyledDocument
* @throws IllegalStateException - if parser is not set
*/
public void insertBeforeEnd(Element elem, String htmlText)
- throws BadLocationException, IOException, NotImplementedException
+ throws BadLocationException, IOException
{
- if (parser == null)
- throw new IllegalStateException("Parser has not been set");
- // FIXME: Not implemented fully, use InsertHTML* in HTMLEditorKit?
- System.out.println("insertBeforeEnd not implemented");
+ HTMLEditorKit.ParserCallback reader = getInsertingReader(
+ elem.getEndOffset(), 0, 0, HTML.Tag.BODY, elem);
+
+ // TODO charset
+ getParser().parse(new StringReader(htmlText), reader, true);
+
}
/**
@@ -1624,12 +1700,13 @@ public class HTMLDocument extends DefaultStyledDocument
* @throws IllegalStateException - if parser is not set
*/
public void insertAfterEnd(Element elem, String htmlText)
- throws BadLocationException, IOException, NotImplementedException
+ throws BadLocationException, IOException
{
- if (parser == null)
- throw new IllegalStateException("Parser has not been set");
- // FIXME: Not implemented fully, use InsertHTML* in HTMLEditorKit?
- System.out.println("insertAfterEnd not implemented");
+ HTMLEditorKit.ParserCallback reader = getInsertingReader(
+ elem.getEndOffset(), 0, 0, HTML.Tag.BODY, elem);
+
+ // TODO charset
+ getParser().parse(new StringReader(htmlText), reader, true);
}
/**
@@ -1643,11 +1720,12 @@ public class HTMLDocument extends DefaultStyledDocument
* @throws IllegalStateException - if parser is not set
*/
public void insertAfterStart(Element elem, String htmlText)
- throws BadLocationException, IOException, NotImplementedException
+ throws BadLocationException, IOException
{
- if (parser == null)
- throw new IllegalStateException("Parser has not been set");
- // FIXME: Not implemented fully, use InsertHTML* in HTMLEditorKit?
- System.out.println("insertAfterStart not implemented");
+ HTMLEditorKit.ParserCallback reader = getInsertingReader(
+ elem.getStartOffset(), 0, 0, HTML.Tag.BODY, elem);
+
+ // TODO charset
+ getParser().parse(new StringReader(htmlText), reader, true);
}
}
diff --git a/libjava/classpath/javax/swing/text/html/HTMLEditorKit.java b/libjava/classpath/javax/swing/text/html/HTMLEditorKit.java
index adda4922d57..5d77be8fdd4 100644
--- a/libjava/classpath/javax/swing/text/html/HTMLEditorKit.java
+++ b/libjava/classpath/javax/swing/text/html/HTMLEditorKit.java
@@ -71,6 +71,11 @@ import javax.swing.text.View;
import javax.swing.text.ViewFactory;
import javax.swing.text.html.parser.ParserDelegator;
+/* Move these imports here after javax.swing.text.html to make it compile
+ with jikes. */
+import gnu.javax.swing.text.html.parser.GnuParserDelegator;
+import gnu.javax.swing.text.html.parser.HTML_401Swing;
+
/**
* @author Lillian Angel (langel at redhat dot com)
*/
@@ -557,19 +562,18 @@ public class HTMLEditorKit
else if (tag == HTML.Tag.HEAD)
view = new NullView(element);
else if (tag.equals(HTML.Tag.TABLE))
- view = new HTMLTableView(element);
+ view = new javax.swing.text.html.TableView(element);
else if (tag.equals(HTML.Tag.TD))
view = new ParagraphView(element);
-
+ else if (tag.equals(HTML.Tag.HR))
+ view = new HRuleView(element);
+ else if (tag.equals(HTML.Tag.BR))
+ view = new BRView(element);
/*
else if (tag.equals(HTML.Tag.MENU) || tag.equals(HTML.Tag.DIR)
|| tag.equals(HTML.Tag.UL) || tag.equals(HTML.Tag.OL))
view = new ListView(element);
- else if (tag.equals(HTML.Tag.HR))
- view = new HRuleView(element);
- else if (tag.equals(HTML.Tag.BR))
- view = new BRView(element);
else if (tag.equals(HTML.Tag.INPUT) || tag.equals(HTML.Tag.SELECT)
|| tag.equals(HTML.Tag.TEXTAREA))
view = new FormView(element);
@@ -887,7 +891,9 @@ public class HTMLEditorKit
protected Parser getParser()
{
if (parser == null)
- parser = new ParserDelegator();
+ {
+ parser = new GnuParserDelegator(HTML_401Swing.getInstance());
+ }
return parser;
}
diff --git a/libjava/classpath/javax/swing/text/html/StyleSheet.java b/libjava/classpath/javax/swing/text/html/StyleSheet.java
index 2466a2808fe..d92abde7825 100644
--- a/libjava/classpath/javax/swing/text/html/StyleSheet.java
+++ b/libjava/classpath/javax/swing/text/html/StyleSheet.java
@@ -38,6 +38,8 @@ exception statement from your version. */
package javax.swing.text.html;
+import gnu.javax.swing.text.html.CharacterAttributeTranslator;
+
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
@@ -585,47 +587,15 @@ public class StyleSheet extends StyleContext
}
/**
- * Converst a color string to a color. If it is not found, null is returned.
- *
- * @param color - the color string such as "RED" or "#NNNNNN"
- * @return the Color, or null if not found.
- */
- public Color stringToColor(String color)
- {
- color = color.toLowerCase();
- if (color.equals("black") || color.equals("#000000"))
- return Color.BLACK;
- else if (color.equals("aqua") || color.equals("#00FFFF"))
- return new Color(127, 255, 212);
- else if (color.equals("gray") || color.equals("#808080"))
- return Color.GRAY;
- else if (color.equals("navy") || color.equals("#000080"))
- return new Color(0, 0, 128);
- else if (color.equals("silver") || color.equals("#C0C0C0"))
- return Color.LIGHT_GRAY;
- else if (color.equals("green") || color.equals("#008000"))
- return Color.GREEN;
- else if (color.equals("olive") || color.equals("#808000"))
- return new Color(128, 128, 0);
- else if (color.equals("teal") || color.equals("#008080"))
- return new Color(0, 128, 128);
- else if (color.equals("blue") || color.equals("#0000FF"))
- return Color.BLUE;
- else if (color.equals("lime") || color.equals("#00FF00"))
- return new Color(0, 255, 0);
- else if (color.equals("purple") || color.equals("#800080"))
- return new Color(128, 0, 128);
- else if (color.equals("white") || color.equals("#FFFFFF"))
- return Color.WHITE;
- else if (color.equals("fuchsia") || color.equals("#FF00FF"))
- return Color.MAGENTA;
- else if (color.equals("maroon") || color.equals("#800000"))
- return new Color(128, 0, 0);
- else if (color.equals("Red") || color.equals("#FF0000"))
- return Color.RED;
- else if (color.equals("Yellow") || color.equals("#FFFF00"))
- return Color.YELLOW;
- return null;
+ * Convert the color string represenation into java.awt.Color. The valid
+ * values are like "aqua" , "#00FFFF" or "rgb(1,6,44)".
+ *
+ * @param colorName the color to convert.
+ * @return the matching java.awt.color
+ */
+ public Color stringToColor(String colorName)
+ {
+ return CharacterAttributeTranslator.getColor(colorName);
}
/**
diff --git a/libjava/classpath/javax/swing/text/html/TableView.java b/libjava/classpath/javax/swing/text/html/TableView.java
new file mode 100644
index 00000000000..c2edc8cdd64
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/TableView.java
@@ -0,0 +1,137 @@
+/* TableView.java -- A table view for HTML tables
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+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.html;
+
+import javax.swing.text.Document;
+import javax.swing.text.Element;
+import javax.swing.text.View;
+import javax.swing.text.ViewFactory;
+
+/**
+ * A conrete implementation of TableView that renders HTML tables.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+class TableView
+ extends javax.swing.text.TableView
+{
+ /**
+ * Represents a single table row.
+ */
+ public class RowView extends TableRow
+ {
+ /**
+ * Creates a new instance of the <code>RowView</code>.
+ *
+ * @param el the element for which to create a row view
+ */
+ public RowView(Element el)
+ {
+ super(el);
+ }
+
+ /**
+ * Get the associated style sheet from the document.
+ *
+ * @return the associated style sheet.
+ */
+ protected StyleSheet getStyleSheet()
+ {
+ Document d = getElement().getDocument();
+ if (d instanceof HTMLDocument)
+ return ((HTMLDocument) d).getStyleSheet();
+ else
+ return null;
+ }
+ }
+
+ /**
+ * Creates a new HTML table view for the specified element.
+ *
+ * @param el the element for the table view
+ */
+ public TableView(Element el)
+ {
+ super(el);
+ }
+
+ /**
+ * Get the associated style sheet from the document.
+ *
+ * @return the associated style sheet.
+ */
+ protected StyleSheet getStyleSheet()
+ {
+ Document d = getElement().getDocument();
+ if (d instanceof HTMLDocument)
+ return ((HTMLDocument) d).getStyleSheet();
+ else
+ return null;
+ }
+
+ /**
+ * Creates a view for a table row.
+ *
+ * @param el the element that represents the table row
+ * @return a view for rendering the table row
+ * (and instance of {@link RowView}).
+ */
+ protected TableRow createTableRow(Element el)
+ {
+ return new RowView(el);
+ }
+
+ /**
+ * Loads the children of the Table. This completely bypasses the ViewFactory
+ * and creates instances of TableRow instead.
+ *
+ * @param vf ignored
+ */
+ protected void loadChildren(ViewFactory vf)
+ {
+ Element el = getElement();
+ int numChildren = el.getElementCount();
+ View[] rows = new View[numChildren];
+ for (int i = 0; i < numChildren; ++i)
+ {
+ rows[i] = createTableRow(el.getElement(i));
+ }
+ replace(0, getViewCount(), rows);
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/html/parser/ParserDelegator.java b/libjava/classpath/javax/swing/text/html/parser/ParserDelegator.java
index e5d2db4df7c..70636d92923 100644
--- a/libjava/classpath/javax/swing/text/html/parser/ParserDelegator.java
+++ b/libjava/classpath/javax/swing/text/html/parser/ParserDelegator.java
@@ -52,9 +52,6 @@ import javax.swing.text.html.HTMLEditorKit.ParserCallback;
* This class instantiates and starts the working instance of
* html parser, being responsible for providing the default DTD.
*
- * TODO Later this class must be derived from the totally abstract class
- * HTMLEditorKit.Parser. HTMLEditorKit that does not yet exist.
- *
* @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
*/
public class ParserDelegator
diff --git a/libjava/classpath/javax/swing/text/rtf/RTFParser.java b/libjava/classpath/javax/swing/text/rtf/RTFParser.java
index 4f0f967c117..de1b1c6ff15 100644
--- a/libjava/classpath/javax/swing/text/rtf/RTFParser.java
+++ b/libjava/classpath/javax/swing/text/rtf/RTFParser.java
@@ -140,9 +140,17 @@ class RTFParser
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");
+ }
}
diff --git a/libjava/classpath/javax/swing/text/rtf/RTFScanner.java b/libjava/classpath/javax/swing/text/rtf/RTFScanner.java
index 3cdd6e8e0b9..060e087eb67 100644
--- a/libjava/classpath/javax/swing/text/rtf/RTFScanner.java
+++ b/libjava/classpath/javax/swing/text/rtf/RTFScanner.java
@@ -71,6 +71,11 @@ class RTFScanner
private StringBuffer buffer;
/**
+ * Lookahead token.
+ */
+ private Token lastToken;
+
+ /**
* Constructs a new RTFScanner without initializing the {@link Reader}.
*/
private RTFScanner()
@@ -120,7 +125,7 @@ class RTFScanner
*
* @throws IOException if the underlying stream has problems
*/
- public Token readToken()
+ private Token readTokenImpl()
throws IOException
{
Token token = null;
@@ -156,6 +161,27 @@ class RTFScanner
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.
*
OpenPOWER on IntegriCloud