Logo Search packages:      
Sourcecode: jedit version File versions  Download package

ExtendedGridLayout.java

/*
 * ExtendedGridLayout.java - a grid layout manager with variable cell sizes
 * that supports colspans and rowspans
 * :tabSize=8:indentSize=8:noTabs=false:
 * :folding=explicit:collapseFolds=1:
 *
 * Originally written by Björn Kautler for the jEdit project. This work has been
 * placed into the public domain. You may use this work in any way and for any
 * purpose you wish.
 *
 * THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND, NOT EVEN THE
 * IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR OF THIS SOFTWARE, ASSUMES
 * _NO_ RESPONSIBILITY FOR ANY CONSEQUENCE RESULTING FROM THE USE, MODIFICATION,
 * OR REDISTRIBUTION OF THIS SOFTWARE.
 */

package org.gjt.sp.jedit.gui;

import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.LayoutManager2;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;

import static java.awt.Component.CENTER_ALIGNMENT;

import static org.gjt.sp.jedit.gui.ExtendedGridLayoutConstraints.REMAINDER;

/**
  * A layout manager that places components in a rectangular grid
  * with variable cell sizes that supports colspans and rowspans.
  * <p>
  * The container is divided into rectangles, and each component is placed
  * in a rectangular space defined by its colspan and rowspan.
  * Each row is as large as the largest component in
  * that row, and each column is as wide as the widest component in
  * that column. </p>
  * <p>
  * This behavior is similar to 
  * <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/awt/GridLayout.html">{@code java.awt.GridLayout}</a>
  * but it supports different row heights and
  * column widths for each row/column. </p>
  * <p>
  * For example, the following is a Dialog that lays out ten buttons
  * exactly the same as in the example of the JavaDoc of
  * <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/awt/GridBagLayout.html">{@code java.awt.GridBagLayout}</a>
  * with the difference of vertical and horizontal gaps that can be configured:
  * <hr>
  * <blockquote><pre><font color="#000000">
  * <font color="#000000">   1:</font><font color="#009966"><strong>import</strong></font> java.awt.Button;
  * <font color="#000000">   2:</font><font color="#009966"><strong>import</strong></font> java.awt.Dimension;
  * <font color="#000000">   3:</font>
  * <font color="#000000">   4:</font><font color="#009966"><strong>import</strong></font> javax.swing.JDialog;
  * <font color="#990066">   5:</font>
  * <font color="#000000">   6:</font><font color="#009966"><strong>import</strong></font> org.gjt.sp.jedit.gui.ExtendedGridLayout;
  * <font color="#000000">   7:</font><font color="#009966"><strong>import</strong></font> org.gjt.sp.jedit.gui.ExtendedGridLayoutConstraints;
  * <font color="#000000">   8:</font>
  * <font color="#000000">   9:</font><font color="#009966"><strong>import</strong></font> <font color="#006699"><strong>static</strong></font> org.gjt.sp.jedit.gui.ExtendedGridLayoutConstraints.REMAINDER;
  * <font color="#990066">  10:</font>
  * <font color="#000000">  11:</font><font color="#006699"><strong>public</strong></font> <font color="#0099ff"><strong>class</strong></font> ExampleDialog <font color="#006699"><strong>extends</strong></font> JDialog <font color="#000000"><strong>{</strong></font>
  * <font color="#000000">  12:</font>    <font color="#006699"><strong>public</strong></font> <font color="#9966ff">ExampleDialog</font>() <font color="#000000"><strong>{</strong></font>
  * <font color="#000000">  13:</font>        <font color="#cc00cc">super</font>(<font color="#cc00cc">null</font>,<font color="#ff00cc">&quot;</font><font color="#ff00cc">Example</font><font color="#ff00cc"> </font><font color="#ff00cc">Dialog</font><font color="#ff00cc">&quot;</font>,<font color="#cc00cc">true</font>);
  * <font color="#000000">  14:</font>        <font color="#9966ff">setLayout</font>(<font color="#006699"><strong>new</strong></font> <font color="#9966ff">ExtendedGridLayout</font>(<font color="#ff0000">5</font>,<font color="#ff0000">5</font>,<font color="#006699"><strong>new</strong></font> <font color="#9966ff">Insets</font>(<font color="#ff0000">5</font>,<font color="#ff0000">5</font>,<font color="#ff0000">5</font>,<font color="#ff0000">5</font>)));
  * <font color="#990066">  15:</font>        
  * <font color="#000000">  16:</font>        <font color="#9966ff">add</font>(<font color="#9966ff">makeButton</font>(<font color="#ff00cc">&quot;</font><font color="#ff00cc">Button1</font><font color="#ff00cc">&quot;</font>));
  * <font color="#000000">  17:</font>        <font color="#9966ff">add</font>(<font color="#9966ff">makeButton</font>(<font color="#ff00cc">&quot;</font><font color="#ff00cc">Button2</font><font color="#ff00cc">&quot;</font>));
  * <font color="#000000">  18:</font>        <font color="#9966ff">add</font>(<font color="#9966ff">makeButton</font>(<font color="#ff00cc">&quot;</font><font color="#ff00cc">Button3</font><font color="#ff00cc">&quot;</font>));
  * <font color="#000000">  19:</font>        <font color="#9966ff">add</font>(<font color="#9966ff">makeButton</font>(<font color="#ff00cc">&quot;</font><font color="#ff00cc">Button4</font><font color="#ff00cc">&quot;</font>));
  * <font color="#990066">  20:</font>        Button button <font color="#000000"><strong>=</strong></font> <font color="#9966ff">makeButton</font>(<font color="#ff00cc">&quot;</font><font color="#ff00cc">Button5</font><font color="#ff00cc">&quot;</font>);
  * <font color="#000000">  21:</font>        <font color="#9966ff">add</font>(button,<font color="#006699"><strong>new</strong></font> <font color="#9966ff">ExtendedGridLayoutConstraints</font>(<font color="#ff0000">1</font>,REMAINDER,<font color="#ff0000">1</font>,button));
  * <font color="#000000">  22:</font>        button <font color="#000000"><strong>=</strong></font> <font color="#9966ff">makeButton</font>(<font color="#ff00cc">&quot;</font><font color="#ff00cc">Button6</font><font color="#ff00cc">&quot;</font>);
  * <font color="#000000">  23:</font>        <font color="#9966ff">add</font>(button,<font color="#006699"><strong>new</strong></font> <font color="#9966ff">ExtendedGridLayoutConstraints</font>(<font color="#ff0000">2</font>,<font color="#ff0000">3</font>,<font color="#ff0000">1</font>,button));
  * <font color="#000000">  24:</font>        button <font color="#000000"><strong>=</strong></font> <font color="#9966ff">makeButton</font>(<font color="#ff00cc">&quot;</font><font color="#ff00cc">Button7</font><font color="#ff00cc">&quot;</font>);
  * <font color="#990066">  25:</font>        <font color="#9966ff">add</font>(button,<font color="#006699"><strong>new</strong></font> <font color="#9966ff">ExtendedGridLayoutConstraints</font>(<font color="#ff0000">2</font>,button));
  * <font color="#000000">  26:</font>        button <font color="#000000"><strong>=</strong></font> <font color="#9966ff">makeButton</font>(<font color="#ff00cc">&quot;</font><font color="#ff00cc">Button8</font><font color="#ff00cc">&quot;</font>);
  * <font color="#000000">  27:</font>        <font color="#9966ff">add</font>(button,<font color="#006699"><strong>new</strong></font> <font color="#9966ff">ExtendedGridLayoutConstraints</font>(<font color="#ff0000">3</font>,<font color="#ff0000">1</font>,<font color="#ff0000">2</font>,button));
  * <font color="#000000">  28:</font>        button <font color="#000000"><strong>=</strong></font> <font color="#9966ff">makeButton</font>(<font color="#ff00cc">&quot;</font><font color="#ff00cc">Button9</font><font color="#ff00cc">&quot;</font>);
  * <font color="#000000">  29:</font>        <font color="#9966ff">add</font>(button,<font color="#006699"><strong>new</strong></font> <font color="#9966ff">ExtendedGridLayoutConstraints</font>(<font color="#ff0000">3</font>,<font color="#ff0000">3</font>,<font color="#ff0000">1</font>,button));
  * <font color="#990066">  30:</font>        button <font color="#000000"><strong>=</strong></font> <font color="#9966ff">makeButton</font>(<font color="#ff00cc">&quot;</font><font color="#ff00cc">Button10</font><font color="#ff00cc">&quot;</font>);
  * <font color="#000000">  31:</font>        <font color="#9966ff">add</font>(button,<font color="#006699"><strong>new</strong></font> <font color="#9966ff">ExtendedGridLayoutConstraints</font>(<font color="#ff0000">4</font>,REMAINDER,<font color="#ff0000">1</font>,button));
  * <font color="#000000">  32:</font>        
  * <font color="#000000">  33:</font>        <font color="#9966ff">pack</font>();
  * <font color="#000000">  34:</font>        <font color="#9966ff">setLocationRelativeTo</font>(<font color="#cc00cc">null</font>);
  * <font color="#990066">  35:</font>        <font color="#9966ff">setVisible</font>(<font color="#cc00cc">true</font>);
  * <font color="#000000">  36:</font>    <font color="#000000"><strong>}</strong></font>
  * <font color="#000000">  37:</font>    
  * <font color="#000000">  38:</font>    <font color="#006699"><strong>private</strong></font> Button <font color="#9966ff">makeButton</font>(String name) <font color="#000000"><strong>{</strong></font>
  * <font color="#000000">  39:</font>        Button button <font color="#000000"><strong>=</strong></font> <font color="#006699"><strong>new</strong></font> <font color="#9966ff">Button</font>(name);
  * <font color="#990066">  40:</font>        button.<font color="#9966ff">setMaximumSize</font>(<font color="#006699"><strong>new</strong></font> <font color="#9966ff">Dimension</font>(Integer.MAX_VALUE,Integer.MAX_VALUE));
  * <font color="#000000">  41:</font>        <font color="#006699"><strong>return</strong></font> button;
  * <font color="#000000">  42:</font>    <font color="#000000"><strong>}</strong></font>
  * <font color="#000000">  43:</font><font color="#000000"><strong>}</strong></font>
  * </font></pre></blockquote>
  * <hr>
  * If you use {@code REMAINDER} as colspan or rowspan then a component takes
  * up the remaining space in that column or row. Any additional components in
  * a row are ignored and not displayed. Additional components in a column are
  * moved rightside. If a rowspan hits a colspan, the colspan ends and the
  * rowspan takes precedence.
  * <p>
  * Components for which {@code isVisible() == false} are ignored. Because
  * of this, components can be replaced "in-place" by adding two components next to
  * each other, with different {@code isVisible()} values, and toggling the 
  * {@code setVisible()} values of both when we wish to swap the currently
  * visible component with the one that is hidden. </p>
  *
  * <p>
  * If you want to reserve free space in a row inbetween components,  
  * add a <a href="http://java.sun.com/j2se/1.5.0/docs/api/javax/swing/Box.Filler.html">{@code javax.swing.Box.Filler}</a>
  * to the layout if the free space is in the middle of a row,
  * or just don't add components if the free space
  * should be at the end of a row.</p>
  * <p>
  * If a row is taller, or a column is wider than the {@code maximumSize} of a component,
  * the component is resized to its maximum size and aligned according to its
  * {@code alignmentX} and {@code alignmentY} values. </p>
  * <p>
  * One instance of this class can be used to layout multiple
  * containers at the same time. </p>
  *
  * @author Björn "Vampire" Kautler
  * @version 1.0
  * @see ExtendedGridLayoutConstraints
  * @see <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/awt/Component.html"><code>java.awt.Component</code></a>
  * @see <a href="http://java.sun.com/j2se/1.5.0/docs/api/javax/swing/Box.Filler.html"><code>javax.swing.Box.Filler</code></a>
  */
public class ExtendedGridLayout implements LayoutManager2
{
      /**
        * This hashtable maintains the association between
        * a component and its ExtendedGridLayoutConstraints.
        * The Keys in {@code comptable} are the components and the
        * values are the instances of {@code ExtendedGridLayoutConstraints}.
        *
        * @see ExtendedGridLayoutConstraints
        */
      private final Hashtable<Component,ExtendedGridLayoutConstraints> comptable;
      
      /**
        * Specifies the horizontal space between two columns.
        * The default value is 0.
        * 
        * @see #distanceToBorders
        * @see #vgap
        */
      private final int hgap;
      
      /**
        * Specifies the vertical space between two rows.
        * The default value is 0.
        * 
        * @see #distanceToBorders
        * @see #hgap
        */
      private final int vgap;
      
      /**
        * Specifies the gap between the grid and the borders of the parent container.
        * The default value is 0 for all four borders.
        * 
        * @see #hgap
        * @see #vgap
        */
      private final Insets distanceToBorders;
      
      /**
        * An enum to tell the {@code getSize()} method which size is requested.
        * 
        * @see #getSize()
        */
      private static enum LayoutSize { MINIMUM, PREFERRED, MAXIMUM }
      
      /**
        * Creates an extended grid layout manager with the specified horizontal
        * and vertical gap, and the specified distance to the borders
        * of the parent container.
        * 
        * @param hgap The horizontal space between two columns ({@literal >=0})
        * @param vgap The vertical space between two rows ({@literal >=0})
        * @param distanceToBorders The distances to the borders of the parent container
        * @throws IllegalArgumentException if hgap {@literal < 0}
        * @throws IllegalArgumentException if vgap {@literal < 0}
        */
      public ExtendedGridLayout(int hgap, int vgap, Insets distanceToBorders)
      {
            if (hgap < 0)
            {
                  throw new IllegalArgumentException("hgap must be non-negative (" + hgap + ')');
            }
            if (vgap < 0)
            {
                  throw new IllegalArgumentException("vgap must be non-negative (" + vgap + ')');
            }
            this.hgap = hgap;
            this.vgap = vgap;
            this.distanceToBorders = (Insets)distanceToBorders.clone();
            comptable = new Hashtable<Component,ExtendedGridLayoutConstraints>();
      }
      
      /**
        * Creates an extended grid layout manager with zero horizontal
        * and vertical gap, and zero distance to the borders
        * of the parent container.
        */
      public ExtendedGridLayout()
      {
            this(0,0,new Insets(0,0,0,0));
      }
      
      /**
        * If the layout manager uses a per-component string,
        * adds the component <code>component</code> to the layout,
        * associating it with the string specified by <code>name</code>.
        * 
        * @param name      The string to be associated with the component.
        *                  Has to be {@code null}, so that default constraints are used.
        * @param component The component to be added
        * @throws IllegalArgumentException if {@code name} is not {@code null}
        * @see #addLayoutComponent(java.awt.Component, java.lang.Object)
        */
      public void addLayoutComponent(String name, Component component)
      {
            addLayoutComponent(component,name);
      }
      
      /**
        * Adds the specified component to the layout, using the specified
        * constraints object.
        * 
        * @param component    The component to be added
        * @param constraints  Where/how the component is added to the layout.
        * @throws IllegalArgumentException if {@code constraints} is not an ExtendedGridLayoutConstraints object
        * @throws IllegalArgumentException if {@code constraints} is a placeholder
        * @throws IllegalArgumentException if {@code constraints} is not the right one for the component
        * @see ExtendedGridLayoutConstraints
        */
      public void addLayoutComponent(Component component, Object constraints)
      {
            if (null == constraints)
            {
                  constraints = new ExtendedGridLayoutConstraints(component);
            }
            if (constraints instanceof ExtendedGridLayoutConstraints)
            {
                  ExtendedGridLayoutConstraints eglConstraints = (ExtendedGridLayoutConstraints)constraints;
                  if (eglConstraints.isPlaceholder())
                  {
                        throw new IllegalArgumentException("constraints must not be a placeholder");
                  }
                  else if (component != eglConstraints.getComponent())
                  {
                        throw new IllegalArgumentException("constraints is not the right one for this component");
                  }
                  comptable.put(component,eglConstraints);
            }
            else 
            {
                  throw new IllegalArgumentException("constraints must not be an ExtendedGridLayoutConstraints object");
            }
      }
      
      /**
        * Retrieves the constraints for the specified {@code component}.
        * If {@code component} is not in the {@code ExtendedGridLayout},
        * a set of default {@code ExtendedGridLayoutConstraints} are returned.
        * 
        * @param component the {@code component} to be queried
        * @return the contraints for the specified {@code component}
        * @throws NullPointerException if {@code component} is {@code null}
        * @see ExtendedGridLayoutConstraints
        */
      private ExtendedGridLayoutConstraints lookupConstraints(Component component)
      {
            if (null == component)
            {
                  throw new NullPointerException("component must not be null");
            }
            ExtendedGridLayoutConstraints constraints = comptable.get(component);
            if (null == constraints)
            {
                  constraints = new ExtendedGridLayoutConstraints(component);
                  comptable.put(component,constraints);
            }
            return constraints;
      }
      
      /**
        * Removes the specified component from the layout.
        * 
        * @param component The component to be removed
        */
      public void removeLayoutComponent(Component component)
      {
            comptable.remove(component);
      }
      
      /**
        * Returns the alignment along the X axis.  This specifies how
        * the component would like to be aligned relative to other
        * components.  The value should be a number between 0 and 1
        * where 0 represents alignment along the origin, 1 is aligned
        * the furthest away from the origin, 0.5 is centered, etc.
        * 
        * @param container The container for which the alignment should be returned
        * @return {@code java.awt.Component.CENTER_ALIGNMENT}
        */
      public float getLayoutAlignmentX(Container container)
      {
            return CENTER_ALIGNMENT;
      }
      
      /**
        * Returns the alignment along the Y axis. This specifies how
        * the component would like to be aligned relative to other
        * components. The value should be a number between 0 and 1
        * where 0 represents alignment along the origin, 1 is aligned
        * the furthest away from the origin, 0.5 is centered, etc.
        * 
        * @param container The container for which the alignment should be returned
        * @return {@code java.awt.Component.CENTER_ALIGNMENT}
        */
      public float getLayoutAlignmentY(Container container)
      {
            return CENTER_ALIGNMENT;
      }
      
      /**
        * Calculates the minimum size dimensions for the specified
        * container, given the components it contains.
        * 
        * @param parent The component to be laid out
        * @return The minimum size for the container
        * @see #maximumLayoutSize
        * @see #preferredLayoutSize
        */
      public Dimension minimumLayoutSize(Container parent)
      {
            synchronized (parent.getTreeLock())
            {
                  List<List<ExtendedGridLayoutConstraints>> gridRows = new ArrayList<List<ExtendedGridLayoutConstraints>>();
                  Set<ExtendedGridLayoutConstraints> colspans = new HashSet<ExtendedGridLayoutConstraints>();
                  Set<ExtendedGridLayoutConstraints> rowspans = new HashSet<ExtendedGridLayoutConstraints>();
                  Dimension gridSize = buildGrid(parent,gridRows,colspans,rowspans);
                  return getSize(parent,LayoutSize.MINIMUM,false,gridSize,gridRows,colspans,rowspans,new int[0][0]);
            }
      }
      
      /**
        * Calculates the preferred size dimensions for the specified
        * container, given the components it contains.
        * 
        * @param parent The container to be laid out
        * @return The preferred size for the container
        * @see #maximumLayoutSize
        * @see #minimumLayoutSize
        */
      public Dimension preferredLayoutSize(Container parent)
      {
            synchronized (parent.getTreeLock())
            {
                  List<List<ExtendedGridLayoutConstraints>> gridRows = new ArrayList<List<ExtendedGridLayoutConstraints>>();
                  Set<ExtendedGridLayoutConstraints> colspans = new HashSet<ExtendedGridLayoutConstraints>();
                  Set<ExtendedGridLayoutConstraints> rowspans = new HashSet<ExtendedGridLayoutConstraints>();
                  Dimension gridSize = buildGrid(parent,gridRows,colspans,rowspans);
                  return getSize(parent,LayoutSize.PREFERRED,false,gridSize,gridRows,colspans,rowspans,new int[0][0]);
            }
      }
      
      /**
        * Calculates the maximum size dimensions for the specified
        * container, given the components it contains.
        * 
        * @param parent The container to be laid out
        * @return The maximum size for the container
        * @see #minimumLayoutSize
        * @see #preferredLayoutSize
        */
      public Dimension maximumLayoutSize(Container parent)
      {
            synchronized (parent.getTreeLock())
            {
                  List<List<ExtendedGridLayoutConstraints>> gridRows = new ArrayList<List<ExtendedGridLayoutConstraints>>();
                  Set<ExtendedGridLayoutConstraints> colspans = new HashSet<ExtendedGridLayoutConstraints>();
                  Set<ExtendedGridLayoutConstraints> rowspans = new HashSet<ExtendedGridLayoutConstraints>();
                  Dimension gridSize = buildGrid(parent,gridRows,colspans,rowspans);
                  return getSize(parent,LayoutSize.MAXIMUM,false,gridSize,gridRows,colspans,rowspans,new int[0][0]);
            }
      }
      
      /**
        * Invalidates the layout, indicating that if the layout manager
        * has cached information it should be discarded.
        * 
        * @param container The container for which the cached information should be discarded
        */
      public void invalidateLayout(Container container)
      {
      }
      
      /**
        * Lays out the specified container.
        * 
        * @param parent The container to be laid out 
        */
      public void layoutContainer(Container parent)
      {
            synchronized (parent.getTreeLock())
            {
                  // Pass 1: build the grid
                  List<List<ExtendedGridLayoutConstraints>> gridRows = new ArrayList<List<ExtendedGridLayoutConstraints>>();
                  Set<ExtendedGridLayoutConstraints> colspans = new HashSet<ExtendedGridLayoutConstraints>();
                  Set<ExtendedGridLayoutConstraints> rowspans = new HashSet<ExtendedGridLayoutConstraints>();
                  Dimension gridSize = buildGrid(parent,gridRows,colspans,rowspans);
                  
                  // Pass 2: compute minimum, preferred and maximum column widths / row heights
                  int[][] layoutSizes = new int[6][];
                  Dimension preferredSize = getSize(parent,LayoutSize.PREFERRED,true,gridSize,gridRows,colspans,rowspans,layoutSizes);
                  int[] minimumColWidths = layoutSizes[0];
                  int[] minimumRowHeights = layoutSizes[1];
                  int[] preferredColWidths = layoutSizes[2];
                  int[] preferredRowHeights = layoutSizes[3];
                  int[] maximumColWidths = layoutSizes[4];
                  int[] maximumRowHeights = layoutSizes[5];
                  
                  // Pass 3: redistribute free space
                  Dimension parentSize = parent.getSize();
                  Insets insets = parent.getInsets();
                  int freeWidth = parentSize.width
                              - insets.left - insets.right
                              - (gridSize.width - 1) * hgap
                              - distanceToBorders.left - distanceToBorders.right;
                  int freeHeight = parentSize.height
                               - insets.top - insets.bottom
                               - (gridSize.height - 1) * vgap
                               - distanceToBorders.top - distanceToBorders.bottom;
                  redistributeSpace(preferredSize.width,
                                freeWidth,
                                0,gridSize.width,
                                preferredColWidths,
                                minimumColWidths,
                                maximumColWidths);
                  redistributeSpace(preferredSize.height,
                                freeHeight,
                                0,gridSize.height,
                                preferredRowHeights,
                                minimumRowHeights,
                                maximumRowHeights);
                  
                  // Pass 4: layout components
                  for (int row=0, y=insets.top+distanceToBorders.top ; row<gridSize.height ; y+=preferredRowHeights[row]+vgap, row++)
                  {
                        List<ExtendedGridLayoutConstraints> gridRow = gridRows.get(row);
                        for (int col=0, x=insets.left+distanceToBorders.left ; col<gridSize.width; x+=preferredColWidths[col]+hgap, col++)
                        {
                              ExtendedGridLayoutConstraints cell = gridRow.get(col);
                              if ((null != cell) && (null != cell.getComponent()) && !cell.isPlaceholder())
                              {
                                    Component component = cell.getComponent();
                                    Dimension maxSize = component.getMaximumSize();
                                    int fromCol = cell.getCol();
                                    int colspan = cell.getEffectiveColspan();
                                    int toCol = fromCol + colspan;
                                    int width = 0;
                                    for (int col2=fromCol ; col2<toCol ; col2++)
                                    {
                                          width += preferredColWidths[col2];
                                    }
                                    width += (colspan - 1) * hgap;
                                    int fromRow = cell.getRow();
                                    int rowspan = cell.getEffectiveRowspan();
                                    int toRow = fromRow + rowspan;
                                    int height = 0;
                                    for (int row2=fromRow ; row2<toRow ; row2++)
                                    {
                                          height += preferredRowHeights[row2];
                                    }
                                    height += (rowspan - 1) * vgap;
                                    int xCorrection = 0;
                                    int yCorrection = 0;
                                    if (width > maxSize.width)
                                    {
                                          xCorrection = (int)((width - maxSize.width) * component.getAlignmentX());
                                          width = maxSize.width;
                                    }
                                    if (height > maxSize.height)
                                    {
                                          yCorrection = (int)((height-maxSize.height) * component.getAlignmentY());
                                          height = maxSize.height;
                                    }
                                    
                                    component.setBounds(x + xCorrection, y + yCorrection, width, height);
                              }
                        }
                  }
            }
      }
      
      /**
        * Redistributs free space (positive or negative) to all available
        * columns or rows while taking elements maximum and minimum sizes into
        * account if possible.
        * 
        * @param totalSize             The cumulated preferred sizes of the components
        * @param freeSize              The available space for displaying components
        *                              without any gaps between components or between
        *                              the grid and the borders of the parent container
        * @param start                 The start in the arrays of rows or columns inclusive
        * @param stop                  The stop in the arrays of rows or columns exclusive
        * @param preferredElementSizes The preferredSizes of the rows or columns.
        *                              After invocation of this method, this array
        *                              holds the sizes that should be used
        * @param minimumElementSizes   The minimumSizes of the rows or columns
        * @param maximumElementSizes   The maximumSizes of the rows or columns
        */
      private void redistributeSpace(int totalSize, int freeSize,
                               int start, int stop,
                               int[] preferredElementSizes,
                               int[] minimumElementSizes,
                               int[] maximumElementSizes)
      {
            if (totalSize != freeSize)
            {
                  boolean grow = totalSize < freeSize;
                  // calculate the size that is available for redistribution
                  freeSize = (freeSize - totalSize) * (grow ? 1 : -1);
                  while (freeSize > 0)
                  {
                        // calculate the amount of elements that can be resized without violating
                        // the minimum and maximum sizes and their current cumulated size
                        int modifyableAmount = 0;
                        long modifySize = 0;
                        for (int i=start ; i<stop ; i++)
                        {
                              if ((grow && (preferredElementSizes[i] < maximumElementSizes[i])) ||
                                  (!grow && (preferredElementSizes[i] > minimumElementSizes[i])))
                              {
                                    modifyableAmount++;
                                    modifySize += preferredElementSizes[i];
                              }
                        }
                        boolean checkBounds = true;
                        // if all elements are at their minimum or maximum size, resize all elements
                        if (0 == modifyableAmount)
                        {
                              for (int i=start ; i<stop ; i++)
                              {
                                    modifySize += preferredElementSizes[i];
                              }
                              checkBounds = false;
                              modifyableAmount = stop - start;
                        }
                        // to prevent an endless loop if the container gets resized to a very small amount
                        if (modifySize == 0)
                        {
                              break;
                        }
                        // resize the elements
                        if (freeSize < modifyableAmount)
                        {
                              for (int i=start ; i<stop ; i++)
                              {
                                    if ((freeSize != 0) &&
                                        (!checkBounds ||
                                         (checkBounds &&
                                          (grow && (preferredElementSizes[i] < maximumElementSizes[i])) ||
                                          (!grow && (preferredElementSizes[i] > minimumElementSizes[i])))))
                                    {
                                          preferredElementSizes[i] += (grow ? 1 : -1);
                                          if (0 > preferredElementSizes[i])
                                          {
                                                preferredElementSizes[i] = 0;
                                          }
                                          freeSize--;
                                    }
                              }
                        }
                        else
                        {
                              long modifySizeAddition = 0;
                              double factor = (double)(freeSize + modifySize) / (double)modifySize;
                              for (int i=start ; i<stop ; i++)
                              {
                                    long modifyableSize = (checkBounds ? (grow ? maximumElementSizes[i] - preferredElementSizes[i] : preferredElementSizes[i] - minimumElementSizes[i]) : Integer.MAX_VALUE - preferredElementSizes[i]);
                                    long elementModifySize = Math.abs(Math.round((factor * preferredElementSizes[i]) - preferredElementSizes[i]));
                                    if (elementModifySize <= modifyableSize)
                                    {
                                          preferredElementSizes[i] += (grow ? elementModifySize : -elementModifySize);
                                          modifySizeAddition += (grow ? elementModifySize : -elementModifySize);
                                          freeSize -= elementModifySize;
                                    }
                                    else
                                    {
                                          preferredElementSizes[i] += (grow ? modifyableSize : -modifyableSize);
                                          modifySizeAddition += (grow ? modifyableSize : -modifyableSize);
                                          freeSize -= modifyableSize;
                                    }
                                    if (0 > preferredElementSizes[i])
                                    {
                                          preferredElementSizes[i] = 0;
                                    }
                              }
                              modifySize += modifySizeAddition;
                        }
                  }
            }
      }
      
      /**
        * Calculates the minimum, preferred or maximum size dimensions
        * for the specified container, given the components it contains.
        * 
        * @param parent       The container to be laid out
        * @param layoutSize   if {@code LayoutSize.MINIMUM} compute minimum layout size,
        *                     if {@code LayoutSize.PREFERRED} compute preferred layout size,
        *                     if {@code LayoutSize.MAXIMUM} compute maximum layout size,
        *                     if {@code fillRawSizes} is {@code true}, the layout size is computed
        *                     without applying gaps between components or between
        *                     the grid and the borders of the parent container
        * @param fillRawSizes Whether to fill the resultArrays with the raw
        *                     row heights and column widths and whether to apply
        *                     gaps between components or between
        *                     the grid and the borders of the parent container
        *                     when computing the layout size
        * @param gridSize     The amount of rows and columns in the grid
        * @param gridRows     The grid holding the constraints for the components
        * @param colspans     In this {@code Set} the constraints which are part
        *                     of a colspan are stored
        * @param rowspans     In this {@code Set} the constraints which are part
        *                     of a rowspan are stored
        * @param resultArrays If {@code fillRawSizes} is {@code true}, the first six arrays
        *                     get filled with the raw row heights and column widths.
        *                     resultArrays[0] = resultMinimumColWidths;
        *                     resultArrays[1] = resultMinimumRowHeights;
        *                     resultArrays[2] = resultPreferredColWidths;
        *                     resultArrays[3] = resultPreferredRowHeights;
        *                     resultArrays[4] = resultMaximumColWidths;
        *                     resultArrays[5] = resultMaximumRowHeights;
        * @return The minimum, preferred or maximum size dimensions for the specified container
        * @throws IllegalArgumentException If {@code fillRawSizes == true} and {@code resultArrays.length < 6}
        */
      private Dimension getSize(Container parent, LayoutSize layoutSize, boolean fillRawSizes,
                          Dimension gridSize, List<List<ExtendedGridLayoutConstraints>> gridRows,
                          Set<ExtendedGridLayoutConstraints> colspans,
                          Set<ExtendedGridLayoutConstraints> rowspans,
                          int[][] resultArrays)
      {
            if (fillRawSizes && (resultArrays.length < 6))
            {
                  throw new IllegalArgumentException("If fillRawSizes is true, resultArrays.length must be >= 6 (" + resultArrays.length + ')');
            }
            int[] minimumColWidths = new int[gridSize.width];
            int[] minimumRowHeights = new int[gridSize.height];
            int[] preferredColWidths = new int[gridSize.width];
            int[] preferredRowHeights = new int[gridSize.height];
            int[] maximumColWidths = new int[gridSize.width];
            int[] maximumRowHeights = new int[gridSize.height];
            Arrays.fill(minimumColWidths,0);
            Arrays.fill(minimumRowHeights,0);
            Arrays.fill(preferredColWidths,0);
            Arrays.fill(preferredRowHeights,0);
            Arrays.fill(maximumColWidths,0);
            Arrays.fill(maximumRowHeights,0);
            
            // get the maximum of the minimum sizes,
            //     the maximum of the preferred sizes and
            //     the minimum of the maximum sizes
            // of all rows and columns, not taking
            // rowspans and colspans into account
            for (int row=0 ; row<gridSize.height ; row++)
            {
                  List<ExtendedGridLayoutConstraints> gridRow = gridRows.get(row);
                  for (int col=0 ; col<gridSize.width ; col++)
                  {
                        ExtendedGridLayoutConstraints cell = gridRow.get(col);
                        if ((null != cell) && (null != cell.getComponent()))
                        {
                              Component component = cell.getComponent();
                              Dimension minimumSize = component.getMinimumSize();
                              Dimension preferredSize = component.getPreferredSize();
                              Dimension maximumSize = component.getMaximumSize();
                              if (!colspans.contains(cell))
                              {
                                    minimumColWidths[col] = Math.max(minimumColWidths[col],minimumSize.width);
                                    preferredColWidths[col] = Math.max(preferredColWidths[col],preferredSize.width);
                                    maximumColWidths[col] = Math.max(maximumColWidths[col],maximumSize.width);
                              }
                              if (!rowspans.contains(cell))
                              {
                                    minimumRowHeights[row] = Math.max(minimumRowHeights[row],minimumSize.height);
                                    preferredRowHeights[row] = Math.max(preferredRowHeights[row],preferredSize.height);
                                    maximumRowHeights[row] = Math.max(maximumRowHeights[row],maximumSize.height);
                              }
                        }
                  }
            }
            
            // correct cases where
            // minimumColWidths[col] <= preferredColWidths[col] <= maximumColWidths[col]
            // is not true by clipping to the minimumColWidths and maximumColWidths
            for (int col=0 ; col<gridSize.width ; col++)
            {
                  if (minimumColWidths[col] >= maximumColWidths[col])
                  {
                        maximumColWidths[col] = minimumColWidths[col];
                        preferredColWidths[col] = minimumColWidths[col];
                  }
                  else if (preferredColWidths[col] < minimumColWidths[col])
                  {
                        preferredColWidths[col] = minimumColWidths[col];
                  }
                  else if (preferredColWidths[col] > maximumColWidths[col])
                  {
                        preferredColWidths[col] = maximumColWidths[col];
                  }
            }
            
            // plug in the colspans and correct the minimum, preferred and
            // maximum column widths the colspans are part of
            for (ExtendedGridLayoutConstraints cell : colspans)
            {
                  int fromCol = cell.getCol();
                  int colspan = cell.getEffectiveColspan();
                  int toCol = fromCol + colspan;
                  int currentMinimumColWidth = 0;
                  int currentPreferredColWidth = 0;
                  int currentMaximumColWidth = 0;
                  for (int col=fromCol ; col<toCol ; col++)
                  {
                        int minimumColWidth = minimumColWidths[col];
                        if ((Integer.MAX_VALUE-minimumColWidth) < currentMinimumColWidth)
                        {
                              currentMinimumColWidth = Integer.MAX_VALUE;
                        }
                        else
                        {
                              currentMinimumColWidth += minimumColWidth;
                        }
                        int preferredColWidth = preferredColWidths[col];
                        if ((Integer.MAX_VALUE-preferredColWidth) < currentPreferredColWidth)
                        {
                              currentPreferredColWidth = Integer.MAX_VALUE;
                        }
                        else
                        {
                              currentPreferredColWidth += preferredColWidth;
                        }
                        int maximumColWidth = maximumColWidths[col];
                        if ((Integer.MAX_VALUE-maximumColWidth) < currentMaximumColWidth)
                        {
                              currentMaximumColWidth = Integer.MAX_VALUE;
                        }
                        else
                        {
                              currentMaximumColWidth += maximumColWidth;
                        }
                  }
                  Component component = cell.getComponent();
                  int wantedMaximumColWidth = component.getMaximumSize().width - ((colspan - 1) * hgap);
                  if (currentMaximumColWidth < wantedMaximumColWidth)
                  {
                        redistributeSpace(currentMaximumColWidth,
                                      wantedMaximumColWidth,
                                      fromCol,toCol,
                                      maximumColWidths,
                                      maximumColWidths,
                                      maximumColWidths);
                  }
                  int wantedMinimumColWidth = component.getMinimumSize().width - ((colspan - 1) * hgap);
                  if (currentMinimumColWidth < wantedMinimumColWidth)
                  {
                        redistributeSpace(currentMinimumColWidth,
                                      wantedMinimumColWidth,
                                      fromCol,toCol,
                                      minimumColWidths,
                                      minimumColWidths,
                                      maximumColWidths);
                  }
                  int wantedPreferredColWidth = component.getPreferredSize().width - ((colspan - 1) * hgap);
                  if (currentPreferredColWidth < wantedPreferredColWidth)
                  {
                        redistributeSpace(currentPreferredColWidth,
                                      wantedPreferredColWidth,
                                      fromCol,toCol,
                                      preferredColWidths,
                                      minimumColWidths,
                                      maximumColWidths);
                  }
            }
            
            // correct cases where
            // minimumColWidths[col] <= preferredColWidths[col] <= maximumColWidths[col]
            // is not true by clipping to the minimumColWidths and maximumColWidths
            for (int col=0 ; col<gridSize.width ; col++)
            {
                  if (minimumColWidths[col] >= maximumColWidths[col])
                  {
                        maximumColWidths[col] = minimumColWidths[col];
                        preferredColWidths[col] = minimumColWidths[col];
                  }
                  else if (preferredColWidths[col] < minimumColWidths[col])
                  {
                        preferredColWidths[col] = minimumColWidths[col];
                  }
                  else if (preferredColWidths[col] > maximumColWidths[col])
                  {
                        preferredColWidths[col] = maximumColWidths[col];
                  }
            }
            
            // correct cases where
            // minimumRowHeights[row] <= preferredRowHeights[row] <= maximumRowHeights[row]
            // is not true by clipping to the minimumRowHeights and maximumRowHeights
            for (int row=0 ; row<gridSize.height ; row++)
            {
                  if (minimumRowHeights[row] >= maximumRowHeights[row])
                  {
                        maximumRowHeights[row] = minimumRowHeights[row];
                        preferredRowHeights[row] = minimumRowHeights[row];
                  }
                  else if (preferredRowHeights[row] < minimumRowHeights[row])
                  {
                        preferredRowHeights[row] = minimumRowHeights[row];
                  }
                  else if (preferredRowHeights[row] > maximumRowHeights[row])
                  {
                        preferredRowHeights[row] = maximumRowHeights[row];
                  }
            }
            
            // plug in the rowspans and correct the minimum, preferred and
            // maximum row heights the rowspans are part of
            for (ExtendedGridLayoutConstraints cell : rowspans)
            {
                  int fromRow = cell.getRow();
                  int rowspan = cell.getEffectiveRowspan();
                  int toRow = fromRow + rowspan;
                  int currentMinimumRowHeight = 0;
                  int currentPreferredRowHeight = 0;
                  int currentMaximumRowHeight = 0;
                  for (int row=fromRow ; row<toRow ; row++)
                  {
                        int minimumRowHeight = minimumRowHeights[row];
                        if ((Integer.MAX_VALUE-minimumRowHeight) < currentMinimumRowHeight)
                        {
                              currentMinimumRowHeight = Integer.MAX_VALUE;
                        }
                        else
                        {
                              currentMinimumRowHeight += minimumRowHeight;
                        }
                        int preferredRowHeight = preferredRowHeights[row];
                        if ((Integer.MAX_VALUE-preferredRowHeight) < currentPreferredRowHeight)
                        {
                              currentPreferredRowHeight = Integer.MAX_VALUE;
                        }
                        else
                        {
                              currentPreferredRowHeight += preferredRowHeight;
                        }
                        int maximumRowHeight = maximumRowHeights[row];
                        if ((Integer.MAX_VALUE-maximumRowHeight) < currentMaximumRowHeight)
                        {
                              currentMaximumRowHeight = Integer.MAX_VALUE;
                        }
                        else
                        {
                              currentMaximumRowHeight += maximumRowHeight;
                        }
                  }
                  Component component = cell.getComponent();
                  int wantedMaximumRowHeight = component.getMaximumSize().height - ((rowspan - 1) * vgap);
                  if (currentMaximumRowHeight < wantedMaximumRowHeight)
                  {
                        redistributeSpace(currentMaximumRowHeight,
                                      wantedMaximumRowHeight,
                                      fromRow,toRow,
                                      maximumRowHeights,
                                      maximumRowHeights,
                                      maximumRowHeights);
                  }
                  int wantedMinimumRowHeight = component.getMinimumSize().height - ((rowspan - 1) * vgap);
                  if (currentMinimumRowHeight < wantedMinimumRowHeight)
                  {
                        redistributeSpace(currentMinimumRowHeight,
                                      wantedMinimumRowHeight,
                                      fromRow,toRow,
                                      minimumRowHeights,
                                      minimumRowHeights,
                                      maximumRowHeights);
                  }
                  int wantedPreferredRowHeight = component.getPreferredSize().height - ((rowspan - 1) * vgap);
                  if (currentPreferredRowHeight < wantedPreferredRowHeight)
                  {
                        redistributeSpace(currentPreferredRowHeight,
                                      wantedPreferredRowHeight,
                                      fromRow,toRow,
                                      preferredRowHeights,
                                      minimumRowHeights,
                                      maximumRowHeights);
                  }
            }
            
            // correct cases where
            // minimumRowHeights[row] <= preferredRowHeights[row] <= maximumRowHeights[row]
            // is not true by clipping to the minimumRowHeights and maximumRowHeights
            for (int row=0 ; row<gridSize.height ; row++)
            {
                  if (minimumRowHeights[row] >= maximumRowHeights[row])
                  {
                        maximumRowHeights[row] = minimumRowHeights[row];
                        preferredRowHeights[row] = minimumRowHeights[row];
                  }
                  else if (preferredRowHeights[row] < minimumRowHeights[row])
                  {
                        preferredRowHeights[row] = minimumRowHeights[row];
                  }
                  else if (preferredRowHeights[row] > maximumRowHeights[row])
                  {
                        preferredRowHeights[row] = maximumRowHeights[row];
                  }
            }
            
            // copies the computed sizes to the result arrays
            if (fillRawSizes)
            {
                  resultArrays[0] = minimumColWidths;
                  resultArrays[1] = minimumRowHeights;
                  resultArrays[2] = preferredColWidths;
                  resultArrays[3] = preferredRowHeights;
                  resultArrays[4] = maximumColWidths;
                  resultArrays[5] = maximumRowHeights;
            }
            
            // sums up the sizes for return value
            int[] colWidths;
            int[] rowHeights;
            switch (layoutSize)
            {
                  case MINIMUM:
                        colWidths = minimumColWidths;
                        rowHeights = minimumRowHeights;
                        break;
                  
                  case PREFERRED:
                        colWidths = preferredColWidths;
                        rowHeights = preferredRowHeights;
                        break;
                  
                  case MAXIMUM:
                        colWidths = maximumColWidths;
                        rowHeights = maximumRowHeights;
                        break;
                  
                  default:
                        throw new InternalError("Missing case branch for LayoutSize: " + layoutSize);
            }
            long totalWidth = 0;
            long totalHeight = 0;
            for (int width : colWidths)
            {
                  totalWidth += width;
            }
            for (int height : rowHeights)
            {
                  totalHeight += height;
            }
            
            // add space between components or between
            // componetns and the borders of the parent container
            if (!fillRawSizes)
            {
                  Insets insets = parent.getInsets();
                  totalWidth += insets.left + insets.right + ((gridSize.width - 1) * hgap) + distanceToBorders.left + distanceToBorders.right;
                  totalHeight += insets.top + insets.bottom + ((gridSize.height - 1) * vgap) + distanceToBorders.top + distanceToBorders.bottom;
            }
            
            // clip the size to Integer.MAX_VALUE if too big
            if (totalWidth > Integer.MAX_VALUE)
            {
                  totalWidth = Integer.MAX_VALUE;
            }
            if (totalHeight > Integer.MAX_VALUE)
            {
                  totalHeight = Integer.MAX_VALUE;
            }
            
            return new Dimension((int)totalWidth,(int)totalHeight);
      }
      
      /**
        * Builds up the grid for the specified container,
        * given the components it contains.
        * 
        * @param parent   The container to be laid out
        * @param gridRows In this {@code List<List>} the grid gets stored
        * @param colspans In this {@code Set} the constraints which are part
        *                 of a colspan get stored
        * @param rowspans In this {@code Set} the constraints which are part
        *                 of a rowspan get stored
        * @return The amount of rows and columns in the grid
        */
      private Dimension buildGrid(Container parent, List<List<ExtendedGridLayoutConstraints>> gridRows,
                            Set<ExtendedGridLayoutConstraints> colspans, Set<ExtendedGridLayoutConstraints> rowspans)
      {
            // put the parent's components in source rows
            List<List<ExtendedGridLayoutConstraints>> rows = new ArrayList<List<ExtendedGridLayoutConstraints>>();
            Component[] components = parent.getComponents();
            for (Component component : components)
            {
                  if (component.isVisible())
                  {
                        ExtendedGridLayoutConstraints constraints = lookupConstraints(component).getWorkCopy();
                        int rowNumber = constraints.getRow();
                        for (int i=rowNumber, c=rows.size() ; i>=c ; i--)
                        {
                              rows.add(new ArrayList<ExtendedGridLayoutConstraints>());
                        }
                        List<ExtendedGridLayoutConstraints> row = rows.get(rowNumber);
                        row.add(constraints);
                  }
            }
            
            // initialize the rowIterators, gridRowIterators and gridRows
            List<Iterator<ExtendedGridLayoutConstraints>> rowIterators = new ArrayList<Iterator<ExtendedGridLayoutConstraints>>();
            List<ListIterator<ExtendedGridLayoutConstraints>> gridRowIterators = new ArrayList<ListIterator<ExtendedGridLayoutConstraints>>();
            boolean haveNext = false;
            for (List<ExtendedGridLayoutConstraints> row : rows)
            {
                  Iterator<ExtendedGridLayoutConstraints> rowIterator = row.iterator();
                  rowIterators.add(rowIterator);
                  if (rowIterator.hasNext())
                  {
                        haveNext = true;
                  }
                  List<ExtendedGridLayoutConstraints> gridRow = new ArrayList<ExtendedGridLayoutConstraints>();
                  gridRows.add(gridRow);
                  gridRowIterators.add(gridRow.listIterator());
            }
            
            // build the grid
            int col = -1;
            while (haveNext)
            {
                  col++;
                  haveNext = false;
                  for (int row=0, c=gridRows.size() ; row<c ; row++)
                  {
                        Iterator<ExtendedGridLayoutConstraints> rowIterator = rowIterators.get(row);
                        ListIterator<ExtendedGridLayoutConstraints> gridRowIterator = gridRowIterators.get(row);
                        
                        // look for a rowspan in the previous row
                        if (row > 0)
                        {
                              ExtendedGridLayoutConstraints rowspanSource = gridRows.get(row-1).get(col);
                              if (null != rowspanSource)
                              {
                                    ExtendedGridLayoutConstraints rowspanPlaceholder = rowspanSource.getRowspanPlaceholder(true);
                                    if (null != rowspanPlaceholder)
                                    {
                                          rowspans.add(rowspanSource);
                                          gridRowIterator.add(rowspanPlaceholder);
                                          if (null != rowspanPlaceholder.getColspanPlaceholder(false))
                                          {
                                                switch (rowspanPlaceholder.getColspan())
                                                {
                                                      case REMAINDER:
                                                            break;
                                                      
                                                      default:
                                                            haveNext = true;
                                                }
                                          }
                                          else if (rowIterator.hasNext())
                                          {
                                                haveNext = true;
                                          }
                                          continue;
                                    }
                              }
                        }
                        
                        // look for a colspan in the previous column
                        if (gridRowIterator.hasPrevious())
                        {
                              ExtendedGridLayoutConstraints colspanSource = gridRowIterator.previous();
                              gridRowIterator.next();
                              if (null != colspanSource)
                              {
                                    ExtendedGridLayoutConstraints colspanPlaceholder = colspanSource.getColspanPlaceholder(true);
                                    if (null != colspanPlaceholder)
                                    {
                                          colspans.add(colspanSource);
                                          gridRowIterator.add(colspanPlaceholder);
                                          if (null != colspanPlaceholder.getColspanPlaceholder(false))
                                          {
                                                switch (colspanPlaceholder.getColspan())
                                                {
                                                      case REMAINDER:
                                                            break;
                                                      
                                                      default:
                                                            haveNext = true;
                                                }
                                          }
                                          else if (rowIterator.hasNext())
                                          {
                                                haveNext = true;
                                          }
                                          continue;
                                    }
                              }
                        }
                        
                        // add a new element or null
                        if (rowIterator.hasNext())
                        {
                              ExtendedGridLayoutConstraints newConstraints = rowIterator.next();
                              newConstraints.setCol(col);
                              gridRowIterator.add(newConstraints);
                              if (null != newConstraints.getColspanPlaceholder(false))
                              {
                                    switch (newConstraints.getColspan())
                                    {
                                          case REMAINDER:
                                                break;
                                          
                                          default:
                                                haveNext = true;
                                    }
                              }
                              else if (rowIterator.hasNext())
                              {
                                    haveNext = true;
                              }
                        }
                        else
                        {
                              gridRowIterator.add(null);
                        }
                  }
            }
            
            // check the last gridRow for rowspans and probably add rows for these
            haveNext = false;
            int gridRowsSize = gridRows.size();
            if (gridRowsSize > 0)
            {
                  ListIterator<ExtendedGridLayoutConstraints> gridRowIterator = gridRows.get(gridRows.size()-1).listIterator();
                  while (gridRowIterator.hasNext())
                  {
                        ExtendedGridLayoutConstraints cell = gridRowIterator.next();
                        if ((null != cell) &&
                            ((REMAINDER != cell.getRowspan()) &&
                             (null != cell.getRowspanPlaceholder(false))))
                        {
                              haveNext = true;
                              break;
                        }
                  }
                  while (haveNext)
                  {
                        haveNext = false;
                        gridRowIterator = gridRows.get(gridRows.size()-1).listIterator();
                        List<ExtendedGridLayoutConstraints> gridRow = new ArrayList<ExtendedGridLayoutConstraints>();
                        gridRows.add(gridRow);
                        ListIterator<ExtendedGridLayoutConstraints> newGridRowIterator = gridRow.listIterator();
                        while (gridRowIterator.hasNext())
                        {
                              ExtendedGridLayoutConstraints cell = gridRowIterator.next();
                              if ((null != cell) &&
                                  (null != cell.getRowspanPlaceholder(false)))
                              {
                                    rowspans.add(cell);
                                    ExtendedGridLayoutConstraints rowspanPlaceholder = cell.getRowspanPlaceholder(true);
                                    newGridRowIterator.add(rowspanPlaceholder);
                              }
                              else
                              {
                                    newGridRowIterator.add(null);
                              }
                        }
                        gridRowIterator = gridRow.listIterator();
                        while (gridRowIterator.hasNext())
                        {
                              ExtendedGridLayoutConstraints cell = gridRowIterator.next();
                              if ((null != cell) &&
                                  ((REMAINDER != cell.getRowspan()) &&
                                   (null != cell.getRowspanPlaceholder(false))))
                              {
                                    haveNext = true;
                                    break;
                              }
                        }
                  }
            }
            
            return new Dimension(col+1,gridRows.size());
      }
      
      /**
        * Returns a string representation of the object. In general, the
        * {@code toString} method returns a string that
        * "textually represents" this object. The result should
        * be a concise but informative representation that is easy for a
        * person to read.
        * 
        * @return  a string representation of the object.
        */
      public String toString()
      {
            return getClass().getName() + "[hgap=" + hgap + ",vgap=" + vgap
                  + ",distanceToBorders=" + distanceToBorders
                  + ",comptable=" + comptable + "]";
      }
}

Generated by  Doxygen 1.6.0   Back to index