OSDN Git Service

2005-02-17 Michael Koch <konqueror@gmx.de>
[pf3gnuchains/gcc-fork.git] / libjava / java / awt / GridBagLayout.java
1 /* GridBagLayout - Layout manager for components according to GridBagConstraints
2    Copyright (C) 2002, 2003, 2004, 2005  Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA.
20
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37
38
39 package java.awt;
40
41 import java.io.Serializable;
42 import java.util.ArrayList;
43 import java.util.HashMap;
44 import java.util.Hashtable;
45
46 /**
47  * @author Michael Koch (konqueror@gmx.de)
48  * @author Jeroen Frijters (jeroen@frijters.net)
49  */
50 public class GridBagLayout
51     implements Serializable, LayoutManager2
52 {
53     private static final long serialVersionUID = 8838754796412211005L;
54
55     protected static final int MINSIZE = 1;
56     protected static final int PREFERREDSIZE = 2;
57     protected static final int MAXGRIDSIZE = 512;
58
59     // comptable remembers the original contraints given to us.
60     // internalcomptable is used to keep track of modified constraint values
61     // that we calculate, particularly when we are given RELATIVE and
62     // REMAINDER constraints.
63     // Constraints kept in comptable are never modified, and constraints
64     // kept in internalcomptable can be modified internally only.
65     protected Hashtable comptable;
66     private Hashtable internalcomptable;
67     protected GridBagLayoutInfo layoutInfo;
68     protected GridBagConstraints defaultConstraints;
69
70     public double[] columnWeights;
71     public int[] columnWidths;
72     public double[] rowWeights;
73     public int[] rowHeights;
74
75     public GridBagLayout ()
76     {
77         this.comptable = new Hashtable();
78         this.internalcomptable = new Hashtable();
79         this.defaultConstraints= new GridBagConstraints();
80     }
81
82     /**
83      * Helper method to calc the sum of a range of elements in an int array.
84      */
85     private int sumIntArray (int[] array, int upto)
86     {
87         int result = 0;
88
89         for (int i = 0; i < upto; i++)
90             result += array [i];
91
92         return result;
93     }
94
95     /**
96      * Helper method to calc the sum of all elements in an int array.
97      */
98     private int sumIntArray (int[] array)
99     {
100         return sumIntArray(array, array.length);
101     }
102
103     /**
104      * Helper method to calc the sum of all elements in an double array.
105      */
106     private double sumDoubleArray (double[] array)
107     {
108         double result = 0;
109
110         for (int i = 0; i < array.length; i++)
111             result += array [i];
112
113         return result;
114     }
115
116     public void addLayoutComponent (String name, Component component)
117     {
118         // do nothing here.
119     }
120
121     public void removeLayoutComponent (Component component)
122     {
123         // do nothing here
124     }
125
126     public void addLayoutComponent (Component component, Object constraints)
127     {
128         if (constraints == null)
129             return;
130
131         if (!(constraints instanceof GridBagConstraints))
132             throw new IllegalArgumentException();
133
134         setConstraints (component, (GridBagConstraints) constraints);
135     }
136
137     public Dimension preferredLayoutSize (Container parent)
138     {
139         if (parent == null)
140             return new Dimension (0, 0);
141     
142         GridBagLayoutInfo li = getLayoutInfo (parent, PREFERREDSIZE);
143         return getMinSize (parent, li);
144     }
145
146     public Dimension minimumLayoutSize (Container parent)
147     {
148         if (parent == null)
149             return new Dimension (0, 0);
150     
151         GridBagLayoutInfo li = getLayoutInfo (parent, MINSIZE);
152         return getMinSize (parent, li);
153     }
154
155     public Dimension maximumLayoutSize (Container target)
156     {
157         return new Dimension (Integer.MAX_VALUE, Integer.MAX_VALUE);
158     }
159
160     public void layoutContainer (Container parent)
161     {
162       arrangeGrid (parent);
163     }
164
165     public float getLayoutAlignmentX (Container target)
166     {
167         return Component.CENTER_ALIGNMENT;
168     }
169
170     public float getLayoutAlignmentY (Container target)
171     {
172         return Component.CENTER_ALIGNMENT;
173     }
174
175     public void invalidateLayout (Container target)
176     {
177         this.layoutInfo = null;
178     }
179
180     public void setConstraints (Component component,
181         GridBagConstraints constraints)
182     {
183         GridBagConstraints clone = (GridBagConstraints) constraints.clone();
184
185         if (clone.gridx < 0)
186             clone.gridx = GridBagConstraints.RELATIVE;
187     
188         if (clone.gridy < 0)
189             clone.gridy = GridBagConstraints.RELATIVE;
190
191         if (clone.gridwidth == 0)
192             clone.gridwidth = GridBagConstraints.REMAINDER;
193         else if (clone.gridwidth < 0
194             && clone.gridwidth != GridBagConstraints.REMAINDER
195             && clone.gridwidth != GridBagConstraints.RELATIVE)
196             clone.gridwidth = 1;
197     
198         if (clone.gridheight == 0)
199             clone.gridheight = GridBagConstraints.REMAINDER;
200         else if (clone.gridheight < 0
201             && clone.gridheight != GridBagConstraints.REMAINDER
202             && clone.gridheight != GridBagConstraints.RELATIVE)
203             clone.gridheight = 1;
204     
205         comptable.put (component, clone);
206     }
207
208     public GridBagConstraints getConstraints (Component component)
209     {
210         return (GridBagConstraints) (lookupConstraints (component).clone());
211     }
212
213     protected GridBagConstraints lookupConstraints (Component component)
214     {
215         GridBagConstraints result = (GridBagConstraints) comptable.get (component);
216
217         if (result == null)
218         {
219             setConstraints (component, defaultConstraints);
220             result = (GridBagConstraints) comptable.get (component);
221         }
222     
223         return result;
224     }
225
226     private GridBagConstraints lookupInternalConstraints (Component component)
227     {
228         GridBagConstraints result =
229             (GridBagConstraints) internalcomptable.get (component);
230
231         if (result == null)
232         {
233             result = (GridBagConstraints) lookupConstraints(component).clone();
234             internalcomptable.put (component, result);
235         }
236     
237         return result;
238     }
239
240     /**
241      * @since 1.1
242      */
243     public Point getLayoutOrigin ()
244     {
245         if (layoutInfo == null)
246             return new Point (0, 0);
247     
248         return new Point (layoutInfo.pos_x, layoutInfo.pos_y);
249     }
250
251     /**
252      * @since 1.1
253      */
254     public int[][] getLayoutDimensions ()
255     {
256         int[][] result = new int [2][];
257         if (layoutInfo == null)
258           {
259             result[0] = new int[0];
260             result[1] = new int[0];
261
262             return result;
263           }
264
265         result [0] = new int [layoutInfo.cols];
266         System.arraycopy (layoutInfo.colWidths, 0, result [0], 0, layoutInfo.cols);
267         result [1] = new int [layoutInfo.rows];
268         System.arraycopy (layoutInfo.rowHeights, 0, result [1], 0, layoutInfo.rows);
269         return result;
270     }
271
272     public double[][] getLayoutWeights ()
273     {
274         double[][] result = new double [2][];
275         if (layoutInfo == null)
276           {
277             result[0] = new double[0];
278             result[1] = new double[0];
279
280             return result;
281           }
282
283         result [0] = new double [layoutInfo.cols];
284         System.arraycopy (layoutInfo.colWeights, 0, result [0], 0, layoutInfo.cols);
285         result [1] = new double [layoutInfo.rows];
286         System.arraycopy (layoutInfo.rowWeights, 0, result [1], 0, layoutInfo.rows);
287         return result;
288     }
289
290     /**
291      * @since 1.1
292      */
293     public Point location (int x, int y)
294     {
295         if (layoutInfo == null)
296             return new Point (0, 0);
297
298         int col;
299         int row;
300         int pixel_x = layoutInfo.pos_x;
301         int pixel_y = layoutInfo.pos_y;
302
303         for (col = 0; col < layoutInfo.cols; col++)
304         {
305             int w = layoutInfo.colWidths [col];
306             if (x < pixel_x + w)
307                 break;
308
309             pixel_x += w;
310         }
311
312         for (row = 0; row < layoutInfo.rows; row++)
313         {
314             int h = layoutInfo.rowHeights [row];
315             if (y < pixel_y + h)
316                 break;
317
318             pixel_y += h;
319         }
320
321         return new Point (col, row);
322     }
323
324     /**
325      * Obsolete.
326      */
327     protected void AdjustForGravity (GridBagConstraints gbc, Rectangle rect)
328     {
329       // FIXME
330       throw new Error ("Not implemented");
331     }
332
333     /**
334      * Obsolete.
335      */
336     protected void ArrangeGrid (Container parent)
337     {
338       Component[] components = parent.getComponents();
339
340       if (components.length == 0)
341         return;
342
343       GridBagLayoutInfo info = getLayoutInfo (parent, PREFERREDSIZE);
344       if (info.cols == 0 && info.rows == 0)
345         return;
346       layoutInfo = info;
347
348       // DEBUG
349       //dumpLayoutInfo (layoutInfo);
350     
351       for(int i = 0; i < components.length; i++)
352         {
353           Component component = components [i];
354                 
355           // If component is not visible we dont have to care about it.
356           if (!component.isVisible())
357             continue;
358                 
359           GridBagConstraints constraints =
360               lookupInternalConstraints(component);
361
362           int cellx = sumIntArray(layoutInfo.colWidths, constraints.gridx);
363           int celly = sumIntArray(layoutInfo.rowHeights, constraints.gridy);
364           int cellw = sumIntArray(layoutInfo.colWidths,
365                                   constraints.gridx + constraints.gridwidth) - cellx;
366           int cellh = sumIntArray(layoutInfo.rowHeights,
367                                   constraints.gridy + constraints.gridheight) - celly;
368
369           Insets insets = constraints.insets;
370           if (insets != null)
371             {
372               cellx += insets.left;
373               celly += insets.top;
374               cellw -= insets.left + insets.right;
375               cellh -= insets.top + insets.bottom;
376             }
377
378           Dimension dim = component.getPreferredSize();
379
380           // Note: Documentation says that padding is added on both sides, but
381           // visual inspection shows that the Sun implementation only adds it
382           // once, so we do the same.
383           dim.width += constraints.ipadx;
384           dim.height += constraints.ipady;
385
386           switch(constraints.fill)
387             {
388             case GridBagConstraints.HORIZONTAL:
389               dim.width = cellw;
390               break;
391             case GridBagConstraints.VERTICAL:
392               dim.height = cellh;
393               break;
394             case GridBagConstraints.BOTH:
395               dim.width = cellw;
396               dim.height = cellh;
397               break;
398             }
399
400           int x;
401           int y;
402
403           switch(constraints.anchor)
404             {
405             case GridBagConstraints.NORTH:
406               x = cellx + (cellw - dim.width) / 2;
407               y = celly;
408               break;
409             case GridBagConstraints.SOUTH:
410               x = cellx + (cellw - dim.width) / 2;
411               y = celly + cellh - dim.height;
412               break;
413             case GridBagConstraints.WEST:
414               x = cellx;
415               y = celly + (cellh - dim.height) / 2;
416               break;
417             case GridBagConstraints.EAST:
418               x = cellx + cellw - dim.width;
419               y = celly + (cellh - dim.height) / 2;
420               break;
421             case GridBagConstraints.NORTHEAST:
422               x = cellx + cellw - dim.width;
423               y = celly;
424               break;
425             case GridBagConstraints.NORTHWEST:
426               x = cellx;
427               y = celly;
428               break;
429             case GridBagConstraints.SOUTHEAST:
430               x = cellx + cellw - dim.width;
431               y = celly + cellh - dim.height;
432               break;
433             case GridBagConstraints.SOUTHWEST:
434               x = cellx;
435               y = celly + cellh - dim.height;
436               break;
437             default:
438               x = cellx + (cellw - dim.width) / 2;
439               y = celly + (cellh - dim.height) / 2;
440               break;
441             }
442
443           component.setBounds(layoutInfo.pos_x + x, layoutInfo.pos_y + y, dim.width, dim.height);
444         }
445
446       // DEBUG
447       //dumpLayoutInfo (layoutInfo);
448     }
449
450     /**
451      * Obsolete.
452      */
453     protected GridBagLayoutInfo GetLayoutInfo (Container parent, int sizeflag)
454     {
455       if (sizeflag != MINSIZE && sizeflag != PREFERREDSIZE)
456         throw new IllegalArgumentException();
457
458       Dimension parentDim = parent.getSize ();
459       Insets parentInsets = parent.getInsets ();
460       parentDim.width -= parentInsets.left + parentInsets.right;
461       parentDim.height -= parentInsets.top + parentInsets.bottom;
462    
463       int current_y = 0;
464       int max_x = 0;
465       int max_y = 0;
466
467       // Guaranteed to contain the last component added to the given row
468       // or column, whose gridwidth/height is not REMAINDER.
469       HashMap lastInRow = new HashMap();
470       HashMap lastInCol = new HashMap();
471
472       Component[] components = parent.getComponents();
473
474       // Components sorted by gridwidths/heights,
475       // smallest to largest, with REMAINDER and RELATIVE at the end.
476       // These are useful when determining sizes and weights.
477       ArrayList sortedByWidth = new ArrayList(components.length);
478       ArrayList sortedByHeight = new ArrayList(components.length);
479
480       // STEP 1: first we figure out how many rows/columns
481       for (int i = 0; i < components.length; i++)
482         {
483           Component component = components [i];
484                 
485           // If component is not visible we dont have to care about it.
486           if (!component.isVisible())
487             continue;
488                 
489           // When looking up the constraint for the first time, check the
490           // original unmodified constraint.  After the first time, always
491           // refer to the internal modified constraint.
492           GridBagConstraints originalConstraints = lookupConstraints (component);
493           GridBagConstraints constraints = (GridBagConstraints) originalConstraints.clone();
494           internalcomptable.put(component, constraints);
495
496           // Cases:
497           //
498           // 1. gridy == RELATIVE, gridx == RELATIVE
499           //
500           //       use y as the row number; check for the next
501           //       available slot at row y
502           //
503           // 2. only gridx == RELATIVE
504           //
505           //       check for the next available slot at row gridy
506           //
507           // 3. only gridy == RELATIVE
508           //
509           //       check for the next available slot at column gridx
510           //
511           // 4. neither gridx or gridy == RELATIVE
512           //
513           //       nothing to check; just add it
514
515
516           // cases 1 and 2
517           if(constraints.gridx == GridBagConstraints.RELATIVE)
518             {
519               if (constraints.gridy == GridBagConstraints.RELATIVE)
520               constraints.gridy = current_y;
521
522               int x;
523
524               // Check the component that occupies the right-most spot in this
525               // row. We want to add this component after it.
526               // If this row is empty, add to the 0 position.
527               if (!lastInRow.containsKey(new Integer(constraints.gridy))) 
528                 x = 0;
529               else
530                 {
531                   Component lastComponent = (Component) lastInRow.get(new Integer(constraints.gridy));
532                   GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent);
533                   x = lastConstraints.gridx + Math.max(1, lastConstraints.gridwidth);
534                 }
535
536               // Determine if this component will fit in the slot vertically.
537               // If not, bump it over to where it does fit.
538               for (int y = constraints.gridy + 1; y < constraints.gridy + Math.max(1, constraints.gridheight); y++)
539                 {
540                   if (lastInRow.containsKey(new Integer(y)))
541                     {
542                       Component lastComponent = (Component) lastInRow.get(new Integer(y));
543                       GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent);
544                       x = Math.max (x,
545                                     lastConstraints.gridx + Math.max(1, lastConstraints.gridwidth));
546                     }
547                 }
548
549               constraints.gridx = x;
550             }
551           // case 3
552           else if(constraints.gridy == GridBagConstraints.RELATIVE)
553             {
554               int y;
555               // Check the component that occupies the bottom-most spot in
556               // this column. We want to add this component below it.
557               // If this column is empty, add to the 0 position.
558               if (!lastInCol.containsKey(new Integer(constraints.gridx))) 
559                 y = 0;
560               else
561                 {
562                   Component lastComponent = (Component)lastInCol.get(new Integer(constraints.gridx));
563                   GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent);
564                   y = lastConstraints.gridy + Math.max(1, lastConstraints.gridheight);
565                 }
566
567               // Determine if this component will fit in the slot horizontally.
568               // If not, bump it down to where it does fit.
569               for (int x = constraints.gridx + 1; x < constraints.gridx + Math.max(1, constraints.gridwidth); x++)
570                 {
571                   if (lastInCol.containsKey(new Integer(x)))
572                     {
573                       Component lastComponent = (Component) lastInCol.get(new Integer(x));
574                       GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent);
575                       y = Math.max (y,
576                                     lastConstraints.gridy + Math.max(1, lastConstraints.gridheight));
577                     }
578                 }
579
580               constraints.gridy = y;
581             }
582           // case 4: do nothing
583
584           max_x = Math.max(max_x, 
585                            constraints.gridx + Math.max(1, constraints.gridwidth));
586           max_y = Math.max(max_y,
587                            constraints.gridy + Math.max(1, constraints.gridheight));
588
589           sortBySpan(component, constraints.gridwidth, sortedByWidth, true);
590           sortBySpan(component, constraints.gridheight, sortedByHeight, false);
591
592           // Update our reference points for RELATIVE gridx and gridy.
593           if(constraints.gridwidth == GridBagConstraints.REMAINDER)
594             {
595               current_y = constraints.gridy + Math.max(1, constraints.gridheight);
596             }
597           else if (constraints.gridwidth != GridBagConstraints.REMAINDER)
598             {
599               for (int y = constraints.gridy; y < constraints.gridy + Math.max(1, constraints.gridheight); y++)
600                 {
601                   if(lastInRow.containsKey(new Integer(y)))
602                     {
603                       Component lastComponent = (Component) lastInRow.get(new Integer(y));
604                       GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent);
605                       if (constraints.gridx > lastConstraints.gridx)
606                         {
607                           lastInRow.put(new Integer(y), component);
608                         }
609                     }
610                   else
611                     {
612                       lastInRow.put(new Integer(y), component);
613                     }
614                 }
615
616               for (int x = constraints.gridx; x < constraints.gridx + Math.max(1, constraints.gridwidth); x++)
617                 {
618                   if(lastInCol.containsKey(new Integer(x)))
619                     {
620                       Component lastComponent = (Component) lastInCol.get(new Integer(x));
621                       GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent);
622                       if (constraints.gridy > lastConstraints.gridy)
623                         {
624                           lastInCol.put(new Integer(x), component);
625                         }
626                     }
627                   else
628                     {
629                       lastInCol.put(new Integer(x), component);
630                     }
631                 }
632             }
633         } // end of STEP 1
634         
635       GridBagLayoutInfo info = new GridBagLayoutInfo(max_x, max_y);
636
637       // Check if column widths and row heights are overridden.
638
639       for (int x = 0; x < max_x; x++)
640         {
641           if(columnWidths != null && columnWidths.length > x)
642             info.colWidths[x] = columnWidths[x];
643           if(columnWeights != null && columnWeights.length > x)
644             info.colWeights[x] = columnWeights[x];
645         }
646
647       for (int y = 0; y < max_y; y++)
648         {
649           if(rowHeights != null && rowHeights.length > y)
650             info.rowHeights[y] = rowHeights[y];
651           if(rowWeights != null && rowWeights.length > y)
652             info.rowWeights[y] = rowWeights[y];
653         }
654
655       // STEP 2: Fix up any cells with width/height as REMAINDER/RELATIVE.
656       for (int i = 0; i < components.length; i++)
657         {
658           Component component = components [i];
659                         
660           // If component is not visible we dont have to care about it.
661           if (!component.isVisible())
662             continue;
663                         
664           GridBagConstraints constraints = lookupInternalConstraints (component);
665
666           if(constraints.gridwidth == GridBagConstraints.REMAINDER || constraints.gridwidth == GridBagConstraints.RELATIVE)
667             {
668               if(constraints.gridwidth == GridBagConstraints.REMAINDER)
669                 {
670                   for (int y = constraints.gridy; y < constraints.gridy + Math.max(1, constraints.gridheight); y++)
671                     {
672                       if (lastInRow.containsKey(new Integer(y)))
673                         {
674                           Component lastComponent = (Component) lastInRow.get(new Integer(y));
675                           GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent);
676
677                           if (lastConstraints.gridwidth == GridBagConstraints.RELATIVE)
678                             {
679                               constraints.gridx = max_x - 1;
680                               break;
681                             }
682                           else
683                             {
684                               constraints.gridx = Math.max (constraints.gridx,
685                                                             lastConstraints.gridx + Math.max (1, lastConstraints.gridwidth));
686                             }
687                         }
688                     }
689                   constraints.gridwidth = max_x - constraints.gridx;
690                 }
691               else if (constraints.gridwidth == GridBagConstraints.RELATIVE)
692                 {
693                   constraints.gridwidth = max_x - constraints.gridx - 1;
694                 }
695
696               // Re-sort
697               sortedByWidth.remove(sortedByWidth.indexOf(component));
698               sortBySpan(component, constraints.gridwidth, sortedByWidth, true);
699             }
700
701           if(constraints.gridheight == GridBagConstraints.REMAINDER || constraints.gridheight == GridBagConstraints.RELATIVE)
702             {
703               if(constraints.gridheight == GridBagConstraints.REMAINDER)
704                 {
705                   for (int x = constraints.gridx; x < constraints.gridx + Math.max(1, constraints.gridwidth); x++)
706                     {
707                       if (lastInCol.containsKey(new Integer(x)))
708                         {
709                           Component lastComponent = (Component) lastInRow.get(new Integer(x));
710                           GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent);
711
712                           if (lastConstraints.gridheight == GridBagConstraints.RELATIVE)
713                             {
714                               constraints.gridy = max_y - 1;
715                               break;
716                             }
717                           else
718                             {
719                               constraints.gridy = Math.max (constraints.gridy,
720                                                             lastConstraints.gridy + Math.max (1, lastConstraints.gridheight));
721                             }
722                         }
723                     }
724                   constraints.gridheight = max_y - constraints.gridy;
725                 }
726               else if (constraints.gridheight == GridBagConstraints.RELATIVE)
727                 {
728                   constraints.gridheight = max_y - constraints.gridy - 1;
729                 }
730
731               // Re-sort
732               sortedByHeight.remove(sortedByHeight.indexOf(component));
733               sortBySpan(component, constraints.gridheight, sortedByHeight, false);
734             }
735         } // end of STEP 2
736
737       // STEP 3: Determine sizes and weights for columns.
738       for (int i = 0; i < sortedByWidth.size(); i++)
739         {
740           Component component = (Component) sortedByWidth.get(i);
741                         
742           // If component is not visible we dont have to care about it.
743           if (!component.isVisible())
744             continue;
745
746           GridBagConstraints constraints = lookupInternalConstraints (component);
747
748           int width = (sizeflag == PREFERREDSIZE) ?
749                       component.getPreferredSize().width :
750                       component.getMinimumSize().width;
751
752           if(constraints.insets != null)
753             width += constraints.insets.left + constraints.insets.right;
754
755           width += constraints.ipadx;
756
757           distributeSizeAndWeight(width,
758                                   constraints.weightx, 
759                                   constraints.gridx,
760                                   constraints.gridwidth,
761                                   info.colWidths,
762                                   info.colWeights);
763         } // end of STEP 3
764
765       // STEP 4: Determine sizes and weights for rows.
766       for (int i = 0; i < sortedByHeight.size(); i++)
767         {
768           Component component = (Component) sortedByHeight.get(i);
769                         
770           // If component is not visible we dont have to care about it.
771           if (!component.isVisible())
772             continue;
773
774           GridBagConstraints constraints = lookupInternalConstraints (component);
775
776           int height = (sizeflag == PREFERREDSIZE) ?
777                        component.getPreferredSize().height :
778                        component.getMinimumSize().height;
779
780           if(constraints.insets != null)
781             height += constraints.insets.top + constraints.insets.bottom;
782
783           height += constraints.ipady;
784
785           distributeSizeAndWeight(height,
786                                   constraints.weighty, 
787                                   constraints.gridy,
788                                   constraints.gridheight,
789                                   info.rowHeights,
790                                   info.rowWeights);
791         } // end of STEP 4
792
793       // Adjust cell sizes iff parent size not zero.
794       if (parentDim.width > 0 && parentDim.height > 0)
795         {
796           calcCellSizes (info.colWidths, info.colWeights, parentDim.width);
797           calcCellSizes (info.rowHeights, info.rowWeights, parentDim.height);
798         }
799
800       int totalWidth = sumIntArray(info.colWidths);
801       int totalHeight = sumIntArray(info.rowHeights);
802
803       // Make sure pos_x and pos_y are never negative.
804       if (totalWidth >= parentDim.width)
805         info.pos_x = parentInsets.left;
806       else
807         info.pos_x = parentInsets.left + (parentDim.width - totalWidth) / 2;
808
809       if (totalHeight >= parentDim.height)
810         info.pos_y = parentInsets.top;
811       else
812         info.pos_y = parentInsets.top + (parentDim.height - totalHeight) / 2;
813
814       // DEBUG
815       //dumpLayoutInfo (info);
816
817       return info;
818     }
819
820     /**
821      * Obsolete.
822      */
823     protected Dimension GetMinSize (Container parent, GridBagLayoutInfo info)
824     {
825       if (parent == null || info == null)
826         return new Dimension (0, 0);
827
828       Insets insets = parent.getInsets();
829       int width = sumIntArray (info.colWidths) + insets.left + insets.right;
830       int height = sumIntArray (info.rowHeights) + insets.top + insets.bottom;
831       return new Dimension (width, height);
832     }
833
834     /**
835      * @since 1.4
836      */
837     protected Dimension getMinSize (Container parent, GridBagLayoutInfo info)
838     {
839       return GetMinSize (parent, info);
840     }
841
842     /**
843      * Helper method used by GetLayoutInfo to keep components sorted, either
844      * by gridwidth or gridheight.
845      *
846      * @param component   Component to add to the sorted list.
847      * @param span        Either the component's gridwidth or gridheight.
848      * @param list        <code>ArrayList</code> of components, sorted by
849      *                    their span.
850      * @param sortByWidth Flag indicating sorting index. If true, sort by
851      *                    width. Otherwise, sort by height.
852      * FIXME: Use a better sorting algorithm.
853      */
854     private void sortBySpan (Component component, int span, ArrayList list, boolean sortByWidth)
855     {
856       if (span == GridBagConstraints.REMAINDER
857           || span == GridBagConstraints.RELATIVE)
858         {
859           // Put all RELATIVE and REMAINDER components at the end.
860           list.add(component);
861         }
862       else
863         {
864           int i = 0;
865           if (list.size() > 0)
866             {
867               GridBagConstraints gbc = lookupInternalConstraints((Component) list.get(i));
868               int otherspan = sortByWidth ?
869                               gbc.gridwidth :
870                               gbc.gridheight;
871               while (otherspan != GridBagConstraints.REMAINDER
872                      && otherspan != GridBagConstraints.RELATIVE
873                      && span >= otherspan)
874                 {
875                   i++;
876                   if (i < list.size())
877                     {
878                       gbc = lookupInternalConstraints((Component) list.get(i));
879                       otherspan = sortByWidth ?
880                                   gbc.gridwidth :
881                                   gbc.gridheight;
882                     }
883                   else
884                     break;
885                 }
886             }
887           list.add(i, component);
888         }
889     }
890
891     /**
892      * Helper method used by GetLayoutInfo to distribute a component's size
893      * and weight.
894      *
895      * @param size    Preferred size of component, with inset and padding
896      *                already added.
897      * @param weight  Weight of component.
898      * @param start   Starting position of component. Either
899      *                constraints.gridx or gridy.
900      * @param span    Span of component. either contraints.gridwidth or
901      *                gridheight.
902      * @param sizes   Sizes of rows or columns.
903      * @param weights Weights of rows or columns.
904      */
905     private void distributeSizeAndWeight (int size, double weight,
906                                           int start, int span,
907                                           int[] sizes, double[] weights)
908     {
909       if (span == 1)
910         {
911           sizes[start] = Math.max(sizes[start], size);
912           weights[start] = Math.max(weights[start], weight);
913         }
914       else
915         {
916           int numOccupied = span;
917           int lastOccupied = -1;
918
919           for(int i = start; i < start + span; i++)
920             {
921               if (sizes[i] == 0.0)
922                 numOccupied--;
923               else
924                 {
925                   size -= sizes[i];
926                   lastOccupied = i;
927                 }
928             }
929
930           // A component needs to occupy at least one row.
931           if(numOccupied == 0)
932             sizes[start + span - 1] = size;
933           else if (size > 0)
934             sizes[lastOccupied] += size;
935
936           calcCellWeights(weight, weights, start, span);
937         }
938     }
939
940     /**
941      * Helper method used by GetLayoutInfo to calculate weight distribution.
942      * @param weight  Weight of component.
943      * @param weights Weights of rows/columns.
944      * @param start   Starting position of component in grid (gridx/gridy).
945      * @param span    Span of component (gridwidth/gridheight).
946      */
947     private void calcCellWeights (double weight, double[] weights, int start, int span)
948     {
949       double totalWeight = 0.0;
950       for(int k = start; k < start + span; k++)
951         totalWeight += weights[k];
952
953       if(weight > totalWeight)
954         {
955           if (totalWeight == 0.0)
956             {
957               weights[start + span - 1] += weight;
958             }
959           else
960             {
961               double diff = weight - totalWeight ;
962               double remaining = diff;
963
964               for(int k = start; k < start + span; k++)
965                 {
966                   double extraWeight = diff * weights[k] / totalWeight;
967                   weights[k] += extraWeight;
968                   remaining -= extraWeight;
969                 } 
970
971               if (remaining > 0.0 && weights[start + span - 1] != 0.0)
972                 {
973                   weights[start + span - 1] += remaining;
974                 }
975             }
976         }
977     }
978
979     /**
980      * Helper method used by GetLayoutInfo to distribute extra space
981      * based on weight distribution.
982      *
983      * @param sizes   Sizes of rows/columns.
984      * @param weights Weights of rows/columns.
985      * @param range   Dimension of container.
986      */
987     private void calcCellSizes (int[] sizes, double[] weights, int range)
988     {
989       int totalSize = sumIntArray (sizes);
990       double totalWeight = sumDoubleArray (weights);
991
992       int diff = range - totalSize;
993
994       if (diff == 0)
995         return;
996
997       for (int i = 0; i < sizes.length; i++)
998         {
999           int newsize = (int) (sizes[i] + (((double) diff) * weights [i] / totalWeight ));
1000
1001           if (newsize > 0)
1002             sizes[i] = newsize;
1003         }
1004     }
1005
1006     private void dumpLayoutInfo (GridBagLayoutInfo info)
1007     {
1008         System.out.println ("GridBagLayoutInfo:");
1009         System.out.println ("cols: " + info.cols + ", rows: " + info.rows);
1010         System.out.print ("colWidths: ");
1011         dumpArray(info.colWidths);
1012         System.out.print ("rowHeights: ");
1013         dumpArray(info.rowHeights);
1014         System.out.print ("colWeights: ");
1015         dumpArray(info.colWeights);
1016         System.out.print ("rowWeights: ");
1017         dumpArray(info.rowWeights);
1018     }
1019
1020     private void dumpArray(int[] array)
1021     {
1022         String sep = "";
1023         for(int i = 0; i < array.length; i++)
1024         {
1025             System.out.print(sep);
1026             System.out.print(array[i]);
1027             sep = ", ";
1028         }
1029         System.out.println();
1030     }
1031
1032     private void dumpArray(double[] array)
1033     {
1034         String sep = "";
1035         for(int i = 0; i < array.length; i++)
1036         {
1037             System.out.print(sep);
1038             System.out.print(array[i]);
1039             sep = ", ";
1040         }
1041         System.out.println();
1042     }
1043   
1044     /**
1045      * @since 1.4
1046      */
1047     protected void arrangeGrid (Container parent)
1048     {
1049       ArrangeGrid (parent);
1050     }
1051
1052     /**
1053      * @since 1.4
1054      */
1055     protected GridBagLayoutInfo getLayoutInfo (Container parent, int sizeflag)
1056     {
1057       return GetLayoutInfo (parent, sizeflag);
1058     }
1059
1060     /**
1061      * @since 1.4
1062      */
1063     protected void adjustForGravity (GridBagConstraints gbc, Rectangle rect)
1064     {
1065       AdjustForGravity (gbc, rect);
1066     }
1067 }