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 {@link #setSize()} is
 159:    * called, typically from within the {@link #paint()} method.
 160:    *
 161:    * Valid values for the axis are {@link View#X_AXIS} and
 162:    * {@link View#Y_AXIS}.
 163:    *
 164:    * @param axis an <code>int</code> value
 165:    */
 166:   public void layoutChanged(int axis)
 167:   {
 168:     switch (axis)
 169:       {
 170:       case X_AXIS:
 171:         xLayoutValid = false;
 172:         break;
 173:       case Y_AXIS:
 174:         yLayoutValid = false;
 175:         break;
 176:       default:
 177:         throw new IllegalArgumentException("Invalid axis parameter.");
 178:       }
 179:   }
 180: 
 181:   /**
 182:    * Returns <code>true</code> if the layout along the specified
 183:    * <code>axis</code> is valid, <code>false</code> otherwise.
 184:    *
 185:    * Valid values for the axis are {@link View#X_AXIS} and
 186:    * {@link View#Y_AXIS}.
 187:    *
 188:    * @param axis the axis
 189:    *
 190:    * @return <code>true</code> if the layout along the specified
 191:    *         <code>axis</code> is valid, <code>false</code> otherwise
 192:    */
 193:   protected boolean isLayoutValid(int axis)
 194:   {
 195:     boolean valid = false;
 196:     switch (axis)
 197:       {
 198:       case X_AXIS:
 199:         valid = xLayoutValid;
 200:         break;
 201:       case Y_AXIS:
 202:         valid = yLayoutValid;
 203:         break;
 204:       default:
 205:         throw new IllegalArgumentException("Invalid axis parameter.");
 206:       }
 207:     return valid;
 208:   }
 209: 
 210:   /**
 211:    * Paints the child <code>View</code> at the specified <code>index</code>.
 212:    * This method modifies the actual values in <code>alloc</code> so make
 213:    * sure you have a copy of the original values if you need them.
 214:    *
 215:    * @param g the <code>Graphics</code> context to paint to
 216:    * @param alloc the allocated region for the child to paint into
 217:    * @param index the index of the child to be painted
 218:    *
 219:    * @see {@link #childAllocation}
 220:    */
 221:   protected void paintChild(Graphics g, Rectangle alloc, int index)
 222:   {
 223:     View child = getView(index);
 224:     childAllocation(index, alloc);
 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: 
 305:     Rectangle copy = new Rectangle(inside);
 306:     int count = getViewCount();
 307:     for (int i = 0; i < count; ++i)
 308:       {
 309:         // TODO: Figure out if the parameter to paintChild is meant to
 310:         // be the child allocation or the allocation of this BoxView.
 311:         // I assume the second option here.
 312:         // We pass this method a copy of the inside rectangle here because
 313:         // it modifies the actual values.
 314:         copy.setBounds(inside);
 315:         paintChild(g, copy, i);
 316:       }
 317:   }
 318: 
 319:   /**
 320:    * Returns the preferred span of the content managed by this
 321:    * <code>View</code> along the specified <code>axis</code>.
 322:    *
 323:    * @param axis the axis
 324:    *
 325:    * @return the preferred span of this <code>View</code>.
 326:    */
 327:   public float getPreferredSpan(int axis)
 328:   {
 329:     SizeRequirements sr = new SizeRequirements();
 330:     int pref = baselineRequirements(axis, sr).preferred;
 331:     return (float) pref;
 332:   }
 333: 
 334:   public float getMaximumSpan(int axis)
 335:   {
 336:     if (axis == getAxis())
 337:       return getPreferredSpan(axis);
 338:     else
 339:       return Integer.MAX_VALUE;
 340:   }
 341: 
 342:   /**
 343:    * Calculates the size requirements for this <code>BoxView</code> along
 344:    * the specified axis.
 345:    *
 346:    * @param axis the axis that is examined
 347:    * @param sr the <code>SizeRequirements</code> object to hold the result,
 348:    *        if <code>null</code>, a new one is created
 349:    *
 350:    * @return the size requirements for this <code>BoxView</code> along
 351:    *         the specified axis
 352:    */
 353:   protected SizeRequirements baselineRequirements(int axis,
 354:                                                   SizeRequirements sr)
 355:   {
 356:     SizeRequirements result;
 357:     if (axis == myAxis)
 358:       result = calculateMajorAxisRequirements(axis, sr);
 359:     else
 360:       result = calculateMinorAxisRequirements(axis, sr);
 361:     return result;
 362:   }
 363: 
 364:   /**
 365:    * Calculates the size requirements of this <code>BoxView</code> along
 366:    * its major axis, that is the axis specified in the constructor.
 367:    *
 368:    * @param axis the axis that is examined
 369:    * @param sr the <code>SizeRequirements</code> object to hold the result,
 370:    *        if <code>null</code>, a new one is created
 371:    *
 372:    * @return the size requirements for this <code>BoxView</code> along
 373:    *         the specified axis
 374:    */
 375:   protected SizeRequirements calculateMajorAxisRequirements(int axis,
 376:                                                            SizeRequirements sr)
 377:   {
 378:     if (sr == null)
 379:       sr = new SizeRequirements();
 380:     else
 381:       {
 382:         sr.maximum = 0;
 383:         sr.minimum = 0;
 384:         sr.preferred = 0;
 385:         sr.alignment = 0.5F;
 386:       }
 387: 
 388:     int count = getViewCount();
 389: 
 390:     // Sum up the sizes of the children along the specified axis.
 391:     for (int i = 0; i < count; ++i)
 392:       {
 393:         View child = getView(i);
 394:         sr.minimum += child.getMinimumSpan(axis);
 395:         sr.preferred += child.getPreferredSpan(axis);
 396:         sr.maximum += child.getMaximumSpan(axis);
 397:       }
 398:     return sr;
 399:   }
 400: 
 401:   /**
 402:    * Calculates the size requirements of this <code>BoxView</code> along
 403:    * its minor axis, that is the axis opposite to the axis specified in the
 404:    * constructor.
 405:    *
 406:    * @param axis the axis that is examined
 407:    * @param sr the <code>SizeRequirements</code> object to hold the result,
 408:    *        if <code>null</code>, a new one is created
 409:    *
 410:    * @return the size requirements for this <code>BoxView</code> along
 411:    *         the specified axis
 412:    */
 413:   protected SizeRequirements calculateMinorAxisRequirements(int axis,
 414:                                                            SizeRequirements sr)
 415:   {
 416:     if (sr == null)
 417:       sr = new SizeRequirements();
 418:     else
 419:       {
 420:         sr.maximum = 0;
 421:         sr.minimum = 0;
 422:         sr.preferred = 0;
 423:         sr.alignment = 0.5F;
 424:       }
 425: 
 426:     int count = getViewCount();
 427: 
 428:     int aboveBaseline = 0;
 429:     int belowBaseline = 0;
 430:     int aboveBaselineMin = 0;
 431:     int belowBaselineMin = 0;
 432:     int aboveBaselineMax = 0;
 433:     int belowBaselineMax = 0;
 434:     
 435:     for (int i = 0; i < count; ++i)
 436:       {
 437:         View child = getView(i);
 438:         float align = child.getAlignment(axis);
 439:         int pref = (int) child.getPreferredSpan(axis);
 440:         int min = (int) child.getMinimumSpan(axis);
 441:         int max = (int) child.getMaximumSpan(axis);
 442:         aboveBaseline += (int) (align * pref);
 443:         belowBaseline += (int) ((1.F - align) * pref);
 444:         aboveBaselineMin += (int) (align * min);
 445:         belowBaselineMin += (int) ((1.F - align) * min);
 446:         aboveBaselineMax += (int) (align * max);
 447:         belowBaselineMax += (int) ((1.F - align) * max);
 448:       }
 449:     sr.minimum = aboveBaselineMin + belowBaselineMin;
 450:     sr.maximum = aboveBaselineMax + belowBaselineMax;
 451:     sr.preferred = aboveBaseline + belowBaseline;
 452:     if (aboveBaseline == 0)
 453:       sr.alignment = 1.0F;
 454:     else
 455:       sr.alignment = (float) (sr.preferred / aboveBaseline);
 456: 
 457:     return sr;
 458:   }
 459: 
 460:   /**
 461:    * Returns <code>true</code> if the specified point lies before the
 462:    * given <code>Rectangle</code>, <code>false</code> otherwise.
 463:    *
 464:    * &quot;Before&quot; is typically defined as being to the left or above.
 465:    *
 466:    * @param x the X coordinate of the point
 467:    * @param y the Y coordinate of the point
 468:    * @param r the rectangle to test the point against
 469:    *
 470:    * @return <code>true</code> if the specified point lies before the
 471:    *         given <code>Rectangle</code>, <code>false</code> otherwise
 472:    */
 473:   protected boolean isBefore(int x, int y, Rectangle r)
 474:   {
 475:     boolean result = false;
 476: 
 477:     if (myAxis == X_AXIS)
 478:       result = x < r.x;
 479:     else
 480:       result = y < r.y;
 481: 
 482:     return result;
 483:   }
 484: 
 485:   /**
 486:    * Returns <code>true</code> if the specified point lies after the
 487:    * given <code>Rectangle</code>, <code>false</code> otherwise.
 488:    *
 489:    * &quot;After&quot; is typically defined as being to the right or below.
 490:    *
 491:    * @param x the X coordinate of the point
 492:    * @param y the Y coordinate of the point
 493:    * @param r the rectangle to test the point against
 494:    *
 495:    * @return <code>true</code> if the specified point lies after the
 496:    *         given <code>Rectangle</code>, <code>false</code> otherwise
 497:    */
 498:   protected boolean isAfter(int x, int y, Rectangle r)
 499:   {
 500:     boolean result = false;
 501: 
 502:     if (myAxis == X_AXIS)
 503:       result = x > r.x;
 504:     else
 505:       result = y > r.y;
 506: 
 507:     return result;
 508:   }
 509: 
 510:   /**
 511:    * Returns the child <code>View</code> at the specified location.
 512:    *
 513:    * @param x the X coordinate
 514:    * @param y the Y coordinate
 515:    * @param r the inner allocation of this <code>BoxView</code> on entry,
 516:    *        the allocation of the found child on exit
 517:    *
 518:    * @return the child <code>View</code> at the specified location
 519:    */
 520:   protected View getViewAtPoint(int x, int y, Rectangle r)
 521:   {
 522:     View result = null;
 523: 
 524:     int count = getViewCount();
 525:     Rectangle copy = new Rectangle(r);
 526: 
 527:     for (int i = 0; i < count; ++i)
 528:       {
 529:         copy.setBounds(r);
 530:         childAllocation(i, r);
 531:         if (copy.contains(x, y))
 532:           {
 533:             result = getView(i);
 534:             break;
 535:           }
 536:       }
 537: 
 538:     return result;
 539:   }
 540: 
 541:   /**
 542:    * Computes the allocation for a child <code>View</code>. The parameter
 543:    * <code>a</code> stores the allocation of this <code>CompositeView</code>
 544:    * and is then adjusted to hold the allocation of the child view.
 545:    *
 546:    * @param index the index of the child <code>View</code>
 547:    * @param a the allocation of this <code>CompositeView</code> before the
 548:    *        call, the allocation of the child on exit
 549:    */
 550:   protected void childAllocation(int index, Rectangle a)
 551:   {
 552:     if (! isAllocationValid())
 553:       layout(a.width, a.height);
 554: 
 555:     a.x += offsetsX[index];
 556:     a.y += offsetsY[index];
 557:     a.width = spansX[index];
 558:     a.height = spansY[index];
 559:   }
 560: 
 561:   /**
 562:    * Lays out the children of this <code>BoxView</code> with the specified
 563:    * bounds.
 564:    *
 565:    * @param width the width of the allocated region for the children (that
 566:    *        is the inner allocation of this <code>BoxView</code>
 567:    * @param height the height of the allocated region for the children (that
 568:    *        is the inner allocation of this <code>BoxView</code>
 569:    */
 570:   protected void layout(int width, int height)
 571:   {
 572:     this.width = width;
 573:     this.height = height;
 574: 
 575:     if (myAxis == X_AXIS)
 576:       {
 577:         layoutMajorAxis(width, X_AXIS, offsetsX, spansX);
 578:         layoutMinorAxis(height, Y_AXIS, offsetsY, spansY);
 579:       }
 580:     else
 581:       {
 582:         layoutMajorAxis(height, Y_AXIS, offsetsY, spansY);
 583:         layoutMinorAxis(width, X_AXIS, offsetsX, spansX);
 584:       }
 585:   }
 586: 
 587:   /**
 588:    * Performs the layout along the major axis of a <code>BoxView</code>.
 589:    *
 590:    * @param targetSpan the (inner) span of the <code>BoxView</code> in which
 591:    *        to layout the children
 592:    * @param axis the axis along which the layout is performed
 593:    * @param offsets the array that holds the offsets of the children on exit
 594:    * @param offsets the array that holds the spans of the children on exit
 595:    */
 596:   protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets,
 597:                                  int[] spans)
 598:   {
 599:     // Allocate SizeRequirements for each child view.
 600:     int count = getViewCount();
 601:     SizeRequirements[] childReqs = new SizeRequirements[count];
 602:     for (int i = 0; i < count; ++i)
 603:       {
 604:         View view = getView(i);
 605:         childReqs[i] = new SizeRequirements((int) view.getMinimumSpan(axis),
 606:                                             (int) view.getPreferredSpan(axis),
 607:                                             (int) view.getMaximumSpan(axis),
 608:                                             view.getAlignment(axis));
 609:       }
 610: 
 611:     // Calculate the spans and offsets using the SizeRequirements uility
 612:     // methods.
 613:     SizeRequirements.calculateTiledPositions(targetSpan, null, childReqs,
 614:                                              offsets, spans);
 615: 
 616:     validateLayout(axis);
 617:   }
 618: 
 619:   /**
 620:    * Performs the layout along the minor axis of a <code>BoxView</code>.
 621:    *
 622:    * @param targetSpan the (inner) span of the <code>BoxView</code> in which
 623:    *        to layout the children
 624:    * @param axis the axis along which the layout is performed
 625:    * @param offsets the array that holds the offsets of the children on exit
 626:    * @param offsets the array that holds the spans of the children on exit
 627:    */
 628:   protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets,
 629:                                  int[] spans)
 630:   {
 631:     // Allocate SizeRequirements for each child view.
 632:     int count = getViewCount();
 633:     SizeRequirements[] childReqs = new SizeRequirements[count];
 634:     for (int i = 0; i < count; ++i)
 635:       {
 636:         View view = getView(i);
 637:         childReqs[i] = new SizeRequirements((int) view.getMinimumSpan(axis),
 638:                                             (int) view.getPreferredSpan(axis),
 639:                                             (int) view.getMaximumSpan(axis),
 640:                                             view.getAlignment(axis));
 641:       }
 642: 
 643:     // Calculate the spans and offsets using the SizeRequirements uility
 644:     // methods.
 645:     SizeRequirements.calculateAlignedPositions(targetSpan, null, childReqs,
 646:                                                offsets, spans);
 647:     validateLayout(axis);
 648:   }
 649: 
 650:   /**
 651:    * Returns <code>true</code> if the cached allocations for the children
 652:    * are still valid, <code>false</code> otherwise.
 653:    *
 654:    * @return <code>true</code> if the cached allocations for the children
 655:    *         are still valid, <code>false</code> otherwise
 656:    */
 657:   protected boolean isAllocationValid()
 658:   {
 659:     return isLayoutValid(X_AXIS) && isLayoutValid(Y_AXIS);
 660:   }
 661: 
 662:   /**
 663:    * Return the current width of the box. This is the last allocated width.
 664:    *
 665:    * @return the current width of the box
 666:    */
 667:   public int getWidth()
 668:   {
 669:     return width;
 670:   }
 671: 
 672:   /**
 673:    * Return the current height of the box. This is the last allocated height.
 674:    *
 675:    * @return the current height of the box
 676:    */
 677:   public int getHeight()
 678:   {
 679:     return height;
 680:   }
 681: 
 682:   /**
 683:    * Sets the size of the view. If the actual size has changed, the layout
 684:    * is updated accordingly.
 685:    *
 686:    * @param width the new width
 687:    * @param height the new height
 688:    */
 689:   public void setSize(float width, float height)
 690:   {
 691:     if (this.width != (int) width)
 692:       layoutChanged(X_AXIS);
 693:     if (this.height != (int) height)
 694:       layoutChanged(Y_AXIS);
 695: 
 696:     Rectangle outside = new Rectangle(0, 0, this.width, this.height);
 697:     Rectangle inside = getInsideAllocation(outside);
 698:     if (!isAllocationValid())
 699:       layout(inside.width, inside.height);
 700:   }
 701: 
 702:   /**
 703:    * Sets the layout to valid for a specific axis.
 704:    *
 705:    * @param axis the axis for which to validate the layout
 706:    */
 707:   void validateLayout(int axis)
 708:   {
 709:     if (axis == X_AXIS)
 710:       xLayoutValid = true;
 711:     if (axis == Y_AXIS)
 712:       yLayoutValid = true;
 713:   }
 714: }