Frames | No Frames |
1: /* FlowView.java -- A 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.Component; 42: import java.awt.Graphics; 43: import java.awt.Rectangle; 44: import java.awt.Shape; 45: 46: import javax.swing.SizeRequirements; 47: import javax.swing.event.DocumentEvent; 48: 49: /** 50: * A <code>View</code> that can flows it's children into it's layout space. 51: * 52: * The <code>FlowView</code> manages a set of logical views (that are 53: * the children of the {@link #layoutPool} field). These are translated 54: * at layout time into a set of physical views. These are the views that 55: * are managed as the real child views. Each of these child views represents 56: * a row and are laid out within a box using the superclasses behaviour. 57: * The concrete implementation of the rows must be provided by subclasses. 58: * 59: * @author Roman Kennke (roman@kennke.org) 60: */ 61: public abstract class FlowView extends BoxView 62: { 63: /** 64: * A strategy for translating the logical views of a <code>FlowView</code> 65: * into the real views. 66: */ 67: public static class FlowStrategy 68: { 69: /** 70: * Creates a new instance of <code>FlowStragegy</code>. 71: */ 72: public FlowStrategy() 73: { 74: // Nothing to do here. 75: } 76: 77: /** 78: * Receives notification from a <code>FlowView</code> that some content 79: * has been inserted into the document at a location that the 80: * <code>FlowView</code> is responsible for. 81: * 82: * The default implementation simply calls {@link #layout}. 83: * 84: * @param fv the flow view that sends the notification 85: * @param e the document event describing the change 86: * @param alloc the current allocation of the flow view 87: */ 88: public void insertUpdate(FlowView fv, DocumentEvent e, Rectangle alloc) 89: { 90: if (alloc == null) 91: { 92: fv.layoutChanged(X_AXIS); 93: fv.layoutChanged(Y_AXIS); 94: } 95: else 96: { 97: Component host = fv.getContainer(); 98: if (host != null) 99: host.repaint(alloc.x, alloc.y, alloc.width, alloc.height); 100: } 101: } 102: 103: /** 104: * Receives notification from a <code>FlowView</code> that some content 105: * has been removed from the document at a location that the 106: * <code>FlowView</code> is responsible for. 107: * 108: * The default implementation simply calls {@link #layout}. 109: * 110: * @param fv the flow view that sends the notification 111: * @param e the document event describing the change 112: * @param alloc the current allocation of the flow view 113: */ 114: public void removeUpdate(FlowView fv, DocumentEvent e, Rectangle alloc) 115: { 116: if (alloc == null) 117: { 118: fv.layoutChanged(X_AXIS); 119: fv.layoutChanged(Y_AXIS); 120: } 121: else 122: { 123: Component host = fv.getContainer(); 124: if (host != null) 125: host.repaint(alloc.x, alloc.y, alloc.width, alloc.height); 126: } 127: } 128: 129: /** 130: * Receives notification from a <code>FlowView</code> that some attributes 131: * have changed in the document at a location that the 132: * <code>FlowView</code> is responsible for. 133: * 134: * The default implementation simply calls {@link #layout}. 135: * 136: * @param fv the flow view that sends the notification 137: * @param e the document event describing the change 138: * @param alloc the current allocation of the flow view 139: */ 140: public void changedUpdate(FlowView fv, DocumentEvent e, Rectangle alloc) 141: { 142: if (alloc == null) 143: { 144: fv.layoutChanged(X_AXIS); 145: fv.layoutChanged(Y_AXIS); 146: } 147: else 148: { 149: Component host = fv.getContainer(); 150: if (host != null) 151: host.repaint(alloc.x, alloc.y, alloc.width, alloc.height); 152: } 153: } 154: 155: /** 156: * Returns the logical view of the managed <code>FlowView</code>. 157: * 158: * @param fv the flow view for which to return the logical view 159: * 160: * @return the logical view of the managed <code>FlowView</code> 161: */ 162: protected View getLogicalView(FlowView fv) 163: { 164: return fv.layoutPool; 165: } 166: 167: /** 168: * Performs the layout for the whole view. By default this rebuilds 169: * all the physical views from the logical views of the managed FlowView. 170: * 171: * This is called by {@link FlowView#layout} to update the layout of 172: * the view. 173: * 174: * @param fv the flow view for which we perform the layout 175: */ 176: public void layout(FlowView fv) 177: { 178: int start = fv.getStartOffset(); 179: int end = fv.getEndOffset(); 180: 181: // Preserve the views from the logical view from beeing removed. 182: View lv = getLogicalView(fv); 183: int viewCount = lv.getViewCount(); 184: for (int i = 0; i < viewCount; i++) 185: { 186: View v = lv.getView(i); 187: v.setParent(lv); 188: } 189: 190: // Then remove all views from the flow view. 191: fv.removeAll(); 192: 193: for (int rowIndex = 0; start < end; rowIndex++) 194: { 195: View row = fv.createRow(); 196: fv.append(row); 197: int next = layoutRow(fv, rowIndex, start); 198: if (row.getViewCount() == 0) 199: { 200: row.append(createView(fv, start, Integer.MAX_VALUE, rowIndex)); 201: next = row.getEndOffset(); 202: } 203: if (start < next) 204: start = next; 205: else 206: assert false: "May not happen"; 207: } 208: } 209: 210: /** 211: * Lays out one row of the flow view. This is called by {@link #layout} to 212: * fill one row with child views until the available span is exhausted. The 213: * default implementation fills the row by calling 214: * {@link #createView(FlowView, int, int, int)} until the available space is 215: * exhausted, a forced break is encountered or there are no more views in 216: * the logical view. If the available space is exhausted, 217: * {@link #adjustRow(FlowView, int, int, int)} is called to fit the row into 218: * the available span. 219: * 220: * @param fv the flow view for which we perform the layout 221: * @param rowIndex the index of the row 222: * @param pos the model position for the beginning of the row 223: * @return the start position of the next row 224: */ 225: protected int layoutRow(FlowView fv, int rowIndex, int pos) 226: { 227: View row = fv.getView(rowIndex); 228: int axis = fv.getFlowAxis(); 229: int span = fv.getFlowSpan(rowIndex); 230: int x = fv.getFlowStart(rowIndex); 231: int end = fv.getEndOffset(); 232: 233: // Needed for adjusting indentation in adjustRow(). 234: int preX = x; 235: int availableSpan = span; 236: 237: TabExpander tabExp = fv instanceof TabExpander ? (TabExpander) fv : null; 238: 239: boolean forcedBreak = false; 240: while (pos < end && span >= 0) 241: { 242: View view = createView(fv, pos, span, rowIndex); 243: if (view == null 244: || (span == 0 && view.getPreferredSpan(axis) > 0)) 245: break; 246: 247: int viewSpan; 248: if (axis == X_AXIS && view instanceof TabableView) 249: viewSpan = (int) ((TabableView) view).getTabbedSpan(x, tabExp); 250: else 251: viewSpan = (int) view.getPreferredSpan(axis); 252: 253: // Break if the line if the view does not fit in this row or the 254: // line just must be broken. 255: int breakWeight = view.getBreakWeight(axis, pos, span); 256: if (breakWeight >= ForcedBreakWeight) 257: { 258: int rowViewCount = row.getViewCount(); 259: if (rowViewCount > 0) 260: { 261: view = view.breakView(axis, pos, x, span); 262: if (view != null) 263: { 264: if (axis == X_AXIS && view instanceof TabableView) 265: viewSpan = 266: (int) ((TabableView) view).getTabbedSpan(x, tabExp); 267: else 268: viewSpan = (int) view.getPreferredSpan(axis); 269: } 270: else 271: viewSpan = 0; 272: } 273: forcedBreak = true; 274: } 275: span -= viewSpan; 276: x += viewSpan; 277: if (view != null) 278: { 279: row.append(view); 280: pos = view.getEndOffset(); 281: } 282: if (forcedBreak) 283: break; 284: } 285: 286: if (span < 0) 287: adjustRow(fv, rowIndex, availableSpan, preX); 288: else if (row.getViewCount() == 0) 289: { 290: View view = createView(fv, pos, Integer.MAX_VALUE, rowIndex); 291: row.append(view); 292: } 293: return row.getEndOffset(); 294: } 295: 296: /** 297: * Creates physical views that form the rows of the flow view. This 298: * can be an entire view from the logical view (if it fits within the 299: * available span), a fragment of such a view (if it doesn't fit in the 300: * available span and can be broken down) or <code>null</code> (if it does 301: * not fit in the available span and also cannot be broken down). 302: * 303: * The default implementation fetches the logical view at the specified 304: * <code>startOffset</code>. If that view has a different startOffset than 305: * specified in the argument, a fragment is created using 306: * {@link View#createFragment(int, int)} that has the correct startOffset 307: * and the logical view's endOffset. 308: * 309: * @param fv the flow view 310: * @param startOffset the start offset for the view to be created 311: * @param spanLeft the available span 312: * @param rowIndex the index of the row 313: * 314: * @return a view to fill the row with, or <code>null</code> if there 315: * is no view or view fragment that fits in the available span 316: */ 317: protected View createView(FlowView fv, int startOffset, int spanLeft, 318: int rowIndex) 319: { 320: View logicalView = getLogicalView(fv); 321: int index = logicalView.getViewIndex(startOffset, 322: Position.Bias.Forward); 323: View retVal = logicalView.getView(index); 324: if (retVal.getStartOffset() != startOffset) 325: retVal = retVal.createFragment(startOffset, retVal.getEndOffset()); 326: return retVal; 327: } 328: 329: /** 330: * Tries to adjust the specified row to fit within the desired span. The 331: * default implementation iterates through the children of the specified 332: * row to find the view that has the highest break weight and - if there 333: * is more than one view with such a break weight - which is nearest to 334: * the end of the row. If there is such a view that has a break weight > 335: * {@link View#BadBreakWeight}, this view is broken using the 336: * {@link View#breakView(int, int, float, float)} method and this view and 337: * all views after the now broken view are replaced by the broken view. 338: * 339: * @param fv the flow view 340: * @param rowIndex the index of the row to be adjusted 341: * @param desiredSpan the layout span 342: * @param x the X location at which the row starts 343: */ 344: protected void adjustRow(FlowView fv, int rowIndex, int desiredSpan, int x) { 345: // Determine the last view that has the highest break weight. 346: int axis = fv.getFlowAxis(); 347: View row = fv.getView(rowIndex); 348: int count = row.getViewCount(); 349: int breakIndex = -1; 350: int breakWeight = BadBreakWeight; 351: int breakSpan = 0; 352: int currentSpan = 0; 353: for (int i = 0; i < count; ++i) 354: { 355: View view = row.getView(i); 356: int spanLeft = desiredSpan - currentSpan; 357: int weight = view.getBreakWeight(axis, x + currentSpan, spanLeft); 358: if (weight >= breakWeight && weight > BadBreakWeight) 359: { 360: breakIndex = i; 361: breakSpan = currentSpan; 362: breakWeight = weight; 363: if (weight >= ForcedBreakWeight) 364: // Don't search further. 365: break; 366: } 367: currentSpan += view.getPreferredSpan(axis); 368: } 369: 370: // If there is a potential break location found, break the row at 371: // this location. 372: if (breakIndex >= 0) 373: { 374: int spanLeft = desiredSpan - breakSpan; 375: View toBeBroken = row.getView(breakIndex); 376: View brokenView = toBeBroken.breakView(axis, 377: toBeBroken.getStartOffset(), 378: x + breakSpan, spanLeft); 379: View lv = getLogicalView(fv); 380: for (int i = breakIndex; i < count; i++) 381: { 382: View tmp = row.getView(i); 383: if (contains(lv, tmp)) 384: tmp.setParent(lv); 385: else if (tmp.getViewCount() > 0) 386: reparent(tmp, lv); 387: } 388: row.replace(breakIndex, count - breakIndex, 389: new View[]{ brokenView }); 390: } 391: 392: } 393: 394: /** 395: * Helper method to determine if one view contains another as child. 396: */ 397: private boolean contains(View view, View child) 398: { 399: boolean ret = false; 400: int n = view.getViewCount(); 401: for (int i = 0; i < n && ret == false; i++) 402: { 403: if (view.getView(i) == child) 404: ret = true; 405: } 406: return ret; 407: } 408: 409: /** 410: * Helper method that reparents the <code>view</code> and all of its 411: * decendents to the <code>parent</code> (the logical view). 412: * 413: * @param view the view to reparent 414: * @param parent the new parent 415: */ 416: private void reparent(View view, View parent) 417: { 418: int n = view.getViewCount(); 419: for (int i = 0; i < n; i++) 420: { 421: View tmp = view.getView(i); 422: if (contains(parent, tmp)) 423: tmp.setParent(parent); 424: else 425: reparent(tmp, parent); 426: } 427: } 428: } 429: 430: /** 431: * This special subclass of <code>View</code> is used to represent 432: * the logical representation of this view. It does not support any 433: * visual representation, this is handled by the physical view implemented 434: * in the <code>FlowView</code>. 435: */ 436: class LogicalView extends CompositeView 437: { 438: /** 439: * Creates a new LogicalView instance. 440: */ 441: LogicalView(Element el) 442: { 443: super(el); 444: } 445: 446: /** 447: * Overridden to return the attributes of the parent 448: * (== the FlowView instance). 449: */ 450: public AttributeSet getAttributes() 451: { 452: View p = getParent(); 453: return p != null ? p.getAttributes() : null; 454: } 455: 456: protected void childAllocation(int index, Rectangle a) 457: { 458: // Nothing to do here (not visual). 459: } 460: 461: protected View getViewAtPoint(int x, int y, Rectangle r) 462: { 463: // Nothing to do here (not visual). 464: return null; 465: } 466: 467: protected boolean isAfter(int x, int y, Rectangle r) 468: { 469: // Nothing to do here (not visual). 470: return false; 471: } 472: 473: protected boolean isBefore(int x, int y, Rectangle r) 474: { 475: // Nothing to do here (not visual). 476: return false; 477: } 478: 479: public float getPreferredSpan(int axis) 480: { 481: float max = 0; 482: float pref = 0; 483: int n = getViewCount(); 484: for (int i = 0; i < n; i++) 485: { 486: View v = getView(i); 487: pref += v.getPreferredSpan(axis); 488: if (v.getBreakWeight(axis, 0, Integer.MAX_VALUE) 489: >= ForcedBreakWeight) 490: { 491: max = Math.max(max, pref); 492: pref = 0; 493: } 494: } 495: max = Math.max(max, pref); 496: return max; 497: } 498: 499: public float getMinimumSpan(int axis) 500: { 501: float max = 0; 502: float min = 0; 503: boolean wrap = true; 504: int n = getViewCount(); 505: for (int i = 0; i < n; i++) 506: { 507: View v = getView(i); 508: if (v.getBreakWeight(axis, 0, Integer.MAX_VALUE) 509: == BadBreakWeight) 510: { 511: min += v.getPreferredSpan(axis); 512: wrap = false; 513: } 514: else if (! wrap) 515: { 516: max = Math.max(min, max); 517: wrap = true; 518: min = 0; 519: } 520: } 521: max = Math.max(max, min); 522: return max; 523: } 524: 525: public void paint(Graphics g, Shape s) 526: { 527: // Nothing to do here (not visual). 528: } 529: 530: /** 531: * Overridden to handle possible leaf elements. 532: */ 533: protected void loadChildren(ViewFactory f) 534: { 535: Element el = getElement(); 536: if (el.isLeaf()) 537: { 538: View v = new LabelView(el); 539: append(v); 540: } 541: else 542: super.loadChildren(f); 543: } 544: 545: /** 546: * Overridden to reparent the children to this logical view, in case 547: * they have been parented by a row. 548: */ 549: protected void forwardUpdateToView(View v, DocumentEvent e, Shape a, 550: ViewFactory f) 551: { 552: v.setParent(this); 553: super.forwardUpdateToView(v, e, a, f); 554: } 555: 556: /** 557: * Overridden to handle possible leaf element. 558: */ 559: protected int getViewIndexAtPosition(int pos) 560: { 561: int index = 0; 562: if (! getElement().isLeaf()) 563: index = super.getViewIndexAtPosition(pos); 564: return index; 565: } 566: } 567: 568: /** 569: * The shared instance of FlowStrategy. 570: */ 571: static final FlowStrategy sharedStrategy = new FlowStrategy(); 572: 573: /** 574: * The span of the <code>FlowView</code> that should be flowed. 575: */ 576: protected int layoutSpan; 577: 578: /** 579: * Represents the logical child elements of this view, encapsulated within 580: * one parent view (an instance of a package private <code>LogicalView</code> 581: * class). These will be translated to a set of real views that are then 582: * displayed on screen. This translation is performed by the inner class 583: * {@link FlowStrategy}. 584: */ 585: protected View layoutPool; 586: 587: /** 588: * The <code>FlowStrategy</code> to use for translating between the 589: * logical and physical view. 590: */ 591: protected FlowStrategy strategy; 592: 593: /** 594: * Creates a new <code>FlowView</code> for the given 595: * <code>Element</code> and <code>axis</code>. 596: * 597: * @param element the element that is rendered by this FlowView 598: * @param axis the axis along which the view is tiled, either 599: * <code>View.X_AXIS</code> or <code>View.Y_AXIS</code>, the flow 600: * axis is orthogonal to this one 601: */ 602: public FlowView(Element element, int axis) 603: { 604: super(element, axis); 605: strategy = sharedStrategy; 606: layoutSpan = Short.MAX_VALUE; 607: } 608: 609: /** 610: * Returns the axis along which the view should be flowed. This is 611: * orthogonal to the axis along which the boxes are tiled. 612: * 613: * @return the axis along which the view should be flowed 614: */ 615: public int getFlowAxis() 616: { 617: int axis = getAxis(); 618: int flowAxis; 619: 620: if (axis == X_AXIS) 621: flowAxis = Y_AXIS; 622: else 623: flowAxis = X_AXIS; 624: 625: return flowAxis; 626: 627: } 628: 629: /** 630: * Returns the span of the flow for the specified child view. A flow 631: * layout can be shaped by providing different span values for different 632: * child indices. The default implementation returns the entire available 633: * span inside the view. 634: * 635: * @param index the index of the child for which to return the span 636: * 637: * @return the span of the flow for the specified child view 638: */ 639: public int getFlowSpan(int index) 640: { 641: return layoutSpan; 642: } 643: 644: /** 645: * Returns the location along the flow axis where the flow span starts 646: * given a child view index. The flow can be shaped by providing 647: * different values here. 648: * 649: * @param index the index of the child for which to return the flow location 650: * 651: * @return the location along the flow axis where the flow span starts 652: */ 653: public int getFlowStart(int index) 654: { 655: return 0; 656: } 657: 658: /** 659: * Creates a new view that represents a row within a flow. 660: * 661: * @return a view for a new row 662: */ 663: protected abstract View createRow(); 664: 665: /** 666: * Loads the children of this view. The <code>FlowView</code> does not 667: * directly load its children. Instead it creates a logical view 668: * ({@link #layoutPool}) which is filled by the logical child views. 669: * The real children are created at layout time and each represent one 670: * row. 671: * 672: * This method is called by {@link View#setParent} in order to initialize 673: * the view. 674: * 675: * @param vf the view factory to use for creating the child views 676: */ 677: protected void loadChildren(ViewFactory vf) 678: { 679: if (layoutPool == null) 680: { 681: layoutPool = new LogicalView(getElement()); 682: } 683: layoutPool.setParent(this); 684: // Initialize the flow strategy. 685: strategy.insertUpdate(this, null, null); 686: } 687: 688: /** 689: * Performs the layout of this view. If the span along the flow axis changed, 690: * this first calls {@link FlowStrategy#layout} in order to rebuild the 691: * rows of this view. Then the superclass's behaviour is called to arrange 692: * the rows within the box. 693: * 694: * @param width the width of the view 695: * @param height the height of the view 696: */ 697: protected void layout(int width, int height) 698: { 699: int flowAxis = getFlowAxis(); 700: int span; 701: if (flowAxis == X_AXIS) 702: span = (int) width; 703: else 704: span = (int) height; 705: 706: if (layoutSpan != span) 707: { 708: layoutChanged(flowAxis); 709: layoutChanged(getAxis()); 710: layoutSpan = span; 711: } 712: 713: if (! isLayoutValid(flowAxis)) 714: { 715: int axis = getAxis(); 716: int oldSpan = axis == X_AXIS ? getWidth() : getHeight(); 717: strategy.layout(this); 718: int newSpan = (int) getPreferredSpan(axis); 719: if (oldSpan != newSpan) 720: { 721: View parent = getParent(); 722: if (parent != null) 723: parent.preferenceChanged(this, axis == X_AXIS, axis == Y_AXIS); 724: } 725: } 726: 727: super.layout(width, height); 728: } 729: 730: /** 731: * Receice notification that some content has been inserted in the region 732: * that this view is responsible for. This calls 733: * {@link FlowStrategy#insertUpdate}. 734: * 735: * @param changes the document event describing the changes 736: * @param a the current allocation of the view 737: * @param vf the view factory that is used for creating new child views 738: */ 739: public void insertUpdate(DocumentEvent changes, Shape a, ViewFactory vf) 740: { 741: // First we must send the insertUpdate to the logical view so it can 742: // be updated accordingly. 743: layoutPool.insertUpdate(changes, a, vf); 744: strategy.insertUpdate(this, changes, getInsideAllocation(a)); 745: } 746: 747: /** 748: * Receice notification that some content has been removed from the region 749: * that this view is responsible for. This calls 750: * {@link FlowStrategy#removeUpdate}. 751: * 752: * @param changes the document event describing the changes 753: * @param a the current allocation of the view 754: * @param vf the view factory that is used for creating new child views 755: */ 756: public void removeUpdate(DocumentEvent changes, Shape a, ViewFactory vf) 757: { 758: layoutPool.removeUpdate(changes, a, vf); 759: strategy.removeUpdate(this, changes, getInsideAllocation(a)); 760: } 761: 762: /** 763: * Receice notification that some attributes changed in the region 764: * that this view is responsible for. This calls 765: * {@link FlowStrategy#changedUpdate}. 766: * 767: * @param changes the document event describing the changes 768: * @param a the current allocation of the view 769: * @param vf the view factory that is used for creating new child views 770: */ 771: public void changedUpdate(DocumentEvent changes, Shape a, ViewFactory vf) 772: { 773: layoutPool.changedUpdate(changes, a, vf); 774: strategy.changedUpdate(this, changes, getInsideAllocation(a)); 775: } 776: 777: /** 778: * Returns the index of the child <code>View</code> for the given model 779: * position. 780: * 781: * This is implemented to iterate over the children of this 782: * view (the rows) and return the index of the first view that contains 783: * the given position. 784: * 785: * @param pos the model position for whicht the child <code>View</code> is 786: * queried 787: * 788: * @return the index of the child <code>View</code> for the given model 789: * position 790: */ 791: protected int getViewIndexAtPosition(int pos) 792: { 793: // First make sure we have a valid layout. 794: if (!isAllocationValid()) 795: layout(getWidth(), getHeight()); 796: 797: int count = getViewCount(); 798: int result = -1; 799: 800: for (int i = 0; i < count; ++i) 801: { 802: View child = getView(i); 803: int start = child.getStartOffset(); 804: int end = child.getEndOffset(); 805: if (start <= pos && end > pos) 806: { 807: result = i; 808: break; 809: } 810: } 811: return result; 812: } 813: 814: /** 815: * Calculates the size requirements of this <code>BoxView</code> along 816: * its minor axis, that is the axis opposite to the axis specified in the 817: * constructor. 818: * 819: * This is overridden and forwards the request to the logical view. 820: * 821: * @param axis the axis that is examined 822: * @param r the <code>SizeRequirements</code> object to hold the result, 823: * if <code>null</code>, a new one is created 824: * 825: * @return the size requirements for this <code>BoxView</code> along 826: * the specified axis 827: */ 828: protected SizeRequirements calculateMinorAxisRequirements(int axis, 829: SizeRequirements r) 830: { 831: SizeRequirements res = r; 832: if (res == null) 833: res = new SizeRequirements(); 834: res.minimum = (int) layoutPool.getMinimumSpan(axis); 835: res.preferred = Math.max(res.minimum, 836: (int) layoutPool.getPreferredSpan(axis)); 837: res.maximum = Integer.MAX_VALUE; 838: res.alignment = 0.5F; 839: return res; 840: } 841: }