View Javadoc

1   // %1116523449125:hoplugins.commons.ui.info.clearthought.layout%
2   /*
3    * ====================================================================
4    *
5    * The Clearthought Software License, Version 1.0
6    *
7    * Copyright (c) 2001 Daniel Barbalace.  All rights reserved.
8    *
9    * Redistribution and use in source and binary forms, with or without
10   * modification, are permitted provided that the following conditions
11   * are met:
12   *
13   * 1. Redistributions of source code must retain the above copyright
14   *    notice, this list of conditions and the following disclaimer.
15   *
16   * 2. The original software may not be altered.  However, the classes
17   *    provided may be subclasses as long as the subclasses are not
18   *    packaged in the info.clearthought package or any subpackage of
19   *    info.clearthought.
20   *
21   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
22   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24   * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR, AFFILATED BUSINESSES,
25   * OR ANYONE ELSE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
28   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
29   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32   * SUCH DAMAGE.
33   * ====================================================================
34   */
35  package hoplugins.commons.ui.info.clearthought.layout;
36  
37  import java.awt.Component;
38  import java.awt.ComponentOrientation;
39  import java.awt.Container;
40  import java.awt.Dimension;
41  import java.awt.Insets;
42  
43  import java.lang.reflect.Method;
44  
45  import java.util.LinkedList;
46  import java.util.ListIterator;
47  
48  /***
49   * TableLayout is a layout manager that arranges components in rows and columns like a spreadsheet.
50   * TableLayout allows each row or column to be a different size.  A row or column can be given an
51   * absolute size in pixels, a percentage of the available space, or it can grow and shrink to fill
52   * the remaining space after other rows and columns have been resized.
53   *
54   * <p>
55   * Using spreadsheet terminology, a cell is the intersection of a row and column.  Cells have
56   * finite, non-negative sizes measured in pixels.  The dimensions of a cell depend solely upon the
57   * dimensions of its row and column.
58   * </p>
59   *
60   * <p>
61   * A component occupies a rectangular group of one or more cells.  The component can be aligned in
62   * four ways within that cell.
63   * </p>
64   *
65   * <p>
66   * A component can be stretched horizontally to fit the cell set (full justification), or it can be
67   * placed in the center of the cell.  The component could also be left justified or right
68   * justified.  Similarly, the component can be full, center, top, or bottom justified along the
69   * <pre>
70   * public static void main (String args[])
71   * {
72   *     // Create a frame
73   *     Frame frame = new Frame("Example of TableLayout");
74   *     frame.setBounds (100, 100, 300, 300);
75   * <spc>
76   *     // Create a TableLayout for the frame
77   *     double border = 10;
78   *     double size[][] =
79   *         {{border, 0.10, 20, TableLayout.FILL, 20, 0.20, border},  // Columns
80   *          {border, 0.20, 20, TableLayout.FILL, 20, 0.20, border}}; // Rows
81   * <spc>
82   *     frame.setLayout (new TableLayout(size));
83   * <spc>
84   *     // Create some buttons
85   *     String label[] = {"Top", "Bottom", "Left", "Right", "Center", "Overlap"};
86   *     Button button[] = new Button[label.length];
87   * <spc>
88   *     for (int i = 0; i < label.length; i++)
89   *         button[i] = new Button(label[i]);
90   * <spc>
91   *     // Add buttons
92   *     frame.add (button[0], "1, 1, 5, 1"); // Top
93   *     frame.add (button[1], "1, 5, 5, 5"); // Bottom
94   *     frame.add (button[2], "1, 3      "); // Left
95   *     frame.add (button[3], "5, 3      "); // Right
96   *     frame.add (button[4], "3, 3, c, c"); // Center
97   *     frame.add (button[5], "3, 3, 3, 5"); // Overlap
98   * <spc>
99   *     // Allow user to close the window to terminate the program
100  *     frame.addWindowListener
101  *         (new WindowListener()
102  *             {
103  *                 public void windowClosing (WindowEvent e)
104  *                 {
105  *                     System.exit (0);
106  *                 }
107  * <spc>
108  *                 public void windowOpened (WindowEvent e) {}
109  *                 public void windowClosed (WindowEvent e) {}
110  *                 public void windowIconified (WindowEvent e) {}
111  *                 public void windowDeiconified (WindowEvent e) {}
112  *                 public void windowActivated (WindowEvent e) {}
113  *                 public void windowDeactivated (WindowEvent e) {}
114  *             }
115  *         );
116  * <spc>
117  *     // Show frame
118  *     frame.show();
119  * }
120  * </pre>
121  * </p>
122  *
123  * @author Daniel E. Barbalace
124  * @version 3.2 5/9/04
125  */
126 public class TableLayout implements java.awt.LayoutManager2,
127     java.io.Serializable,
128     hoplugins.commons.ui.info.clearthought.layout.TableLayoutConstants {
129     /*
130        Note: In this file, a cr refers to either a column or a row.  cr[C] always
131        means column and cr[R] always means row.  A cr size is either a column
132        width or a row Height.  TableLayout views columns and rows as being
133        conceptually symmetric.  Therefore, much of the code applies to both
134        columns and rows, and the use of the cr terminology eliminates redundancy.
135        Also, for ease of reading, z always indicates a parameter whose value is
136        either C or R.
137      */
138 
139     /*** Default row/column size */
140     protected static final double[][] defaultSize = {
141             {  },
142             {  }
143         };
144 
145     /*** Indicates a column */
146     protected static final int C = 0;
147 
148     /*** Indicates a row */
149     protected static final int R = 1;
150 
151     /*** Used to minimize reflection calls */
152     protected static boolean checkForComponentOrientationSupport = true;
153 
154     /***
155      * Method used to get component orientation while preserving compatability with earlier
156      * versions of java.awt.Container.  Necessary for supporting older JDKs and MicroEdition
157      * versions of Java.
158      */
159     protected static Method methodGetComponentOrientation;
160 
161     /*** List of components and their sizes */
162     protected LinkedList list;
163 
164     /***
165      * Offsets of crs in pixels.  The left boarder of column n is at crOffset[C][n] and the right
166      * boarder is at cr[C][n + 1] for all columns including the last one.  crOffset[C].length =
167      * crSize[C].length + 1
168      */
169     protected int[][] crOffset = { null, null };
170 
171     /*** Sizes of crs in pixels */
172     protected int[][] crSize = { null, null };
173 
174     /*** Sizes of crs expressed in absolute and relative terms */
175     protected double[][] crSpec = { null, null };
176 
177     /***
178      * Indicates whether or not the size of the cells are known for the last known size of the
179      * container.  If dirty is true or the container has been resized, the cell sizes must be
180      * recalculated using calculateSize.
181      */
182     protected boolean dirty;
183 
184     /*** Horizontal gap between columns */
185     protected int hGap;
186 
187     /*** Previous known height of the container */
188     protected int oldHeight;
189 
190     /*** Previous known width of the container */
191     protected int oldWidth;
192 
193     /*** Vertical gap between rows */
194     protected int vGap;
195 
196     //*******************************************************************************
197     //** Constructors                                                            ***
198     //******************************************************************************
199 
200     /**
201      * Constructs an instance of TableLayout.  This TableLayout will have no columns or rows.  This
202      * constructor is most useful for bean-oriented programming and dynamically adding columns and
203      * rows.
204      */
205     public TableLayout() {
206         init(defaultSize[C], defaultSize[R]);
207     }
208 
209     /***
210      * Constructs an instance of TableLayout.
211      *
212      * @param size widths of columns and heights of rows in the format, {{col0, col1, col2, ...,
213      *        colN}, {row0, row1, row2, ..., rowM}} If this parameter is invalid, the TableLayout
214      *        will have exactly one row and one column.
215      *
216      * @throws IllegalArgumentException
217      */
218     public TableLayout(double[][] size) {
219         // Make sure columns and rows and nothing else is specified
220         if ((size != null) && (size.length == 2)) {
221             init(size[C], size[R]);
222         }
223         else {
224             throw new IllegalArgumentException(
225                 "Parameter size should be an array, a[2], where a[0] is the " //$NON-NLS-1$
226                 + "is an array of column widths and a[1] is an array or row " //$NON-NLS-1$
227                 + "heights."); //$NON-NLS-1$
228         }
229     }
230 
231     /***
232      * Constructs an instance of TableLayout.
233      *
234      * @param col widths of columns in the format, {{col0, col1, col2, ..., colN}
235      * @param row heights of rows in the format, {{row0, row1, row2, ..., rowN}
236      */
237     public TableLayout(double[] col, double[] row) {
238         init(col, row);
239     }
240 
241     /***
242      * Adjusts the number and sizes of rows in this layout.  After calling this method, the caller
243      * should request this layout manager to perform the layout.  This can be done with the
244      * following code:
245      * <pre>
246      *     layout.layoutContainer(container);
247      *     container.repaint();
248      * </pre>
249      * or
250      * <pre>
251      *     window.pack()
252      * </pre>
253      * If this is not done, the changes in the layout will not be seen until the container is
254      * resized.
255      *
256      * @param column widths of each of the columns
257      *
258      * @see #getColumn
259      */
260     public void setColumn(double[] column) {
261         setCr(C, column);
262     }
263 
264     /***
265      * Adjusts the width of a single column in this layout.  After calling this method, the caller
266      * should request this layout manager to perform the layout.  This can be done with the
267      * following code: <code> layout.layoutContainer(container); container.repaint(); </code> or
268      * <pre>
269      *     window.pack()
270      * </pre>
271      * If this is not done, the changes in the layout will not be seen until the container is
272      * resized.
273      *
274      * @param i zero-based index of column to set.  If this parameter is not valid, an
275      *        ArrayOutOfBoundsException will be thrown.
276      * @param size width of the column.  This parameter cannot be null.
277      *
278      * @see #getColumn
279      */
280     public void setColumn(int i, double size) {
281         setCr(C, i, size);
282     }
283 
284     /***
285      * Gets the sizes of columns in this layout.
286      *
287      * @return widths of each of the columns
288      *
289      * @see #setColumn
290      */
291     public double[] getColumn() {
292         // Copy columns
293         double[] column = new double[crSpec[C].length];
294 
295         System.arraycopy(crSpec[C], 0, column, 0, column.length);
296 
297         return column;
298     }
299 
300     /***
301      * Gets the width of a single column in this layout.
302      *
303      * @param i zero-based index of row to get.  If this parameter is not valid, an
304      *        ArrayOutOfBoundsException will be thrown.
305      *
306      * @return width of the requested column
307      *
308      * @see #setRow
309      */
310     public double getColumn(int i) {
311         return crSpec[C][i];
312     }
313 
314     /***
315      * Sets the constraints of a given component.
316      *
317      * @param component desired component.  This parameter cannot be null.
318      * @param constraint new set of constraints.  This parameter cannot be null.
319      *
320      * @throws IllegalArgumentException
321      */
322     public void setConstraints(Component component,
323         TableLayoutConstraints constraint) {
324         // Check parameters
325         if (component == null) {
326             throw new IllegalArgumentException(
327                 "Parameter component cannot be null."); //$NON-NLS-1$
328         }
329         else if (constraint == null) {
330             throw new IllegalArgumentException(
331                 "Parameter constraint cannot be null."); //$NON-NLS-1$
332         }
333 
334         // Find and update constraints for the given component
335         ListIterator iterator = list.listIterator(0);
336 
337         while (iterator.hasNext()) {
338             Entry entry = (Entry) iterator.next();
339 
340             if (entry.component == component) {
341                 iterator.set(new Entry(component, constraint));
342             }
343         }
344     }
345 
346     //*******************************************************************************
347     //** Get/Set methods                                                         ***
348     //******************************************************************************
349 
350     /**
351      * Gets the constraints of a given component.
352      *
353      * @param component desired component
354      *
355      * @return If the given component is found, the constraints associated with that component.  If
356      *         the given component is null or is not found, null is returned.
357      */
358     public TableLayoutConstraints getConstraints(Component component) {
359         ListIterator iterator = list.listIterator(0);
360 
361         while (iterator.hasNext()) {
362             Entry entry = (Entry) iterator.next();
363 
364             if (entry.component == component) {
365                 return new TableLayoutConstraints(entry.cr1[C], entry.cr1[R],
366                     entry.cr2[C], entry.cr2[R], entry.alignment[C],
367                     entry.alignment[R]);
368             }
369         }
370 
371         return null;
372     }
373 
374     /***
375      * Sets the horizontal gap between colunns.
376      *
377      * @param hGap the horizontal gap in pixels
378      *
379      * @throws IllegalArgumentException
380      */
381     public void setHGap(int hGap) {
382         if (hGap >= 0) {
383             this.hGap = hGap;
384         }
385         else {
386             throw new IllegalArgumentException(
387                 "Parameter hGap must be non-negative."); //$NON-NLS-1$
388         }
389     }
390 
391     /***
392      * Gets the horizontal gap between colunns.
393      *
394      * @return the horizontal gap in pixels
395      */
396     public int getHGap() {
397         return hGap;
398     }
399 
400     /***
401      * Determines whether or not there are any components with invalid constraints. An invalid
402      * constraint is one that references a non-existing row or column. For example, on a table
403      * with five rows, row -1 and row 5 are both invalid. Valid rows are 0 through 4, inclusively.
404      *
405      * @return a list of TableLayout.Entry instances refering to the invalid constraints and
406      *         corresponding components
407      *
408      * @throws RuntimeException
409      *
410      * @see #getOverlappingEntry
411      */
412     public java.util.List getInvalidEntry() {
413         LinkedList listInvalid = new LinkedList();
414 
415         try {
416             ListIterator iterator = list.listIterator(0);
417 
418             while (iterator.hasNext()) {
419                 Entry entry = (Entry) iterator.next();
420 
421                 if ((entry.cr1[R] < 0) || (entry.cr1[C] < 0)
422                     || (entry.cr2[R] >= crSpec[R].length)
423                     || (entry.cr2[C] >= crSpec[C].length)) {
424                     listInvalid.add(entry.copy());
425                 }
426             }
427         }
428         catch (CloneNotSupportedException error) {
429             throw new RuntimeException("Unexpected CloneNotSupportedException"); //$NON-NLS-1$
430         }
431 
432         return listInvalid;
433     }
434 
435     /***
436      * Returns the alignment along the x axis.  This specifies how the component would like to be
437      * aligned relative to other components.  The value should be a number between 0 and 1 where 0
438      * represents alignment along the origin, 1 is aligned the furthest away from the origin, 0.5
439      * is centered, etc.
440      *
441      * @param parent -
442      *
443      * @return unconditionally, 0.5
444      */
445     public float getLayoutAlignmentX(Container parent) {
446         return 0.5f;
447     }
448 
449     /***
450      * Returns the alignment along the y axis.  This specifies how the component would like to be
451      * aligned relative to other components.  The value should be a number between 0 and 1 where 0
452      * represents alignment along the origin, 1 is aligned the furthest away from the origin, 0.5
453      * is centered, etc.
454      *
455      * @param parent
456      *
457      * @return unconditionally, 0.5
458      */
459     public float getLayoutAlignmentY(Container parent) {
460         return 0.5f;
461     }
462 
463     /***
464      * Gets the number of columns in this layout.
465      *
466      * @return the number of columns
467      */
468     public int getNumColumn() {
469         return crSpec[C].length;
470     }
471 
472     /***
473      * Gets the number of rows in this layout.
474      *
475      * @return the number of rows
476      */
477     public int getNumRow() {
478         return crSpec[R].length;
479     }
480 
481     /***
482      * Gets a list of overlapping components and their constraints.  Two components overlap if they
483      * cover at least one common cell.
484      *
485      * @return a list of zero or more TableLayout.Entry instances
486      *
487      * @throws RuntimeException -
488      *
489      * @see #getInvalidEntry
490      */
491     public java.util.List getOverlappingEntry() {
492         LinkedList listOverlapping = new LinkedList();
493 
494         try {
495             // Count contraints
496             int numEntry = list.size();
497 
498             // If there are no components, they can't be overlapping
499             if (numEntry == 0) {
500                 return listOverlapping;
501             }
502 
503             // Put entries in an array
504             Entry[] entry = (Entry[]) list.toArray(new Entry[numEntry]);
505 
506             // Check all components
507             for (int knowUnique = 1; knowUnique < numEntry; knowUnique++) {
508                 for (int checking = knowUnique - 1; checking >= 0;
509                     checking--) {
510                     if (((entry[checking].cr1[C] >= entry[knowUnique].cr1[C])
511                         && (entry[checking].cr1[C] <= entry[knowUnique].cr2[C])
512                         && (entry[checking].cr1[R] >= entry[knowUnique].cr1[R])
513                         && (entry[checking].cr1[R] <= entry[knowUnique].cr2[R]))
514                         || ((entry[checking].cr2[C] >= entry[knowUnique].cr1[C])
515                         && (entry[checking].cr2[C] <= entry[knowUnique].cr2[C])
516                         && (entry[checking].cr2[R] >= entry[knowUnique].cr1[R])
517                         && (entry[checking].cr2[R] <= entry[knowUnique].cr2[R]))) {
518                         listOverlapping.add(entry[checking].copy());
519                     }
520                 }
521             }
522         }
523         catch (CloneNotSupportedException error) {
524             throw new RuntimeException("Unexpected CloneNotSupportedException"); //$NON-NLS-1$
525         }
526 
527         return listOverlapping;
528     }
529 
530     /***
531      * Adjusts the number and sizes of rows in this layout.  After calling this method, the caller
532      * should request this layout manager to perform the layout.  This can be done with the
533      * following code: <code> layout.layoutContainer(container); container.repaint(); </code> or
534      * <pre>
535      *     window.pack()
536      * </pre>
537      * If this is not done, the changes in the layout will not be seen until the container is
538      * resized.
539      *
540      * @param row heights of each of the rows.  This parameter cannot be null.
541      *
542      * @see #getRow
543      */
544     public void setRow(double[] row) {
545         setCr(R, row);
546     }
547 
548     /***
549      * Adjusts the height of a single row in this layout.  After calling this method, the caller
550      * should request this layout manager to perform the layout.  This can be done with the
551      * following code: <code> layout.layoutContainer(container); container.repaint(); </code> or
552      * <pre>
553      *     window.pack()
554      * </pre>
555      * If this is not done, the changes in the layout will not be seen until the container is
556      * resized.
557      *
558      * @param i zero-based index of row to set.  If this parameter is not valid, an
559      *        ArrayOutOfBoundsException will be thrown.
560      * @param size height of the row.  This parameter cannot be null.
561      *
562      * @see #getRow
563      */
564     public void setRow(int i, double size) {
565         setCr(R, i, size);
566     }
567 
568     /***
569      * Gets the height of a single row in this layout.
570      *
571      * @return height of the requested row
572      *
573      * @see #setRow
574      */
575     public double[] getRow() {
576         // Copy rows
577         double[] row = new double[crSpec[R].length];
578 
579         System.arraycopy(crSpec[R], 0, row, 0, row.length);
580 
581         return row;
582     }
583 
584     /***
585      * Gets the sizes of a row in this layout.
586      *
587      * @param i zero-based index of row to get.  If this parameter is not valid, an
588      *        ArrayOutOfBoundsException will be thrown.
589      *
590      * @return height of each of the requested row
591      *
592      * @see #setRow
593      */
594     public double getRow(int i) {
595         return crSpec[R][i];
596     }
597 
598     /***
599      * Sets the vertical gap between rows.
600      *
601      * @param vGap the horizontal gap in pixels
602      *
603      * @throws IllegalArgumentException -
604      */
605     public void setVGap(int vGap) {
606         if (vGap >= 0) {
607             this.vGap = vGap;
608         }
609         else {
610             throw new IllegalArgumentException(
611                 "Parameter vGap must be non-negative."); //$NON-NLS-1$
612         }
613     }
614 
615     /***
616      * Gets the vertical gap between rows.
617      *
618      * @return the vertical gap in pixels
619      */
620     public int getVGap() {
621         return vGap;
622     }
623 
624     /***
625      * Adds the specified component with the specified name to the layout.
626      *
627      * @param name indicates entry's position and anchor
628      * @param component component to add
629      */
630     public void addLayoutComponent(String name, Component component) {
631         addLayoutComponent(component, name);
632     }
633 
634     //*******************************************************************************
635     //** java.awt.event.LayoutManager2 methods                                   ***
636     //******************************************************************************
637 
638     /**
639      * Adds the specified component with the specified name to the layout.
640      *
641      * @param component component to add
642      * @param constraint indicates entry's position and alignment
643      *
644      * @throws IllegalArgumentException -
645      */
646     public void addLayoutComponent(Component component, Object constraint) {
647         if (constraint instanceof String) {
648             // Create an entry to associate component with its constraints
649             constraint = new TableLayoutConstraints((String) constraint);
650 
651             // Add component and constraints to the list
652             list.add(new Entry(component, (TableLayoutConstraints) constraint));
653 
654             // Indicate that the cell sizes are not known
655             dirty = true;
656         }
657         else if (constraint instanceof TableLayoutConstraints) {
658             // Add component and constraints to the list
659             list.add(new Entry(component, (TableLayoutConstraints) constraint));
660 
661             // Indicate that the cell sizes are not known
662             dirty = true;
663         }
664         else if (constraint == null) {
665             throw new IllegalArgumentException(
666                 "No constraint for the component"); //$NON-NLS-1$
667         }
668         else {
669             throw new IllegalArgumentException(
670                 "Cannot accept a constraint of class " + constraint.getClass()); //$NON-NLS-1$
671         }
672     }
673 
674     /***
675      * Deletes a column in this layout.  All components to the right of the deletion point are
676      * moved left one column.  The container will need to be laid out after this method returns.
677      * See <code>setColumn</code>.
678      *
679      * @param i zero-based index of column to delete
680      *
681      * @see #setColumn
682      * @see #deleteColumn
683      */
684     public void deleteColumn(int i) {
685         deleteCr(C, i);
686     }
687 
688     /***
689      * Deletes a row in this layout.  All components below the deletion point are moved up one row.
690      * The container will need to be laid out after this method returns.  See <code>setRow</code>.
691      * There must be at least two rows in order to delete a row.
692      *
693      * @param i zero-based index of row to delete
694      *
695      * @see #setRow
696      * @see #deleteRow
697      */
698     public void deleteRow(int i) {
699         deleteCr(R, i);
700     }
701 
702     //*******************************************************************************
703     //** Insertion/Deletion methods                                              ***
704     //******************************************************************************
705 
706     /**
707      * Inserts a column in this layout.  All components to the right of the insertion point are
708      * moved right one column.  The container will need to be laid out after this method returns.
709      * See <code>setColumn</code>.
710      *
711      * @param i zero-based index at which to insert the column
712      * @param size size of the column to be inserted
713      *
714      * @see #setColumn
715      * @see #deleteColumn
716      */
717     public void insertColumn(int i, double size) {
718         insertCr(C, i, size);
719     }
720 
721     /***
722      * Inserts a cr for the methods insertRow or insertColumn.
723      *
724      * @param z indicates row or column
725      * @param i zero-based index at which to insert the cr
726      * @param size size of cr being inserted
727      *
728      * @throws IllegalArgumentException -
729      */
730     public void insertCr(int z, int i, double size) {
731         // Make sure position is valid
732         if ((i < 0) || (i > crSpec[z].length)) {
733             throw new IllegalArgumentException("Parameter i is invalid.  i = "
734                 + i + ".  Valid range is [0, " //$NON-NLS-1$ //$NON-NLS-2$
735                 + crSpec[z].length + "]."); //$NON-NLS-1$
736         }
737 
738         // Make sure row size is valid
739         if ((size < 0.0) && (size != FILL) && (size != PREFERRED)
740             && (size != MINIMUM)) {
741             size = 0.0;
742         }
743 
744         // Copy crs
745         double[] cr = new double[crSpec[z].length + 1];
746 
747         System.arraycopy(crSpec[z], 0, cr, 0, i);
748         System.arraycopy(crSpec[z], i, cr, i + 1, crSpec[z].length - i);
749 
750         // Insert cr
751         cr[i] = size;
752         crSpec[z] = cr;
753 
754         // Move all components that are below the new cr
755         ListIterator iterator = list.listIterator(0);
756 
757         while (iterator.hasNext()) {
758             // Get next entry
759             Entry entry = (Entry) iterator.next();
760 
761             // Is the first cr below the new cr
762             if (entry.cr1[z] >= i) {
763                 // Move first cr
764                 entry.cr1[z]++;
765             }
766 
767             // Is the second cr below the new cr
768             if (entry.cr2[z] >= i) {
769                 // Move second cr
770                 entry.cr2[z]++;
771             }
772         }
773 
774         // Indicate that the cell sizes are not known
775         dirty = true;
776     }
777 
778     /***
779      * Inserts a row in this layout.  All components below the insertion point are moved down one
780      * row.  The container will need to be laid out after this method returns.  See
781      * <code>setRow</code>.
782      *
783      * @param i zero-based index at which to insert the row
784      * @param size size of the row to be inserted
785      *
786      * @see #setRow
787      * @see #deleteRow
788      */
789     public void insertRow(int i, double size) {
790         insertCr(R, i, size);
791     }
792 
793     /***
794      * Invalidates the layout, indicating that if the layout manager has cached information it
795      * should be discarded.
796      *
797      * @param target -
798      */
799     public void invalidateLayout(Container target) {
800         dirty = true;
801     }
802 
803     //*******************************************************************************
804     //** java.awt.event.LayoutManager methods                                    ***
805     //******************************************************************************
806 
807     /**
808      * To lay out the specified container using this layout.  This method reshapes the components
809      * in the specified target container in order to satisfy the constraints of all components.
810      *
811      * <p>
812      * User code should not have to call this method directly.
813      * </p>
814      *
815      * @param container container being served by this layout manager
816      */
817     public void layoutContainer(Container container) {
818         // Calculate sizes if container has changed size or components were added
819         Dimension d = container.getSize();
820 
821         if (dirty || (d.width != oldWidth) || (d.height != oldHeight)) {
822             calculateSize(container);
823         }
824 
825         // Get components
826         Component[] component = container.getComponents();
827 
828         // Layout components
829         for (int counter = 0; counter < component.length; counter++) {
830             try {
831                 // Get the entry for the next component
832                 ListIterator iterator = list.listIterator(0);
833                 Entry entry = null;
834 
835                 while (iterator.hasNext()) {
836                     entry = (Entry) iterator.next();
837 
838                     if (entry.component == component[counter]) {
839                         break;
840                     }
841                     else {
842                         entry = null;
843                     }
844                 }
845 
846                 // Skip any components that have not been place in a specific cell,
847                 // setting the skip component's bounds to zero
848                 if (entry == null) {
849                     component[counter].setBounds(0, 0, 0, 0);
850 
851                     continue;
852                 }
853 
854                 // The following block of code has been optimized so that the
855                 // preferred size of the component is only obtained if it is
856                 // needed.  There are components in which the getPreferredSize
857                 // method is extremely expensive, such as data driven controls
858                 // with a large amount of data.
859                 // Get the preferred size of the component
860                 int preferredWidth = 0;
861                 int preferredHeight = 0;
862 
863                 if ((entry.alignment[C] != FULL)
864                     || (entry.alignment[R] != FULL)) {
865                     Dimension preferredSize = component[counter]
866                         .getPreferredSize();
867 
868                     preferredWidth = preferredSize.width;
869                     preferredHeight = preferredSize.height;
870                 }
871 
872                 // Calculate the coordinates and size of the component
873                 int[] value = calculateSizeAndOffset(entry, preferredWidth, true);
874                 int x = value[0];
875                 int w = value[1];
876 
877                 value = calculateSizeAndOffset(entry, preferredHeight, false);
878 
879                 int y = value[0];
880                 int h = value[1];
881 
882                 // Compensate for component orientation.
883                 ComponentOrientation co = getComponentOrientation(container);
884 
885                 if (!co.isLeftToRight()) {
886                     x = d.width - x - w;
887                 }
888 
889                 // Move and resize component
890                 component[counter].setBounds(x, y, w, h);
891             }
892             catch (Exception error) {
893                 // If any error occurs, set the bounds of this component to zero
894                 // and continue
895                 component[counter].setBounds(0, 0, 0, 0);
896 
897                 continue;
898             }
899         }
900     }
901 
902     /***
903      * Returns the maximum dimensions for this layout given the components in the specified target
904      * container.
905      *
906      * @param target the component which needs to be laid out
907      *
908      * @return unconditionally, a Dimension of Integer.MAX_VALUE by Integer.MAX_VALUE since
909      *         TableLayout does not limit the maximum size of a container
910      */
911     public Dimension maximumLayoutSize(Container target) {
912         return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
913     }
914 
915     /***
916      * Determines the minimum size of the container argument using this layout. The minimum size is
917      * the smallest size that, if used for the container's size, will ensure that all components
918      * are at least as large as their minimum size.  This method cannot guarantee that all
919      * components will be their minimum size.  For example, if component A and component B are
920      * each allocate half of the container's width and component A wants to be 10 pixels wide
921      * while component B wants to be 100 pixels wide, they cannot both be accommodated.  Since in
922      * general components rather be larger than their minimum size instead of smaller, component
923      * B's request will be fulfilled. The minimum size of the container would be 200 pixels.
924      *
925      * @param container container being served by this layout manager
926      *
927      * @return a dimension indicating the container's minimum size
928      */
929     public Dimension minimumLayoutSize(Container container) {
930         return calculateLayoutSize(container, MINIMUM);
931     }
932 
933     /***
934      * Determines the preferred size of the container argument using this layout. The preferred
935      * size is the smallest size that, if used for the container's size, will ensure that all
936      * components are at least as large as their preferred size.  This method cannot guarantee
937      * that all components will be their preferred size.  For example, if component A and
938      * component B are each allocate half of the container's width and component A wants to be 10
939      * pixels wide while component B wants to be 100 pixels wide, they cannot both be
940      * accommodated.  Since in general components rather be larger than their preferred size
941      * instead of smaller, component B's request will be fulfilled. The preferred size of the
942      * container would be 200 pixels.
943      *
944      * @param container container being served by this layout manager
945      *
946      * @return a dimension indicating the container's preferred size
947      */
948     public Dimension preferredLayoutSize(Container container) {
949         return calculateLayoutSize(container, PREFERRED);
950     }
951 
952     /***
953      * Removes the specified component from the layout.
954      *
955      * @param component component being removed
956      */
957     public void removeLayoutComponent(Component component) {
958         // Remove the component
959         ListIterator iterator = list.listIterator(0);
960 
961         while (iterator.hasNext()) {
962             Entry entry = (Entry) iterator.next();
963 
964             if (entry.component == component) {
965                 iterator.remove();
966             }
967         }
968 
969         // Indicate that the cell sizes are not known since
970         dirty = true;
971     }
972 
973     //*******************************************************************************
974     //** Misc methods                                                            ***
975     //******************************************************************************
976 
977     /**
978      * Converts this TableLayout to a string.
979      *
980      * @return a string representing the columns and row sizes in the form "{{col0, col1, col2,
981      *         ..., colN}, {row0, row1, row2, ..., rowM}}"
982      */
983     public String toString() {
984         int counter;
985 
986         String value = "TableLayout {{"; //$NON-NLS-1$
987 
988         if (crSpec[C].length > 0) {
989             for (counter = 0; counter < (crSpec[C].length - 1); counter++) {
990                 value += (crSpec[C][counter] + ", "); //$NON-NLS-1$
991             }
992 
993             value += (crSpec[C][crSpec[C].length - 1] + "}, {"); //$NON-NLS-1$
994         }
995         else {
996             value += "}, {"; //$NON-NLS-1$
997         }
998 
999         if (crSpec[R].length > 0) {
1000             for (counter = 0; counter < (crSpec[R].length - 1); counter++) {
1001                 value += (crSpec[R][counter] + ", "); //$NON-NLS-1$
1002             }
1003 
1004             value += (crSpec[R][crSpec[R].length - 1] + "}}"); //$NON-NLS-1$
1005         }
1006         else {
1007             value += "}}"; //$NON-NLS-1$
1008         }
1009 
1010         return value;
1011     }
1012 
1013     /***
1014      * Gets the container's component orientation.  If a JDK that does not support component
1015      * orientation is being used, then null is returned.
1016      *
1017      * @param container Container whose orientation is being queried
1018      *
1019      * @return the container's orientation or null if no orientation is supported
1020      */
1021     protected ComponentOrientation getComponentOrientation(Container container) {
1022         // This method is implemented to only get the class and method objects
1023         // once so as to reduce expensive reflection operations.  If the reflection
1024         // fails, then component orientation is not supported.
1025         ComponentOrientation co = null;
1026 
1027         try {
1028             if (checkForComponentOrientationSupport) {
1029                 methodGetComponentOrientation = Class.forName(
1030                         "java.awt.Container").getMethod //$NON-NLS-1$
1031                     ("getComponentOrientation", new Class[0]); //$NON-NLS-1$
1032 
1033                 checkForComponentOrientationSupport = false;
1034             }
1035 
1036             if (methodGetComponentOrientation != null) {
1037                 co = (ComponentOrientation) methodGetComponentOrientation
1038                     .invoke(container, new Object[0]);
1039             }
1040         }
1041         catch (Exception e) {
1042         }
1043 
1044         return co;
1045     }
1046 
1047     /***
1048      * Sets the sizes of rows or columns for the methods setRow or setColumn.
1049      *
1050      * @param z indicates row or column
1051      * @param size new cr size
1052      */
1053     protected void setCr(int z, double[] size) {
1054         // Copy crs
1055         crSpec[z] = new double[size.length];
1056         System.arraycopy(size, 0, crSpec[z], 0, crSpec[z].length);
1057 
1058         // Make sure rows are valid
1059         for (int counter = 0; counter < crSpec[z].length; counter++) {
1060             if ((crSpec[z][counter] < 0.0) && (crSpec[z][counter] != FILL)
1061                 && (crSpec[z][counter] != PREFERRED)
1062                 && (crSpec[z][counter] != MINIMUM)) {
1063                 crSpec[z][counter] = 0.0;
1064             }
1065         }
1066 
1067         // Indicate that the cell sizes are not known
1068         dirty = true;
1069     }
1070 
1071     /***
1072      * Sets the sizes of rows or columns for the methods setRow or setColumn.
1073      *
1074      * @param z indicates row or column
1075      * @param i indicates which cr to resize
1076      * @param size new cr size
1077      */
1078     protected void setCr(int z, int i, double size) {
1079         // Make sure size is valid
1080         if ((size < 0.0) && (size != FILL) && (size != PREFERRED)
1081             && (size != MINIMUM)) {
1082             size = 0.0;
1083         }
1084 
1085         // Copy new size
1086         crSpec[z][i] = size;
1087 
1088         // Indicate that the cell sizes are not known
1089         dirty = true;
1090     }
1091 
1092     /***
1093      * Assigns absolute sizes.
1094      *
1095      * @param z indicates row or column
1096      * @param availableSize amount of space available in the container
1097      *
1098      * @return the amount of space available after absolute crs have been assigned sizes
1099      */
1100     protected int assignAbsoluteSize(int z, int availableSize) {
1101         int numCr = crSpec[z].length;
1102 
1103         for (int counter = 0; counter < numCr; counter++) {
1104             if ((crSpec[z][counter] >= 1.0) || (crSpec[z][counter] == 0.0)) {
1105                 crSize[z][counter] = (int) (crSpec[z][counter] + 0.5);
1106                 availableSize -= crSize[z][counter];
1107             }
1108         }
1109 
1110         return availableSize;
1111     }
1112 
1113     /***
1114      * Assigns FILL sizes.
1115      *
1116      * @param z indicates row or column
1117      * @param availableSize amount of space available in the container
1118      */
1119     protected void assignFillSize(int z, int availableSize) {
1120         // Skip if there is no more space to allocate
1121         if (availableSize <= 0) {
1122             return;
1123         }
1124 
1125         // Count the number of "fill" cells
1126         int numFillSize = 0;
1127         int numCr = crSpec[z].length;
1128 
1129         for (int counter = 0; counter < numCr; counter++) {
1130             if (crSpec[z][counter] == FILL) {
1131                 numFillSize++;
1132             }
1133         }
1134 
1135         // If numFillSize is zero, the if statement below will always evaluate to
1136         // false and the division will not occur.
1137         // If there are more than one "fill" cell, slack may occur due to rounding
1138         // errors
1139         int slackSize = availableSize;
1140 
1141         // Assign "fill" cells equal amounts of the remaining space
1142         for (int counter = 0; counter < numCr; counter++) {
1143             if (crSpec[z][counter] == FILL) {
1144                 crSize[z][counter] = availableSize / numFillSize;
1145                 slackSize -= crSize[z][counter];
1146             }
1147         }
1148 
1149         // Assign one pixel of slack to each FILL cr, starting at the last one,
1150         // until all slack has been consumed
1151         for (int counter = numCr - 1; (counter >= 0) && (slackSize > 0);
1152             counter--) {
1153             if (crSpec[z][counter] == FILL) {
1154                 crSize[z][counter]++;
1155                 slackSize--;
1156             }
1157         }
1158     }
1159 
1160     /***
1161      * Assigned widths to preferred and minimum size columns and rows.  This reduces the available
1162      * width and height.  Minimum widths/heights must be calculated first because they affect
1163      * preferred widths/heights, but not vice versa.  The end result is that any component
1164      * contained wholly or partly in a column/row of minimum/preferred width will get at least its
1165      * minimum/preferred width, respectively.
1166      *
1167      * @param z indicates row or column
1168      * @param availableSize amount of space available in the container
1169      * @param typeOfSize indicates preferred or minimum
1170      *
1171      * @return the amount of space available after absolute crs have been assigned sizes
1172      */
1173     protected int assignPrefMinSize(int z, int availableSize, double typeOfSize) {
1174         // Get variables referring to columns or rows (crs)
1175         int numCr = crSpec[z].length;
1176 
1177         // Address every cr
1178         for (int counter = 0; counter < numCr; counter++) {
1179             // Is the current cr a preferred/minimum (based on typeOfSize) size
1180             if (crSpec[z][counter] == typeOfSize) {
1181                 // Assume a maximum width of zero
1182                 int maxSize = 0;
1183 
1184                 // Find maximum preferred/min width of all components completely
1185                 // or partially contained within this cr
1186                 ListIterator iterator = list.listIterator(0);
1187 
1188 nextComponent: 
1189                 while (iterator.hasNext()) {
1190                     Entry entry = (Entry) iterator.next();
1191 
1192                     // Skip invalid entries
1193                     if ((entry.cr1[z] < 0) || (entry.cr2[z] >= numCr)) {
1194                         continue nextComponent;
1195                     }
1196 
1197                     // Find the maximum desired size of this cr based on all crs
1198                     // the current component occupies
1199                     if ((entry.cr1[z] <= counter) && (entry.cr2[z] >= counter)) {
1200                         // Setup size and number of adjustable crs
1201                         Dimension p = (typeOfSize == PREFERRED)
1202                             ? entry.component.getPreferredSize()
1203                             : entry.component.getMinimumSize();
1204 
1205                         int size = (p == null) ? 0 : ((z == C) ? p.width
1206                                                                : p.height);
1207                         int numAdjustable = 0;
1208 
1209                         // Calculate for preferred size
1210                         if (typeOfSize == PREFERRED) {
1211                             // Consider all crs this component occupies
1212                             for (int entryCr = entry.cr1[z];
1213                                 entryCr <= entry.cr2[z]; entryCr++) {
1214                                 // Subtract absolute, relative, and minumum cr
1215                                 // sizes, which have already been calculated
1216                                 if ((crSpec[z][entryCr] >= 0.0)
1217                                     || (crSpec[z][entryCr] == MINIMUM)) {
1218                                     size -= crSize[z][entryCr];
1219                                 }
1220 
1221                                 // Count preferred/min width columns
1222                                 else if (crSpec[z][entryCr] == PREFERRED) {
1223                                     numAdjustable++;
1224                                 }
1225 
1226                                 // Skip any component that occupies a fill cr
1227                                 // because the fill should fulfill the size
1228                                 // requirements
1229                                 else if (crSpec[z][entryCr] == FILL) {
1230                                     continue nextComponent;
1231                                 }
1232                             }
1233                         }
1234 
1235                         // Calculate for minimum size
1236                         else {
1237                             // Consider all crs this component occupies
1238                             for (int entryCr = entry.cr1[z];
1239                                 entryCr <= entry.cr2[z]; entryCr++) {
1240                                 // Subtract absolute and relative cr sizes, which
1241                                 // have already been calculated
1242                                 if (crSpec[z][entryCr] >= 0.0) {
1243                                     size -= crSize[z][entryCr];
1244                                 }
1245 
1246                                 // Count preferred/min width columns
1247                                 else if ((crSpec[z][entryCr] == PREFERRED)
1248                                     || (crSpec[z][entryCr] == MINIMUM)) {
1249                                     numAdjustable++;
1250                                 }
1251 
1252                                 // Skip any component that occupies a fill cr
1253                                 // because the fill should fulfill the size
1254                                 // requirements
1255                                 else if (crSpec[z][entryCr] == FILL) {
1256                                     continue nextComponent;
1257                                 }
1258                             }
1259                         }
1260 
1261                         // Divide the size evenly among the adjustable crs
1262                         size = (int) Math.ceil(size / (double) numAdjustable);
1263 
1264                         // Take the maximumn size
1265                         if (maxSize < size) {
1266                             maxSize = size;
1267                         }
1268                     }
1269                 }
1270 
1271                 // Assign preferred size
1272                 crSize[z][counter] = maxSize;
1273 
1274                 // Reduce available size
1275                 availableSize -= maxSize;
1276             }
1277         }
1278 
1279         return availableSize;
1280     }
1281 
1282     /***
1283      * Assigns relative sizes.
1284      *
1285      * @param z indicates row or column
1286      * @param availableSize amount of space available in the container
1287      *
1288      * @return the amount of space available after relative crs have been assigned sizes
1289      */
1290     protected int assignRelativeSize(int z, int availableSize) {
1291         int relativeSize = (availableSize < 0) ? 0 : availableSize;
1292         int numCr = crSpec[z].length;
1293 
1294         for (int counter = 0; counter < numCr; counter++) {
1295             if ((crSpec[z][counter] > 0.0) && (crSpec[z][counter] < 1.0)) {
1296                 crSize[z][counter] = (int) ((crSpec[z][counter] * relativeSize)
1297                     + 0.5);
1298 
1299                 availableSize -= crSize[z][counter];
1300             }
1301         }
1302 
1303         return availableSize;
1304     }
1305 
1306     /***
1307      * Calculates the preferred or minimum size for the methods preferredLayoutSize and
1308      * minimumLayoutSize.
1309      *
1310      * @param container container whose size is being calculated
1311      * @param typeOfSize indicates preferred or minimum
1312      *
1313      * @return a dimension indicating the container's preferred or minimum size
1314      */
1315     protected Dimension calculateLayoutSize(Container container,
1316         double typeOfSize) {
1317         //  Get preferred/minimum sizes
1318         Entry[] entryList = (Entry[]) list.toArray(new Entry[list.size()]);
1319         int numEntry = entryList.length;
1320         Dimension[] prefMinSize = new Dimension[numEntry];
1321 
1322         for (int i = 0; i < numEntry; i++) {
1323             prefMinSize[i] = (typeOfSize == PREFERRED)
1324                 ? entryList[i].component.getPreferredSize()
1325                 : entryList[i].component.getMinimumSize();
1326         }
1327 
1328         // Calculate sizes
1329         int width = calculateLayoutSize(container, C, typeOfSize, entryList,
1330                 prefMinSize);
1331 
1332         int height = calculateLayoutSize(container, R, typeOfSize, entryList,
1333                 prefMinSize);
1334 
1335         // Compensate for container's insets
1336         Insets inset = container.getInsets();
1337 
1338         width += (inset.left + inset.right);
1339         height += (inset.top + inset.bottom);
1340 
1341         return new Dimension(width, height);
1342     }
1343 
1344     /***
1345      * Calculates the preferred or minimum size for the method calculateLayoutSize(Container
1346      * container, double typeOfSize).  This method is passed the preferred/minimum sizes of the
1347      * components so that the potentially expensive methods getPreferredSize()/getMinimumSize()
1348      * are not called twice for the same component.
1349      *
1350      * @param container container whose size is being calculated
1351      * @param z -
1352      * @param typeOfSize indicates preferred or minimum
1353      * @param entryList list of Entry objects
1354      * @param prefMinSize list of preferred or minimum sizes
1355      *
1356      * @return a dimension indicating the container's preferred or minimum size
1357      */
1358     protected int calculateLayoutSize(Container container, int z,
1359         double typeOfSize, Entry[] entryList, Dimension[] prefMinSize) {
1360         Dimension size; // Preferred/minimum size of current component
1361         int scaledSize = 0; // Preferred/minimum size of scaled components
1362         int temp; // Temporary variable used to compare sizes
1363         int counter; // Counting variable
1364 
1365         // Get number of crs
1366         int numCr = crSpec[z].length;
1367 
1368         // Determine percentage of space allocated to fill components.  This is
1369         // one minus the sum of all scalable components.
1370         double fillSizeRatio = 1.0;
1371         int numFillSize = 0;
1372 
1373         for (counter = 0; counter < numCr; counter++) {
1374             if ((crSpec[z][counter] > 0.0) && (crSpec[z][counter] < 1.0)) {
1375                 fillSizeRatio -= crSpec[z][counter];
1376             }
1377             else if (crSpec[z][counter] == FILL) {
1378                 numFillSize++;
1379             }
1380         }
1381 
1382         // Adjust fill ratios to reflect number of fill rows/columns
1383         if (numFillSize > 1) {
1384             fillSizeRatio /= numFillSize;
1385         }
1386 
1387         // Cap fill ratio bottoms to 0.0
1388         if (fillSizeRatio < 0.0) {
1389             fillSizeRatio = 0.0;
1390         }
1391 
1392         // Create array to hold actual sizes in pixels
1393         crSize[z] = new int[numCr];
1394 
1395         // Assign absolute sizes (must be done before assignPrefMinSize)
1396         // This is done to calculate absolute cr sizes
1397         assignAbsoluteSize(z, 0);
1398 
1399         // Assign preferred and minimum sizes (must be done after assignAbsoluteSize)
1400         // This is done to calculate preferred/minimum cr sizes
1401         assignPrefMinSize(z, 0, typeOfSize);
1402 
1403         int[] crPrefMin = new int[numCr];
1404 
1405         for (counter = 0; counter < numCr; counter++) {
1406             if ((crSpec[z][counter] == PREFERRED)
1407                 || (crSpec[z][counter] == MINIMUM)) {
1408                 crPrefMin[counter] = crSize[z][counter];
1409             }
1410         }
1411 
1412         // Find maximum preferred/minimum size of all scaled components
1413         int numColumn = crSpec[C].length;
1414         int numRow = crSpec[R].length;
1415         int numEntry = entryList.length;
1416 
1417         for (int entryCounter = 0; entryCounter < numEntry; entryCounter++) {
1418             // Get next entry
1419             Entry entry = entryList[entryCounter];
1420 
1421             // Make sure entry is in valid rows and columns
1422             if ((entry.cr1[C] < 0) || (entry.cr1[C] >= numColumn)
1423                 || (entry.cr2[C] >= numColumn) || (entry.cr1[R] < 0)
1424                 || (entry.cr1[R] >= numRow) || (entry.cr2[R] >= numRow)) {
1425                 // Skip the bad component
1426                 continue;
1427             }
1428 
1429             // Get preferred/minimum size of current component
1430             size = prefMinSize[entryCounter];
1431 
1432             //----------------------------------------------------------------------
1433             // Calculate portion of component that is not absolutely sized
1434             int scalableSize = (z == C) ? size.width : size.height;
1435 
1436             for (counter = entry.cr1[z]; counter <= entry.cr2[z]; counter++) {
1437                 if (crSpec[z][counter] >= 1.0) {
1438                     scalableSize -= crSpec[z][counter];
1439                 }
1440                 else if ((crSpec[z][counter] == PREFERRED)
1441                     || (crSpec[z][counter] == MINIMUM)) {
1442                     scalableSize -= crPrefMin[counter];
1443                 }
1444             }
1445 
1446             //----------------------------------------------------------------------
1447             // Determine total percentage of scalable space that the component
1448             // occupies by adding the relative columns and the fill columns
1449             double relativeSize = 0.0;
1450 
1451             for (counter = entry.cr1[z]; counter <= entry.cr2[z]; counter++) {
1452                 // Cr is scaled
1453                 if ((crSpec[z][counter] > 0.0) && (crSpec[z][counter] < 1.0)) {
1454                     // Add scaled size to relativeWidth
1455                     relativeSize += crSpec[z][counter];
1456                 }
1457 
1458                 // Cr is fill
1459                 else if ((crSpec[z][counter] == FILL) && (fillSizeRatio != 0.0)) {
1460                     // Add fill size to relativeWidth
1461                     relativeSize += fillSizeRatio;
1462                 }
1463             }
1464 
1465             // Determine the total scaled size as estimated by this component
1466             if (relativeSize == 0) {
1467                 temp = 0;
1468             }
1469             else {
1470                 temp = (int) ((scalableSize / relativeSize) + 0.5);
1471             }
1472 
1473             //----------------------------------------------------------------------
1474             // If the container needs to be bigger, make it so
1475             if (scaledSize < temp) {
1476                 scaledSize = temp;
1477             }
1478         }
1479 
1480         // totalSize is the scaledSize plus the sum of all absolute sizes and all
1481         // preferred sizes
1482         int totalSize = scaledSize;
1483 
1484         for (counter = 0; counter < numCr; counter++) {
1485             // Is the current cr an absolute size
1486             if (crSpec[z][counter] >= 1.0) {
1487                 totalSize += (int) (crSpec[z][counter] + 0.5);
1488             }
1489 
1490             // Is the current cr a preferred/minimum size
1491             else if ((crSpec[z][counter] == PREFERRED)
1492                 || (crSpec[z][counter] == MINIMUM)) {
1493                 // Add preferred/minimum width
1494                 totalSize += crPrefMin[counter];
1495             }
1496         }
1497 
1498         // Compensate for horizontal and vertical gap
1499         if (numCr > 0) {
1500             totalSize += (((z == C) ? hGap : vGap) * (numCr - 1));
1501         }
1502 
1503         return totalSize;
1504     }
1505 
1506     /***
1507      * Calculates the offset of each cr.
1508      *
1509      * @param z indicates row or column
1510      * @param inset -
1511      */
1512     protected void calculateOffset(int z, Insets inset) {
1513         int numCr = crSpec[z].length;
1514 
1515         crOffset[z] = new int[numCr + 1];
1516         crOffset[z][0] = (z == C) ? inset.left : inset.top;
1517 
1518         for (int counter = 0; counter < numCr; counter++) {
1519             crOffset[z][counter + 1] = crOffset[z][counter]
1520                 + crSize[z][counter];
1521         }
1522     }
1523 
1524     //*******************************************************************************
1525     //** Calculation methods                                                     ***
1526     //******************************************************************************
1527 
1528     /**
1529      * Calculates the sizes of the rows and columns based on the absolute and relative sizes
1530      * specified in <code>crSpec[R]</code> and <code>crSpec[C]</code> and the size of the
1531      * container.  The result is stored in <code>crSize[R]</code> and <code>crSize[C]</code>.
1532      *
1533      * @param container container using this TableLayout
1534      */
1535     protected void calculateSize(Container container) {
1536         // Get the container's insets
1537         Insets inset = container.getInsets();
1538 
1539         // Get the size of the container's available space
1540         Dimension d = container.getSize();
1541         int availableWidth = d.width - inset.left - inset.right;
1542         int availableHeight = d.height - inset.top - inset.bottom;
1543 
1544         // Compensate for horiztonal and vertical gaps
1545         if (crSpec[C].length > 0) {
1546             availableWidth -= (hGap * (crSpec[C].length - 1));
1547         }
1548 
1549         if (crSpec[R].length > 0) {
1550             availableHeight -= (vGap * (crSpec[R].length - 1));
1551         }
1552 
1553         // Create array to hold actual sizes in pixels
1554         crSize[C] = new int[crSpec[C].length];
1555         crSize[R] = new int[crSpec[R].length];
1556 
1557         // Assign absolute sizes (must be done before assignPrefMinSize)
1558         availableWidth = assignAbsoluteSize(C, availableWidth);
1559         availableHeight = assignAbsoluteSize(R, availableHeight);
1560 
1561         // Assign preferred and minimum sizes (must be done after assignAbsoluteSize)
1562         availableWidth = assignPrefMinSize(C, availableWidth, MINIMUM);
1563         availableWidth = assignPrefMinSize(C, availableWidth, PREFERRED);
1564         availableHeight = assignPrefMinSize(R, availableHeight, MINIMUM);
1565         availableHeight = assignPrefMinSize(R, availableHeight, PREFERRED);
1566 
1567         // Assign relative sizes
1568         availableWidth = assignRelativeSize(C, availableWidth);
1569         availableHeight = assignRelativeSize(R, availableHeight);
1570 
1571         // Assign fill sizes
1572         assignFillSize(C, availableWidth);
1573         assignFillSize(R, availableHeight);
1574 
1575         // Calculate cr offsets for effeciency
1576         calculateOffset(C, inset);
1577         calculateOffset(R, inset);
1578 
1579         // Indicate that the size of the cells are known for the container's
1580         // current size
1581         dirty = false;
1582         oldWidth = d.width;
1583         oldHeight = d.height;
1584     }
1585 
1586     /***
1587      * Calculates the vertical/horizontal offset and size of a component.
1588      *
1589      * @param entry entry containing component and contraints
1590      * @param preferredSize previously calculated preferred width/height of component
1591      * @param isColumn if true, this method is being called to calculate the offset/size of a
1592      *        column.  if false,... of a row.
1593      *
1594      * @return an array, a, of two integers such that a[0] is the offset and a[1] is the size
1595      */
1596     protected int[] calculateSizeAndOffset(Entry entry, int preferredSize,
1597         boolean isColumn) {
1598         // Get references to cr properties
1599         int[] crOffset = isColumn ? this.crOffset[C] : this.crOffset[R];
1600         int entryAlignment = isColumn ? entry.alignment[C] : entry.alignment[R];
1601 
1602         // Determine cell set size
1603         int cellSetSize = isColumn
1604             ? (crOffset[entry.cr2[C] + 1] - crOffset[entry.cr1[C]])
1605             : (crOffset[entry.cr2[R] + 1] - crOffset[entry.cr1[R]]);
1606 
1607         // Determine the size of the component
1608         int size;
1609 
1610         if ((entryAlignment == FULL) || (cellSetSize < preferredSize)) {
1611             size = cellSetSize;
1612         }
1613         else {
1614             size = preferredSize;
1615         }
1616 
1617         // Since the component orientation is adjusted for in the layoutContainer
1618         // method, we can treat leading justification as left justification and
1619         // trailing justification as right justification.
1620         if (isColumn && (entryAlignment == LEADING)) {
1621             entryAlignment = LEFT;
1622         }
1623 
1624         if (isColumn && (entryAlignment == TRAILING)) {
1625             entryAlignment = RIGHT;
1626         }
1627 
1628         // Determine offset
1629         int offset;
1630 
1631         switch (entryAlignment) {
1632         case LEFT: // Align left/top side along left edge of cell
1633             offset = crOffset[isColumn ? entry.cr1[C] : entry.cr1[R]];
1634 
1635             break;
1636 
1637         case RIGHT: // Align right/bottom side along right edge of cell
1638             offset = crOffset[(isColumn ? entry.cr2[C] : entry.cr2[R]) + 1]
1639                 - size;
1640 
1641             break;
1642 
1643         case CENTER: // Center justify component
1644             offset = crOffset[isColumn ? entry.cr1[C] : entry.cr1[R]]
1645                 + ((cellSetSize - size) >> 1);
1646 
1647             break;
1648 
1649         case FULL: // Align left/top side along left/top edge of cell
1650             offset = crOffset[isColumn ? entry.cr1[C] : entry.cr1[R]];
1651 
1652             break;
1653 
1654         default: // This is a never should happen case, but just in case
1655             offset = 0;
1656         }
1657 
1658         // Compensate for gaps
1659         if (isColumn) {
1660             offset += (hGap * entry.cr1[C]);
1661             size += (hGap * (entry.cr2[C] - entry.cr1[C]));
1662         }
1663         else {
1664             offset += (vGap * entry.cr1[R]);
1665             size += (vGap * (entry.cr2[R] - entry.cr1[R]));
1666         }
1667 
1668         // Package return values
1669         int[] value = { offset, size };
1670 
1671         return value;
1672     }
1673 
1674     /***
1675      * Deletes a cr for the methods deleteRow or deleteColumn.
1676      *
1677      * @param z indicates row or column
1678      * @param i zero-based index of cr to delete
1679      *
1680      * @throws IllegalArgumentException -
1681      */
1682     protected void deleteCr(int z, int i) {
1683         // Make sure position is valid
1684         if ((i < 0) || (i >= crSpec[z].length)) {
1685             throw new IllegalArgumentException("Parameter i is invalid.  i = "
1686                 + i + ".  Valid range is [0, " //$NON-NLS-1$ //$NON-NLS-2$
1687                 + (crSpec[z].length - 1) + "]."); //$NON-NLS-1$
1688         }
1689 
1690         // Copy rows
1691         double[] cr = new double[crSpec[z].length - 1];
1692 
1693         System.arraycopy(crSpec[z], 0, cr, 0, i);
1694         System.arraycopy(crSpec[z], i + 1, cr, i, crSpec[z].length - i - 1);
1695 
1696         // Delete row
1697         crSpec[z] = cr;
1698 
1699         // Move all components that are to below the row deleted
1700         ListIterator iterator = list.listIterator(0);
1701 
1702         while (iterator.hasNext()) {
1703             // Get next entry
1704             Entry entry = (Entry) iterator.next();
1705 
1706             // Is the first row below the new row
1707             if (entry.cr1[z] > i) {
1708                 // Move first row
1709                 entry.cr1[z]--;
1710             }
1711 
1712             // Is the second row below the new row
1713             if (entry.cr2[z] > i) {
1714                 // Move second row
1715                 entry.cr2[z]--;
1716             }
1717         }
1718 
1719         // Indicate that the cell sizes are not known
1720         dirty = true;
1721     }
1722 
1723     /***
1724      * Initializes the TableLayout for all constructors.
1725      *
1726      * @param col widths of columns in the format, {{col0, col1, col2, ..., colN}
1727      * @param row heights of rows in the format, {{row0, row1, row2, ..., rowN}
1728      *
1729      * @throws IllegalArgumentException -
1730      */
1731     protected void init(double[] col, double[] row) {
1732         // Check parameters
1733         if (col == null) {
1734             throw new IllegalArgumentException("Parameter col cannot be null"); //$NON-NLS-1$
1735         }
1736 
1737         if (row == null) {
1738             throw new IllegalArgumentException("Parameter row cannot be null"); //$NON-NLS-1$
1739         }
1740 
1741         // Create new rows and columns
1742         crSpec[C] = new double[col.length];
1743         crSpec[R] = new double[row.length];
1744 
1745         // Copy rows and columns
1746         System.arraycopy(col, 0, crSpec[C], 0, crSpec[C].length);
1747         System.arraycopy(row, 0, crSpec[R], 0, crSpec[R].length);
1748 
1749         // Make sure rows and columns are valid
1750         for (int counter = 0; counter < crSpec[C].length; counter++) {
1751             if ((crSpec[C][counter] < 0.0) && (crSpec[C][counter] != FILL)
1752                 && (crSpec[C][counter] != PREFERRED)
1753                 && (crSpec[C][counter] != MINIMUM)) {
1754                 crSpec[C][counter] = 0.0;
1755             }
1756         }
1757 
1758         for (int counter = 0; counter < crSpec[R].length; counter++) {
1759             if ((crSpec[R][counter] < 0.0) && (crSpec[R][counter] != FILL)
1760                 && (crSpec[R][counter] != PREFERRED)
1761                 && (crSpec[R][counter] != MINIMUM)) {
1762                 crSpec[R][counter] = 0.0;
1763             }
1764         }
1765 
1766         // Create an empty list of components
1767         list = new LinkedList();
1768 
1769         // Indicate that the cell sizes are not known
1770         dirty = true;
1771     }
1772 
1773     //*******************************************************************************
1774     //*** Inner Class                                                            ***
1775     //******************************************************************************
1776     // The following inner class is used to bind components to their constraints
1777     public static class Entry implements Cloneable {
1778         /** Component bound by the constraints */
1779         public Component component;
1780 
1781         /*** Horizontal and vertical alignment */
1782         public int[] alignment;
1783 
1784         /*** Cell in which the upper-left corner of the component lies */
1785         public int[] cr1;
1786 
1787         /*** Cell in which the lower-right corner of the component lies */
1788         public int[] cr2;
1789 
1790         /***
1791          * Constructs an Entry that binds a component to a set of constraints.
1792          *
1793          * @param component component being bound
1794          * @param constraint constraints being applied
1795          */
1796         public Entry(Component component, TableLayoutConstraints constraint) {
1797             int[] cr1 = { constraint.col1, constraint.row1 };
1798             int[] cr2 = { constraint.col2, constraint.row2 };
1799             int[] alignment = { constraint.hAlign, constraint.vAlign };
1800 
1801             this.cr1 = cr1;
1802             this.cr2 = cr2;
1803             this.alignment = alignment;
1804             this.component = component;
1805         }
1806 
1807         /***
1808          * Copies this Entry.
1809          *
1810          * @return -
1811          *
1812          * @throws CloneNotSupportedException -
1813          */
1814         public Object copy() throws CloneNotSupportedException {
1815             return clone();
1816         }
1817 
1818         /***
1819          * Gets the string representation of this Entry.
1820          *
1821          * @return a string in the form "(col1, row1, col2, row2, vAlign, hAlign) component"
1822          */
1823         public String toString() {
1824             TableLayoutConstraints c = new TableLayoutConstraints(cr1[C],
1825                     cr1[R], cr2[C], cr2[R], alignment[C], alignment[R]);
1826 
1827             return "(" + c + ") " + component; //$NON-NLS-1$ //$NON-NLS-2$
1828         }
1829     }
1830 }