Clover coverage report - gsbase - 2.0.1
Coverage timestamp: Sat Jan 1 2005 12:30:02 EST
file stats: LOC: 2,104   Methods: 76
NCLOC: 1,150   Classes: 4
 
 Source file Conditionals Statements Methods TOTAL
TableLayout.java 74.6% 75.5% 80.3% 75.7%
coverage coverage
 1    /*
 2    * Copyright (c) 1998, 2005 Gargoyle Software Inc. All rights reserved.
 3    *
 4    * Redistribution and use in source and binary forms, with or without
 5    * modification, are permitted provided that the following conditions are met:
 6    *
 7    * 1. Redistributions of source code must retain the above copyright notice,
 8    * this list of conditions and the following disclaimer.
 9    * 2. Redistributions in binary form must reproduce the above copyright notice,
 10    * this list of conditions and the following disclaimer in the documentation
 11    * and/or other materials provided with the distribution.
 12    * 3. The end-user documentation included with the redistribution, if any, must
 13    * include the following acknowledgment:
 14    *
 15    * "This product includes software developed by Gargoyle Software Inc.
 16    * (http://www.GargoyleSoftware.com/)."
 17    *
 18    * Alternately, this acknowledgment may appear in the software itself, if
 19    * and wherever such third-party acknowledgments normally appear.
 20    * 4. The name "Gargoyle Software" must not be used to endorse or promote
 21    * products derived from this software without prior written permission.
 22    * For written permission, please contact info@GargoyleSoftware.com.
 23    * 5. Products derived from this software may not be called "GSBase", nor may
 24    * "GSBase" appear in their name, without prior written permission of
 25    * Gargoyle Software Inc.
 26    *
 27    * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
 28    * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 29    * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GARGOYLE
 30    * SOFTWARE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 31    * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 32    * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 33    * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 34    * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 35    * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 36    * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 37    */
 38    package com.gargoylesoftware.base.gui;
 39   
 40    import com.gargoylesoftware.base.trace.Trace;
 41    import com.gargoylesoftware.base.trace.TraceChannel;
 42    import com.gargoylesoftware.base.util.DetailedIllegalArgumentException;
 43    import com.gargoylesoftware.base.util.DetailedNullPointerException;
 44    import java.awt.Component;
 45    import java.awt.Container;
 46    import java.awt.Dimension;
 47    import java.awt.Graphics;
 48    import java.awt.Insets;
 49    import java.awt.LayoutManager2;
 50    import java.io.Serializable;
 51    import java.util.ArrayList;
 52    import java.util.HashSet;
 53    import java.util.Iterator;
 54    import java.util.List;
 55    import java.util.Set;
 56    import javax.swing.SwingConstants;
 57   
 58    /**
 59    * The TableLayout lays out items based on a table of rows and columns.<p>
 60    *
 61    * If you are doing simple layout, you can specify constraints as strings of the format
 62    * "row,column". If you want the component to stretch over multiple rows/columns
 63    * then you can specify the constraint as "row+rowspan,column+columnspan" as shown in
 64    * the sample below.
 65    * <pre>
 66    * final TableLayout layout = new TableLayout();
 67    * final JPanel panel = new JPanel(layout);
 68    *
 69    * panel.add( new JLabel("squirrel"), "1,1" );
 70    * panel.add( new JLabel("raccoon"), "1,2" );
 71    * panel.add( new JLabel("bluejay"), "2,1" );
 72    * panel.add( new JLabel("goldfish"), "2,2" );
 73    * panel.add( new JLabel("marshhawk"), "3,1+3" );
 74    * </pre>
 75    *
 76    * If you want more flexibility over the layout then this, use a {@link TableLayoutConstraints}
 77    * object instead of a string. Here is a more complicated sample that uses
 78    * {@link TableLayoutConstraints} to customize the layout a bit more. Note the use of
 79    * {@link TableLayoutDebuggingPanel} - this will draw lines on layout boundaries to help
 80    * debug layout problems.
 81    * <pre>
 82    * final TableLayout layout = new TableLayout();
 83    * final JPanel panel = new TableLayoutDebuggingPanel(layout);
 84    *
 85    * TableLayoutConstraints constraints;
 86    *
 87    * layout.setRowExpandable(1, true);
 88    *
 89    * constraints = new TableLayoutConstraints(1,1);
 90    * constraints.setVerticalStretch(true);
 91    * panel.add( new JButton("squirrel"), constraints );
 92    *
 93    * constraints = new TableLayoutConstraints(1,2);
 94    * constraints.setVerticalAlignment(TableLayout.TOP);
 95    * panel.add( new JButton("raccoon"), constraints );
 96    *
 97    * panel.add( new JButton("bluejay"), "2,1" );
 98    * panel.add( new JButton("goldfish"), "2,2" );
 99    * panel.add( new JButton("marshhawk"), "3,1+3" );
 100    * </pre>
 101    *
 102    * <b>Debugging tip: </b>Most layout problems become obvious if you use a
 103    * {@link TableLayoutDebuggingPanel} to see where the layout boundaries are. In those
 104    * rare cases where this doesn't give you enough information, try calling
 105    * {@link #setTraceChannel(TraceChannel)} with a non-null TraceChannel such as Trace.out
 106    * or Trace.err. This will dump quite a bit of diagnostic information.
 107    * <pre>
 108    * layout.setTraceChannel(Trace.out)
 109    * </pre>
 110    *
 111    * @version $Revision: 1.6 $
 112    * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
 113    */
 114    public class TableLayout
 115    implements
 116    LayoutManager2,
 117    SwingConstants,
 118    Serializable {
 119   
 120    // Required for serialization - do not remove or modify.
 121    private static final long serialVersionUID = 396191633848670929L;
 122   
 123    private final Set rowHeaderPermanentInfos_ = new HashSet();
 124    private final Set columnHeaderPermanentInfos_ = new HashSet();
 125   
 126    private Container parent_;
 127    private final List constraints_ = new ArrayList();
 128   
 129    // If non-null then dump diagnostic information
 130    private TraceChannel traceChannel_ = null;
 131   
 132    // Used to hold temporary sizing information during calculations.
 133    private Header tempColumnHeaders_[] = null;
 134    private Header tempRowHeaders_[] = null;
 135   
 136    // The number of columns/rows. Used when allocating temporary
 137    // storage.
 138    private int columnCount_ = 0;
 139    private int rowCount_ = 0;
 140   
 141    // True if all the calculations have been performed
 142    private boolean tempSizesAreValid_ = false;
 143   
 144    // If the component size is bigger than the minimum size then these
 145    // vars will be used to determine size/position of the resulting
 146    // layout
 147    private int verticalAlignment_ = CENTER;
 148    private int horizontalAlignment_ = CENTER;
 149   
 150    private Dimension minimumSize_ = null;
 151    private Dimension maximumSize_ = null;
 152    private Dimension preferredSize_ = null;
 153    private Dimension actualSize_ = null;
 154   
 155    private boolean ignoreInvisibleComponents_ = true;
 156   
 157   
 158    /**
 159    * Create a new TableLayout.
 160    */
 161  27 public TableLayout() {
 162    }
 163   
 164   
 165    /**
 166    * Convenience method to create a string from a Dimension object.
 167    *
 168    * @param dimension Description of Parameter
 169    * @return Description of the Returned Value
 170    */
 171  0 private static String toString( final Dimension dimension ) {
 172  0 return "(" + dimension.width + "," + dimension.height + ")";
 173    }
 174   
 175   
 176    /**
 177    * Set the vertical alignment. Legal values are:
 178    * <ul>
 179    * <li> <tt>TableLayout.TOP</tt>
 180    * <li> <tt>TableLayout.CENTER</tt>
 181    * <li> <tt>TableLayout.BOTTOM</tt>
 182    * </ul>
 183    *
 184    *
 185    * @param alignment The new vertical alignment.
 186    */
 187  3 public void setVerticalAlignment( final int alignment ) {
 188  3 Trace.println( traceChannel_,
 189    "setVerticalAlignment(" + alignment + ")" );
 190   
 191  3 switch ( alignment ) {
 192  1 case TableLayout.TOP:
 193  1 case TableLayout.BOTTOM:
 194  1 case TableLayout.CENTER:
 195  3 verticalAlignment_ = alignment;
 196  3 break;
 197  0 default:
 198  0 throw new DetailedIllegalArgumentException( "alignment", new Integer(alignment) );
 199    }
 200    }
 201   
 202   
 203    /**
 204    * Set the vertical alignment. Legal values are:
 205    * <ul>
 206    * <li> <tt>TableLayout.LEFT</tt>
 207    * <li> <tt>TableLayout.CENTER</tt>
 208    * <li> <tt>TableLayout.RIGHT</tt>
 209    * </ul>
 210    *
 211    *
 212    * @param alignment The new horizontal alignment.
 213    */
 214  3 public void setHorizontalAlignment( final int alignment ) {
 215  3 Trace.println( traceChannel_, "setHorizontalAlignment()" );
 216  3 switch ( alignment ) {
 217  1 case TableLayout.LEFT:
 218  1 case TableLayout.RIGHT:
 219  1 case TableLayout.CENTER:
 220  3 horizontalAlignment_ = alignment;
 221  3 break;
 222  0 default:
 223  0 throw new DetailedIllegalArgumentException( "alignment", new Integer(alignment) );
 224    }
 225    }
 226   
 227   
 228    /**
 229    * Set the minimum row height for a specific row.
 230    *
 231    * @param index The row that we are setting the height for.
 232    * @param size The new minimum height.
 233    */
 234  3 public void setMinimumRowHeight( final int index, final int size ) {
 235  3 final HeaderPermanentInfo info
 236    = getPermanentInfo( rowHeaderPermanentInfos_, index, true );
 237  3 info.setMin( size );
 238    }
 239   
 240   
 241    /**
 242    * Set the minimum column width for a specific column.
 243    *
 244    * @param index The column that we are setting the width for.
 245    * @param size The new width.
 246    */
 247  2 public void setMinimumColumnWidth( final int index, final int size ) {
 248  2 final HeaderPermanentInfo info
 249    = getPermanentInfo( columnHeaderPermanentInfos_, index, true );
 250  2 info.setMin( size );
 251    }
 252   
 253   
 254    /**
 255    * Set whether this row can be expanded beyond its preferred size.
 256    *
 257    * @param index The row index.
 258    * @param isExpandable true if the row is to be expandable.
 259    */
 260  4 public void setRowExpandable( final int index,
 261    final boolean isExpandable ) {
 262  4 final HeaderPermanentInfo info
 263    = getPermanentInfo( rowHeaderPermanentInfos_, index, true );
 264  4 info.setExpandable( isExpandable );
 265    }
 266   
 267   
 268    /**
 269    * Set whether this column can be expanded beyond its preferred size.
 270    *
 271    * @param index The column index.
 272    * @param isExpandable true if the column is to be expandable.
 273    */
 274  6 public void setColumnExpandable( final int index,
 275    final boolean isExpandable ) {
 276  6 final HeaderPermanentInfo info
 277    = getPermanentInfo( columnHeaderPermanentInfos_, index, true );
 278  6 info.setExpandable( isExpandable );
 279    }
 280   
 281   
 282    /**
 283    * Set the trace channel used for printing diagnostic information. If the
 284    * channel is null then no tracing will be done.
 285    *
 286    * @param channel The new trace channel.
 287    */
 288  0 public void setTraceChannel( final TraceChannel channel ) {
 289  0 traceChannel_ = channel;
 290    }
 291   
 292   
 293    /**
 294    * Set whether or not we should ignore an components that are not visible.
 295    *
 296    * @param ignore True if we should ignore them.
 297    */
 298  0 public void setIgnoreInvisibleComponents( final boolean ignore ) {
 299  0 ignoreInvisibleComponents_ = ignore;
 300    }
 301   
 302   
 303    /**
 304    * I don't really understand what this method is supposed to return so I
 305    * always return 0F. If you can explain this one to me then send me an
 306    * email at mbowler@GargoyleSoftware.com and I'll fix this method up
 307    * appropriately.
 308    *
 309    * @param target The container that this layout is managing.
 310    * @return Zero.
 311    */
 312  0 public float getLayoutAlignmentX( final Container target ) {
 313  0 return 0F;
 314    }
 315   
 316   
 317    /**
 318    * I don't really understand what this method is supposed to return so I
 319    * always return 0F. If you can explain this one to me then send me an
 320    * email at mbowler@GargoyleSoftware.com and I'll fix this method up
 321    * appropriately.
 322    *
 323    * @param target The container that this layout is managing.
 324    * @return Zero.
 325    */
 326  0 public float getLayoutAlignmentY( final Container target ) {
 327  0 return 0F;
 328    }
 329   
 330   
 331    /**
 332    * Return the vertical alignment.
 333    *
 334    * @return The vertical alignment.
 335    * @see #setVerticalAlignment(int)
 336    */
 337  0 public int getVerticalAlignment() {
 338  0 return verticalAlignment_;
 339    }
 340   
 341   
 342    /**
 343    * Return the horizontal alignment.
 344    *
 345    * @return The horizontal alignment.
 346    */
 347  0 public int getHorizontalAlignment() {
 348  0 return horizontalAlignment_;
 349    }
 350   
 351   
 352    /**
 353    * Return true if this row can be expanded beyond its preferred size. The
 354    * default is false.
 355    *
 356    * @param index The row index
 357    * @return true if the specified row is expandable.
 358    */
 359  76 public boolean isRowExpandable( final int index ) {
 360  76 final HeaderPermanentInfo info
 361    = getPermanentInfo( rowHeaderPermanentInfos_, index, false );
 362  76 final boolean isExpandable;
 363  76 if( info == null ) {
 364  69 isExpandable = false;
 365    }
 366    else {
 367  7 isExpandable = info.isExpandable();
 368    }
 369  76 return isExpandable;
 370    }
 371   
 372   
 373    /**
 374    * Return true if this column can be expanded beyond its preferred size.
 375    * The default is false.
 376    *
 377    * @param index The column.
 378    * @return true if the column is expandable.
 379    */
 380  67 public boolean isColumnExpandable( final int index ) {
 381  67 final HeaderPermanentInfo info
 382    = getPermanentInfo( columnHeaderPermanentInfos_, index, false );
 383  67 final boolean isExpandable;
 384  67 if( info == null ) {
 385  57 isExpandable = false;
 386    }
 387    else {
 388  10 isExpandable = info.isExpandable();
 389    }
 390  67 return isExpandable;
 391    }
 392   
 393   
 394    /**
 395    * Return the trace channel.
 396    *
 397    * @return The trace channel or null if one wasn't set.
 398    */
 399  0 public TraceChannel getTraceChannel() {
 400  0 return traceChannel_;
 401    }
 402   
 403   
 404    /**
 405    * Get whether or not we should ignore an components that are not visible.
 406    *
 407    * @return True if we should ignore them.
 408    */
 409  0 public boolean getIgnoreInvisibleComponents() {
 410  0 return ignoreInvisibleComponents_;
 411    }
 412   
 413   
 414    /**
 415    * Add the specified component to the layout with the specified
 416    * constraints. This method should never be called as Container.addImpl()
 417    * should call addLayoutComponent(Component,Object) instead. Not
 418    * implemented.
 419    *
 420    * @param name The constraints string.
 421    * @param comp the component that is being
 422    * added.
 423    * @throws UnsupportedOperationException If called.
 424    */
 425  0 public void addLayoutComponent( final String name, final Component comp )
 426    throws UnsupportedOperationException {
 427  0 throw new UnsupportedOperationException( "Use addLayoutComponent(Component,Object)" );
 428    }
 429   
 430   
 431    /**
 432    * Add the specified component to the layout with the specified
 433    * constraints. Throw an IllegalArgumentException if the same component is
 434    * specified twice. The constraints object can be either an instance of
 435    * TableLayoutConstraints or a String. If it is a string then an instance
 436    * of TableLayoutConstraints will be created with the method
 437    * TableLayoutConstraints.makeConstraints(String).
 438    *
 439    * @param comp The component that is being added.
 440    * @param constraints The constraints object.
 441    * @see TableLayoutConstraints#makeConstraints(String)
 442    */
 443  43 public void addLayoutComponent( final Component comp, final Object constraints ) {
 444  43 assertNotNull("comp", comp);
 445  42 assertNotNull("constraints", constraints);
 446   
 447  42 TableLayoutConstraints tableLayoutConstraints = null;
 448  42 if( constraints instanceof TableLayoutConstraints ) {
 449  37 tableLayoutConstraints = (TableLayoutConstraints)constraints;
 450    }
 451  5 else if( constraints instanceof String ) {
 452  4 tableLayoutConstraints
 453    = TableLayoutConstraints.makeConstraints( (String)constraints );
 454    }
 455    else {
 456  1 throw new DetailedIllegalArgumentException( "constraints", constraints, "Must be an instance "
 457    + "of TableLayoutConstraints or String: "
 458    + constraints.getClass().getName() );
 459    }
 460   
 461  41 final Iterator iterator = constraints_.iterator();
 462  41 while( iterator.hasNext() ) {
 463  34 if( ( (Entry)iterator.next() ).getComponent() == comp ) {
 464  1 throw new DetailedIllegalArgumentException( "comp", comp, "Already in layout" );
 465    }
 466    }
 467   
 468  40 tableLayoutConstraints.setImmutable();
 469  40 final Entry entry = new Entry( comp, tableLayoutConstraints );
 470  40 constraints_.add( entry );
 471  40 invalidateLayout();
 472    }
 473   
 474   
 475    /**
 476    * Remove the specified component from the layout.
 477    *
 478    * @param comp The component to remove.
 479    */
 480  7 public void removeLayoutComponent( final Component comp ) {
 481  7 Trace.println( traceChannel_, "removeLayoutComponent(" + comp + ")" );
 482  7 assertNotNull("comp", comp);
 483   
 484  6 Entry entry;
 485  6 final Iterator iterator = constraints_.iterator();
 486  6 while( iterator.hasNext() ) {
 487  9 entry = (Entry)iterator.next();
 488  9 if( entry.getComponent() == comp ) {
 489  5 iterator.remove();
 490  5 invalidateLayout();
 491  5 return;
 492    }
 493    }
 494   
 495  1 throw new DetailedIllegalArgumentException( "comp", comp, "Not found" );
 496    }
 497   
 498   
 499    /**
 500    * Get the minimum size of this layout.
 501    *
 502    * @param parent The container that this layout is managing.
 503    * @return The minimum size required for this layout.
 504    */
 505  14 public Dimension minimumLayoutSize( final Container parent ) {
 506  14 setParent( parent );
 507   
 508  12 if( minimumSize_ == null ) {
 509  9 calculateMinMaxPreferredSizes();
 510    }
 511  12 return minimumSize_;
 512    }
 513   
 514   
 515    /**
 516    * Return the preferred layout size.
 517    *
 518    * @param parent The container that this layout is managing.
 519    * @return The preferred layout size.
 520    */
 521  35 public Dimension preferredLayoutSize( final Container parent ) {
 522  35 setParent( parent );
 523   
 524  35 if( preferredSize_ == null ) {
 525  15 calculateMinMaxPreferredSizes();
 526    }
 527  35 return preferredSize_;
 528    }
 529   
 530   
 531    /**
 532    * Layout all the components in this container.
 533    *
 534    * @param parent The container that this layout is managing.
 535    */
 536  20 public void layoutContainer( final Container parent ) {
 537  20 setParent( parent );
 538   
 539  20 final Dimension parentSize = parent.getSize();
 540  20 Entry entry;
 541  20 int x = 0;
 542  20 int y = 0;
 543  20 int height = 0;
 544  20 int width = 0;
 545  20 int i;
 546  20 int rowIndex;
 547  20 int columnIndex;
 548   
 549    // Is there anything to do?
 550  20 if( parent.getComponentCount() == 0 ) {
 551  0 return;
 552    }
 553   
 554  20 calculateSizes();
 555  20 calculatePositions( parent, parentSize );
 556   
 557  20 final Iterator iterator = constraints_.iterator();
 558  20 while( iterator.hasNext() ) {
 559  36 entry = (Entry)iterator.next();
 560   
 561  36 rowIndex = entry.getConstraints().getRow();
 562  36 columnIndex = entry.getConstraints().getColumn();
 563   
 564  36 y = tempRowHeaders_[rowIndex].getStart();
 565  36 x = tempColumnHeaders_[columnIndex].getStart();
 566   
 567  36 height = 0;
 568  36 width = 0;
 569  36 for( i = 0; i < entry.getConstraints().getRowSpan(); i++ ) {
 570  38 height += tempRowHeaders_[rowIndex + i].getActual();
 571    }
 572  36 for( i = 0; i < entry.getConstraints().getColumnSpan(); i++ ) {
 573  42 width += tempColumnHeaders_[columnIndex + i].getActual();
 574    }
 575   
 576  36 positionComponent( entry, x, y, width, height );
 577    }
 578    }
 579   
 580   
 581    /**
 582    * Return the maximum layout size.
 583    *
 584    * @param target The container that this layout is managing.
 585    * @return The maximum layout size.
 586    */
 587  1 public Dimension maximumLayoutSize( final Container target ) {
 588  1 setParent( target );
 589  1 if( maximumSize_ == null ) {
 590  0 calculateMinMaxPreferredSizes();
 591    }
 592  1 return maximumSize_;
 593    }
 594   
 595   
 596    /**
 597    * Invalidate the layout and throw away and temporary calculations.
 598    *
 599    * @param target The container that this layout is managing.
 600    */
 601  1 public void invalidateLayout( final Container target ) {
 602  1 setParent( target );
 603  1 invalidateLayout();
 604    }
 605   
 606   
 607    /**
 608    * A debugging method that draws lines on the parent component to show
 609    * where the table cell boundaries are. The lines will be drawn in the
 610    * current colour.
 611    *
 612    * @param graphics The graphics object.
 613    * @see TableLayoutDebuggingPanel
 614    */
 615  0 public void drawOutlines( final Graphics graphics ) {
 616  0 int i;
 617  0 int j;
 618  0 Header column;
 619  0 Header row;
 620   
 621  0 for( i = 0; i < columnCount_; i++ ) {
 622  0 column = tempColumnHeaders_[i];
 623  0 for( j = 0; j < rowCount_; j++ ) {
 624  0 row = tempRowHeaders_[j];
 625  0 graphics.drawRect(
 626    column.getStart(), // x
 627    row.getStart(), // y
 628    column.getActual(), // width
 629    row.getActual() ); // height
 630    }
 631    }
 632    }
 633   
 634   
 635    /**
 636    * Set the parent container for this layout.
 637    *
 638    * @param newParent The new parent value
 639    */
 640  71 private void setParent( final Container newParent ) {
 641  71 assertNotNull("newParent", newParent);
 642   
 643  70 if( ( parent_ != null ) && ( newParent != parent_ ) ) {
 644  1 throw new DetailedIllegalArgumentException( "newParent", newParent, "Attempt to reassign parent" );
 645    }
 646   
 647  69 parent_ = newParent;
 648    }
 649   
 650   
 651    /**
 652    * Return an array containing all the headers that are expandable.
 653    *
 654    * @param first Description of Parameter
 655    * @param last Description of Parameter
 656    * @param headers Description of Parameter
 657    * @return The expandableHeaders value
 658    */
 659  7 private Header[] getExpandableHeaders( final int first,
 660    final int last,
 661    final Header[] headers ) {
 662   
 663  7 final List list = new ArrayList( headers.length );
 664  7 int i;
 665   
 666  7 for( i = first; i <= last; i++ ) {
 667  22 if( headers[i].isExpandable() ) {
 668  5 list.add( headers[i] );
 669    }
 670    }
 671   
 672  7 final Header expandableHeaders[] = new Header[list.size()];
 673  7 list.toArray( expandableHeaders );
 674  7 return expandableHeaders;
 675    }
 676   
 677   
 678    /**
 679    * Return the minimum row height. The default is 0.
 680    *
 681    * @param index Description of Parameter
 682    * @return The minimumRowHeight value
 683    */
 684  152 private int getMinimumRowHeight( final int index ) {
 685  152 final HeaderPermanentInfo info
 686    = getPermanentInfo( rowHeaderPermanentInfos_, index, false );
 687  152 final int result;
 688  152 if( info == null ) {
 689  138 result = 0;
 690    }
 691    else {
 692  14 result = info.getMin();
 693    }
 694  152 return result;
 695    }
 696   
 697   
 698    /**
 699    * Return the minimum column width. The default is 0.
 700    *
 701    * @param index The column index.
 702    * @return The minimum column width for the specified column.
 703    */
 704  134 private int getMinimumColumnWidth( final int index ) {
 705  134 final HeaderPermanentInfo info
 706    = getPermanentInfo( columnHeaderPermanentInfos_, index, false );
 707  134 final int result;
 708  134 if( info == null ) {
 709  114 result = 0;
 710    }
 711    else {
 712  20 result = info.getMin();
 713    }
 714  134 return result;
 715    }
 716   
 717   
 718    /**
 719    * TODO: Provide comments
 720    *
 721    * @param infoList Description of Parameter
 722    * @param index Description of Parameter
 723    * @param createIfNeeded Description of Parameter
 724    * @return The permanentInfo value
 725    */
 726  444 private HeaderPermanentInfo getPermanentInfo( final Set infoList,
 727    final int index,
 728    final boolean createIfNeeded ) {
 729  444 final Iterator iterator = infoList.iterator();
 730  444 HeaderPermanentInfo info;
 731   
 732  444 while( iterator.hasNext() ) {
 733  175 info = (HeaderPermanentInfo)iterator.next();
 734  175 if( info.getIndex() == index ) {
 735  51 return info;
 736    }
 737    }
 738   
 739    // We didn't find one.
 740  393 if( createIfNeeded ) {
 741  15 if( traceChannel_ != null ) {
 742  0 final StringBuffer buffer = new StringBuffer();
 743  0 buffer.append( "getPermanentInfo() creating new info for " );
 744  0 if( infoList == rowHeaderPermanentInfos_ ) {
 745  0 buffer.append( "row " );
 746    }
 747    else {
 748  0 buffer.append( "column " );
 749    }
 750  0 buffer.append( index );
 751  0 Trace.println( buffer.toString() );
 752    }
 753  15 info = new HeaderPermanentInfo( index );
 754  15 infoList.add( info );
 755    }
 756    else {
 757  378 info = null;
 758    }
 759   
 760  393 return info;
 761    }
 762   
 763   
 764    /**
 765    * Return the TableLayoutConstraints object that corresponds to the
 766    * specified component or null if this component could not be found.
 767    *
 768    * @param component Description of Parameter
 769    * @return The constraints value
 770    */
 771  0 private TableLayoutConstraints getConstraints( final Component component ) {
 772  0 Entry entry;
 773   
 774  0 final Iterator iterator = constraints_.iterator();
 775  0 while( iterator.hasNext() ) {
 776  0 entry = (Entry)iterator.next();
 777   
 778  0 if( entry.getComponent() == component ) {
 779  0 return entry.getConstraints();
 780    }
 781    }
 782   
 783  0 return null;
 784    }
 785   
 786   
 787    /**
 788    * Return the minimum size of the specified component. If the component is
 789    * not visible and we are ignoring invisible components then return a size
 790    * of 0,0
 791    *
 792    * @param component The component that we will be querying
 793    * @return The size
 794    */
 795  82 private final Dimension getComponentMinimumSize( final Component component ) {
 796  82 final Dimension size;
 797  82 if( component.isVisible() == false && ignoreInvisibleComponents_ == true ) {
 798  0 size = new Dimension( 0, 0 );
 799    }
 800    else {
 801  82 size = component.getMinimumSize();
 802    }
 803  82 return size;
 804    }
 805   
 806   
 807    /**
 808    * Return the minimum size of the specified component. If the component is
 809    * not visible and we are ignoring invisible components then return a size
 810    * of 0,0
 811    *
 812    * @param component The component that we will be querying
 813    * @return The size
 814    */
 815  15 private final Dimension getComponentMaximumSize( final Component component ) {
 816  15 final Dimension size;
 817  15 if( component.isVisible() == false && ignoreInvisibleComponents_ == true ) {
 818  0 size = new Dimension( 0, 0 );
 819    }
 820    else {
 821  15 size = component.getMaximumSize();
 822    }
 823  15 return size;
 824    }
 825   
 826   
 827    /**
 828    * Return the minimum size of the specified component. If the component is
 829    * not visible and we are ignoring invisible components then return a size
 830    * of 0,0
 831    *
 832    * @param component The component that we will be querying
 833    * @return The size
 834    */
 835  118 private final Dimension getComponentPreferredSize( final Component component ) {
 836  118 final Dimension size;
 837  118 if( component.isVisible() == false && ignoreInvisibleComponents_ == true ) {
 838  0 size = new Dimension( 0, 0 );
 839    }
 840    else {
 841  118 size = component.getPreferredSize();
 842    }
 843  118 return size;
 844    }
 845   
 846   
 847    /**
 848    * Calculate the various sizes.
 849    */
 850  24 private void calculateMinMaxPreferredSizes() {
 851  24 int i;
 852  24 int xMin = 0;
 853  24 int yMin = 0;
 854  24 int xMax = 0;
 855  24 int yMax = 0;
 856  24 int xPreferred = 0;
 857  24 int yPreferred = 0;
 858   
 859  24 calculateRowAndColumnCount();
 860  24 calculateSizes();
 861   
 862  24 if( false ) {
 863  0 Trace.println(
 864    //traceChannel_,
 865    "calculateMinMaxPreferredSize() tempRowHeaders_=["
 866    + tempRowHeaders_
 867    + "] rowCount_=["
 868    + rowCount_
 869    + "] columnCount=["
 870    + columnCount_
 871    + "] tempSizesAreValid_=["
 872    + tempSizesAreValid_
 873    + "]" );
 874    }
 875   
 876  24 for( i = 0; i < rowCount_; i++ ) {
 877  76 yMin += tempRowHeaders_[i].getMin();
 878  76 yMax += tempRowHeaders_[i].getMax();
 879  76 yPreferred += tempRowHeaders_[i].getPreferred();
 880    }
 881   
 882  24 for( i = 0; i < columnCount_; i++ ) {
 883  67 xMin += tempColumnHeaders_[i].getMin();
 884  67 xMax += tempColumnHeaders_[i].getMax();
 885  67 xPreferred += tempColumnHeaders_[i].getPreferred();
 886    }
 887   
 888    // Adjust for the insets
 889  24 final Insets insets = parent_.getInsets();
 890  24 final int horizontalInset = insets.left + insets.right;
 891  24 final int verticalInset = insets.top + insets.bottom;
 892   
 893  24 xMin += horizontalInset;
 894  24 yMin += verticalInset;
 895  24 xPreferred += horizontalInset;
 896  24 yPreferred += verticalInset;
 897  24 xMax += horizontalInset;
 898  24 yMax += verticalInset;
 899   
 900  24 xPreferred = Math.max( xPreferred, xMin );
 901  24 xMax = Math.max( xMax, xPreferred );
 902  24 yPreferred = Math.max( yPreferred, yMin );
 903  24 yMax = Math.max( yMax, yPreferred );
 904   
 905    // If any rows/columns are expandable then the max is infinite
 906  24 if( areAnyExpandable( rowHeaderPermanentInfos_ ) ) {
 907  4 yMax = Integer.MAX_VALUE;
 908    }
 909  24 if( areAnyExpandable( columnHeaderPermanentInfos_ ) ) {
 910  6 xMax = Integer.MAX_VALUE;
 911    }
 912   
 913    // TODO: Cache these values if possible. It's expensive
 914    // to keep creating new Dimensions
 915  24 minimumSize_ = new Dimension( xMin, yMin );
 916  24 maximumSize_ = new Dimension( xMax, yMax );
 917  24 preferredSize_ = new Dimension( xPreferred, yPreferred );
 918   
 919  24 if( constraints_.size() == 0 ) {
 920    // Special case when no children
 921  4 maximumSize_ = new Dimension( Integer.MAX_VALUE, Integer.MAX_VALUE );
 922    }
 923    }
 924   
 925   
 926    /**
 927    * Return true if any of the infos are expandable.
 928    *
 929    * @param permanentInfos The infos.
 930    * @return Description of the Returned Value
 931    */
 932  48 private boolean areAnyExpandable( final Set permanentInfos ) {
 933  48 HeaderPermanentInfo info;
 934   
 935  48 final Iterator iterator = permanentInfos.iterator();
 936  48 while( iterator.hasNext() ) {
 937  12 info = (HeaderPermanentInfo)iterator.next();
 938  12 if( info.isExpandable() ) {
 939  10 return true;
 940    }
 941    }
 942   
 943  38 return false;
 944    }
 945   
 946   
 947    /**
 948    * Invalidate the layout.
 949    */
 950  46 private void invalidateLayout() {
 951  46 tempColumnHeaders_ = null;
 952  46 tempRowHeaders_ = null;
 953  46 tempSizesAreValid_ = false;
 954  46 minimumSize_ = null;
 955  46 maximumSize_ = null;
 956  46 preferredSize_ = null;
 957  46 actualSize_ = null;
 958  46 columnCount_ = 0;
 959  46 rowCount_ = 0;
 960    }
 961   
 962   
 963    /**
 964    * Calculate all the various sizing information required for this layout.
 965    * Called by layoutContainer(), minimumLayoutSize(), maximumLayoutSize()
 966    */
 967  44 private void calculateSizes() {
 968  44 if( false ) {
 969  0 Trace.println( "TableLayout.calculateSizes() "
 970    + "tempSizesAreValid_=["
 971    + tempSizesAreValid_
 972    + "] tempRowHeaders_=["
 973    + tempRowHeaders_
 974    + "] tempColumnHeaders_=["
 975    + tempColumnHeaders_
 976    + "]" );
 977    }
 978  44 if( tempSizesAreValid_ && tempRowHeaders_ == null ) {
 979  0 Trace.whereAmI();
 980    }
 981  44 Dimension minSize;
 982  44 Dimension maxSize;
 983  44 Dimension preferredSize;
 984  44 Entry entry;
 985  44 TableLayoutConstraints constraints;
 986  44 Iterator iterator;
 987   
 988    // See if there's anything to do...
 989  44 if( rowCount_ == 0 || columnCount_ == 0 ) {
 990  13 return;
 991    }
 992   
 993  31 if( tempSizesAreValid_ ) {
 994  11 return;
 995    }
 996  20 tempSizesAreValid_ = true;
 997   
 998  20 initTempSizes();
 999   
 1000    //
 1001    // On the first pass handle only those constraints that only
 1002    // span one cell.
 1003    //
 1004  20 iterator = constraints_.iterator();
 1005  20 while( iterator.hasNext() ) {
 1006  41 entry = (Entry)iterator.next();
 1007  41 constraints = entry.getConstraints();
 1008   
 1009  41 if( constraints.getObeyMinimumSize() ) {
 1010  41 minSize = getComponentMinimumSize( entry.getComponent() );
 1011    }
 1012    else {
 1013  0 minSize = new Dimension( 0, 0 );
 1014    }
 1015   
 1016  41 if( constraints.getObeyMaximumSize() ) {
 1017  5 maxSize = getComponentMaximumSize( entry.getComponent() );
 1018    }
 1019    else {
 1020  36 maxSize = new Dimension( Integer.MAX_VALUE, Integer.MAX_VALUE );
 1021    }
 1022  41 preferredSize = getComponentPreferredSize( entry.getComponent() );
 1023   
 1024    // Handle the rows
 1025  41 if( constraints.getRowSpan() == 1 ) {
 1026  39 Trace.println( traceChannel_, "tempRowHeaders_.length=["
 1027    + tempRowHeaders_.length + "] constraints.getRow()=["
 1028    + constraints.getRow() + "]" );
 1029  39 tempRowHeaders_[constraints.getRow()].setHasComponents( true );
 1030   
 1031  39 if( minSize.height > tempRowHeaders_[constraints.getRow()].getMin() ) {
 1032  33 tempRowHeaders_[constraints.getRow()].setMin( minSize.height );
 1033    }
 1034  39 if( maxSize.height > tempRowHeaders_[constraints.getRow()].getMax() ) {
 1035  0 tempRowHeaders_[constraints.getRow()].setMax( maxSize.height );
 1036    }
 1037  39 if( preferredSize.height > tempRowHeaders_[constraints.getRow()].getPreferred() ) {
 1038  32 tempRowHeaders_[constraints.getRow()].setPreferred( preferredSize.height );
 1039    }
 1040   
 1041    // TODO: Do we need to worry about this here? We will adjust
 1042    // it later.
 1043    // If the minimum and maximum sizes collide then minimum will
 1044    // always win.
 1045  39 if( tempRowHeaders_[constraints.getRow()].getMin()
 1046    > tempRowHeaders_[constraints.getRow()].getMax() ) {
 1047  0 tempRowHeaders_[constraints.getRow()].setMax( tempRowHeaders_[constraints.getRow()].getMin() );
 1048    }
 1049    // If the minimum and preferred sizes collide then minimum will
 1050    // always win.
 1051  39 if( tempRowHeaders_[constraints.getRow()].getMin()
 1052    > tempRowHeaders_[constraints.getRow()].getPreferred() ) {
 1053  1 tempRowHeaders_[constraints.getRow()].setPreferred(
 1054    tempRowHeaders_[constraints.getRow()].getMin() );
 1055    }
 1056    }
 1057   
 1058    // Handle the columns
 1059  41 if( constraints.getColumnSpan() == 1 ) {
 1060  36 if( minSize.width > tempColumnHeaders_[constraints.getColumn()].getMin() ) {
 1061  29 tempColumnHeaders_[constraints.getColumn()].setMin( minSize.width );
 1062    }
 1063  36 if( maxSize.width > tempColumnHeaders_[constraints.getColumn()].getMax() ) {
 1064  0 tempColumnHeaders_[constraints.getColumn()].setMax( maxSize.width );
 1065    }
 1066  36 if( preferredSize.width > tempColumnHeaders_[constraints.getColumn()].getPreferred() ) {
 1067  28 tempColumnHeaders_[constraints.getColumn()].setPreferred( preferredSize.width );
 1068    }
 1069   
 1070  36 tempColumnHeaders_[constraints.getColumn()].setHasComponents( true );
 1071   
 1072    // If the minimum and maximum sizes collide then minimum will
 1073    // always win.
 1074  36 if( tempColumnHeaders_[constraints.getColumn()].getMin()
 1075    > tempColumnHeaders_[constraints.getColumn()].getMax() ) {
 1076  0 tempColumnHeaders_[constraints.getColumn()].setMax(
 1077    tempColumnHeaders_[constraints.getColumn()].getMin() );
 1078    }
 1079    // If the minimum and preferred sizes collide then minimum will
 1080    // always win.
 1081  36 if( tempColumnHeaders_[constraints.getColumn()].getMin()
 1082    > tempColumnHeaders_[constraints.getColumn()].getPreferred() ) {
 1083  1 tempColumnHeaders_[constraints.getColumn()].setPreferred(
 1084    tempColumnHeaders_[constraints.getColumn()].getMin() );
 1085    }
 1086    }
 1087    }
 1088   
 1089    //
 1090    // Do a second pass to handle objects that span multiple cells.
 1091    //
 1092  20 iterator = constraints_.iterator();
 1093  20 while( iterator.hasNext() ) {
 1094  41 entry = (Entry)iterator.next();
 1095  41 constraints = entry.getConstraints();
 1096   
 1097  41 if( constraints.getObeyMinimumSize() ) {
 1098  41 minSize = getComponentMinimumSize( entry.getComponent() );
 1099    }
 1100    else {
 1101  0 minSize = new Dimension( 0, 0 );
 1102    }
 1103   
 1104  41 if( constraints.getObeyMaximumSize() == true ) {
 1105  5 maxSize = getComponentMaximumSize( entry.getComponent() );
 1106    }
 1107    else {
 1108  36 maxSize = new Dimension( Integer.MAX_VALUE, Integer.MAX_VALUE );
 1109    }
 1110  41 preferredSize = getComponentPreferredSize( entry.getComponent() );
 1111   
 1112    // Handle the rows
 1113  41 if( constraints.getRowSpan() != 1 ) {
 1114  2 adjustSizesForSpanning( constraints.getRow(), constraints.getRowSpan(),
 1115    tempRowHeaders_,
 1116    minSize.height, preferredSize.height, maxSize.height );
 1117    }
 1118   
 1119    // Handle the columns
 1120  41 if( constraints.getColumnSpan() != 1 ) {
 1121  5 adjustSizesForSpanning( constraints.getColumn(), constraints.getColumnSpan(),
 1122    tempColumnHeaders_,
 1123    minSize.width, preferredSize.width, maxSize.width );
 1124    }
 1125    }
 1126   
 1127    // Fix up the headers to ensure that:
 1128    // minimum < preferred < maximum
 1129  20 adjustHeaderSizes( tempRowHeaders_ );
 1130  20 adjustHeaderSizes( tempColumnHeaders_ );
 1131    }
 1132   
 1133   
 1134    /**
 1135    * Adjust the various sizes to account for components than span multiple
 1136    * columns/rows.
 1137    *
 1138    * @param start The starting index of the component.
 1139    * @param span The number of columns/rows that the component
 1140    * spans.
 1141    * @param sizes The headers that we are adjusting.
 1142    * @param minSize The minimum size of the component.
 1143    * @param preferredSize The preferred size of the component.
 1144    * @param maxSize The maximum size of the component.
 1145    */
 1146  7 private void adjustSizesForSpanning( final int start,
 1147    final int span,
 1148    final Header sizes[],
 1149    final int minSize,
 1150    final int preferredSize,
 1151    final int maxSize ) {
 1152  7 int combinedSize;
 1153  7 int remainder;
 1154  7 int i;
 1155   
 1156  7 final Header expandableHeaders[] = getExpandableHeaders( start, start + span, sizes );
 1157   
 1158    //TODO: Far too much duplicated code here. This method needs to
 1159    // be refactored.
 1160   
 1161    //
 1162    // Handle Minimum size
 1163    //
 1164  7 combinedSize = 0;
 1165  7 for( i = 0; i < span; i++ ) {
 1166  15 combinedSize += sizes[start + i].getMin();
 1167    }
 1168  7 if( minSize > combinedSize ) {
 1169  0 if( expandableHeaders.length == 0 ) {
 1170  0 final int delta = ( minSize - combinedSize ) / span;
 1171  0 for( i = 0; i < span; i++ ) {
 1172  0 sizes[start + i].setMin( sizes[start + i].getMin() + delta );
 1173  0 combinedSize += delta;
 1174    }
 1175    // Use up the last bit.
 1176  0 remainder = minSize - combinedSize;
 1177  0 for( i = 0; i < remainder; i++ ) {
 1178  0 sizes[start + i].setMin( sizes[start + i].getMin() + 1 );
 1179    }
 1180    }
 1181    else {
 1182  0 final int delta = ( minSize - combinedSize ) / expandableHeaders.length;
 1183  0 for( i = 0; i < expandableHeaders.length; i++ ) {
 1184  0 expandableHeaders[i].setMin( expandableHeaders[i].getMin() + delta );
 1185  0 combinedSize += delta;
 1186    }
 1187    // Use up the last bit.
 1188  0 remainder = minSize - combinedSize;
 1189  0 for( i = 0; i < remainder; i++ ) {
 1190  0 expandableHeaders[i].setMin( expandableHeaders[i].getMin() + 1 );
 1191    }
 1192    }
 1193    }
 1194   
 1195    //
 1196    // Handle preferred size
 1197    //
 1198  7 combinedSize = 0;
 1199  7 for( i = 0; i < span; i++ ) {
 1200  15 combinedSize += sizes[start + i].getPreferred();
 1201    }
 1202  7 if( preferredSize > combinedSize ) {
 1203  3 if( expandableHeaders.length == 0 ) {
 1204    // None of the headers are marked expandable so expand them all a bit.
 1205  0 final int delta = ( preferredSize - combinedSize ) / span;
 1206  0 for( i = 0; i < span; i++ ) {
 1207  0 sizes[start + i].setPreferred( sizes[start + i].getPreferred() + delta );
 1208  0 combinedSize += delta;
 1209    }
 1210    // Use up the last bit.
 1211  0 remainder = preferredSize - combinedSize;
 1212  0 for( i = 0; i < remainder; i++ ) {
 1213  0 sizes[start + i].setPreferred( sizes[start + i].getPreferred() + 1 );
 1214    }
 1215    }
 1216    else {
 1217    // Only expand those that are explicitly marked as expandable.
 1218  3 final int delta = ( preferredSize - combinedSize ) / expandableHeaders.length;
 1219  3 for( i = 0; i < expandableHeaders.length; i++ ) {
 1220  5 expandableHeaders[i].setPreferred( expandableHeaders[i].getPreferred() + delta );
 1221  5 combinedSize += delta;
 1222    }
 1223    // Use up the last bit.
 1224  3 remainder = preferredSize - combinedSize;
 1225  3 for( i = 0; i < remainder; i++ ) {
 1226  1 expandableHeaders[i].setPreferred( expandableHeaders[i].getPreferred() + 1 );
 1227    }
 1228    }
 1229    }
 1230    }
 1231   
 1232   
 1233    /**
 1234    * Calculate all the positions of the various rows/columns
 1235    *
 1236    * @param parent Description of Parameter
 1237    * @param parentSize Description of Parameter
 1238    */
 1239  20 private void calculatePositions( final Container parent,
 1240    final Dimension parentSize ) {
 1241  20 int i;
 1242  20 int rowStart;
 1243  20 int columnStart;
 1244   
 1245  20 final Insets insets = parent.getInsets();
 1246   
 1247    //
 1248    // Account for stretching.
 1249    //
 1250  20 calculateActualSizes( parentSize );
 1251   
 1252    //
 1253    // Determine the starting coordinates
 1254    //
 1255  20 switch ( verticalAlignment_ ) {
 1256  1 case TOP:
 1257  1 rowStart = insets.top;
 1258  1 break;
 1259  1 case BOTTOM:
 1260  1 rowStart = parentSize.height - actualSize_.height - insets.bottom;
 1261  1 break;
 1262  18 case CENTER:
 1263  18 rowStart = ( parentSize.height - actualSize_.height
 1264    - insets.top - insets.bottom ) / 2 + insets.top;
 1265  18 break;
 1266  0 default:
 1267  0 throw new IllegalStateException( "Unknown verticalAlignment: "
 1268    + verticalAlignment_ );
 1269    }
 1270   
 1271  20 switch ( horizontalAlignment_ ) {
 1272  1 case LEFT:
 1273  1 columnStart = insets.left;
 1274  1 break;
 1275  1 case RIGHT:
 1276  1 columnStart = parentSize.width - actualSize_.width - insets.right;
 1277  1 break;
 1278  18 case CENTER:
 1279  18 columnStart = ( parentSize.width - actualSize_.width
 1280    - insets.left - insets.right ) / 2 + insets.left;
 1281  18 break;
 1282  0 default:
 1283  0 throw new IllegalStateException( "Unknown horizontalAlignment: "
 1284    + horizontalAlignment_ );
 1285    }
 1286   
 1287  20 tempRowHeaders_[0].setStart( rowStart );
 1288  20 for( i = 1; i < rowCount_; i++ ) {
 1289  56 tempRowHeaders_[i].setStart( tempRowHeaders_[i - 1].getStart() + tempRowHeaders_[i - 1].getActual() );
 1290    }
 1291   
 1292  20 tempColumnHeaders_[0].setStart( columnStart );
 1293  20 for( i = 1; i < columnCount_; i++ ) {
 1294  47 tempColumnHeaders_[i].setStart( tempColumnHeaders_[i - 1].getStart()
 1295    + tempColumnHeaders_[i - 1].getActual() );
 1296    }
 1297   
 1298    // Dump out a bunch of tracing information
 1299  20 if( traceChannel_ != null ) {
 1300  0 Trace.println( traceChannel_,
 1301    "TableLayout.calculatePositions() START parentSize="
 1302    + parentSize );
 1303  0 for( i = 0; i < rowCount_; i++ ) {
 1304  0 Trace.println( traceChannel_,
 1305    " tempRowSizes[" + i + "]="
 1306    + tempRowHeaders_[i] );
 1307    }
 1308  0 for( i = 0; i < columnCount_; i++ ) {
 1309  0 Trace.println( traceChannel_,
 1310    " tempColumnSizes[" + i + "]="
 1311    + tempColumnHeaders_[i] );
 1312    }
 1313  0 final Component children[] = parent_.getComponents();
 1314  0 StringBuffer buffer;
 1315  0 TableLayoutConstraints constraints;
 1316  0 for( i = 0; i < children.length; i++ ) {
 1317  0 constraints = getConstraints( children[i] );
 1318  0 buffer = new StringBuffer();
 1319  0 buffer.append( " children[" + i + "] min=" );
 1320  0 buffer.append( toString( children[i].getMinimumSize() ) );
 1321  0 buffer.append( " preferred=" );
 1322  0 buffer.append( toString( children[i].getPreferredSize() ) );
 1323  0 buffer.append( " visible=[" );
 1324  0 buffer.append( children[i].isVisible() );
 1325  0 buffer.append( " type=[" );
 1326  0 buffer.append( children[i].getClass().getName() );
 1327  0 buffer.append( "] name=[" );
 1328  0 buffer.append( children[i].getName() );
 1329  0 buffer.append( "] row=[" );
 1330  0 buffer.append( constraints.getRow() );
 1331  0 buffer.append( "+" );
 1332  0 buffer.append( constraints.getRowSpan() );
 1333  0 buffer.append( "] column=[" );
 1334  0 buffer.append( constraints.getColumn() );
 1335  0 buffer.append( "+" );
 1336  0 buffer.append( constraints.getColumnSpan() );
 1337  0 buffer.append( "]" );
 1338  0 Trace.println( traceChannel_, buffer.toString() );
 1339    }
 1340  0 Trace.println( traceChannel_,
 1341    "TableLayout.calculatePositions() END" );
 1342    }
 1343    }
 1344   
 1345   
 1346    /**
 1347    * Position one component given the bounding coordinates
 1348    *
 1349    * @param entry Description of Parameter
 1350    * @param x Description of Parameter
 1351    * @param y Description of Parameter
 1352    * @param width Description of Parameter
 1353    * @param height Description of Parameter
 1354    */
 1355  36 private void positionComponent( final Entry entry,
 1356    final int x, final int y,
 1357    final int width, final int height ) {
 1358   
 1359  36 final TableLayoutConstraints constraints = entry.getConstraints();
 1360  36 final Dimension maxSize;
 1361    // TODO: Investigate why we're using preferred size but calling it minimum size
 1362  36 final Dimension minSize = getComponentPreferredSize( entry.getComponent() );
 1363  36 int newWidth;
 1364  36 int newHeight;
 1365  36 final int newX;
 1366  36 final int newY;
 1367   
 1368  36 if( constraints.getObeyMaximumSize() == true ) {
 1369  5 maxSize = getComponentMaximumSize( entry.getComponent() );
 1370    }
 1371    else {
 1372  31 maxSize = new Dimension( Integer.MAX_VALUE, Integer.MAX_VALUE );
 1373    }
 1374   
 1375  36 if( constraints.getVerticalStretch() ) {
 1376  13 newHeight = Math.min( maxSize.height, height );
 1377    }
 1378    else {
 1379  23 newHeight = minSize.height;
 1380    }
 1381   
 1382  36 if( constraints.getHorizontalStretch() ) {
 1383  18 newWidth = Math.min( maxSize.width, width );
 1384    }
 1385    else {
 1386  18 newWidth = minSize.width;
 1387    }
 1388   
 1389  36 if( newHeight > height ) {
 1390  4 newHeight = height;
 1391    }
 1392  36 if( newWidth > width ) {
 1393  6 newWidth = width;
 1394    }
 1395   
 1396  36 switch ( constraints.getVerticalAlignment() ) {
 1397  1 case TOP:
 1398  1 newY = y;
 1399  1 break;
 1400  0 case BOTTOM:
 1401  0 newY = y + ( height - newHeight );
 1402  0 break;
 1403  35 case CENTER:
 1404  35 newY = y + ( height - newHeight ) / 2;
 1405  35 break;
 1406  0 default:
 1407  0 throw new IllegalStateException(
 1408    "Illegal value for verticalAlignment: "
 1409    + constraints.getVerticalAlignment() );
 1410    }
 1411   
 1412  36 switch ( constraints.getHorizontalAlignment() ) {
 1413  36 case LEFT:
 1414  36 newX = x;
 1415  36 break;
 1416  0 case RIGHT:
 1417  0 newX = x + ( width - newWidth );
 1418  0 break;
 1419  0 case CENTER:
 1420  0 newX = x + ( width - newWidth ) / 2;
 1421  0 break;
 1422  0 default:
 1423  0 throw new IllegalStateException(
 1424    "Illegal value for horizontalAlignment: "
 1425    + constraints.getVerticalAlignment() );
 1426    }
 1427   
 1428  36 entry.getComponent().setBounds( newX, newY, newWidth, newHeight );
 1429    }
 1430   
 1431   
 1432    /**
 1433    * The list of constraints has been modified. Update the row and column
 1434    * counts according to the new constraints.
 1435    */
 1436  24 private void calculateRowAndColumnCount() {
 1437  24 Entry entry;
 1438  24 int lastRow = -1;
 1439  24 int lastColumn = -1;
 1440  24 int row;
 1441  24 int column;
 1442   
 1443  24 Iterator iterator;
 1444  24 TableLayoutConstraints constraints;
 1445   
 1446  24 iterator = constraints_.iterator();
 1447  24 while( iterator.hasNext() ) {
 1448  41 entry = (Entry)iterator.next();
 1449  41 constraints = entry.getConstraints();
 1450   
 1451  41 row = constraints.getRow()
 1452    + constraints.getRowSpan();
 1453  41 if( row > lastRow ) {
 1454  30 lastRow = row;
 1455    }
 1456   
 1457  41 column = constraints.getColumn()
 1458    + constraints.getColumnSpan();
 1459  41 if( column > lastColumn ) {
 1460  30 lastColumn = column;
 1461    }
 1462    }
 1463   
 1464  24 HeaderPermanentInfo info;
 1465   
 1466    // Walk through the permanent infos to see if we have any for
 1467    // rows or columns that aren't accounted for above.
 1468   
 1469  24 iterator = rowHeaderPermanentInfos_.iterator();
 1470  24 while( iterator.hasNext() ) {
 1471  7 info = (HeaderPermanentInfo)iterator.next();
 1472  7 if( info.getIndex() > lastRow ) {
 1473  1 lastRow = info.getIndex();
 1474    }
 1475    }
 1476   
 1477  24 iterator = columnHeaderPermanentInfos_.iterator();
 1478  24 while( iterator.hasNext() ) {
 1479  10 info = (HeaderPermanentInfo)iterator.next();
 1480  10 if( info.getIndex() > lastColumn ) {
 1481  0 Trace.println( traceChannel_,
 1482    "Increasing column count to " + info.getIndex() );
 1483  0 lastColumn = info.getIndex();
 1484    }
 1485    }
 1486   
 1487  24 rowCount_ = lastRow + 1;
 1488  24 columnCount_ = lastColumn + 1;
 1489   
 1490    // KLUDGE: In some circumstances, it is possible to end up with
 1491    // one count being zero and the other non-zero. This is a bug
 1492    // but unfortunately, I haven't been able to reproduce it in a
 1493    // testcase. The workaround is to set both counts to zero if
 1494    // either one is zero. Ugh!
 1495  24 if( rowCount_ == 0 || columnCount_ == 0 ) {
 1496  4 rowCount_ = 0;
 1497  4 columnCount_ = 0;
 1498    }
 1499   
 1500  24 if( traceChannel_ != null ) {
 1501  0 Trace.println( traceChannel_,
 1502    "calculateRowAndColumnCount() rowCount="
 1503    + rowCount_
 1504    + " columnCount_="
 1505    + columnCount_ );
 1506    }
 1507    }
 1508   
 1509   
 1510    /**
 1511    * Calculate the actual sizes to be used based on the actual dimension of
 1512    * the parent container.
 1513    *
 1514    * @param parentSize Description of Parameter
 1515    */
 1516  20 private void calculateActualSizes( final Dimension parentSize ) {
 1517  20 final Dimension preferredSize = preferredLayoutSize( parent_ );
 1518  20 final Insets insets = parent_.getInsets();
 1519   
 1520  20 final int x = calculateActualSizes( tempColumnHeaders_,
 1521    preferredSize.width,
 1522    parentSize.width - insets.left - insets.right );
 1523  20 final int y = calculateActualSizes( tempRowHeaders_,
 1524    preferredSize.height,
 1525    parentSize.height - insets.top - insets.bottom );
 1526  20 actualSize_ = new Dimension( x, y );
 1527    }
 1528   
 1529   
 1530    /**
 1531    * Fix up all the headers such that minimum <= preferred <= maximum
 1532    *
 1533    * @param sizes Description of Parameter
 1534    */
 1535  40 private void adjustHeaderSizes( final Header sizes[] ) {
 1536  40 int i;
 1537  40 Header header;
 1538   
 1539  40 for( i = 0; i < sizes.length; i++ ) {
 1540  143 header = sizes[i];
 1541  143 if( header.getMin() > header.getPreferred() ) {
 1542  0 header.setPreferred( header.getMin() );
 1543    }
 1544  143 if( header.getMin() > header.getMax() ) {
 1545  0 header.setMax( header.getMin() );
 1546    }
 1547  143 if( header.getPreferred() > header.getMax() ) {
 1548  0 header.setPreferred( header.getMax() );
 1549    }
 1550    }
 1551    }
 1552   
 1553   
 1554    /**
 1555    * Calculate the actual sizes for the specified row or column headers.
 1556    * Return the actual length.
 1557    *
 1558    * @param sizes Description of Parameter
 1559    * @param preferredLength Description of Parameter
 1560    * @param clipLength Description of Parameter
 1561    * @return Description of the Returned Value
 1562    */
 1563  40 private int calculateActualSizes( final Header sizes[],
 1564    final int preferredLength,
 1565    final int clipLength ) {
 1566   
 1567  40 int i;
 1568   
 1569  40 if( clipLength < 1 ) {
 1570    // The actual length is not big enough to even display the borders properly
 1571    // therefore all components will have to have a zero size
 1572  4 for( i = 0; i < sizes.length; i++ ) {
 1573  14 sizes[i].setActual( 0 );
 1574    }
 1575  4 return 0;
 1576    }
 1577   
 1578    // If the parent is big enough to hold the preferred size then expand
 1579    // all components to their preferred sizes.
 1580  36 if( preferredLength <= clipLength ) {
 1581  33 for( i = 0; i < sizes.length; i++ ) {
 1582  116 sizes[i].setActual( sizes[i].getPreferred() );
 1583    }
 1584   
 1585  33 if( preferredLength < clipLength ) {
 1586  27 expandToFit( sizes, clipLength );
 1587    }
 1588    }
 1589    else {
 1590  3 shrinkToFit( sizes, clipLength );
 1591    }
 1592   
 1593  36 int actualLength = 0;
 1594  36 for( i = 0; i < sizes.length; i++ ) {
 1595  129 actualLength += sizes[i].getActual();
 1596    }
 1597   
 1598  36 return actualLength;
 1599    }
 1600   
 1601   
 1602    /**
 1603    * Expand the specified sizes to fit within the specified clipLength.
 1604    *
 1605    * @param sizes Description of Parameter
 1606    * @param clipLength Description of Parameter
 1607    */
 1608  27 private void expandToFit( final Header sizes[], final int clipLength ) {
 1609   
 1610  27 int i;
 1611  27 int numberExpandable = 0;
 1612  27 int currentLength = 0;
 1613   
 1614  27 for( i = 0; i < sizes.length; i++ ) {
 1615  88 if( sizes[i].isExpandable() == true ) {
 1616  7 numberExpandable++;
 1617    }
 1618  88 currentLength += sizes[i].getActual();
 1619    }
 1620   
 1621    // If none of the sizes can be expanded then just return.
 1622  27 if( numberExpandable == 0 ) {
 1623  20 return;
 1624    }
 1625  7 int addAmount = ( clipLength - currentLength ) / numberExpandable;
 1626  7 for( i = 0; i < sizes.length; i++ ) {
 1627  21 if( sizes[i].isExpandable() == true ) {
 1628  7 sizes[i].setActual( sizes[i].getActual() + addAmount );
 1629    }
 1630    }
 1631   
 1632    // TODO: Clean up this loop
 1633  7 int remaining = ( clipLength - currentLength )
 1634    - ( addAmount * numberExpandable );
 1635  7 if( remaining != 0 ) {
 1636  0 for( i = 0; i < sizes.length; i++ ) {
 1637  0 if( sizes[i].isExpandable() == true ) {
 1638  0 sizes[i].setActual( sizes[i].getActual() + 1 );
 1639  0 remaining--;
 1640  0 if( remaining == 0 ) {
 1641  0 break;
 1642    }
 1643    }
 1644    }
 1645    }
 1646   
 1647    }
 1648   
 1649   
 1650    /**
 1651    * Shrink the specified sizes to fit within the specified clipLength. Do
 1652    * not shrink beyond the minimum size.
 1653    *
 1654    * @param sizes Description of Parameter
 1655    * @param clipLength Description of Parameter
 1656    */
 1657  3 private void shrinkToFit( final Header sizes[], final int clipLength ) {
 1658  3 if( clipLength < 0 ) {
 1659  0 throw new DetailedIllegalArgumentException(
 1660    "clipLength", new Integer(clipLength), "may not be negative" );
 1661    }
 1662   
 1663  3 int i;
 1664  3 int remaining = clipLength;
 1665   
 1666    // Initialize all sizes to their minimum values
 1667  3 for( i = 0; i < sizes.length; i++ ) {
 1668  13 sizes[i].setActual( sizes[i].getMin() );
 1669  13 remaining -= sizes[i].getActual();
 1670    }
 1671   
 1672  3 if( remaining < 0 ) {
 1673    // The clipLength is smaller then the minimum sizes. Since we
 1674    // can't shrink beyond minimum size, return now.
 1675  0 return;
 1676    }
 1677   
 1678    // Now enlarge each one until either we've reached the size we want or
 1679    // we can't add any more
 1680  3 int delta;
 1681  3 int addAmount = 1;
 1682  3 int numberChanged = sizes.length;
 1683  7 while( numberChanged != 0 ) {
 1684   
 1685    // TODO: Clean up this loop
 1686  7 addAmount = remaining / numberChanged;
 1687  7 if( addAmount == 0 ) {
 1688  0 addAmount = 1;
 1689    }
 1690   
 1691  7 numberChanged = 0;
 1692  7 for( i = 0; i < sizes.length; i++ ) {
 1693  30 delta = sizes[i].getPreferred() - sizes[i].getActual();
 1694   
 1695  30 if( delta > 0 ) {
 1696  11 delta = Math.min( delta, addAmount );
 1697  11 sizes[i].setActual( sizes[i].getActual() + delta );
 1698  11 numberChanged++;
 1699  11 remaining -= delta;
 1700  11 if( remaining == 0 ) {
 1701  3 return;
 1702    }
 1703    }
 1704    }
 1705    }
 1706    }
 1707   
 1708   
 1709    /**
 1710    * Initialize the temporary arrays (tempRowHeaders_ and tempColumnHeaders_)
 1711    * for use in a calculation.
 1712    */
 1713  20 private void initTempSizes() {
 1714  20 int i;
 1715   
 1716    //TODO: We have potential lingerers here. Null out the tempRowHeaders
 1717    // when they aren't needed anymore.
 1718    //
 1719    // Ensure that the temp arrays are of the correct size
 1720    //
 1721  20 if( ( tempRowHeaders_ == null ) || ( tempRowHeaders_.length != rowCount_ ) ) {
 1722  20 tempRowHeaders_ = new Header[rowCount_];
 1723  20 for( i = 0; i < rowCount_; i++ ) {
 1724  76 tempRowHeaders_[i] = new Header();
 1725    }
 1726    }
 1727  20 if( ( tempColumnHeaders_ == null ) || ( tempColumnHeaders_.length != columnCount_ ) ) {
 1728  20 tempColumnHeaders_ = new Header[columnCount_];
 1729  20 for( i = 0; i < columnCount_; i++ ) {
 1730  67 tempColumnHeaders_[i] = new Header();
 1731    }
 1732    }
 1733   
 1734    //
 1735    // Initialize the temp vars to known values.
 1736    //
 1737  20 for( i = 0; i < tempRowHeaders_.length; i++ ) {
 1738  76 tempRowHeaders_[i].setMin( getMinimumRowHeight( i ) );
 1739  76 tempRowHeaders_[i].setPreferred( getMinimumRowHeight( i ) );
 1740  76 tempRowHeaders_[i].setMax( Integer.MAX_VALUE );
 1741  76 tempRowHeaders_[i].setHasComponents( false );
 1742  76 tempRowHeaders_[i].setExpandable( isRowExpandable( i ) );
 1743    }
 1744  20 for( i = 0; i < tempColumnHeaders_.length; i++ ) {
 1745  67 tempColumnHeaders_[i].setMin( getMinimumColumnWidth( i ) );
 1746  67 tempColumnHeaders_[i].setPreferred( getMinimumColumnWidth( i ) );
 1747  67 tempColumnHeaders_[i].setMax( Integer.MAX_VALUE );
 1748  67 tempColumnHeaders_[i].setHasComponents( false );
 1749  67 tempColumnHeaders_[i].setExpandable( isColumnExpandable( i ) );
 1750    }
 1751    }
 1752   
 1753   
 1754    /**
 1755    * A convenience class to attach the constraints to a component.
 1756    */
 1757    private class Entry implements Serializable {
 1758    private static final long serialVersionUID = 396191633848670929L;
 1759   
 1760    /**
 1761    * Description of the Field
 1762    */
 1763    private final Component component_;
 1764    /**
 1765    * Description of the Field
 1766    */
 1767    private final TableLayoutConstraints constraints_;
 1768   
 1769   
 1770    /**
 1771    * Constructor for the Entry object
 1772    *
 1773    * @param comp Description of Parameter
 1774    * @param constraints Description of Parameter
 1775    */
 1776  40 public Entry( final Component comp,
 1777    final TableLayoutConstraints constraints ) {
 1778  40 component_ = comp;
 1779  40 constraints_ = constraints;
 1780    }
 1781   
 1782   
 1783    // Accessors
 1784    /**
 1785    * Gets the component attribute of the Entry object
 1786    *
 1787    * @return The component value
 1788    */
 1789  294 public final Component getComponent() {
 1790  294 return component_;
 1791    }
 1792   
 1793   
 1794    /**
 1795    * Gets the constraints attribute of the Entry object
 1796    *
 1797    * @return The constraints value
 1798    */
 1799  383 public final TableLayoutConstraints getConstraints() {
 1800  383 return constraints_;
 1801    }
 1802   
 1803   
 1804    /**
 1805    * Description of the Method
 1806    *
 1807    * @return Description of the Returned Value
 1808    */
 1809  0 public String toString() {
 1810  0 return this.getClass().getName()
 1811    + " component_=" + getComponent()
 1812    + " constraints_=" + getConstraints();
 1813    }
 1814    }
 1815   
 1816   
 1817    /**
 1818    * A convenience class to hold information specific to a row or column.
 1819    */
 1820    private class Header implements Serializable {
 1821    private static final long serialVersionUID = 396191633848670929L;
 1822   
 1823    private int min_;
 1824    private int max_;
 1825    private int preferred_;
 1826    private int actual_;
 1827   
 1828    private int start_;
 1829    private boolean hasComponents_;
 1830    private boolean isExpandable_;
 1831   
 1832   
 1833    // Accessors
 1834    /**
 1835    * Sets the actual attribute of the Header object
 1836    *
 1837    * @param actual The new actual value
 1838    */
 1839  161 public final void setActual( int actual ) {
 1840  161 actual_ = actual;
 1841    }
 1842   
 1843   
 1844    /**
 1845    * Sets the preferred attribute of the Header object
 1846    *
 1847    * @param preferred The new preferred value
 1848    */
 1849  211 public final void setPreferred( int preferred ) {
 1850  211 preferred_ = preferred;
 1851    }
 1852   
 1853   
 1854    /**
 1855    * Sets the min attribute of the Header object
 1856    *
 1857    * @param min The new min value
 1858    */
 1859  205 public final void setMin( int min ) {
 1860  205 min_ = min;
 1861    }
 1862   
 1863   
 1864    /**
 1865    * Sets the max attribute of the Header object
 1866    *
 1867    * @param max The new max value
 1868    */
 1869  143 public final void setMax( int max ) {
 1870  143 max_ = max;
 1871    }
 1872   
 1873   
 1874    /**
 1875    * Sets the start attribute of the Header object
 1876    *
 1877    * @param start The new start value
 1878    */
 1879  143 public final void setStart( int start ) {
 1880  143 start_ = start;
 1881    }
 1882   
 1883   
 1884    /**
 1885    * Sets the hasComponents attribute of the Header object
 1886    *
 1887    * @param hasComponents The new hasComponents value
 1888    */
 1889  218 public final void setHasComponents( boolean hasComponents ) {
 1890  218 hasComponents_ = hasComponents;
 1891    }
 1892   
 1893   
 1894    /**
 1895    * Sets the expandable attribute of the Header object
 1896    *
 1897    * @param expandable The new expandable value
 1898    */
 1899  143 public final void setExpandable( boolean expandable ) {
 1900  143 isExpandable_ = expandable;
 1901    }
 1902   
 1903   
 1904    /**
 1905    * Gets the actual attribute of the Header object
 1906    *
 1907    * @return The actual value
 1908    */
 1909  461 public final int getActual() {
 1910  461 return actual_;
 1911    }
 1912   
 1913   
 1914    /**
 1915    * Gets the preferred attribute of the Header object
 1916    *
 1917    * @return The preferred value
 1918    */
 1919  746 public final int getPreferred() {
 1920  746 return preferred_;
 1921    }
 1922   
 1923   
 1924    /**
 1925    * Gets the min attribute of the Header object
 1926    *
 1927    * @return The min value
 1928    */
 1929  684 public final int getMin() {
 1930  684 return min_;
 1931    }
 1932   
 1933   
 1934    /**
 1935    * Gets the max attribute of the Header object
 1936    *
 1937    * @return The max value
 1938    */
 1939  579 public final int getMax() {
 1940  579 return max_;
 1941    }
 1942   
 1943   
 1944    /**
 1945    * Gets the start attribute of the Header object
 1946    *
 1947    * @return The start value
 1948    */
 1949  175 public final int getStart() {
 1950  175 return start_;
 1951    }
 1952   
 1953   
 1954    /**
 1955    * Gets the hasComponents attribute of the Header object
 1956    *
 1957    * @return The hasComponents value
 1958    */
 1959  0 public final boolean getHasComponents() {
 1960  0 return hasComponents_;
 1961    }
 1962   
 1963   
 1964    /**
 1965    * Gets the expandable attribute of the Header object
 1966    *
 1967    * @return The expandable value
 1968    */
 1969  131 public final boolean isExpandable() {
 1970  131 return isExpandable_;
 1971    }
 1972   
 1973   
 1974    /**
 1975    * Description of the Method
 1976    *
 1977    * @return Description of the Returned Value
 1978    */
 1979  0 public String toString() {
 1980  0 final StringBuffer buffer = new StringBuffer();
 1981  0 buffer.append( "TableLayout.Header[" );
 1982  0 buffer.append( " min=[" );
 1983  0 buffer.append( getMin() );
 1984  0 buffer.append( "] max=[" );
 1985  0 final int max = getMax();
 1986  0 if( max == Integer.MAX_VALUE ) {
 1987  0 buffer.append( "max_int" );
 1988    }
 1989    else {
 1990  0 buffer.append( max );
 1991    }
 1992  0 buffer.append( "] preferred=[" );
 1993  0 buffer.append( getPreferred() );
 1994  0 buffer.append( "] start=[" );
 1995  0 buffer.append( getStart() );
 1996  0 buffer.append( "] actual=[" );
 1997  0 buffer.append( getActual() );
 1998  0 buffer.append( "] hasComponents=[" );
 1999  0 buffer.append( getHasComponents() );
 2000  0 buffer.append( "] isExpandable=[" );
 2001  0 buffer.append( isExpandable() );
 2002  0 buffer.append( "]]" );
 2003   
 2004  0 return buffer.toString();
 2005    }
 2006    }
 2007   
 2008   
 2009    /**
 2010    * Contains the information that the user has specified for the specific
 2011    * row or column.
 2012    */
 2013    //TODO: Document why "permanent". Perhaps rename these to "user specified"?
 2014    private class HeaderPermanentInfo implements Serializable {
 2015    private static final long serialVersionUID = 396191633848670929L;
 2016    private final int index_;
 2017    // row or column number
 2018    private int min_;
 2019    private boolean isExpandable_;
 2020   
 2021   
 2022    /**
 2023    * Constructor for the HeaderPermanentInfo object
 2024    *
 2025    * @param newIndex Description of Parameter
 2026    */
 2027  15 public HeaderPermanentInfo( final int newIndex ) {
 2028  15 if( newIndex < 0 ) {
 2029  0 throw new DetailedIllegalArgumentException( "newIndex", newIndex, "May not be negative" );
 2030    }
 2031  15 index_ = newIndex;
 2032  15 min_ = 0;
 2033  15 isExpandable_ = false;
 2034    }
 2035   
 2036   
 2037    /**
 2038    * Sets the min attribute of the HeaderPermanentInfo object
 2039    *
 2040    * @param min The new min value
 2041    */
 2042  5 public final void setMin( final int min ) {
 2043  5 min_ = min;
 2044    }
 2045   
 2046   
 2047    /**
 2048    * Sets the expandable attribute of the HeaderPermanentInfo object
 2049    *
 2050    * @param expandable The new expandable value
 2051    */
 2052  10 public final void setExpandable( final boolean expandable ) {
 2053  10 isExpandable_ = expandable;
 2054    }
 2055   
 2056   
 2057    /**
 2058    * Gets the min attribute of the HeaderPermanentInfo object
 2059    *
 2060    * @return The min value
 2061    */
 2062  34 public final int getMin() {
 2063  34 return min_;
 2064    }
 2065   
 2066   
 2067    /**
 2068    * Gets the index attribute of the HeaderPermanentInfo object
 2069    *
 2070    * @return The index value
 2071    */
 2072  193 public final int getIndex() {
 2073  193 return index_;
 2074    }
 2075   
 2076   
 2077    /**
 2078    * Gets the expandable attribute of the HeaderPermanentInfo object
 2079    *
 2080    * @return The expandable value
 2081    */
 2082  29 public final boolean isExpandable() {
 2083  29 return isExpandable_;
 2084    }
 2085    }
 2086   
 2087   
 2088    /**
 2089    * Verify that the specified value is not null. If it is then throw an exception
 2090    *
 2091    * @param fieldName The name of the field to check
 2092    * @param fieldValue The value of the field to check
 2093    * @exception DetailedNullPointerException If fieldValue is null
 2094    */
 2095  163 protected final void assertNotNull( final String fieldName, final Object fieldValue )
 2096    throws DetailedNullPointerException {
 2097   
 2098  163 if( fieldValue == null ) {
 2099  3 throw new DetailedNullPointerException(fieldName);
 2100    }
 2101    }
 2102    }
 2103   
 2104