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:             && g.hitClip(copy.x, copy.y, copy.width, copy.height))
 312:           paintChild(g, copy, i);
 313:       }
 314:   }
 315: 
 316:   /**
 317:    * Returns the preferred span of the content managed by this
 318:    * <code>View</code> along the specified <code>axis</code>.
 319:    *
 320:    * @param axis the axis
 321:    *
 322:    * @return the preferred span of this <code>View</code>.
 323:    */
 324:   public float getPreferredSpan(int axis)
 325:   {
 326:     SizeRequirements sr = new SizeRequirements();
 327:     int pref = baselineRequirements(axis, sr).preferred;
 328:     return (float) pref;
 329:   }
 330: 
 331:   public float getMaximumSpan(int axis)
 332:   {
 333:     if (axis == getAxis())
 334:       return getPreferredSpan(axis);
 335:     else
 336:       return Integer.MAX_VALUE;
 337:   }
 338: 
 339:   /**
 340:    * Calculates the size requirements for this <code>BoxView</code> along
 341:    * the specified axis.
 342:    *
 343:    * @param axis the axis that is examined
 344:    * @param sr the <code>SizeRequirements</code> object to hold the result,
 345:    *        if <code>null</code>, a new one is created
 346:    *
 347:    * @return the size requirements for this <code>BoxView</code> along
 348:    *         the specified axis
 349:    */
 350:   protected SizeRequirements baselineRequirements(int axis,
 351:                                                   SizeRequirements sr)
 352:   {
 353:     SizeRequirements result;
 354:     if (axis == myAxis)
 355:       result = calculateMajorAxisRequirements(axis, sr);
 356:     else
 357:       result = calculateMinorAxisRequirements(axis, sr);
 358:     return result;
 359:   }
 360: 
 361:   /**
 362:    * Calculates the layout of the children of this <code>BoxView</code> along
 363:    * the specified axis.
 364:    *
 365:    * @param span the target span
 366:    * @param axis the axis that is examined
 367:    * @param offsets an empty array, filled with the offsets of the children
 368:    * @param spans an empty array, filled with the spans of the children
 369:    */
 370:   protected void baselineLayout(int span, int axis, int[] offsets,
 371:                                 int[] spans)
 372:   {
 373:     if (axis == myAxis)
 374:       layoutMajorAxis(span, axis, offsets, spans);
 375:     else
 376:       layoutMinorAxis(span, axis, offsets, spans);
 377:   }
 378: 
 379:   /**
 380:    * Calculates the size requirements of this <code>BoxView</code> along
 381:    * its major axis, that is the axis specified in the constructor.
 382:    *
 383:    * @param axis the axis that is examined
 384:    * @param sr the <code>SizeRequirements</code> object to hold the result,
 385:    *        if <code>null</code>, a new one is created
 386:    *
 387:    * @return the size requirements for this <code>BoxView</code> along
 388:    *         the specified axis
 389:    */
 390:   protected SizeRequirements calculateMajorAxisRequirements(int axis,
 391:                                                            SizeRequirements sr)
 392:   {
 393:     SizeRequirements[] childReqs = getChildRequirements(axis);
 394:     return SizeRequirements.getTiledSizeRequirements(childReqs);
 395:   }
 396: 
 397:   /**
 398:    * Calculates the size requirements of this <code>BoxView</code> along
 399:    * its minor axis, that is the axis opposite to the axis specified in the
 400:    * constructor.
 401:    *
 402:    * @param axis the axis that is examined
 403:    * @param sr the <code>SizeRequirements</code> object to hold the result,
 404:    *        if <code>null</code>, a new one is created
 405:    *
 406:    * @return the size requirements for this <code>BoxView</code> along
 407:    *         the specified axis
 408:    */
 409:   protected SizeRequirements calculateMinorAxisRequirements(int axis,
 410:                                                            SizeRequirements sr)
 411:   {
 412:     SizeRequirements[] childReqs = getChildRequirements(axis);
 413:     return SizeRequirements.getAlignedSizeRequirements(childReqs);
 414:   }
 415: 
 416:   /**
 417:    * Returns <code>true</code> if the specified point lies before the
 418:    * given <code>Rectangle</code>, <code>false</code> otherwise.
 419:    *
 420:    * &quot;Before&quot; is typically defined as being to the left or above.
 421:    *
 422:    * @param x the X coordinate of the point
 423:    * @param y the Y coordinate of the point
 424:    * @param r the rectangle to test the point against
 425:    *
 426:    * @return <code>true</code> if the specified point lies before the
 427:    *         given <code>Rectangle</code>, <code>false</code> otherwise
 428:    */
 429:   protected boolean isBefore(int x, int y, Rectangle r)
 430:   {
 431:     boolean result = false;
 432: 
 433:     if (myAxis == X_AXIS)
 434:       result = x < r.x;
 435:     else
 436:       result = y < r.y;
 437: 
 438:     return result;
 439:   }
 440: 
 441:   /**
 442:    * Returns <code>true</code> if the specified point lies after the
 443:    * given <code>Rectangle</code>, <code>false</code> otherwise.
 444:    *
 445:    * &quot;After&quot; is typically defined as being to the right or below.
 446:    *
 447:    * @param x the X coordinate of the point
 448:    * @param y the Y coordinate of the point
 449:    * @param r the rectangle to test the point against
 450:    *
 451:    * @return <code>true</code> if the specified point lies after the
 452:    *         given <code>Rectangle</code>, <code>false</code> otherwise
 453:    */
 454:   protected boolean isAfter(int x, int y, Rectangle r)
 455:   {
 456:     boolean result = false;
 457: 
 458:     if (myAxis == X_AXIS)
 459:       result = x > r.x;
 460:     else
 461:       result = y > r.y;
 462: 
 463:     return result;
 464:   }
 465: 
 466:   /**
 467:    * Returns the child <code>View</code> at the specified location.
 468:    *
 469:    * @param x the X coordinate
 470:    * @param y the Y coordinate
 471:    * @param r the inner allocation of this <code>BoxView</code> on entry,
 472:    *        the allocation of the found child on exit
 473:    *
 474:    * @return the child <code>View</code> at the specified location
 475:    */
 476:   protected View getViewAtPoint(int x, int y, Rectangle r)
 477:   {
 478:     View result = null;
 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:     if (result == null && count > 0)
 494:       return getView(count - 1);
 495:     return result;
 496:   }
 497: 
 498:   /**
 499:    * Computes the allocation for a child <code>View</code>. The parameter
 500:    * <code>a</code> stores the allocation of this <code>CompositeView</code>
 501:    * and is then adjusted to hold the allocation of the child view.
 502:    * 
 503:    * @param index
 504:    *          the index of the child <code>View</code>
 505:    * @param a
 506:    *          the allocation of this <code>CompositeView</code> before the
 507:    *          call, the allocation of the child on exit
 508:    */
 509:   protected void childAllocation(int index, Rectangle a)
 510:   {
 511:     if (! isAllocationValid())
 512:       layout(a.width, a.height);
 513: 
 514:     a.x += offsetsX[index];
 515:     a.y += offsetsY[index];
 516:     a.width = spansX[index];
 517:     a.height = spansY[index];
 518:   }
 519: 
 520:   /**
 521:    * Lays out the children of this <code>BoxView</code> with the specified
 522:    * bounds.
 523:    *
 524:    * @param width the width of the allocated region for the children (that
 525:    *        is the inner allocation of this <code>BoxView</code>
 526:    * @param height the height of the allocated region for the children (that
 527:    *        is the inner allocation of this <code>BoxView</code>
 528:    */
 529:   protected void layout(int width, int height)
 530:   {
 531:     baselineLayout(width, X_AXIS, offsetsX, spansX);
 532:     baselineLayout(height, Y_AXIS, offsetsY, spansY);
 533:   }
 534: 
 535:   /**
 536:    * Performs the layout along the major axis of a <code>BoxView</code>.
 537:    *
 538:    * @param targetSpan the (inner) span of the <code>BoxView</code> in which
 539:    *        to layout the children
 540:    * @param axis the axis along which the layout is performed
 541:    * @param offsets the array that holds the offsets of the children on exit
 542:    * @param spans the array that holds the spans of the children on exit
 543:    */
 544:   protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets,
 545:                                  int[] spans)
 546:   {
 547:     SizeRequirements[] childReqs = getChildRequirements(axis);
 548:     // Calculate the spans and offsets using the SizeRequirements uility
 549:     // methods.
 550:     SizeRequirements.calculateTiledPositions(targetSpan, null, childReqs,
 551:                                              offsets, spans);
 552:     validateLayout(axis);
 553:   }
 554: 
 555:   /**
 556:    * Performs the layout along the minor axis of a <code>BoxView</code>.
 557:    *
 558:    * @param targetSpan the (inner) span of the <code>BoxView</code> in which
 559:    *        to layout the children
 560:    * @param axis the axis along which the layout is performed
 561:    * @param offsets the array that holds the offsets of the children on exit
 562:    * @param spans the array that holds the spans of the children on exit
 563:    */
 564:   protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets,
 565:                                  int[] spans)
 566:   {
 567:     SizeRequirements[] childReqs = getChildRequirements(axis);
 568:     // Calculate the spans and offsets using the SizeRequirements uility
 569:     // methods.
 570:     // TODO: This might be an opportunity for performance optimization. Here
 571:     // we could use a cached instance of SizeRequirements instead of passing
 572:     // null to baselineRequirements. However, this would involve rewriting
 573:     // the baselineRequirements() method to not use the SizeRequirements
 574:     // utility method, since they cannot reuse a cached instance.
 575:     SizeRequirements total = baselineRequirements(axis, null);
 576:     SizeRequirements.calculateAlignedPositions(targetSpan, total, childReqs,
 577:                                                offsets, spans);
 578:     validateLayout(axis);
 579:   }
 580: 
 581:   /**
 582:    * Returns <code>true</code> if the cached allocations for the children
 583:    * are still valid, <code>false</code> otherwise.
 584:    *
 585:    * @return <code>true</code> if the cached allocations for the children
 586:    *         are still valid, <code>false</code> otherwise
 587:    */
 588:   protected boolean isAllocationValid()
 589:   {
 590:     return isLayoutValid(X_AXIS) && isLayoutValid(Y_AXIS);
 591:   }
 592: 
 593:   /**
 594:    * Return the current width of the box. This is the last allocated width.
 595:    *
 596:    * @return the current width of the box
 597:    */
 598:   public int getWidth()
 599:   {
 600:     return width;
 601:   }
 602: 
 603:   /**
 604:    * Return the current height of the box. This is the last allocated height.
 605:    *
 606:    * @return the current height of the box
 607:    */
 608:   public int getHeight()
 609:   {
 610:     return height;
 611:   }
 612: 
 613:   /**
 614:    * Sets the size of the view. If the actual size has changed, the layout
 615:    * is updated accordingly.
 616:    *
 617:    * @param width the new width
 618:    * @param height the new height
 619:    */
 620:   public void setSize(float width, float height)
 621:   {
 622:     if (this.width != (int) width)
 623:       layoutChanged(X_AXIS);
 624:     if (this.height != (int) height)
 625:       layoutChanged(Y_AXIS);
 626:     
 627:     this.width = (int) width;
 628:     this.height = (int) height;
 629: 
 630:     Rectangle outside = new Rectangle(0, 0, this.width, this.height);
 631:     Rectangle inside = getInsideAllocation(outside);
 632:     if (!isAllocationValid())
 633:       layout(inside.width, inside.height);
 634:   }
 635: 
 636:   /**
 637:    * Sets the layout to valid for a specific axis.
 638:    *
 639:    * @param axis the axis for which to validate the layout
 640:    */
 641:   void validateLayout(int axis)
 642:   {
 643:     if (axis == X_AXIS)
 644:       xLayoutValid = true;
 645:     if (axis == Y_AXIS)
 646:       yLayoutValid = true;
 647:   }
 648: 
 649:   /**
 650:    * Returns the size requirements of this view's children for the major
 651:    * axis.
 652:    *
 653:    * @return the size requirements of this view's children for the major
 654:    *         axis
 655:    */
 656:   SizeRequirements[] getChildRequirements(int axis)
 657:   {
 658:     // Allocate SizeRequirements for each child view.
 659:     int count = getViewCount();
 660:     SizeRequirements[] childReqs = new SizeRequirements[count];
 661:     for (int i = 0; i < count; ++i)
 662:       {
 663:         View view = getView(i);
 664:         childReqs[i] = new SizeRequirements((int) view.getMinimumSpan(axis),
 665:                                             (int) view.getPreferredSpan(axis),
 666:                                             (int) view.getMaximumSpan(axis),
 667:                                             view.getAlignment(axis));
 668:       }
 669:     return childReqs;
 670:   }
 671: 
 672:   /**
 673:    * Returns the span for the child view with the given index for the specified
 674:    * axis.
 675:    *
 676:    * @param axis the axis to examine, either <code>X_AXIS</code> or
 677:    *        <code>Y_AXIS</code>
 678:    * @param childIndex the index of the child for for which to return the span
 679:    *
 680:    * @return the span for the child view with the given index for the specified
 681:    *         axis
 682:    */
 683:   protected int getSpan(int axis, int childIndex)
 684:   {
 685:     if (axis == X_AXIS)
 686:       return spansX[childIndex];
 687:     else
 688:       return spansY[childIndex];
 689:   }
 690: 
 691:   /**
 692:    * Returns the offset for the child view with the given index for the
 693:    * specified axis.
 694:    *
 695:    * @param axis the axis to examine, either <code>X_AXIS</code> or
 696:    *        <code>Y_AXIS</code>
 697:    * @param childIndex the index of the child for for which to return the span
 698:    *
 699:    * @return the offset for the child view with the given index for the
 700:    *         specified axis
 701:    */
 702:   protected int getOffset(int axis, int childIndex)
 703:   {
 704:     if (axis == X_AXIS)
 705:       return offsetsX[childIndex];
 706:     else
 707:       return offsetsY[childIndex];
 708:   }
 709: 
 710:   /**
 711:    * Returns the alignment for this box view for the specified axis. The
 712:    * axis that is tiled (the major axis) will be requested to be aligned
 713:    * centered (0.5F). The minor axis alignment depends on the child view's
 714:    * total alignment.
 715:    *
 716:    * @param axis the axis which is examined
 717:    *
 718:    * @return the alignment for this box view for the specified axis
 719:    */
 720:   public float getAlignment(int axis)
 721:   {
 722:     if (axis == myAxis)
 723:       return 0.5F;
 724:     else
 725:       return baselineRequirements(axis, null).alignment;
 726:   }
 727:   
 728:   /**
 729:    * Called by a child View when its preferred span has changed.
 730:    * 
 731:    * @param width indicates that the preferred width of the child changed.
 732:    * @param height indicates that the preferred height of the child changed.
 733:    * @param child the child View. 
 734:    */
 735:   public void preferenceChanged (View child, boolean width, boolean height)
 736:   {
 737:     if (width)
 738:       xLayoutValid = false;
 739:     if (height)
 740:       yLayoutValid = false;
 741:     super.preferenceChanged(child, width, height);
 742:   }
 743:   
 744:   /**
 745:    * Maps the document model position <code>pos</code> to a Shape
 746:    * in the view coordinate space.  This method overrides CompositeView's
 747:    * method to make sure the children are allocated properly before
 748:    * calling the super's behaviour.
 749:    */
 750:   public Shape modelToView(int pos, Shape a, Position.Bias bias)
 751:       throws BadLocationException
 752:   {
 753:     // Make sure everything is allocated properly and then call super
 754:     if (!isAllocationValid())
 755:       {
 756:         Rectangle bounds = a.getBounds();
 757:         setSize(bounds.width, bounds.height);
 758:       }
 759:     return super.modelToView(pos, a, bias);
 760:   }
 761: }