/* | 
|
 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. | 
|
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | 
|
 * | 
|
 * This code is free software; you can redistribute it and/or modify it | 
|
 * under the terms of the GNU General Public License version 2 only, as | 
|
 * published by the Free Software Foundation.  Oracle designates this | 
|
 * particular file as subject to the "Classpath" exception as provided | 
|
 * by Oracle in the LICENSE file that accompanied this code. | 
|
 * | 
|
 * This code 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 | 
|
 * version 2 for more details (a copy is included in the LICENSE file that | 
|
 * accompanied this code). | 
|
 * | 
|
 * You should have received a copy of the GNU General Public License version | 
|
 * 2 along with this work; if not, write to the Free Software Foundation, | 
|
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | 
|
 * | 
|
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | 
|
 * or visit www.oracle.com if you need additional information or have any | 
|
 * questions. | 
|
*/  | 
|
package javax.swing.text;  | 
|
import java.util.Vector;  | 
|
import java.awt.*;  | 
|
import javax.swing.event.*;  | 
|
import javax.swing.SwingConstants;  | 
|
/** | 
|
 * <code>CompositeView</code> is an abstract <code>View</code> | 
|
 * implementation which manages one or more child views. | 
|
 * (Note that <code>CompositeView</code> is intended | 
|
 * for managing relatively small numbers of child views.) | 
|
 * <code>CompositeView</code> is intended to be used as | 
|
 * a starting point for <code>View</code> implementations, | 
|
 * such as <code>BoxView</code>, that will contain child | 
|
 * <code>View</code>s. Subclasses that wish to manage the | 
|
 * collection of child <code>View</code>s should use the | 
|
 * {@link #replace} method.  As <code>View</code> invokes | 
|
 * <code>replace</code> during <code>DocumentListener</code> | 
|
 * notification, you normally won't need to directly | 
|
 * invoke <code>replace</code>. | 
|
 * | 
|
 * <p>While <code>CompositeView</code> | 
|
 * does not impose a layout policy on its child <code>View</code>s, | 
|
 * it does allow for inseting the child <code>View</code>s | 
|
 * it will contain.  The insets can be set by either | 
|
 * {@link #setInsets} or {@link #setParagraphInsets}. | 
|
 * | 
|
 * <p>In addition to the abstract methods of | 
|
 * {@link javax.swing.text.View}, | 
|
 * subclasses of <code>CompositeView</code> will need to | 
|
 * override: | 
|
 * <ul> | 
|
 * <li>{@link #isBefore} - Used to test if a given | 
|
 *     <code>View</code> location is before the visual space | 
|
 *     of the <code>CompositeView</code>. | 
|
 * <li>{@link #isAfter} - Used to test if a given | 
|
 *     <code>View</code> location is after the visual space | 
|
 *     of the <code>CompositeView</code>. | 
|
 * <li>{@link #getViewAtPoint} - Returns the view at | 
|
 *     a given visual location. | 
|
 * <li>{@link #childAllocation} - Returns the bounds of | 
|
 *     a particular child <code>View</code>. | 
|
 *     <code>getChildAllocation</code> will invoke | 
|
 *     <code>childAllocation</code> after offseting | 
|
 *     the bounds by the <code>Inset</code>s of the | 
|
 *     <code>CompositeView</code>. | 
|
 * </ul> | 
|
 * | 
|
 * @author  Timothy Prinzing | 
|
*/  | 
|
public abstract class CompositeView extends View {  | 
|
    /** | 
|
     * Constructs a <code>CompositeView</code> for the given element. | 
|
     * | 
|
     * @param elem  the element this view is responsible for | 
|
*/  | 
|
public CompositeView(Element elem) {  | 
|
super(elem);  | 
|
children = new View[1];  | 
|
nchildren = 0;  | 
|
childAlloc = new Rectangle();  | 
|
}  | 
|
    /** | 
|
     * Loads all of the children to initialize the view. | 
|
     * This is called by the {@link #setParent} | 
|
     * method.  Subclasses can reimplement this to initialize | 
|
     * their child views in a different manner.  The default | 
|
     * implementation creates a child view for each | 
|
     * child element. | 
|
     * | 
|
     * @param f the view factory | 
|
     * @see #setParent | 
|
*/  | 
|
protected void loadChildren(ViewFactory f) {  | 
|
if (f == null) {  | 
|
// No factory. This most likely indicates the parent view  | 
|
            // has changed out from under us, bail! | 
|
return;  | 
|
}  | 
|
Element e = getElement();  | 
|
int n = e.getElementCount();  | 
|
if (n > 0) {  | 
|
View[] added = new View[n];  | 
|
for (int i = 0; i < n; i++) {  | 
|
added[i] = f.create(e.getElement(i));  | 
|
}  | 
|
replace(0, 0, added);  | 
|
}  | 
|
}  | 
|
// --- View methods ---------------------------------------------  | 
|
    /** | 
|
     * Sets the parent of the view. | 
|
     * This is reimplemented to provide the superclass | 
|
     * behavior as well as calling the <code>loadChildren</code> | 
|
     * method if this view does not already have children. | 
|
     * The children should not be loaded in the | 
|
     * constructor because the act of setting the parent | 
|
     * may cause them to try to search up the hierarchy | 
|
     * (to get the hosting <code>Container</code> for example). | 
|
     * If this view has children (the view is being moved | 
|
     * from one place in the view hierarchy to another), | 
|
     * the <code>loadChildren</code> method will not be called. | 
|
     * | 
|
     * @param parent the parent of the view, <code>null</code> if none | 
|
*/  | 
|
public void setParent(View parent) {  | 
|
super.setParent(parent);  | 
|
if ((parent != null) && (nchildren == 0)) {  | 
|
ViewFactory f = getViewFactory();  | 
|
loadChildren(f);  | 
|
}  | 
|
}  | 
|
    /** | 
|
     * Returns the number of child views of this view. | 
|
     * | 
|
     * @return the number of views >= 0 | 
|
     * @see #getView | 
|
*/  | 
|
    public int getViewCount() { | 
|
return nchildren;  | 
|
}  | 
|
    /** | 
|
     * Returns the n-th view in this container. | 
|
     * | 
|
     * @param n the number of the desired view, >= 0 && < getViewCount() | 
|
     * @return the view at index <code>n</code> | 
|
*/  | 
|
public View getView(int n) {  | 
|
return children[n];  | 
|
}  | 
|
    /** | 
|
     * Replaces child views.  If there are no views to remove | 
|
     * this acts as an insert.  If there are no views to | 
|
     * add this acts as a remove.  Views being removed will | 
|
     * have the parent set to <code>null</code>, | 
|
     * and the internal reference to them removed so that they | 
|
     * may be garbage collected. | 
|
     * | 
|
     * @param offset the starting index into the child views to insert | 
|
     *   the new views; >= 0 and <= getViewCount | 
|
     * @param length the number of existing child views to remove; | 
|
     *   this should be a value >= 0 and <= (getViewCount() - offset) | 
|
     * @param views the child views to add; this value can be | 
|
     *  <code>null</code> | 
|
     *   to indicate no children are being added (useful to remove) | 
|
*/  | 
|
public void replace(int offset, int length, View[] views) {  | 
|
        // make sure an array exists | 
|
if (views == null) {  | 
|
views = ZERO;  | 
|
}  | 
|
        // update parent reference on removed views | 
|
for (int i = offset; i < offset + length; i++) {  | 
|
if (children[i].getParent() == this) {  | 
|
// in FlowView.java view might be referenced  | 
|
                // from two super-views as a child. see logicalView | 
|
children[i].setParent(null);  | 
|
}  | 
|
children[i] = null;  | 
|
}  | 
|
        // update the array | 
|
int delta = views.length - length;  | 
|
int src = offset + length;  | 
|
int nmove = nchildren - src;  | 
|
int dest = src + delta;  | 
|
if ((nchildren + delta) >= children.length) {  | 
|
            // need to grow the array | 
|
int newLength = Math.max(2*children.length, nchildren + delta);  | 
|
View[] newChildren = new View[newLength];  | 
|
System.arraycopy(children, 0, newChildren, 0, offset);  | 
|
System.arraycopy(views, 0, newChildren, offset, views.length);  | 
|
System.arraycopy(children, src, newChildren, dest, nmove);  | 
|
children = newChildren;  | 
|
        } else { | 
|
            // patch the existing array | 
|
System.arraycopy(children, src, children, dest, nmove);  | 
|
System.arraycopy(views, 0, children, offset, views.length);  | 
|
}  | 
|
nchildren = nchildren + delta;  | 
|
        // update parent reference on added views | 
|
for (int i = 0; i < views.length; i++) {  | 
|
views[i].setParent(this);  | 
|
}  | 
|
}  | 
|
    /** | 
|
     * Fetches the allocation for the given child view to | 
|
     * render into. This enables finding out where various views | 
|
     * are located. | 
|
     * | 
|
     * @param index the index of the child, >= 0 && < getViewCount() | 
|
     * @param a  the allocation to this view | 
|
     * @return the allocation to the child | 
|
*/  | 
|
public Shape getChildAllocation(int index, Shape a) {  | 
|
Rectangle alloc = getInsideAllocation(a);  | 
|
childAllocation(index, alloc);  | 
|
return alloc;  | 
|
}  | 
|
    /** | 
|
     * Provides a mapping from the document model coordinate space | 
|
     * to the coordinate space of the view mapped to it. | 
|
     * | 
|
     * @param pos the position to convert >= 0 | 
|
     * @param a the allocated region to render into | 
|
     * @param b a bias value of either <code>Position.Bias.Forward</code> | 
|
     *  or <code>Position.Bias.Backward</code> | 
|
     * @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 | 
|
*/  | 
|
public Shape modelToView(int pos, Shape a, Position.Bias b) throws BadLocationException {  | 
|
boolean isBackward = (b == Position.Bias.Backward);  | 
|
int testPos = (isBackward) ? Math.max(0, pos - 1) : pos;  | 
|
if(isBackward && testPos < getStartOffset()) {  | 
|
return null;  | 
|
}  | 
|
int vIndex = getViewIndexAtPosition(testPos);  | 
|
if ((vIndex != -1) && (vIndex < getViewCount())) {  | 
|
View v = getView(vIndex);  | 
|
if(v != null && testPos >= v.getStartOffset() &&  | 
|
testPos < v.getEndOffset()) {  | 
|
Shape childShape = getChildAllocation(vIndex, a);  | 
|
if (childShape == null) {  | 
|
                    // We are likely invalid, fail. | 
|
return null;  | 
|
}  | 
|
Shape retShape = v.modelToView(pos, childShape, b);  | 
|
if(retShape == null && v.getEndOffset() == pos) {  | 
|
if(++vIndex < getViewCount()) {  | 
|
v = getView(vIndex);  | 
|
retShape = v.modelToView(pos, getChildAllocation(vIndex, a), b);  | 
|
}  | 
|
}  | 
|
return retShape;  | 
|
}  | 
|
}  | 
|
throw new BadLocationException("Position not represented by view",  | 
|
pos);  | 
|
}  | 
|
    /** | 
|
     * Provides a mapping from the document model coordinate space | 
|
     * to the coordinate space of the view mapped to it. | 
|
     * | 
|
     * @param p0 the position to convert >= 0 | 
|
     * @param b0 the bias toward the previous character or the | 
|
     *  next character represented by p0, in case the | 
|
     *  position is a boundary of two views; either | 
|
     *  <code>Position.Bias.Forward</code> or | 
|
     *  <code>Position.Bias.Backward</code> | 
|
     * @param p1 the position to convert >= 0 | 
|
     * @param b1 the bias toward the previous character or the | 
|
     *  next character represented by p1, in case the | 
|
     *  position is a boundary of two views | 
|
     * @param a the allocated region to render into | 
|
     * @return the bounding box of the given position is returned | 
|
     * @exception BadLocationException  if the given position does | 
|
     *   not represent a valid location in the associated document | 
|
     * @exception IllegalArgumentException for an invalid bias argument | 
|
     * @see View#viewToModel | 
|
*/  | 
|
public Shape modelToView(int p0, Position.Bias b0, int p1, Position.Bias b1, Shape a) throws BadLocationException {  | 
|
if (p0 == getStartOffset() && p1 == getEndOffset()) {  | 
|
return a;  | 
|
}  | 
|
Rectangle alloc = getInsideAllocation(a);  | 
|
Rectangle r0 = new Rectangle(alloc);  | 
|
View v0 = getViewAtPosition((b0 == Position.Bias.Backward) ?  | 
|
Math.max(0, p0 - 1) : p0, r0);  | 
|
Rectangle r1 = new Rectangle(alloc);  | 
|
View v1 = getViewAtPosition((b1 == Position.Bias.Backward) ?  | 
|
Math.max(0, p1 - 1) : p1, r1);  | 
|
if (v0 == v1) {  | 
|
if (v0 == null) {  | 
|
return a;  | 
|
}  | 
|
            // Range contained in one view | 
|
return v0.modelToView(p0, b0, p1, b1, r0);  | 
|
}  | 
|
        // Straddles some views. | 
|
int viewCount = getViewCount();  | 
|
int counter = 0;  | 
|
while (counter < viewCount) {  | 
|
View v;  | 
|
// Views may not be in same order as model.  | 
|
// v0 or v1 may be null if there is a gap in the range this  | 
|
            // view contains. | 
|
if ((v = getView(counter)) == v0 || v == v1) {  | 
|
View endView;  | 
|
Rectangle retRect;  | 
|
Rectangle tempRect = new Rectangle();  | 
|
if (v == v0) {  | 
|
retRect = v0.modelToView(p0, b0, v0.getEndOffset(),  | 
|
Position.Bias.Backward, r0).  | 
|
getBounds();  | 
|
endView = v1;  | 
|
}  | 
|
                else { | 
|
retRect = v1.modelToView(v1.getStartOffset(),  | 
|
Position.Bias.Forward,  | 
|
p1, b1, r1).getBounds();  | 
|
endView = v0;  | 
|
}  | 
|
                // Views entirely covered by range. | 
|
while (++counter < viewCount &&  | 
|
(v = getView(counter)) != endView) {  | 
|
tempRect.setBounds(alloc);  | 
|
childAllocation(counter, tempRect);  | 
|
retRect.add(tempRect);  | 
|
}  | 
|
                // End view. | 
|
if (endView != null) {  | 
|
Shape endShape;  | 
|
if (endView == v1) {  | 
|
endShape = v1.modelToView(v1.getStartOffset(),  | 
|
Position.Bias.Forward,  | 
|
p1, b1, r1);  | 
|
}  | 
|
                    else { | 
|
endShape = v0.modelToView(p0, b0, v0.getEndOffset(),  | 
|
Position.Bias.Backward, r0);  | 
|
}  | 
|
if (endShape instanceof Rectangle) {  | 
|
retRect.add((Rectangle)endShape);  | 
|
}  | 
|
                    else { | 
|
retRect.add(endShape.getBounds());  | 
|
}  | 
|
}  | 
|
return retRect;  | 
|
}  | 
|
counter++;  | 
|
}  | 
|
throw new BadLocationException("Position not represented by view", p0);  | 
|
}  | 
|
    /** | 
|
     * 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 | 
|
     * @param bias either <code>Position.Bias.Forward</code> or | 
|
     *  <code>Position.Bias.Backward</code> | 
|
     * @return the location within the model that best represents the | 
|
     *  given point in the view >= 0 | 
|
     * @see View#viewToModel | 
|
*/  | 
|
public int viewToModel(float x, float y, Shape a, Position.Bias[] bias) {  | 
|
Rectangle alloc = getInsideAllocation(a);  | 
|
if (isBefore((int) x, (int) y, alloc)) {  | 
|
            // point is before the range represented | 
|
int retValue = -1;  | 
|
            try { | 
|
retValue = getNextVisualPositionFrom(-1, Position.Bias.Forward,  | 
|
a, EAST, bias);  | 
|
} catch (BadLocationException ble) { }  | 
|
catch (IllegalArgumentException iae) { }  | 
|
if(retValue == -1) {  | 
|
retValue = getStartOffset();  | 
|
bias[0] = Position.Bias.Forward;  | 
|
}  | 
|
return retValue;  | 
|
} else if (isAfter((int) x, (int) y, alloc)) {  | 
|
            // point is after the range represented. | 
|
int retValue = -1;  | 
|
            try { | 
|
retValue = getNextVisualPositionFrom(-1, Position.Bias.Forward,  | 
|
a, WEST, bias);  | 
|
} catch (BadLocationException ble) { }  | 
|
catch (IllegalArgumentException iae) { }  | 
|
if(retValue == -1) {  | 
|
                // NOTE: this could actually use end offset with backward. | 
|
retValue = getEndOffset() - 1;  | 
|
bias[0] = Position.Bias.Forward;  | 
|
}  | 
|
return retValue;  | 
|
        } else { | 
|
            // locate the child and pass along the request | 
|
View v = getViewAtPoint((int) x, (int) y, alloc);  | 
|
if (v != null) {  | 
|
return v.viewToModel(x, y, alloc, bias);  | 
|
}  | 
|
}  | 
|
return -1;  | 
|
}  | 
|
    /** | 
|
     * Provides a way to determine the next visually represented model | 
|
     * location that one might place a caret.  Some views may not be visible, | 
|
     * they might not be in the same order found in the model, or they just | 
|
     * might not allow access to some of the locations in the model. | 
|
     * This is a convenience method for {@link #getNextNorthSouthVisualPositionFrom} | 
|
     * and {@link #getNextEastWestVisualPositionFrom}. | 
|
     * This method enables specifying a position to convert | 
|
     * within the range of >=0.  If the value is -1, a position | 
|
     * will be calculated automatically.  If the value < -1, | 
|
     * the {@code BadLocationException} will be thrown. | 
|
     * | 
|
     * @param pos the position to convert | 
|
     * @param b a bias value of either <code>Position.Bias.Forward</code> | 
|
     *  or <code>Position.Bias.Backward</code> | 
|
     * @param a the allocated region to render into | 
|
     * @param direction the direction from the current position that can | 
|
     *  be thought of as the arrow keys typically found on a keyboard; | 
|
     *  this may be one of the following: | 
|
     *  <ul> | 
|
     *  <li><code>SwingConstants.WEST</code> | 
|
     *  <li><code>SwingConstants.EAST</code> | 
|
     *  <li><code>SwingConstants.NORTH</code> | 
|
     *  <li><code>SwingConstants.SOUTH</code> | 
|
     *  </ul> | 
|
     * @param biasRet an array containing the bias that was checked | 
|
     * @return the location within the model that best represents the next | 
|
     *  location visual position | 
|
     * @exception BadLocationException the given position is not a valid | 
|
     *                                 position within the document | 
|
     * @exception IllegalArgumentException if <code>direction</code> is invalid | 
|
*/  | 
|
public int getNextVisualPositionFrom(int pos, Position.Bias b, Shape a,  | 
|
int direction, Position.Bias[] biasRet)  | 
|
throws BadLocationException {  | 
|
if (pos < -1) {  | 
|
throw new BadLocationException("invalid position", pos);  | 
|
}  | 
|
Rectangle alloc = getInsideAllocation(a);  | 
|
switch (direction) {  | 
|
case NORTH:  | 
|
return getNextNorthSouthVisualPositionFrom(pos, b, a, direction,  | 
|
biasRet);  | 
|
case SOUTH:  | 
|
return getNextNorthSouthVisualPositionFrom(pos, b, a, direction,  | 
|
biasRet);  | 
|
case EAST:  | 
|
return getNextEastWestVisualPositionFrom(pos, b, a, direction,  | 
|
biasRet);  | 
|
case WEST:  | 
|
return getNextEastWestVisualPositionFrom(pos, b, a, direction,  | 
|
biasRet);  | 
|
default:  | 
|
throw new IllegalArgumentException("Bad direction: " + direction);  | 
|
}  | 
|
}  | 
|
    /** | 
|
     * Returns the child view index representing the given | 
|
     * position in the model.  This is implemented to call the | 
|
     * <code>getViewIndexByPosition</code> | 
|
     * method for backward compatibility. | 
|
     * | 
|
     * @param pos the position >= 0 | 
|
     * @return  index of the view representing the given position, or | 
|
     *   -1 if no view represents that position | 
|
     * @since 1.3 | 
|
*/  | 
|
public int getViewIndex(int pos, Position.Bias b) {  | 
|
if(b == Position.Bias.Backward) {  | 
|
pos -= 1;  | 
|
}  | 
|
if ((pos >= getStartOffset()) && (pos < getEndOffset())) {  | 
|
return getViewIndexAtPosition(pos);  | 
|
}  | 
|
return -1;  | 
|
}  | 
|
// --- local methods ----------------------------------------------------  | 
|
    /** | 
|
     * Tests whether a point lies before the rectangle range. | 
|
     * | 
|
     * @param x the X coordinate >= 0 | 
|
     * @param y the Y coordinate >= 0 | 
|
     * @param alloc the rectangle | 
|
     * @return true if the point is before the specified range | 
|
*/  | 
|
protected abstract boolean isBefore(int x, int y, Rectangle alloc);  | 
|
    /** | 
|
     * Tests whether a point lies after the rectangle range. | 
|
     * | 
|
     * @param x the X coordinate >= 0 | 
|
     * @param y the Y coordinate >= 0 | 
|
     * @param alloc the rectangle | 
|
     * @return true if the point is after the specified range | 
|
*/  | 
|
protected abstract boolean isAfter(int x, int y, 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 parent's allocation on entry, which should | 
|
     *   be changed to the child's allocation on exit | 
|
     * @return the child view | 
|
*/  | 
|
protected abstract View getViewAtPoint(int x, int y, Rectangle alloc);  | 
|
    /** | 
|
     * Returns the allocation for a given child. | 
|
     * | 
|
     * @param index the index of the child, >= 0 && < getViewCount() | 
|
     * @param a  the allocation to the interior of the box on entry, | 
|
     *   and the allocation of the child view at the index on exit. | 
|
*/  | 
|
protected abstract void childAllocation(int index, Rectangle a);  | 
|
    /** | 
|
     * Fetches the child view that represents the given position in | 
|
     * the model.  This is implemented to fetch the view in the case | 
|
     * where there is a child view for each child element. | 
|
     * | 
|
     * @param pos the position >= 0 | 
|
     * @param a  the allocation to the interior of the box on entry, | 
|
     *   and the allocation of the view containing the position on exit | 
|
     * @return  the view representing the given position, or | 
|
     *   <code>null</code> if there isn't one | 
|
*/  | 
|
protected View getViewAtPosition(int pos, Rectangle a) {  | 
|
int index = getViewIndexAtPosition(pos);  | 
|
if ((index >= 0) && (index < getViewCount())) {  | 
|
View v = getView(index);  | 
|
if (a != null) {  | 
|
childAllocation(index, a);  | 
|
}  | 
|
return v;  | 
|
}  | 
|
return null;  | 
|
}  | 
|
    /** | 
|
     * Fetches the child view index representing the given position in | 
|
     * the model.  This is implemented to fetch the view in the case | 
|
     * where there is a child view for each child element. | 
|
     * | 
|
     * @param pos the position >= 0 | 
|
     * @return  index of the view representing the given position, or | 
|
     *   -1 if no view represents that position | 
|
*/  | 
|
    protected int getViewIndexAtPosition(int pos) { | 
|
Element elem = getElement();  | 
|
return elem.getElementIndex(pos);  | 
|
}  | 
|
    /** | 
|
     * Translates the immutable allocation given to the view | 
|
     * to a mutable allocation that represents the interior | 
|
     * allocation (i.e. the bounds of the given allocation | 
|
     * with the top, left, bottom, and right insets removed. | 
|
     * It is expected that the returned value would be further | 
|
     * mutated to represent an allocation to a child view. | 
|
     * This is implemented to reuse an instance variable so | 
|
     * it avoids creating excessive Rectangles.  Typically | 
|
     * the result of calling this method would be fed to | 
|
     * the <code>childAllocation</code> method. | 
|
     * | 
|
     * @param a the allocation given to the view | 
|
     * @return the allocation that represents the inside of the | 
|
     *   view after the margins have all been removed; if the | 
|
     *   given allocation was <code>null</code>, | 
|
     *   the return value is <code>null</code> | 
|
*/  | 
|
protected Rectangle getInsideAllocation(Shape a) {  | 
|
if (a != null) {  | 
|
// get the bounds, hopefully without allocating  | 
|
// a new rectangle. The Shape argument should  | 
|
// not be modified... we copy it into the  | 
|
            // child allocation. | 
|
Rectangle alloc;  | 
|
if (a instanceof Rectangle) {  | 
|
alloc = (Rectangle) a;  | 
|
            } else { | 
|
alloc = a.getBounds();  | 
|
}  | 
|
childAlloc.setBounds(alloc);  | 
|
childAlloc.x += getLeftInset();  | 
|
childAlloc.y += getTopInset();  | 
|
childAlloc.width -= getLeftInset() + getRightInset();  | 
|
childAlloc.height -= getTopInset() + getBottomInset();  | 
|
return childAlloc;  | 
|
}  | 
|
return null;  | 
|
}  | 
|
    /** | 
|
     * Sets the insets from the paragraph attributes specified in | 
|
     * the given attributes. | 
|
     * | 
|
     * @param attr the attributes | 
|
*/  | 
|
protected void setParagraphInsets(AttributeSet attr) {  | 
|
// Since version 1.1 doesn't have scaling and assumes  | 
|
// a pixel is equal to a point, we just cast the point  | 
|
        // sizes to integers. | 
|
top = (short) StyleConstants.getSpaceAbove(attr);  | 
|
left = (short) StyleConstants.getLeftIndent(attr);  | 
|
bottom = (short) StyleConstants.getSpaceBelow(attr);  | 
|
right = (short) StyleConstants.getRightIndent(attr);  | 
|
}  | 
|
    /** | 
|
     * Sets the insets for the view. | 
|
     * | 
|
     * @param top the top inset >= 0 | 
|
     * @param left the left inset >= 0 | 
|
     * @param bottom the bottom inset >= 0 | 
|
     * @param right the right inset >= 0 | 
|
*/  | 
|
    protected void setInsets(short top, short left, short bottom, short right) { | 
|
this.top = top;  | 
|
this.left = left;  | 
|
this.right = right;  | 
|
this.bottom = bottom;  | 
|
}  | 
|
    /** | 
|
     * Gets the left inset. | 
|
     * | 
|
     * @return the inset >= 0 | 
|
*/  | 
|
    protected short getLeftInset() { | 
|
return left;  | 
|
}  | 
|
    /** | 
|
     * Gets the right inset. | 
|
     * | 
|
     * @return the inset >= 0 | 
|
*/  | 
|
    protected short getRightInset() { | 
|
return right;  | 
|
}  | 
|
    /** | 
|
     * Gets the top inset. | 
|
     * | 
|
     * @return the inset >= 0 | 
|
*/  | 
|
    protected short getTopInset() { | 
|
return top;  | 
|
}  | 
|
    /** | 
|
     * Gets the bottom inset. | 
|
     * | 
|
     * @return the inset >= 0 | 
|
*/  | 
|
    protected short getBottomInset() { | 
|
return bottom;  | 
|
}  | 
|
    /** | 
|
     * Returns the next visual position for the cursor, in either the | 
|
     * north or south direction. | 
|
     * | 
|
     * @param pos the position to convert >= 0 | 
|
     * @param b a bias value of either <code>Position.Bias.Forward</code> | 
|
     *  or <code>Position.Bias.Backward</code> | 
|
     * @param a the allocated region to render into | 
|
     * @param direction the direction from the current position that can | 
|
     *  be thought of as the arrow keys typically found on a keyboard; | 
|
     *  this may be one of the following: | 
|
     *  <ul> | 
|
     *  <li><code>SwingConstants.NORTH</code> | 
|
     *  <li><code>SwingConstants.SOUTH</code> | 
|
     *  </ul> | 
|
     * @param biasRet an array containing the bias that was checked | 
|
     * @return the location within the model that best represents the next | 
|
     *  north or south location | 
|
     * @exception BadLocationException | 
|
     * @exception IllegalArgumentException if <code>direction</code> is invalid | 
|
     * @see #getNextVisualPositionFrom | 
|
     * | 
|
     * @return the next position west of the passed in position | 
|
*/  | 
|
protected int getNextNorthSouthVisualPositionFrom(int pos, Position.Bias b,  | 
|
Shape a, int direction,  | 
|
Position.Bias[] biasRet)  | 
|
throws BadLocationException {  | 
|
return Utilities.getNextVisualPositionFrom(  | 
|
this, pos, b, a, direction, biasRet);  | 
|
}  | 
|
    /** | 
|
     * Returns the next visual position for the cursor, in either the | 
|
     * east or west direction. | 
|
     * | 
|
    * @param pos the position to convert >= 0 | 
|
     * @param b a bias value of either <code>Position.Bias.Forward</code> | 
|
     *  or <code>Position.Bias.Backward</code> | 
|
     * @param a the allocated region to render into | 
|
     * @param direction the direction from the current position that can | 
|
     *  be thought of as the arrow keys typically found on a keyboard; | 
|
     *  this may be one of the following: | 
|
     *  <ul> | 
|
     *  <li><code>SwingConstants.WEST</code> | 
|
     *  <li><code>SwingConstants.EAST</code> | 
|
     *  </ul> | 
|
     * @param biasRet an array containing the bias that was checked | 
|
     * @return the location within the model that best represents the next | 
|
     *  west or east location | 
|
     * @exception BadLocationException | 
|
     * @exception IllegalArgumentException if <code>direction</code> is invalid | 
|
     * @see #getNextVisualPositionFrom | 
|
*/  | 
|
protected int getNextEastWestVisualPositionFrom(int pos, Position.Bias b,  | 
|
Shape a,  | 
|
int direction,  | 
|
Position.Bias[] biasRet)  | 
|
throws BadLocationException {  | 
|
return Utilities.getNextVisualPositionFrom(  | 
|
this, pos, b, a, direction, biasRet);  | 
|
}  | 
|
    /** | 
|
     * Determines in which direction the next view lays. | 
|
     * Consider the <code>View</code> at index n. Typically the | 
|
     * <code>View</code>s are layed out from left to right, | 
|
     * so that the <code>View</code> to the EAST will be | 
|
     * at index n + 1, and the <code>View</code> to the WEST | 
|
     * will be at index n - 1. In certain situations, | 
|
     * such as with bidirectional text, it is possible | 
|
     * that the <code>View</code> to EAST is not at index n + 1, | 
|
     * but rather at index n - 1, or that the <code>View</code> | 
|
     * to the WEST is not at index n - 1, but index n + 1. | 
|
     * In this case this method would return true, indicating the | 
|
     * <code>View</code>s are layed out in descending order. | 
|
     * <p> | 
|
     * This unconditionally returns false, subclasses should override this | 
|
     * method if there is the possibility for laying <code>View</code>s in | 
|
     * descending order. | 
|
     * | 
|
     * @param position position into the model | 
|
     * @param bias either <code>Position.Bias.Forward</code> or | 
|
     *          <code>Position.Bias.Backward</code> | 
|
     * @return false | 
|
*/  | 
|
protected boolean flipEastAndWestAtEnds(int position,  | 
|
Position.Bias bias) {  | 
|
return false;  | 
|
}  | 
|
// ---- member variables ---------------------------------------------  | 
|
private static View[] ZERO = new View[0];  | 
|
private View[] children;  | 
|
private int nchildren;  | 
|
private short left;  | 
|
private short right;  | 
|
private short top;  | 
|
private short bottom;  | 
|
private Rectangle childAlloc;  | 
|
}  |