FileDocCategorySizeDatePackage
BoxView.javaAPI DocJava SE 6 API41214Tue Jun 10 00:26:56 BST 2008javax.swing.text

BoxView

public class BoxView extends CompositeView
A view that arranges its children into a box shape by tiling its children along an axis. The box is somewhat like that found in TeX where there is alignment of the children, flexibility of the children is considered, etc. This is a building block that might be useful to represent things like a collection of lines, paragraphs, lists, columns, pages, etc. The axis along which the children are tiled is considered the major axis. The orthoginal axis is the minor axis.

Layout for each axis is handled separately by the methods layoutMajorAxis and layoutMinorAxis. Subclasses can change the layout algorithm by reimplementing these methods. These methods will be called as necessary depending upon whether or not there is cached layout information and the cache is considered valid. These methods are typically called if the given size along the axis changes, or if layoutChanged is called to force an updated layout. The layoutChanged method invalidates cached layout information, if there is any. The requirements published to the parent view are calculated by the methods calculateMajorAxisRequirements and calculateMinorAxisRequirements. If the layout algorithm is changed, these methods will likely need to be reimplemented.

author
Timothy Prinzing
version
1.70 02/15/07

Fields Summary
int
majorAxis
int
majorSpan
int
minorSpan
boolean
majorReqValid
boolean
minorReqValid
SizeRequirements
majorRequest
SizeRequirements
minorRequest
boolean
majorAllocValid
int[]
majorOffsets
int[]
majorSpans
boolean
minorAllocValid
int[]
minorOffsets
int[]
minorSpans
Rectangle
tempRect
used in paint.
Constructors Summary
public BoxView(Element elem, int axis)
Constructs a BoxView.

param
elem the element this view is responsible for
param
axis either View.X_AXIS or View.Y_AXIS

	super(elem);
	tempRect = new Rectangle();
	this.majorAxis = axis;

	majorOffsets = new int[0];
	majorSpans = new int[0];
	majorReqValid = false;
	majorAllocValid = false;
	minorOffsets = new int[0];
	minorSpans = new int[0];
	minorReqValid = false;
	minorAllocValid = false;
    
Methods Summary
protected voidbaselineLayout(int targetSpan, int axis, int[] offsets, int[] spans)
Computes the location and extent of each child view in this BoxView given the targetSpan, which is the width (or height) of the region we have to work with.

param
targetSpan the total span given to the view, which would be used to layout the children
param
axis the axis being studied, either View.X_AXIS or View.Y_AXIS
param
offsets an empty array filled by this method with values specifying the location of each child view
param
spans an empty array filled by this method with values specifying the extent of each child view

        int totalAscent = (int)(targetSpan * getAlignment(axis));
        int totalDescent = targetSpan - totalAscent;

        int n = getViewCount();

        for (int i = 0; i < n; i++) {
            View v = getView(i);
            float align = v.getAlignment(axis);
            float viewSpan;

            if (v.getResizeWeight(axis) > 0) {
                // if resizable then resize to the best fit

                // the smallest span possible
                float minSpan = v.getMinimumSpan(axis);
                // the largest span possible
                float maxSpan = v.getMaximumSpan(axis);

                if (align == 0.0f) {
                    // if the alignment is 0 then we need to fit into the descent
                    viewSpan = Math.max(Math.min(maxSpan, totalDescent), minSpan);
                } else if (align == 1.0f) {
                    // if the alignment is 1 then we need to fit into the ascent
                    viewSpan = Math.max(Math.min(maxSpan, totalAscent), minSpan);
                } else {
                    // figure out the span that we must fit into
                    float fitSpan = Math.min(totalAscent / align,
                                             totalDescent / (1.0f - align));
                    // fit into the calculated span
                    viewSpan = Math.max(Math.min(maxSpan, fitSpan), minSpan);
                }
            } else {
                // otherwise use the preferred spans
                viewSpan = v.getPreferredSpan(axis);
            }

            offsets[i] = totalAscent - (int)(viewSpan * align);
            spans[i] = (int)viewSpan;
        }     
    
protected javax.swing.SizeRequirementsbaselineRequirements(int axis, javax.swing.SizeRequirements r)
Calculates the size requirements for this BoxView by examining the size of each child view.

param
axis the axis being studied
param
r the SizeRequirements object; if null one will be created
return
the newly initialized SizeRequirements object

        SizeRequirements totalAscent = new SizeRequirements();
        SizeRequirements totalDescent = new SizeRequirements();
        
        if (r == null) {
            r = new SizeRequirements();
        }
        
        r.alignment = 0.5f;

        int n = getViewCount();

        // loop through all children calculating the max of all their ascents and
        // descents at minimum, preferred, and maximum sizes
        for (int i = 0; i < n; i++) {
            View v = getView(i);
            float align = v.getAlignment(axis);
            float span;
            int ascent;
            int descent;

            // find the maximum of the preferred ascents and descents
            span = v.getPreferredSpan(axis);
            ascent = (int)(align * span);
            descent = (int)(span - ascent);
            totalAscent.preferred = Math.max(ascent, totalAscent.preferred);
            totalDescent.preferred = Math.max(descent, totalDescent.preferred);
            
            if (v.getResizeWeight(axis) > 0) {
                // if the view is resizable then do the same for the minimum and
                // maximum ascents and descents
                span = v.getMinimumSpan(axis);
                ascent = (int)(align * span);
                descent = (int)(span - ascent);
                totalAscent.minimum = Math.max(ascent, totalAscent.minimum);
                totalDescent.minimum = Math.max(descent, totalDescent.minimum);

                span = v.getMaximumSpan(axis);
                ascent = (int)(align * span);
                descent = (int)(span - ascent);
                totalAscent.maximum = Math.max(ascent, totalAscent.maximum);
                totalDescent.maximum = Math.max(descent, totalDescent.maximum);
            } else {
                // otherwise use the preferred
                totalAscent.minimum = Math.max(ascent, totalAscent.minimum);
                totalDescent.minimum = Math.max(descent, totalDescent.minimum);
                totalAscent.maximum = Math.max(ascent, totalAscent.maximum);
                totalDescent.maximum = Math.max(descent, totalDescent.maximum);
            }
        }
        
        // we now have an overall preferred, minimum, and maximum ascent and descent

        // calculate the preferred span as the sum of the preferred ascent and preferred descent
        r.preferred = (int)Math.min((long)totalAscent.preferred + (long)totalDescent.preferred,
                                    Integer.MAX_VALUE);

        // calculate the preferred alignment as the preferred ascent divided by the preferred span
        if (r.preferred > 0) {
            r.alignment = (float)totalAscent.preferred / r.preferred;
        }
        

        if (r.alignment == 0.0f) {
            // if the preferred alignment is 0 then the minimum and maximum spans are simply
            // the minimum and maximum descents since there's nothing above the baseline
            r.minimum = totalDescent.minimum;
            r.maximum = totalDescent.maximum;
        } else if (r.alignment == 1.0f) {
            // if the preferred alignment is 1 then the minimum and maximum spans are simply
            // the minimum and maximum ascents since there's nothing below the baseline
            r.minimum = totalAscent.minimum;
            r.maximum = totalAscent.maximum;
        } else {
            // we want to honor the preferred alignment so we calculate two possible minimum
            // span values using 1) the minimum ascent and the alignment, and 2) the minimum
            // descent and the alignment. We'll choose the larger of these two numbers.
            r.minimum = Math.round(Math.max(totalAscent.minimum / r.alignment,
                                          totalDescent.minimum / (1.0f - r.alignment)));
            // a similar calculation is made for the maximum but we choose the smaller number.
            r.maximum = Math.round(Math.min(totalAscent.maximum / r.alignment,
                                          totalDescent.maximum / (1.0f - r.alignment)));
        }

        return r;
    
protected javax.swing.SizeRequirementscalculateMajorAxisRequirements(int axis, javax.swing.SizeRequirements r)
Calculates the size requirements for the major axis axis.

param
axis the axis being studied
param
r the SizeRequirements object; if null one will be created
return
the newly initialized SizeRequirements object
see
javax.swing.SizeRequirements

	// calculate tiled request
	float min = 0;
	float pref = 0;
	float max = 0;

	int n = getViewCount();
	for (int i = 0; i < n; i++) {
	    View v = getView(i);
	    min += v.getMinimumSpan(axis);
	    pref += v.getPreferredSpan(axis);
	    max += v.getMaximumSpan(axis);
	}

	if (r == null) {
	    r = new SizeRequirements();
	}
	r.alignment = 0.5f;
	r.minimum = (int) min;
	r.preferred = (int) pref;
	r.maximum = (int) max;
	return r;
    
protected javax.swing.SizeRequirementscalculateMinorAxisRequirements(int axis, javax.swing.SizeRequirements r)
Calculates the size requirements for the minor axis axis.

param
axis the axis being studied
param
r the SizeRequirements object; if null one will be created
return
the newly initialized SizeRequirements object
see
javax.swing.SizeRequirements

	int min = 0;
	long pref = 0;
	int max = Integer.MAX_VALUE;
	int n = getViewCount();
	for (int i = 0; i < n; i++) {
	    View v = getView(i);
	    min = Math.max((int) v.getMinimumSpan(axis), min);
	    pref = Math.max((int) v.getPreferredSpan(axis), pref);
	    max = Math.max((int) v.getMaximumSpan(axis), max);
	}

	if (r == null) {
	    r = new SizeRequirements();
	    r.alignment = 0.5f;
	}
	r.preferred = (int) pref;
	r.minimum = min;
	r.maximum = max;
	return r;
    
voidcheckRequests(int axis)
Checks the request cache and update if needed.

param
axis the axis being studied
exception
IllegalArgumentException if axis is neither View.X_AXIS nor View.Y_AXIS

	if ((axis != X_AXIS) && (axis != Y_AXIS)) {
	    throw new IllegalArgumentException("Invalid axis: " + axis);
	}
	if (axis == majorAxis) {
            if (!majorReqValid) {
                majorRequest = calculateMajorAxisRequirements(axis,
                                                              majorRequest);
                majorReqValid = true;
            }
	} else if (! minorReqValid) {
	    minorRequest = calculateMinorAxisRequirements(axis, minorRequest);
	    minorReqValid = true;
	}
    
protected voidchildAllocation(int index, java.awt.Rectangle alloc)
Allocates a region for a child view.

param
index the index of the child view to allocate, >= 0 && < getViewCount()
param
alloc the allocated region

	alloc.x += getOffset(X_AXIS, index);
	alloc.y += getOffset(Y_AXIS, index);
	alloc.width = getSpan(X_AXIS, index);
	alloc.height = getSpan(Y_AXIS, index);
    
protected booleanflipEastAndWestAtEnds(int position, javax.swing.text.Position$Bias bias)
Determines in which direction the next view lays. Consider the View at index n. Typically the Views are layed out from left to right, so that the View to the EAST will be at index n + 1, and the View to the WEST will be at index n - 1. In certain situations, such as with bidirectional text, it is possible that the View to EAST is not at index n + 1, but rather at index n - 1, or that the View to the WEST is not at index n - 1, but index n + 1. In this case this method would return true, indicating the Views are layed out in descending order. Otherwise the method would return false indicating the Views are layed out in ascending order.

If the receiver is laying its Views along the Y_AXIS, this will will return the value from invoking the same method on the View responsible for rendering position and bias. Otherwise this will return false.

param
position position into the model
param
bias either Position.Bias.Forward or Position.Bias.Backward
return
true if the Views surrounding the View responding for rendering position and bias are layed out in descending order; otherwise false

	if(majorAxis == Y_AXIS) {
	    int testPos = (bias == Position.Bias.Backward) ?
		          Math.max(0, position - 1) : position;
	    int index = getViewIndexAtPosition(testPos);
	    if(index != -1) {
		View v = getView(index);
		if(v != null && v instanceof CompositeView) {
		    return ((CompositeView)v).flipEastAndWestAtEnds(position,
								    bias);
		}
	    }
	}
	return false;
    
protected voidforwardUpdate(javax.swing.event.DocumentEvent$ElementChange ec, javax.swing.event.DocumentEvent e, java.awt.Shape a, javax.swing.text.ViewFactory f)
Forwards the given DocumentEvent to the child views that need to be notified of the change to the model. If a child changed its requirements and the allocation was valid prior to forwarding the portion of the box from the starting child to the end of the box will be repainted.

param
ec changes to the element this view is responsible for (may be null if there were no changes)
param
e the change information from the associated document
param
a the current allocation of the view
param
f the factory to use to rebuild if the view has children
see
#insertUpdate
see
#removeUpdate
see
#changedUpdate
since
1.3

	boolean wasValid = isLayoutValid(majorAxis);
	super.forwardUpdate(ec, e, a, f);

	// determine if a repaint is needed
	if (wasValid && (! isLayoutValid(majorAxis))) {
	    // Repaint is needed because one of the tiled children 
	    // have changed their span along the major axis.  If there 
	    // is a hosting component and an allocated shape we repaint.
	    Component c = getContainer();
	    if ((a != null) && (c != null)) {
		int pos = e.getOffset();
		int index = getViewIndexAtPosition(pos);
		Rectangle alloc = getInsideAllocation(a);
		if (majorAxis == X_AXIS) {
		    alloc.x += majorOffsets[index];
		    alloc.width -= majorOffsets[index];
		} else {
		    alloc.y += minorOffsets[index];
		    alloc.height -= minorOffsets[index];
		}
		c.repaint(alloc.x, alloc.y, alloc.width, alloc.height);
	    }
	}
    
public floatgetAlignment(int axis)
Determines the desired alignment for this view along an axis. This is implemented to give the total alignment needed to position the children with the alignment points lined up along the axis orthoginal to the axis that is being tiled. The axis being tiled will request to be centered (i.e. 0.5f).

param
axis may be either View.X_AXIS or View.Y_AXIS
return
the desired alignment >= 0.0f && <= 1.0f; this should be a value between 0.0 and 1.0 where 0 indicates alignment at the origin and 1.0 indicates alignment to the full span away from the origin; an alignment of 0.5 would be the center of the view
exception
IllegalArgumentException for an invalid axis

	checkRequests(axis);
	if (axis == majorAxis) {
	    return majorRequest.alignment;
	} else {
	    return minorRequest.alignment;
	}
    
public intgetAxis()
Fetches the tile axis property. This is the axis along which the child views are tiled.

return
the major axis of the box, either View.X_AXIS or View.Y_AXIS
since
1.3

	return majorAxis;
    
public java.awt.ShapegetChildAllocation(int index, java.awt.Shape a)
Fetches the allocation for the given child view. This enables finding out where various views are located. This is implemented to return null if the layout is invalid, otherwise the superclass behavior is executed.

param
index the index of the child, >= 0 && < getViewCount()
param
a the allocation to this view
return
the allocation to the child; or null if a is null; or null if the layout is invalid

	if (a != null) {
	    Shape ca = super.getChildAllocation(index, a);
	    if ((ca != null) && (! isAllocationValid())) {
		// The child allocation may not have been set yet.
		Rectangle r = (ca instanceof Rectangle) ? 
		    (Rectangle) ca : ca.getBounds();
		if ((r.width == 0) && (r.height == 0)) {
		    return null;
		}
	    }
	    return ca;
	}
	return null;
    
public intgetHeight()
Returns the current height of the box. This is the height that it was last allocated.

return
the current height of the box

	int span;
	if (majorAxis == Y_AXIS) {
	    span = majorSpan;
	} else {
	    span = minorSpan;
	}
	span += getTopInset() - getBottomInset();
	return span;
    
public floatgetMaximumSpan(int axis)
Determines the maximum span for this view along an axis.

param
axis may be either View.X_AXIS or View.Y_AXIS
return
the span the view would like to be rendered into >= 0; typically the view is told to render into the span that is returned, although there is no guarantee; the parent may choose to resize or break the view
exception
IllegalArgumentException for an invalid axis type

	checkRequests(axis);
	float marginSpan = (axis == X_AXIS) ? getLeftInset() + getRightInset() :
	    getTopInset() + getBottomInset();
	if (axis == majorAxis) {
	    return ((float)majorRequest.maximum) + marginSpan;
	} else {
	    return ((float)minorRequest.maximum) + marginSpan;
	}
    
public floatgetMinimumSpan(int axis)
Determines the minimum span for this view along an axis.

param
axis may be either View.X_AXIS or View.Y_AXIS
return
the span the view would like to be rendered into >= 0; typically the view is told to render into the span that is returned, although there is no guarantee; the parent may choose to resize or break the view
exception
IllegalArgumentException for an invalid axis type

	checkRequests(axis);
	float marginSpan = (axis == X_AXIS) ? getLeftInset() + getRightInset() :
	    getTopInset() + getBottomInset();
	if (axis == majorAxis) {
	    return ((float)majorRequest.minimum) + marginSpan;
	} else {
	    return ((float)minorRequest.minimum) + marginSpan;
	}
    
protected intgetOffset(int axis, int childIndex)
Fetches the offset of a particular child's current layout.

param
axis the axis being studied
param
childIndex the index of the requested child
return
the offset (location) for the specified child

	int[] offsets = (axis == majorAxis) ? majorOffsets : minorOffsets;
	return offsets[childIndex];
    
public floatgetPreferredSpan(int axis)
Determines the preferred span for this view along an axis.

param
axis may be either View.X_AXIS or View.Y_AXIS
return
the span the view would like to be rendered into >= 0; typically the view is told to render into the span that is returned, although there is no guarantee; the parent may choose to resize or break the view
exception
IllegalArgumentException for an invalid axis type

	checkRequests(axis);
	float marginSpan = (axis == X_AXIS) ? getLeftInset() + getRightInset() :
	    getTopInset() + getBottomInset();
	if (axis == majorAxis) {
	    return ((float)majorRequest.preferred) + marginSpan;
	} else {
	    return ((float)minorRequest.preferred) + marginSpan;
	}
    
public intgetResizeWeight(int axis)
Gets the resize weight. A value of 0 or less is not resizable.

param
axis may be either View.X_AXIS or View.Y_AXIS
return
the weight
exception
IllegalArgumentException for an invalid axis

	checkRequests(axis);
        if (axis == majorAxis) {
	    if ((majorRequest.preferred != majorRequest.minimum) ||
		(majorRequest.preferred != majorRequest.maximum)) {
		return 1;
	    }
	} else {
	    if ((minorRequest.preferred != minorRequest.minimum) ||
		(minorRequest.preferred != minorRequest.maximum)) {
		return 1;
	    }
	}
	return 0;
    
protected intgetSpan(int axis, int childIndex)
Fetches the span of a particular childs current layout.

param
axis the axis being studied
param
childIndex the index of the requested child
return
the span (width or height) of the specified child

	int[] spans = (axis == majorAxis) ? majorSpans : minorSpans;
	return spans[childIndex];
    
floatgetSpanOnAxis(int axis)
Returns the size of the view along an axis. This is implemented to return zero.

param
axis may be either View.X_AXIS or View.Y_AXIS
return
the current span of the view along the given axis, >= 0

	if (axis == majorAxis) {
	    return majorSpan;
	} else {
	    return minorSpan;
	}
    
protected javax.swing.text.ViewgetViewAtPoint(int x, int y, java.awt.Rectangle alloc)
Fetches the child view at the given coordinates.

param
x the X coordinate >= 0
param
y the Y coordinate >= 0
param
alloc the parents inner allocation on entry, which should be changed to the childs allocation on exit
return
the view

	int n = getViewCount();
	if (majorAxis == View.X_AXIS) {
	    if (x < (alloc.x + majorOffsets[0])) {
		childAllocation(0, alloc);
		return getView(0);
	    }
	    for (int i = 0; i < n; i++) {
		if (x < (alloc.x + majorOffsets[i])) {
		    childAllocation(i - 1, alloc);
		    return getView(i - 1);
		}
	    }
	    childAllocation(n - 1, alloc);
	    return getView(n - 1);
	} else {
	    if (y < (alloc.y + majorOffsets[0])) {
		childAllocation(0, alloc);
		return getView(0);
	    }
	    for (int i = 0; i < n; i++) {
		if (y < (alloc.y + majorOffsets[i])) {
		    childAllocation(i - 1, alloc);
		    return getView(i - 1);
		}
	    }
	    childAllocation(n - 1, alloc);
	    return getView(n - 1);
	}
    
public intgetWidth()
Returns the current width of the box. This is the width that it was last allocated.

return
the current width of the box

	int span;
	if (majorAxis == X_AXIS) {
	    span = majorSpan;
	} else {
	    span = minorSpan;
	}
	span += getLeftInset() - getRightInset();
	return span;
    
protected booleanisAfter(int x, int y, java.awt.Rectangle innerAlloc)
Determines if a point falls after an allocated region.

param
x the X coordinate >= 0
param
y the Y coordinate >= 0
param
innerAlloc the allocated region; this is the area inside of the insets
return
true if the point lies after the region else false

	if (majorAxis == View.X_AXIS) {
	    return (x > (innerAlloc.width + innerAlloc.x));
	} else {
	    return (y > (innerAlloc.height + innerAlloc.y));
	}
    
protected booleanisAllocationValid()
Are the allocations for the children still valid?

return
true if allocations still valid

	return (majorAllocValid && minorAllocValid);
    
protected booleanisBefore(int x, int y, java.awt.Rectangle innerAlloc)
Determines if a point falls before an allocated region.

param
x the X coordinate >= 0
param
y the Y coordinate >= 0
param
innerAlloc the allocated region; this is the area inside of the insets
return
true if the point lies before the region else false

	if (majorAxis == View.X_AXIS) {
	    return (x < innerAlloc.x);
	} else {
	    return (y < innerAlloc.y);
	}
    
protected booleanisLayoutValid(int axis)
Determines if the layout is valid along the given axis.

param
axis either View.X_AXIS or View.Y_AXIS
since
1.4

 	if (axis == majorAxis) {
 	    return majorAllocValid;
 	} else {
 	    return minorAllocValid;
 	}
    
protected voidlayout(int width, int height)
Perform layout on the box

param
width the width (inside of the insets) >= 0
param
height the height (inside of the insets) >= 0

	setSpanOnAxis(X_AXIS, width);
	setSpanOnAxis(Y_AXIS, height);
    
public voidlayoutChanged(int axis)
Invalidates the layout along an axis. This happens automatically if the preferences have changed for any of the child views. In some cases the layout may need to be recalculated when the preferences have not changed. The layout can be marked as invalid by calling this method. The layout will be updated the next time the setSize method is called on this view (typically in paint).

param
axis either View.X_AXIS or View.Y_AXIS
since
1.3

 	if (axis == majorAxis) {
 	    majorAllocValid = false;
 	} else {
 	    minorAllocValid = false;
 	}
    
protected voidlayoutMajorAxis(int targetSpan, int axis, int[] offsets, int[] spans)
Performs layout for the major axis of the box (i.e. the axis that it represents). The results of the layout (the offset and span for each children) are placed in the given arrays which represent the allocations to the children along the major axis.

param
targetSpan the total span given to the view, which would be used to layout the children
param
axis the axis being layed out
param
offsets the offsets from the origin of the view for each of the child views; this is a return value and is filled in by the implementation of this method
param
spans the span of each child view; this is a return value and is filled in by the implementation of this method

	/*
	 * first pass, calculate the preferred sizes
	 * and the flexibility to adjust the sizes.
	 */
	long preferred = 0;
	int n = getViewCount();
	for (int i = 0; i < n; i++) {
	    View v = getView(i);
	    spans[i] = (int) v.getPreferredSpan(axis);
	    preferred += spans[i];
	}

	/*
	 * Second pass, expand or contract by as much as possible to reach
	 * the target span.  
	 */

	// determine the adjustment to be made
	long desiredAdjustment = targetSpan - preferred;
	float adjustmentFactor = 0.0f;
        int[] diffs = null;

	if (desiredAdjustment != 0) {
            long totalSpan = 0;
            diffs = new int[n];
            for (int i = 0; i < n; i++) {
                View v = getView(i);
                int tmp;
                if (desiredAdjustment < 0) {
                    tmp = (int)v.getMinimumSpan(axis);
                    diffs[i] = spans[i] - tmp;
                } else {
                    tmp = (int)v.getMaximumSpan(axis);
                    diffs[i] = tmp - spans[i];
                }
                totalSpan += tmp;
            }
            
            float maximumAdjustment = Math.abs(totalSpan - preferred);
                adjustmentFactor = desiredAdjustment / maximumAdjustment;
                adjustmentFactor = Math.min(adjustmentFactor, 1.0f);
                adjustmentFactor = Math.max(adjustmentFactor, -1.0f);
            }

	// make the adjustments
	int totalOffset = 0;
	for (int i = 0; i < n; i++) {
	    offsets[i] = totalOffset;
            if (desiredAdjustment != 0) {
                float adjF = adjustmentFactor * diffs[i];
                spans[i] += Math.round(adjF);
            }
	    totalOffset = (int) Math.min((long) totalOffset + (long) spans[i], Integer.MAX_VALUE);
	}
    
protected voidlayoutMinorAxis(int targetSpan, int axis, int[] offsets, int[] spans)
Performs layout for the minor axis of the box (i.e. the axis orthoginal to the axis that it represents). The results of the layout (the offset and span for each children) are placed in the given arrays which represent the allocations to the children along the minor axis.

param
targetSpan the total span given to the view, which would be used to layout the children
param
axis the axis being layed out
param
offsets the offsets from the origin of the view for each of the child views; this is a return value and is filled in by the implementation of this method
param
spans the span of each child view; this is a return value and is filled in by the implementation of this method

	int n = getViewCount();
	for (int i = 0; i < n; i++) {
	    View v = getView(i);
	    int max = (int) v.getMaximumSpan(axis);
	    if (max < targetSpan) {
		// can't make the child this wide, align it
		float align = v.getAlignment(axis);
		offsets[i] = (int) ((targetSpan - max) * align);
		spans[i] = max;
	    } else {
		// make it the target width, or as small as it can get.
                int min = (int)v.getMinimumSpan(axis);
		offsets[i] = 0;
		spans[i] = Math.max(min, targetSpan);
	    }
	}
    
public java.awt.ShapemodelToView(int pos, java.awt.Shape a, javax.swing.text.Position$Bias b)
Provides a mapping from the document model coordinate space to the coordinate space of the view mapped to it. This makes sure the allocation is valid before calling the superclass.

param
pos the position to convert >= 0
param
a the allocated region to render into
return
the bounding box of the given position
exception
BadLocationException if the given position does not represent a valid location in the associated document
see
View#modelToView

	if (! isAllocationValid()) {
	    Rectangle alloc = a.getBounds();
	    setSize(alloc.width, alloc.height);
	}
	return super.modelToView(pos, a, b);
    
public voidpaint(java.awt.Graphics g, java.awt.Shape allocation)
Renders the BoxView using the given rendering surface and area on that surface. Only the children that intersect the clip bounds of the given Graphics will be rendered.

param
g the rendering surface to use
param
allocation the allocated region to render into
see
View#paint

	Rectangle alloc = (allocation instanceof Rectangle) ?
	                   (Rectangle)allocation : allocation.getBounds();
	int n = getViewCount();
	int x = alloc.x + getLeftInset();
	int y = alloc.y + getTopInset();
	Rectangle clip = g.getClipBounds();
	for (int i = 0; i < n; i++) {
	    tempRect.x = x + getOffset(X_AXIS, i);
	    tempRect.y = y + getOffset(Y_AXIS, i);
	    tempRect.width = getSpan(X_AXIS, i);
	    tempRect.height = getSpan(Y_AXIS, i);
            int trx0 = tempRect.x, trx1 = trx0 + tempRect.width;
            int try0 = tempRect.y, try1 = try0 + tempRect.height;
            int crx0 = clip.x, crx1 = crx0 + clip.width;
            int cry0 = clip.y, cry1 = cry0 + clip.height;
            // We should paint views that intersect with clipping region
            // even if the intersection has no inside points (is a line).
            // This is needed for supporting views that have zero width, like
            // views that contain only combining marks.
            if ((trx1 >= crx0) && (try1 >= cry0) && (crx1 >= trx0) && (cry1 >= try0)) {
		paintChild(g, tempRect, i);
	    }
	}
    
protected voidpaintChild(java.awt.Graphics g, java.awt.Rectangle alloc, int index)
Paints a child. By default that is all it does, but a subclass can use this to paint things relative to the child.

param
g the graphics context
param
alloc the allocated region to paint into
param
index the child index, >= 0 && < getViewCount()

	View child = getView(index);
	child.paint(g, alloc);
    
public voidpreferenceChanged(javax.swing.text.View child, boolean width, boolean height)
This is called by a child to indicate its preferred span has changed. This is implemented to throw away cached layout information so that new calculations will be done the next time the children need an allocation.

param
child the child view
param
width true if the width preference should change
param
height true if the height preference should change

	boolean majorChanged = (majorAxis == X_AXIS) ? width : height;
	boolean minorChanged = (majorAxis == X_AXIS) ? height : width;
	if (majorChanged) {
	    majorReqValid = false;
	    majorAllocValid = false;
	}
	if (minorChanged) {
	    minorReqValid = false;
	    minorAllocValid = false;
	}
	super.preferenceChanged(child, width, height);
    
public voidreplace(int index, int length, javax.swing.text.View[] elems)
Invalidates the layout and resizes the cache of requests/allocations. The child allocations can still be accessed for the old layout, but the new children will have an offset and span of 0.

param
index the starting index into the child views to insert the new views; this should be a value >= 0 and <= getViewCount
param
length the number of existing child views to remove; This should be a value >= 0 and <= (getViewCount() - offset)
param
elems the child views to add; this value can be nullto indicate no children are being added (useful to remove)

	super.replace(index, length, elems);

	// invalidate cache 
	int nInserted = (elems != null) ? elems.length : 0;
	majorOffsets = updateLayoutArray(majorOffsets, index, nInserted);
	majorSpans = updateLayoutArray(majorSpans, index, nInserted);
	majorReqValid = false;
	majorAllocValid = false;
	minorOffsets = updateLayoutArray(minorOffsets, index, nInserted);
	minorSpans = updateLayoutArray(minorSpans, index, nInserted);
	minorReqValid = false;
	minorAllocValid = false;
    
public voidsetAxis(int axis)
Sets the tile axis property. This is the axis along which the child views are tiled.

param
axis either View.X_AXIS or View.Y_AXIS
since
1.3

	boolean axisChanged = (axis != majorAxis);
	majorAxis = axis;
	if (axisChanged) {
	    preferenceChanged(null, true, true);
	}
    
public voidsetSize(float width, float height)
Sets the size of the view. This should cause layout of the view if the view caches any layout information. This is implemented to call the layout method with the sizes inside of the insets.

param
width the width >= 0
param
height the height >= 0

        layout(Math.max(0, (int)(width - getLeftInset() - getRightInset())), 
               Math.max(0, (int)(height - getTopInset() - getBottomInset())));
    
voidsetSpanOnAxis(int axis, float span)
Sets the size of the view along an axis. This should cause layout of the view along the given axis.

param
axis may be either View.X_AXIS or View.Y_AXIS
param
span the span to layout to >= 0

	if (axis == majorAxis) {
	    if (majorSpan != (int) span) {
		majorAllocValid = false;
	    }
	    if (! majorAllocValid) {
		// layout the major axis
		majorSpan = (int) span;
		checkRequests(majorAxis);
		layoutMajorAxis(majorSpan, axis, majorOffsets, majorSpans);
		majorAllocValid = true;

		// flush changes to the children
		updateChildSizes();
	    }
	} else {
	    if (((int) span) != minorSpan) { 
		minorAllocValid = false;
	    }
	    if (! minorAllocValid) {
		// layout the minor axis
		minorSpan = (int) span;
		checkRequests(axis);
		layoutMinorAxis(minorSpan, axis, minorOffsets, minorSpans);
		minorAllocValid = true;

		// flush changes to the children
		updateChildSizes();
	    }
	}
    
voidupdateChildSizes()
Propagates the current allocations to the child views.

	int n = getViewCount();
	if (majorAxis == X_AXIS) {
	    for (int i = 0; i < n; i++) {
		View v = getView(i);
		v.setSize((float) majorSpans[i], (float) minorSpans[i]);
	    }
	} else {
	    for (int i = 0; i < n; i++) {
		View v = getView(i);
		v.setSize((float) minorSpans[i], (float) majorSpans[i]);
	    }
	}
    
int[]updateLayoutArray(int[] oldArray, int offset, int nInserted)
Resizes the given layout array to match the new number of child views. The current number of child views are used to produce the new array. The contents of the old array are inserted into the new array at the appropriate places so that the old layout information is transferred to the new array.

param
oldArray the original layout array
param
offset location where new views will be inserted
param
nInserted the number of child views being inserted; therefore the number of blank spaces to leave in the new array at location offset
return
the new layout array

	int n = getViewCount();
	int[] newArray = new int[n];

	System.arraycopy(oldArray, 0, newArray, 0, offset);
	System.arraycopy(oldArray, offset, 
			 newArray, offset + nInserted, n - nInserted - offset);
	return newArray;
    
public intviewToModel(float x, float y, java.awt.Shape a, javax.swing.text.Position$Bias[] bias)
Provides a mapping from the view coordinate space to the logical coordinate space of the model.

param
x x coordinate of the view location to convert >= 0
param
y y coordinate of the view location to convert >= 0
param
a the allocated region to render into
return
the location within the model that best represents the given point in the view >= 0
see
View#viewToModel

	if (! isAllocationValid()) {
	    Rectangle alloc = a.getBounds();
	    setSize(alloc.width, alloc.height);
	}
	return super.viewToModel(x, y, a, bias);