diff options
Diffstat (limited to 'javax/swing/text/BoxView.java')
-rw-r--r-- | javax/swing/text/BoxView.java | 350 |
1 files changed, 217 insertions, 133 deletions
diff --git a/javax/swing/text/BoxView.java b/javax/swing/text/BoxView.java index 7e8f19f74..962d06219 100644 --- a/javax/swing/text/BoxView.java +++ b/javax/swing/text/BoxView.java @@ -92,11 +92,6 @@ public class BoxView private int[] span = new int[2]; /** - * The SizeRequirements of the child views along the X_AXIS and Y_AXIS. - */ - private SizeRequirements[][] childReqs = new SizeRequirements[2][]; - - /** * Creates a new <code>BoxView</code> for the given * <code>Element</code> and axis. Valid values for the axis are * {@link View#X_AXIS} and {@link View#Y_AXIS}. @@ -227,48 +222,30 @@ public class BoxView */ public void replace(int offset, int length, View[] views) { - int numViews = 0; - if (views != null) - numViews = views.length; - - // Resize and copy data for cache arrays. - // The spansX cache. - int oldSize = getViewCount(); - - int[] newSpansX = new int[oldSize - length + numViews]; - System.arraycopy(spans[X_AXIS], 0, newSpansX, 0, offset); - System.arraycopy(spans[X_AXIS], offset + length, newSpansX, - offset + numViews, - oldSize - (offset + length)); - spans[X_AXIS] = newSpansX; - - // The spansY cache. - int[] newSpansY = new int[oldSize - length + numViews]; - System.arraycopy(spans[Y_AXIS], 0, newSpansY, 0, offset); - System.arraycopy(spans[Y_AXIS], offset + length, newSpansY, - offset + numViews, - oldSize - (offset + length)); - spans[Y_AXIS] = newSpansY; - - // The offsetsX cache. - int[] newOffsetsX = new int[oldSize - length + numViews]; - System.arraycopy(offsets[X_AXIS], 0, newOffsetsX, 0, offset); - System.arraycopy(offsets[X_AXIS], offset + length, newOffsetsX, - offset + numViews, - oldSize - (offset + length)); - offsets[X_AXIS] = newOffsetsX; - - // The offsetsY cache. - int[] newOffsetsY = new int[oldSize - length + numViews]; - System.arraycopy(offsets[Y_AXIS], 0, newOffsetsY, 0, offset); - System.arraycopy(offsets[Y_AXIS], offset + length, newOffsetsY, - offset + numViews, - oldSize - (offset + length)); - offsets[Y_AXIS] = newOffsetsY; + int oldNumChildren = getViewCount(); // Actually perform the replace. super.replace(offset, length, views); + // Resize and copy data for cache arrays. + int newItems = views != null ? views.length : 0; + int delta = newItems - length; + int src = offset + length; + int numMove = oldNumChildren - src; + int dst = src + delta; + offsets[X_AXIS] = replaceLayoutArray(offsets[X_AXIS], offset, + oldNumChildren, delta, src, dst, + numMove); + spans[X_AXIS] = replaceLayoutArray(spans[X_AXIS], offset, + oldNumChildren, delta, src, dst, + numMove); + offsets[Y_AXIS] = replaceLayoutArray(offsets[Y_AXIS], offset, + oldNumChildren, delta, src, dst, + numMove); + spans[Y_AXIS] = replaceLayoutArray(spans[Y_AXIS], offset, + oldNumChildren, delta, src, dst, + numMove); + // Invalidate layout information. layoutValid[X_AXIS] = false; requirementsValid[X_AXIS] = false; @@ -277,6 +254,34 @@ public class BoxView } /** + * Helper method. This updates the layout cache arrays in response + * to a call to {@link #replace(int, int, View[])}. + * + * @param oldArray the old array + * + * @return the replaced array + */ + private int[] replaceLayoutArray(int[] oldArray, int offset, int numChildren, + int delta, int src, int dst, int numMove) + + { + int[] newArray; + if (numChildren + delta > oldArray.length) + { + int newLength = Math.max(2 * oldArray.length, numChildren + delta); + newArray = new int[newLength]; + System.arraycopy(oldArray, 0, newArray, 0, offset); + System.arraycopy(oldArray, src, newArray, dst, numMove); + } + else + { + newArray = oldArray; + System.arraycopy(newArray, src, newArray, dst, numMove); + } + return newArray; + } + + /** * Renders the <code>Element</code> that is associated with this * <code>View</code>. * @@ -373,9 +378,9 @@ public class BoxView } /** - * This method is obsolete and no longer in use. It is replaced by - * {@link #calculateMajorAxisRequirements(int, SizeRequirements)} and - * {@link #calculateMinorAxisRequirements(int, SizeRequirements)}. + * Calculates size requirements for a baseline layout. This is not + * used by the BoxView itself, but by subclasses that wish to perform + * a baseline layout, like the FlowView's rows. * * @param axis the axis that is examined * @param sr the <code>SizeRequirements</code> object to hold the result, @@ -387,50 +392,94 @@ public class BoxView protected SizeRequirements baselineRequirements(int axis, SizeRequirements sr) { - updateChildRequirements(axis); + // Create new instance if sr == null. + if (sr == null) + sr = new SizeRequirements(); + sr.alignment = 0.5F; + + // Calculate overall ascent and descent. + int totalAscentMin = 0; + int totalAscentPref = 0; + int totalAscentMax = 0; + int totalDescentMin = 0; + int totalDescentPref = 0; + int totalDescentMax = 0; + + int count = getViewCount(); + for (int i = 0; i < count; i++) + { + View v = getView(i); + float align = v.getAlignment(axis); + int span = (int) v.getPreferredSpan(axis); + int ascent = (int) (align * span); + int descent = span - ascent; + + totalAscentPref = Math.max(ascent, totalAscentPref); + totalDescentPref = Math.max(descent, totalDescentPref); + if (v.getResizeWeight(axis) > 0) + { + // If the view is resizable, then use the min and max size + // of the view. + span = (int) v.getMinimumSpan(axis); + ascent = (int) (align * span); + descent = span - ascent; + totalAscentMin = Math.max(ascent, totalAscentMin); + totalDescentMin = Math.max(descent, totalDescentMin); + + span = (int) v.getMaximumSpan(axis); + ascent = (int) (align * span); + descent = span - ascent; + totalAscentMax = Math.max(ascent, totalAscentMax); + totalDescentMax = Math.max(descent, totalDescentMax); + } + else + { + // If the view is not resizable, use the preferred span. + totalAscentMin = Math.max(ascent, totalAscentMin); + totalDescentMin = Math.max(descent, totalDescentMin); + totalAscentMax = Math.max(ascent, totalAscentMax); + totalDescentMax = Math.max(descent, totalDescentMax); + } + } - SizeRequirements res = sr; - if (res == null) - res = new SizeRequirements(); + // Preferred overall span is the sum of the preferred ascent and descent. + // With overflow check. + sr.preferred = (int) Math.min((long) totalAscentPref + + (long) totalDescentPref, + Integer.MAX_VALUE); - 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++) + // Align along the baseline. + if (sr.preferred > 0) + sr.alignment = (float) totalAscentPref / sr.preferred; + + if (sr.alignment == 0) { - 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); + // Nothing above the baseline, use the descent. + sr.minimum = totalDescentMin; + sr.maximum = totalDescentMax; } - 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; + else if (sr.alignment == 1.0F) + { + // Nothing below the baseline, use the descent. + sr.minimum = totalAscentMin; + sr.maximum = totalAscentMax; + } + else + { + sr.minimum = Math.max((int) (totalAscentMin / sr.alignment), + (int) (totalDescentMin / (1.0F - sr.alignment))); + sr.maximum = Math.min((int) (totalAscentMax / sr.alignment), + (int) (totalDescentMax / (1.0F - sr.alignment))); + } + return sr; } /** - * Calculates the layout of the children of this <code>BoxView</code> along - * the specified axis. + * Calculates the baseline layout of the children of this + * <code>BoxView</code> along the specified axis. + * + * This is not used by the BoxView itself, but by subclasses that wish to + * perform a baseline layout, like the FlowView's rows. * * @param span the target span * @param axis the axis that is examined @@ -440,13 +489,36 @@ public class BoxView protected void baselineLayout(int span, int axis, int[] offsets, int[] spans) { - updateChildRequirements(axis); - updateRequirements(axis); + int totalAscent = (int) (span * getAlignment(axis)); + int totalDescent = span - totalAscent; - // Calculate the spans and offsets using the SizeRequirements uility - // methods. - SizeRequirements.calculateAlignedPositions(span, requirements[axis], - childReqs[axis], offsets, spans); + int count = getViewCount(); + for (int i = 0; i < count; i++) + { + View v = getView(i); + float align = v.getAlignment(axis); + int viewSpan; + if (v.getResizeWeight(axis) > 0) + { + // If possible, then resize for best fit. + int min = (int) v.getMinimumSpan(axis); + int max = (int) v.getMaximumSpan(axis); + if (align == 0.0F) + viewSpan = Math.max(Math.min(max, totalDescent), min); + else if (align == 1.0F) + viewSpan = Math.max(Math.min(max, totalAscent), min); + else + { + int fit = (int) Math.min(totalAscent / align, + totalDescent / (1.0F - align)); + viewSpan = Math.max(Math.min(max, fit), min); + } + } + else + viewSpan = (int) v.getPreferredSpan(axis); + offsets[i] = totalAscent - (int) (viewSpan * align); + spans[i] = viewSpan; + } } /** @@ -509,7 +581,7 @@ public class BoxView res.minimum = 0; res.preferred = 0; - res.maximum = 0; + res.maximum = Integer.MAX_VALUE; res.alignment = 0.5F; int n = getViewCount(); for (int i = 0; i < n; i++) @@ -589,24 +661,54 @@ public class BoxView { View result = null; int count = getViewCount(); - Rectangle copy = new Rectangle(r); - - for (int i = 0; i < count; ++i) + if (myAxis == X_AXIS) { - copy.setBounds(r); - // The next call modifies copy. - childAllocation(i, copy); - if (copy.contains(x, y)) + // Border case. Requested point is left from the box. + if (x < r.x + offsets[X_AXIS][0]) { - // Modify r on success. - r.setBounds(copy); - result = getView(i); - break; + childAllocation(0, r); + result = getView(0); + } + else + { + // Search views inside box. + for (int i = 0; i < count && result == null; i++) + { + if (x < r.x + offsets[X_AXIS][i]) + { + childAllocation(i - 1, r); + result = getView(i - 1); + } + } } } - - if (result == null && count > 0) - return getView(count - 1); + else // Same algorithm for Y_AXIS. + { + // Border case. Requested point is above the box. + if (y < r.y + offsets[Y_AXIS][0]) + { + childAllocation(0, r); + result = getView(0); + } + else + { + // Search views inside box. + for (int i = 0; i < count && result == null; i++) + { + if (y < r.y + offsets[Y_AXIS][i]) + { + childAllocation(i - 1, r); + result = getView(i - 1); + } + } + } + } + // Not found, other border case: point is right from or below the box. + if (result == null) + { + childAllocation(count - 1, r); + result = getView(count - 1); + } return result; } @@ -808,7 +910,9 @@ public class BoxView */ public int getWidth() { - return span[X_AXIS] + getLeftInset() - getRightInset(); + // The RI returns the following here, however, I'd think that is a bug. + // return span[X_AXIS] + getLeftInset() - getRightInset(); + return span[X_AXIS] + getLeftInset() + getRightInset(); } /** @@ -818,7 +922,9 @@ public class BoxView */ public int getHeight() { - return span[Y_AXIS] + getTopInset() - getBottomInset(); + // The RI returns the following here, however, I'd think that is a bug. + // return span[Y_AXIS] + getTopInset() - getBottomInset(); + return span[Y_AXIS] + getTopInset() + getBottomInset(); } /** @@ -977,7 +1083,11 @@ public class BoxView public int viewToModel(float x, float y, Shape a, Position.Bias[] bias) { - // FIXME: What to do here? + if (! isAllocationValid()) + { + Rectangle r = a instanceof Rectangle ? (Rectangle) a : a.getBounds(); + setSize(r.width, r.height); + } return super.viewToModel(x, y, a, bias); } @@ -988,32 +1098,6 @@ public class BoxView } /** - * Updates the child requirements along the specified axis. The requirements - * are only updated if the layout for the specified axis is marked as - * invalid. - * - * @param axis the axis to be updated - */ - private void updateChildRequirements(int axis) - { - if (! isLayoutValid(axis)) - { - int numChildren = getViewCount(); - if (childReqs[axis] == null || childReqs[axis].length != numChildren) - childReqs[axis] = new SizeRequirements[numChildren]; - for (int i = 0; i < numChildren; ++i) - { - View child = getView(i); - childReqs[axis][i] = - new SizeRequirements((int) child.getMinimumSpan(axis), - (int) child.getPreferredSpan(axis), - (int) child.getMaximumSpan(axis), - child.getAlignment(axis)); - } - } - } - - /** * Updates the view's cached requirements along the specified axis if * necessary. The requirements are only updated if the layout for the * specified axis is marked as invalid. |