Source for javax.swing.text.BoxView

   1: /* BoxView.java -- An composite view
   2:    Copyright (C) 2005  Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package javax.swing.text;
  40: 
  41: import java.awt.Graphics;
  42: import java.awt.Rectangle;
  43: import java.awt.Shape;
  44: 
  45: import javax.swing.SizeRequirements;
  46: 
  47: /**
  48:  * An implementation of {@link CompositeView} that arranges its children in
  49:  * a box along one axis. This is comparable to how the <code>BoxLayout</code>
  50:  * works, but for <code>View</code> children.
  51:  *
  52:  * @author Roman Kennke (roman@kennke.org)
  53:  */
  54: public class BoxView
  55:   extends CompositeView
  56: {
  57: 
  58:   /**
  59:    * The axis along which this <code>BoxView</code> is laid out.
  60:    */
  61:   int myAxis;
  62: 
  63:   /**
  64:    * Indicates wether the layout in X_AXIS is valid.
  65:    */
  66:   boolean xLayoutValid;
  67: 
  68:   /**
  69:    * Indicates whether the layout in Y_AXIS is valid.
  70:    */
  71:   boolean yLayoutValid;
  72: 
  73:   /**
  74:    * The spans in X direction of the children.
  75:    */
  76:   int[] spansX;
  77: 
  78:   /**
  79:    * The spans in Y direction of the children.
  80:    */
  81:   int[] spansY;
  82: 
  83:   /**
  84:    * The offsets of the children in X direction relative to this BoxView's
  85:    * inner bounds.
  86:    */
  87:   int[] offsetsX;
  88: 
  89:   /**
  90:    * The offsets of the children in Y direction relative to this BoxView's
  91:    * inner bounds.
  92:    */
  93:   int[] offsetsY;
  94: 
  95:   /**
  96:    * The current width.
  97:    */
  98:   int width;
  99: 
 100:   /**
 101:    * The current height.
 102:    */
 103:   int height;
 104: 
 105:   /**
 106:    * Creates a new <code>BoxView</code> for the given
 107:    * <code>Element</code> and axis. Valid values for the axis are
 108:    * {@link View#X_AXIS} and {@link View#Y_AXIS}.
 109:    *
 110:    * @param element the element that is rendered by this BoxView
 111:    * @param axis the axis along which the box is laid out
 112:    */
 113:   public BoxView(Element element, int axis)
 114:   {
 115:     super(element);
 116:     myAxis = axis;
 117:     xLayoutValid = false;
 118:     yLayoutValid = false;
 119: 
 120:     // Initialize the cache arrays.
 121:     spansX = new int[0];
 122:     spansY = new int[0];
 123:     offsetsX = new int[0];
 124:     offsetsY = new int[0];
 125: 
 126:     width = 0;
 127:     height = 0;
 128:   }
 129: 
 130:   /**
 131:    * Returns the axis along which this <code>BoxView</code> is laid out.
 132:    *
 133:    * @return the axis along which this <code>BoxView</code> is laid out
 134:    */
 135:   public int getAxis()
 136:   {
 137:     return myAxis;
 138:   }
 139: 
 140:   /**
 141:    * Sets the axis along which this <code>BoxView</code> is laid out.
 142:    *
 143:    * Valid values for the axis are {@link View#X_AXIS} and
 144:    * {@link View#Y_AXIS}.
 145:    *
 146:    * @param axis the axis along which this <code>BoxView</code> is laid out
 147:    */
 148:   public void setAxis(int axis)
 149:   {
 150:     myAxis = axis;
 151:   }
 152: 
 153:   /**
 154:    * Marks the layout along the specified axis as invalid. This is triggered
 155:    * automatically when any of the child view changes its preferences
 156:    * via {@link #preferenceChanged(View, boolean, boolean)}.
 157:    *
 158:    * The layout will be updated the next time when 
 159:    * {@link #setSize(float, float)} is called, typically from within the 
 160:    * {@link #paint(Graphics, Shape)} method.
 161:    *
 162:    * Valid values for the axis are {@link View#X_AXIS} and
 163:    * {@link View#Y_AXIS}.
 164:    *
 165:    * @param axis an <code>int</code> value
 166:    */
 167:   public void layoutChanged(int axis)
 168:   {
 169:     switch (axis)
 170:       {
 171:       case X_AXIS:
 172:         xLayoutValid = false;
 173:         break;
 174:       case Y_AXIS:
 175:         yLayoutValid = false;
 176:         break;
 177:       default:
 178:         throw new IllegalArgumentException("Invalid axis parameter.");
 179:       }
 180:   }
 181: 
 182:   /**
 183:    * Returns <code>true</code> if the layout along the specified
 184:    * <code>axis</code> is valid, <code>false</code> otherwise.
 185:    *
 186:    * Valid values for the axis are {@link View#X_AXIS} and
 187:    * {@link View#Y_AXIS}.
 188:    *
 189:    * @param axis the axis
 190:    *
 191:    * @return <code>true</code> if the layout along the specified
 192:    *         <code>axis</code> is valid, <code>false</code> otherwise
 193:    */
 194:   protected boolean isLayoutValid(int axis)
 195:   {
 196:     boolean valid = false;
 197:     switch (axis)
 198:       {
 199:       case X_AXIS:
 200:         valid = xLayoutValid;
 201:         break;
 202:       case Y_AXIS:
 203:         valid = yLayoutValid;
 204:         break;
 205:       default:
 206:         throw new IllegalArgumentException("Invalid axis parameter.");
 207:       }
 208:     return valid;
 209:   }
 210: 
 211:   /**
 212:    * Paints the child <code>View</code> at the specified <code>index</code>.
 213:    * This method modifies the actual values in <code>alloc</code> so make
 214:    * sure you have a copy of the original values if you need them.
 215:    *
 216:    * @param g the <code>Graphics</code> context to paint to
 217:    * @param alloc the allocated region for the child to paint into
 218:    * @param index the index of the child to be painted
 219:    *
 220:    * @see #childAllocation(int, Rectangle)
 221:    */
 222:   protected void paintChild(Graphics g, Rectangle alloc, int index)
 223:   {
 224:     View child = getView(index);
 225:     child.paint(g, alloc);
 226:   }
 227: 
 228:   /**
 229:    * Replaces child views by some other child views. If there are no views to
 230:    * remove (<code>length == 0</code>), the result is a simple insert, if
 231:    * there are no children to add (<code>view == null</code>) the result
 232:    * is a simple removal.
 233:    *
 234:    * In addition this invalidates the layout and resizes the internal cache
 235:    * for the child allocations. The old children's cached allocations can
 236:    * still be accessed (although they are not guaranteed to be valid), and
 237:    * the new children will have an initial offset and span of 0.
 238:    *
 239:    * @param offset the start offset from where to remove children
 240:    * @param length the number of children to remove
 241:    * @param views the views that replace the removed children
 242:    */
 243:   public void replace(int offset, int length, View[] views)
 244:   {
 245:     // Resize and copy data for cache arrays.
 246:     // The spansX cache.
 247:     int oldSize = getViewCount();
 248: 
 249:     int[] newSpansX = new int[oldSize - length + views.length];
 250:     System.arraycopy(spansX, 0, newSpansX, 0, offset);
 251:     System.arraycopy(spansX, offset + length, newSpansX,
 252:                      offset + views.length,
 253:                      oldSize - (offset + length));
 254:     spansX = newSpansX;
 255: 
 256:     // The spansY cache.
 257:     int[] newSpansY = new int[oldSize - length + views.length];
 258:     System.arraycopy(spansY, 0, newSpansY, 0, offset);
 259:     System.arraycopy(spansY, offset + length, newSpansY,
 260:                      offset + views.length,
 261:                      oldSize - (offset + length));
 262:     spansY = newSpansY;
 263: 
 264:     // The offsetsX cache.
 265:     int[] newOffsetsX = new int[oldSize - length + views.length];
 266:     System.arraycopy(offsetsX, 0, newOffsetsX, 0, offset);
 267:     System.arraycopy(offsetsX, offset + length, newOffsetsX,
 268:                      offset + views.length,
 269:                      oldSize - (offset + length));
 270:     offsetsX = newOffsetsX;
 271: 
 272:     // The offsetsY cache.
 273:     int[] newOffsetsY = new int[oldSize - length + views.length];
 274:     System.arraycopy(offsetsY, 0, newOffsetsY, 0, offset);
 275:     System.arraycopy(offsetsY, offset + length, newOffsetsY,
 276:                      offset + views.length,
 277:                      oldSize - (offset + length));
 278:     offsetsY = newOffsetsY;
 279: 
 280:     // Actually perform the replace.
 281:     super.replace(offset, length, views);
 282: 
 283:     // Invalidate layout information.
 284:     layoutChanged(X_AXIS);
 285:     layoutChanged(Y_AXIS);
 286:   }
 287: 
 288:   /**
 289:    * Renders the <code>Element</code> that is associated with this
 290:    * <code>View</code>.
 291:    *
 292:    * @param g the <code>Graphics</code> context to render to
 293:    * @param a the allocated region for the <code>Element</code>
 294:    */
 295:   public void paint(Graphics g, Shape a)
 296:   {
 297:     // Adjust size if the size is changed.
 298:     Rectangle bounds = a.getBounds();
 299: 
 300:     if (bounds.width != getWidth() || bounds.height != getHeight())
 301:       setSize(bounds.width, bounds.height);
 302: 
 303:     Rectangle inside = getInsideAllocation(a);
 304:     Rectangle copy = new Rectangle(inside);
 305:     int count = getViewCount();
 306:     for (int i = 0; i < count; ++i)
 307:       {
 308:         copy.setBounds(inside);
 309:         childAllocation(i, copy);
 310:         if (!copy.isEmpty())
 311:           paintChild(g, copy, i);
 312:       }
 313:   }
 314: 
 315:   /**
 316:    * Returns the preferred span of the content managed by this
 317:    * <code>View</code> along the specified <code>axis</code>.
 318:    *
 319:    * @param axis the axis
 320:    *
 321:    * @return the preferred span of this <code>View</code>.
 322:    */
 323:   public float getPreferredSpan(int axis)
 324:   {
 325:     SizeRequirements sr = new SizeRequirements();
 326:     int pref = baselineRequirements(axis, sr).preferred;
 327:     return (float) pref;
 328:   }
 329: 
 330:   public float getMaximumSpan(int axis)
 331:   {
 332:     if (axis == getAxis())
 333:       return getPreferredSpan(axis);
 334:     else
 335:       return Integer.MAX_VALUE;
 336:   }
 337: 
 338:   /**
 339:    * Calculates the size requirements for this <code>BoxView</code> along
 340:    * the specified axis.
 341:    *
 342:    * @param axis the axis that is examined
 343:    * @param sr the <code>SizeRequirements</code> object to hold the result,
 344:    *        if <code>null</code>, a new one is created
 345:    *
 346:    * @return the size requirements for this <code>BoxView</code> along
 347:    *         the specified axis
 348:    */
 349:   protected SizeRequirements baselineRequirements(int axis,
 350:                                                   SizeRequirements sr)
 351:   {
 352:     SizeRequirements result;
 353:     if (axis == myAxis)
 354:       result = calculateMajorAxisRequirements(axis, sr);
 355:     else
 356:       result = calculateMinorAxisRequirements(axis, sr);
 357:     return result;
 358:   }
 359: 
 360:   /**
 361:    * Calculates the layout of the children of this <code>BoxView</code> along
 362:    * the specified axis.
 363:    *
 364:    * @param span the target span
 365:    * @param axis the axis that is examined
 366:    * @param offsets an empty array, filled with the offsets of the children
 367:    * @param spans an empty array, filled with the spans of the children
 368:    */
 369:   protected void baselineLayout(int span, int axis, int[] offsets,
 370:                                 int[] spans)
 371:   {
 372:     if (axis == myAxis)
 373:       layoutMajorAxis(span, axis, offsets, spans);
 374:     else
 375:       layoutMinorAxis(span, axis, offsets, spans);
 376:   }
 377: 
 378:   /**
 379:    * Calculates the size requirements of this <code>BoxView</code> along
 380:    * its major axis, that is the axis specified in the constructor.
 381:    *
 382:    * @param axis the axis that is examined
 383:    * @param sr the <code>SizeRequirements</code> object to hold the result,
 384:    *        if <code>null</code>, a new one is created
 385:    *
 386:    * @return the size requirements for this <code>BoxView</code> along
 387:    *         the specified axis
 388:    */
 389:   protected SizeRequirements calculateMajorAxisRequirements(int axis,
 390:                                                            SizeRequirements sr)
 391:   {
 392:     SizeRequirements[] childReqs = getChildRequirements(axis);
 393:     return SizeRequirements.getTiledSizeRequirements(childReqs);
 394:   }
 395: 
 396:   /**
 397:    * Calculates the size requirements of this <code>BoxView</code> along
 398:    * its minor axis, that is the axis opposite to the axis specified in the
 399:    * constructor.
 400:    *
 401:    * @param axis the axis that is examined
 402:    * @param sr the <code>SizeRequirements</code> object to hold the result,
 403:    *        if <code>null</code>, a new one is created
 404:    *
 405:    * @return the size requirements for this <code>BoxView</code> along
 406:    *         the specified axis
 407:    */
 408:   protected SizeRequirements calculateMinorAxisRequirements(int axis,
 409:                                                            SizeRequirements sr)
 410:   {
 411:     SizeRequirements[] childReqs = getChildRequirements(axis);
 412:     return SizeRequirements.getAlignedSizeRequirements(childReqs);
 413:   }
 414: 
 415:   /**
 416:    * Returns <code>true</code> if the specified point lies before the
 417:    * given <code>Rectangle</code>, <code>false</code> otherwise.
 418:    *
 419:    * &quot;Before&quot; is typically defined as being to the left or above.
 420:    *
 421:    * @param x the X coordinate of the point
 422:    * @param y the Y coordinate of the point
 423:    * @param r the rectangle to test the point against
 424:    *
 425:    * @return <code>true</code> if the specified point lies before the
 426:    *         given <code>Rectangle</code>, <code>false</code> otherwise
 427:    */
 428:   protected boolean isBefore(int x, int y, Rectangle r)
 429:   {
 430:     boolean result = false;
 431: 
 432:     if (myAxis == X_AXIS)
 433:       result = x < r.x;
 434:     else
 435:       result = y < r.y;
 436: 
 437:     return result;
 438:   }
 439: 
 440:   /**
 441:    * Returns <code>true</code> if the specified point lies after the
 442:    * given <code>Rectangle</code>, <code>false</code> otherwise.
 443:    *
 444:    * &quot;After&quot; is typically defined as being to the right or below.
 445:    *
 446:    * @param x the X coordinate of the point
 447:    * @param y the Y coordinate of the point
 448:    * @param r the rectangle to test the point against
 449:    *
 450:    * @return <code>true</code> if the specified point lies after the
 451:    *         given <code>Rectangle</code>, <code>false</code> otherwise
 452:    */
 453:   protected boolean isAfter(int x, int y, Rectangle r)
 454:   {
 455:     boolean result = false;
 456: 
 457:     if (myAxis == X_AXIS)
 458:       result = x > r.x;
 459:     else
 460:       result = y > r.y;
 461: 
 462:     return result;
 463:   }
 464: 
 465:   /**
 466:    * Returns the child <code>View</code> at the specified location.
 467:    *
 468:    * @param x the X coordinate
 469:    * @param y the Y coordinate
 470:    * @param r the inner allocation of this <code>BoxView</code> on entry,
 471:    *        the allocation of the found child on exit
 472:    *
 473:    * @return the child <code>View</code> at the specified location
 474:    */
 475:   protected View getViewAtPoint(int x, int y, Rectangle r)
 476:   {
 477:     View result = null;
 478: 
 479:     int count = getViewCount();
 480:     Rectangle copy = new Rectangle(r);
 481: 
 482:     for (int i = 0; i < count; ++i)
 483:       {
 484:         copy.setBounds(r);
 485:         childAllocation(i, r);
 486:         if (copy.contains(x, y))
 487:           {
 488:             result = getView(i);
 489:             break;
 490:           }
 491:       }
 492: 
 493:     return result;
 494:   }
 495: 
 496:   /**
 497:    * Computes the allocation for a child <code>View</code>. The parameter
 498:    * <code>a</code> stores the allocation of this <code>CompositeView</code>
 499:    * and is then adjusted to hold the allocation of the child view.
 500:    *
 501:    * @param index the index of the child <code>View</code>
 502:    * @param a the allocation of this <code>CompositeView</code> before the
 503:    *        call, the allocation of the child on exit
 504:    */
 505:   protected void childAllocation(int index, Rectangle a)
 506:   {
 507:     if (! isAllocationValid())
 508:       layout(a.width, a.height);
 509: 
 510:     a.x += offsetsX[index];
 511:     a.y += offsetsY[index];
 512:     a.width = spansX[index];
 513:     a.height = spansY[index];
 514:   }
 515: 
 516:   /**
 517:    * Lays out the children of this <code>BoxView</code> with the specified
 518:    * bounds.
 519:    *
 520:    * @param width the width of the allocated region for the children (that
 521:    *        is the inner allocation of this <code>BoxView</code>
 522:    * @param height the height of the allocated region for the children (that
 523:    *        is the inner allocation of this <code>BoxView</code>
 524:    */
 525:   protected void layout(int width, int height)
 526:   {
 527:     baselineLayout(width, X_AXIS, offsetsX, spansX);
 528:     baselineLayout(height, Y_AXIS, offsetsY, spansY);
 529:   }
 530: 
 531:   /**
 532:    * Performs the layout along the major axis of a <code>BoxView</code>.
 533:    *
 534:    * @param targetSpan the (inner) span of the <code>BoxView</code> in which
 535:    *        to layout the children
 536:    * @param axis the axis along which the layout is performed
 537:    * @param offsets the array that holds the offsets of the children on exit
 538:    * @param spans the array that holds the spans of the children on exit
 539:    */
 540:   protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets,
 541:                                  int[] spans)
 542:   {
 543:     SizeRequirements[] childReqs = getChildRequirements(axis);
 544:     // Calculate the spans and offsets using the SizeRequirements uility
 545:     // methods.
 546:     SizeRequirements.calculateTiledPositions(targetSpan, null, childReqs,
 547:                                              offsets, spans);
 548:     validateLayout(axis);
 549:   }
 550: 
 551:   /**
 552:    * Performs the layout along the minor axis of a <code>BoxView</code>.
 553:    *
 554:    * @param targetSpan the (inner) span of the <code>BoxView</code> in which
 555:    *        to layout the children
 556:    * @param axis the axis along which the layout is performed
 557:    * @param offsets the array that holds the offsets of the children on exit
 558:    * @param spans the array that holds the spans of the children on exit
 559:    */
 560:   protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets,
 561:                                  int[] spans)
 562:   {
 563:     SizeRequirements[] childReqs = getChildRequirements(axis);
 564:     // Calculate the spans and offsets using the SizeRequirements uility
 565:     // methods.
 566:     // TODO: This might be an opportunity for performance optimization. Here
 567:     // we could use a cached instance of SizeRequirements instead of passing
 568:     // null to baselineRequirements. However, this would involve rewriting
 569:     // the baselineRequirements() method to not use the SizeRequirements
 570:     // utility method, since they cannot reuse a cached instance.
 571:     SizeRequirements total = baselineRequirements(axis, null);
 572:     SizeRequirements.calculateAlignedPositions(targetSpan, total, childReqs,
 573:                                                offsets, spans);
 574:     validateLayout(axis);
 575:   }
 576: 
 577:   /**
 578:    * Returns <code>true</code> if the cached allocations for the children
 579:    * are still valid, <code>false</code> otherwise.
 580:    *
 581:    * @return <code>true</code> if the cached allocations for the children
 582:    *         are still valid, <code>false</code> otherwise
 583:    */
 584:   protected boolean isAllocationValid()
 585:   {
 586:     return isLayoutValid(X_AXIS) && isLayoutValid(Y_AXIS);
 587:   }
 588: 
 589:   /**
 590:    * Return the current width of the box. This is the last allocated width.
 591:    *
 592:    * @return the current width of the box
 593:    */
 594:   public int getWidth()
 595:   {
 596:     return width;
 597:   }
 598: 
 599:   /**
 600:    * Return the current height of the box. This is the last allocated height.
 601:    *
 602:    * @return the current height of the box
 603:    */
 604:   public int getHeight()
 605:   {
 606:     return height;
 607:   }
 608: 
 609:   /**
 610:    * Sets the size of the view. If the actual size has changed, the layout
 611:    * is updated accordingly.
 612:    *
 613:    * @param width the new width
 614:    * @param height the new height
 615:    */
 616:   public void setSize(float width, float height)
 617:   {
 618:     if (this.width != (int) width)
 619:       layoutChanged(X_AXIS);
 620:     if (this.height != (int) height)
 621:       layoutChanged(Y_AXIS);
 622:     
 623:     this.width = (int) width;
 624:     this.height = (int) height;
 625: 
 626:     Rectangle outside = new Rectangle(0, 0, this.width, this.height);
 627:     Rectangle inside = getInsideAllocation(outside);
 628:     if (!isAllocationValid())
 629:       layout(inside.width, inside.height);
 630:   }
 631: 
 632:   /**
 633:    * Sets the layout to valid for a specific axis.
 634:    *
 635:    * @param axis the axis for which to validate the layout
 636:    */
 637:   void validateLayout(int axis)
 638:   {
 639:     if (axis == X_AXIS)
 640:       xLayoutValid = true;
 641:     if (axis == Y_AXIS)
 642:       yLayoutValid = true;
 643:   }
 644: 
 645:   /**
 646:    * Returns the size requirements of this view's children for the major
 647:    * axis.
 648:    *
 649:    * @return the size requirements of this view's children for the major
 650:    *         axis
 651:    */
 652:   SizeRequirements[] getChildRequirements(int axis)
 653:   {
 654:     // Allocate SizeRequirements for each child view.
 655:     int count = getViewCount();
 656:     SizeRequirements[] childReqs = new SizeRequirements[count];
 657:     for (int i = 0; i < count; ++i)
 658:       {
 659:         View view = getView(i);
 660:         childReqs[i] = new SizeRequirements((int) view.getMinimumSpan(axis),
 661:                                             (int) view.getPreferredSpan(axis),
 662:                                             (int) view.getMaximumSpan(axis),
 663:                                             view.getAlignment(axis));
 664:       }
 665:     return childReqs;
 666:   }
 667: 
 668:   /**
 669:    * Returns the span for the child view with the given index for the specified
 670:    * axis.
 671:    *
 672:    * @param axis the axis to examine, either <code>X_AXIS</code> or
 673:    *        <code>Y_AXIS</code>
 674:    * @param childIndex the index of the child for for which to return the span
 675:    *
 676:    * @return the span for the child view with the given index for the specified
 677:    *         axis
 678:    */
 679:   protected int getSpan(int axis, int childIndex)
 680:   {
 681:     if (axis == X_AXIS)
 682:       return spansX[childIndex];
 683:     else
 684:       return spansY[childIndex];
 685:   }
 686: 
 687:   /**
 688:    * Returns the offset for the child view with the given index for the
 689:    * specified axis.
 690:    *
 691:    * @param axis the axis to examine, either <code>X_AXIS</code> or
 692:    *        <code>Y_AXIS</code>
 693:    * @param childIndex the index of the child for for which to return the span
 694:    *
 695:    * @return the offset for the child view with the given index for the
 696:    *         specified axis
 697:    */
 698:   protected int getOffset(int axis, int childIndex)
 699:   {
 700:     if (axis == X_AXIS)
 701:       return offsetsX[childIndex];
 702:     else
 703:       return offsetsY[childIndex];
 704:   }
 705: 
 706:   /**
 707:    * Returns the alignment for this box view for the specified axis. The
 708:    * axis that is tiled (the major axis) will be requested to be aligned
 709:    * centered (0.5F). The minor axis alignment depends on the child view's
 710:    * total alignment.
 711:    *
 712:    * @param axis the axis which is examined
 713:    *
 714:    * @return the alignment for this box view for the specified axis
 715:    */
 716:   public float getAlignment(int axis)
 717:   {
 718:     if (axis == myAxis)
 719:       return 0.5F;
 720:     else
 721:       return baselineRequirements(axis, null).alignment;
 722:   }
 723:   
 724:   /**
 725:    * Called by a child View when its preferred span has changed.
 726:    * 
 727:    * @param width indicates that the preferred width of the child changed.
 728:    * @param height indicates that the preferred height of the child changed.
 729:    * @param child the child View. 
 730:    */
 731:   public void preferenceChanged (View child, boolean width, boolean height)
 732:   {
 733:     if (width)
 734:       xLayoutValid = false;
 735:     if (height)
 736:       yLayoutValid = false;
 737:     super.preferenceChanged(child, width, height);
 738:   }
 739: }