summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Wielaard <mark@klomp.org>2006-08-08 20:40:49 +0000
committerMark Wielaard <mark@klomp.org>2006-08-08 20:40:49 +0000
commit61cab9b7c774229aa09a35cd9cfcf8d736c982b4 (patch)
tree6381d5c7cbb219b24235c8a549c9999378e408f7
parent50f69a943fc08be8b1e70973e5b7de2b93821183 (diff)
downloadclasspath-61cab9b7c774229aa09a35cd9cfcf8d736c982b4.tar.gz
2006-08-08 Roman Kennke <kennke@aicas.com>
* javax/swing/plaf/basic/BasicTextUI.java (damageRange(JTextComponent,int,int)): Call damageRange() with correct biases, rather than null. (damageRange(JTextComponent,int,int,Bias,Bias)): Rewritten to use simpler modelToView() approach without much special casing. This seems not worth the effort and actually caused problems. Added locking of the document. * javax/swing/text/BoxView.java (requirementsValid): New field. (calculateMajorAxisRequirements): Rewritten without using SizeRequirements. The SizeRequirements algorithms are slightly different and too inefficient. (calculateMinorAxisRequirements): Rewritten without using SizeRequirements. The SizeRequirements algorithms are slightly different and too inefficient. (getAlignment): Simply return the alignment of the cached requirements. (getMaximumSpan): Add insets. (getMinimumSpan): Add insets. (getPreferredSpan): Add insets. (layoutMajorAxis): Rewritten without using SizeRequirements. The SizeRequirements algorithms are slightly different and too inefficient. (layoutMinorAxis): Rewritten without using SizeRequirements. The SizeRequirements algorithms are slightly different and too inefficient. (modelToView): Call setSize() rather than layout(). (paint): Check clip for more efficient painting. (preferenceChanged): Invalidate requirements here. (replace): Invalidate requirements here. (updateRequirements): Update requirements only when requirements are marked invalid. * javax/swing/text/CompositeView.java (modelToView): Added some more checks and handling of corner cases. * javax/swing/text/FlowView.java (calculateMinorAxisRequirements): Set aligment to 0.5 and maximum span to Integer.MAX_VALUE. Limit preferredSize to minimumSize. * javax/swing/text/IconView.java (getAlignment): Implemented to return 1.0 for vertical alignment. * javax/swing/text/ParagraphView.java (Row.getMaximumSpan): Implemented to let Rows span the whole ParagraphView. (getAlignment): Fixed horizontal alignment and vertical alignment for empty paragraphs to be 0.5. 2006-08-08 Roman Kennke <kennke@aicas.com> * javax/swing/text/View.java (modelToView): Added special handling for corner case at the end of the view and for multiline views. 2006-08-08 Roman Kennke <kennke@aicas.com> * javax/swing/plaf/basic/BasicTextUI.java (modelToView): Read-lock the document. Set size of the root view before fetching the model-to-view mapping. (getViewIndex): Check of the position is inside the range and return -1 if this is not the case. (getViewAtPosition(int,Rectangle): Update child allocation for valid view index. (getViewIndexAtPosition(int)): Delegate the index search to the element since we have a 1:1 mapping between elements and views here. * javax/swing/text/DefaultCaret.java (appear): Ignore BadLocationException. (paint): Ignore BadLocationException. * javax/swing/text/FlowView.java (changedUpdate): Also notify the layoutPool view. (removeUpdate): Also notify the layoutPool view. * javax/swing/text/ParagraphView.java (Row.getViewIndexAtPosition): Overridden to search linearily through the view instead of relying on a 1:1 model to view mapping. * javax/swing/text/View.java (removeUpdate): Clear ElementChange object if updateChildren returns false. (forwardUpdate): Special handle some boundary cases.
-rw-r--r--ChangeLog80
-rw-r--r--javax/swing/plaf/basic/BasicTextUI.java144
-rw-r--r--javax/swing/text/BoxView.java264
-rw-r--r--javax/swing/text/CompositeView.java82
-rw-r--r--javax/swing/text/DefaultCaret.java16
-rw-r--r--javax/swing/text/FlowView.java14
-rw-r--r--javax/swing/text/IconView.java18
-rw-r--r--javax/swing/text/ParagraphView.java37
-rw-r--r--javax/swing/text/View.java113
9 files changed, 504 insertions, 264 deletions
diff --git a/ChangeLog b/ChangeLog
index 54728531e..341e8a5cf 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,83 @@
+2006-08-08 Roman Kennke <kennke@aicas.com>
+
+ * javax/swing/plaf/basic/BasicTextUI.java
+ (damageRange(JTextComponent,int,int)): Call damageRange() with
+ correct biases, rather than null.
+ (damageRange(JTextComponent,int,int,Bias,Bias)): Rewritten
+ to use simpler modelToView() approach without much special
+ casing. This seems not worth the effort and actually
+ caused problems. Added locking of the document.
+ * javax/swing/text/BoxView.java
+ (requirementsValid): New field.
+ (calculateMajorAxisRequirements): Rewritten without using
+ SizeRequirements. The SizeRequirements algorithms are slightly
+ different and too inefficient.
+ (calculateMinorAxisRequirements): Rewritten without using
+ SizeRequirements. The SizeRequirements algorithms are slightly
+ different and too inefficient.
+ (getAlignment): Simply return the alignment of the cached
+ requirements.
+ (getMaximumSpan): Add insets.
+ (getMinimumSpan): Add insets.
+ (getPreferredSpan): Add insets.
+ (layoutMajorAxis): Rewritten without using
+ SizeRequirements. The SizeRequirements algorithms are slightly
+ different and too inefficient.
+ (layoutMinorAxis): Rewritten without using
+ SizeRequirements. The SizeRequirements algorithms are slightly
+ different and too inefficient.
+ (modelToView): Call setSize() rather than layout().
+ (paint): Check clip for more efficient painting.
+ (preferenceChanged): Invalidate requirements here.
+ (replace): Invalidate requirements here.
+ (updateRequirements): Update requirements only when requirements
+ are marked invalid.
+ * javax/swing/text/CompositeView.java
+ (modelToView): Added some more checks and handling of corner cases.
+ * javax/swing/text/FlowView.java
+ (calculateMinorAxisRequirements): Set aligment to 0.5 and maximum
+ span to Integer.MAX_VALUE. Limit preferredSize to minimumSize.
+ * javax/swing/text/IconView.java
+ (getAlignment): Implemented to return 1.0 for vertical alignment.
+ * javax/swing/text/ParagraphView.java
+ (Row.getMaximumSpan): Implemented to let Rows span the whole
+ ParagraphView.
+ (getAlignment): Fixed horizontal alignment and vertical alignment
+ for empty paragraphs to be 0.5.
+
+2006-08-08 Roman Kennke <kennke@aicas.com>
+
+ * javax/swing/text/View.java
+ (modelToView): Added special handling for corner case at the end
+ of the view and for multiline views.
+
+2006-08-08 Roman Kennke <kennke@aicas.com>
+
+ * javax/swing/plaf/basic/BasicTextUI.java
+ (modelToView): Read-lock the document. Set size of the
+ root view before fetching the model-to-view mapping.
+ (getViewIndex): Check of the position is inside the range and
+ return -1 if this is not the case.
+ (getViewAtPosition(int,Rectangle): Update child allocation for valid
+ view index.
+ (getViewIndexAtPosition(int)): Delegate the index search to
+ the element since we have a 1:1 mapping between elements and
+ views here.
+ * javax/swing/text/DefaultCaret.java
+ (appear): Ignore BadLocationException.
+ (paint): Ignore BadLocationException.
+ * javax/swing/text/FlowView.java
+ (changedUpdate): Also notify the layoutPool view.
+ (removeUpdate): Also notify the layoutPool view.
+ * javax/swing/text/ParagraphView.java
+ (Row.getViewIndexAtPosition): Overridden to search linearily
+ through the view instead of relying on a 1:1 model to view
+ mapping.
+ * javax/swing/text/View.java
+ (removeUpdate): Clear ElementChange object if updateChildren
+ returns false.
+ (forwardUpdate): Special handle some boundary cases.
+
2006-08-07 Raif S. Naffah <raif@swiftdsl.com.au>
* gnu/java/security/key/dss/DSSKey.java: Updated documentation.
diff --git a/javax/swing/plaf/basic/BasicTextUI.java b/javax/swing/plaf/basic/BasicTextUI.java
index 5febe141d..8e9c8c949 100644
--- a/javax/swing/plaf/basic/BasicTextUI.java
+++ b/javax/swing/plaf/basic/BasicTextUI.java
@@ -83,7 +83,6 @@ import javax.swing.text.Highlighter;
import javax.swing.text.JTextComponent;
import javax.swing.text.Keymap;
import javax.swing.text.Position;
-import javax.swing.text.Utilities;
import javax.swing.text.View;
import javax.swing.text.ViewFactory;
@@ -1042,7 +1041,7 @@ public abstract class BasicTextUI extends TextUI
*/
public void damageRange(JTextComponent t, int p0, int p1)
{
- damageRange(t, p0, p1, null, null);
+ damageRange(t, p0, p1, Position.Bias.Forward, Position.Bias.Backward);
}
/**
@@ -1062,106 +1061,36 @@ public abstract class BasicTextUI extends TextUI
public void damageRange(JTextComponent t, int p0, int p1,
Position.Bias firstBias, Position.Bias secondBias)
{
- // Do nothing if the component cannot be properly displayed.
- if (t.getWidth() == 0 || t.getHeight() == 0)
- return;
-
- try
+ Rectangle alloc = getVisibleEditorRect();
+ if (alloc != null)
{
- // Limit p0 and p1 to sane values to prevent unfriendly
- // BadLocationExceptions. This makes it possible for the highlighter
- // to send us illegal values which can happen when a large number
- // of selected characters are removed (eg. by pressing delete
- // or backspace).
- // The reference implementation does not throw an exception, too.
- p0 = Math.min(p0, t.getDocument().getLength());
- p1 = Math.min(p1, t.getDocument().getLength());
-
- Rectangle l1 = modelToView(t, p0, firstBias);
- Rectangle l2 = modelToView(t, p1, secondBias);
- if (l1 == null || l2 == null)
+ Document doc = t.getDocument();
+
+ // Acquire lock here to avoid structural changes in between.
+ if (doc instanceof AbstractDocument)
+ ((AbstractDocument) doc).readLock();
+ try
{
- // Unable to determine the start or end of the selection.
- t.repaint();
+ rootView.setSize(alloc.width, alloc.height);
+ Shape damage = rootView.modelToView(p0, firstBias, p1, secondBias,
+ alloc);
+ Rectangle r = damage instanceof Rectangle ? (Rectangle) damage
+ : damage.getBounds();
+ textComponent.repaint(r.x, r.y, r.width, r.height);
}
- else if (l1.y == l2.y)
+ catch (BadLocationException ex)
{
- SwingUtilities.computeUnion(l2.x, l2.y, l2.width, l2.height, l1);
- t.repaint(l1);
+ // Lets ignore this as it causes no serious problems.
+ // For debugging, comment this out.
+ // ex.printStackTrace();
}
- else
+ finally
{
- // The two rectangles lie on different lines and we need a
- // different algorithm to calculate the damaged area:
- // 1. The line of p0 is damaged from the position of p0
- // to the right border.
- // 2. All lines between the ones where p0 and p1 lie on
- // are completely damaged. Use the allocation area to find
- // out the bounds.
- // 3. The final line is damaged from the left bound to the
- // position of p1.
- Insets insets = t.getInsets();
-
- // Damage first line until the end.
- l1.width = insets.right + t.getWidth() - l1.x;
- t.repaint(l1);
-
- // Note: Utilities.getPositionBelow() may return the offset
- // that was put in. In that case there is no next line and
- // we should stop searching for one.
-
- int posBelow = Utilities.getPositionBelow(t, p0, l1.x);
- int p1RowStart = Utilities.getRowStart(t, p1);
-
- if (posBelow != -1
- && posBelow != p0
- && Utilities.getRowStart(t, posBelow) != p1RowStart)
- {
- // Take the rectangle of the offset we just found and grow it
- // to the maximum width. Retain y because this is our start
- // height.
- Rectangle grow = modelToView(t, posBelow);
- grow.x = insets.left;
- grow.width = t.getWidth() + insets.right;
-
- // Find further lines which have to be damaged completely.
- int nextPosBelow = posBelow;
- while (nextPosBelow != -1
- && posBelow != nextPosBelow
- && Utilities.getRowStart(t, nextPosBelow) != p1RowStart)
- {
- posBelow = nextPosBelow;
- nextPosBelow = Utilities.getPositionBelow(t, posBelow,
- l1.x);
-
- if (posBelow == nextPosBelow)
- break;
- }
- // Now posBelow is an offset on the last line which has to be
- // damaged completely. (newPosBelow is on the same line as p1)
-
- // Retrieve the rectangle of posBelow and use its y and height
- // value to calculate the final height of the multiple line
- // spanning rectangle.
- Rectangle end = modelToView(t, posBelow);
- grow.height = end.y + end.height - grow.y;
-
- // Mark that area as damage.
- t.repaint(grow);
- }
-
- // Damage last line from its beginning to the position of p1.
- l2.width += l2.x;
- l2.x = insets.left;
- t.repaint(l2);
+ // Release lock.
+ if (doc instanceof AbstractDocument)
+ ((AbstractDocument) doc).readUnlock();
}
}
- catch (BadLocationException ex)
- {
- AssertionError err = new AssertionError("Unexpected bad location");
- err.initCause(ex);
- throw err;
- }
}
/**
@@ -1258,10 +1187,29 @@ public abstract class BasicTextUI extends TextUI
public Rectangle modelToView(JTextComponent t, int pos, Position.Bias bias)
throws BadLocationException
{
- Rectangle r = getVisibleEditorRect();
-
- return (r != null) ? rootView.modelToView(pos, r, bias).getBounds()
- : null;
+ // We need to read-lock here because we depend on the document
+ // structure not beeing changed in between.
+ Document doc = textComponent.getDocument();
+ if (doc instanceof AbstractDocument)
+ ((AbstractDocument) doc).readLock();
+ Rectangle rect = null;
+ try
+ {
+ Rectangle r = getVisibleEditorRect();
+ if (r != null)
+ {
+ rootView.setSize(r.width, r.height);
+ Shape s = rootView.modelToView(pos, r, bias);
+ if (s != null)
+ rect = s.getBounds();
+ }
+ }
+ finally
+ {
+ if (doc instanceof AbstractDocument)
+ ((AbstractDocument) doc).readUnlock();
+ }
+ return rect;
}
/**
diff --git a/javax/swing/text/BoxView.java b/javax/swing/text/BoxView.java
index a184a8131..27e3c0f9a 100644
--- a/javax/swing/text/BoxView.java
+++ b/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/javax/swing/text/CompositeView.java b/javax/swing/text/CompositeView.java
index 17f13dbed..6f487b898 100644
--- a/javax/swing/text/CompositeView.java
+++ b/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/javax/swing/text/DefaultCaret.java b/javax/swing/text/DefaultCaret.java
index ffce9a1b7..8557e63c3 100644
--- a/javax/swing/text/DefaultCaret.java
+++ b/javax/swing/text/DefaultCaret.java
@@ -911,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)
@@ -1148,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);
diff --git a/javax/swing/text/FlowView.java b/javax/swing/text/FlowView.java
index 89fcc6fcd..3de95ed7f 100644
--- a/javax/swing/text/FlowView.java
+++ b/javax/swing/text/FlowView.java
@@ -524,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;
}
@@ -539,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;
}
@@ -597,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/javax/swing/text/IconView.java b/javax/swing/text/IconView.java
index 699cda90e..7bb7635b4 100644
--- a/javax/swing/text/IconView.java
+++ b/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/javax/swing/text/ParagraphView.java b/javax/swing/text/ParagraphView.java
index 15bed7818..c4857863d 100644
--- a/javax/swing/text/ParagraphView.java
+++ b/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/javax/swing/text/View.java b/javax/swing/text/View.java
index d8ad5f585..55a63f6b6 100644
--- a/javax/swing/text/View.java
+++ b/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);
}
/**