--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/javax/swing/text/CompositeView.java Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,794 @@
+/*
+ * Copyright 1997-2006 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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}.
+ *
+ * @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>
+ * <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
+ * @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 {
+ 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;
+}