/[classpath]/classpath/javax/swing/BoxLayout.java
ViewVC logotype

Diff of /classpath/javax/swing/BoxLayout.java

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.17 by rabbit78, Tue Jul 26 15:30:54 2005 UTC revision 1.18 by rabbit78, Sun Sep 25 10:17:19 2005 UTC
# Line 42  import java.awt.Component; Line 42  import java.awt.Component;
42  import java.awt.ComponentOrientation;  import java.awt.ComponentOrientation;
43  import java.awt.Container;  import java.awt.Container;
44  import java.awt.Dimension;  import java.awt.Dimension;
 import java.awt.Insets;  
45  import java.awt.LayoutManager2;  import java.awt.LayoutManager2;
46  import java.io.Serializable;  import java.io.Serializable;
 import java.util.Collection;  
 import java.util.Iterator;  
 import java.util.List;  
 import java.util.Vector;  
   
 import gnu.java.awt.AWTUtilities;  
47    
48  /**  /**
49   * A layout that stacks the children of a container in a Box, either   * A layout that stacks the children of a container in a Box, either
# Line 63  public class BoxLayout implements Layout Line 56  public class BoxLayout implements Layout
56  {  {
57    
58    /**    /**
    * This is an abstraction that allows the BoxLayout algorithm to  
    * be applied to both direction (X and Y) without duplicating the  
    * algorithm. It defines several methods that access properties of  
    * a component for a specific direction.  
    */  
   static interface Direction  
   {  
     /**  
      * Returns the correct part of <code>d</code> for this direction. This will  
      * be <code>d.width</code> for horizontal and <code>d.height</code> for  
      * vertical direction.  
      *  
      * @param d the size as Dimension object  
      *  
      * @return the correct part of <code>d</code> for this direction  
      */  
     int size(Dimension d);  
   
     /**  
      * Returns the lower bounds of the {@link Insets} object according to this  
      * direction. This will be <code>insets.top</code> for vertical direction  
      * and <code>insets.left</code> for horizontal direction.  
      *  
      * @param the {@link Insets} object from which to return the lower bounds  
      *  
      * @return the lower bounds of the {@link Insets} object according to this  
      *     direction  
      */  
     int lower(Insets insets);  
   
     /**  
      * Returns the alignment property according to this direction.  
      *  
      * @param comp the Component for which to return the alignment property  
      *  
      * @return the alignment property according to this direction  
      */  
     float alignment(Component comp);  
   
     /**  
      * Sets the location for Component <code>c</code>. <code>coord1</code>  
      * specifies the coordinate of the location in this direction,  
      * <code>coord2</code> the coordinate of the location in the opposite  
      * direction.  
      *  
      * @param c the Component for which to set the location  
      * @param coord1 the coordinate in this direction  
      * @param coord2 the coordinate in the opposite direction  
      */  
     void setLocation(Component c, int coord1, int coord2);  
   
     /**  
      * Sets the size for Component <code>c</code>. <code>coord1</code>  
      * specifies the size in this direction,  
      * <code>coord2</code> the size in the opposite  
      * direction.  
      *  
      * @param c the Component for which to set the size  
      * @param size1 the size in this direction  
      * @param size2 the size in the opposite direction  
      */  
     void setSize(Component c, int size1, int size2);  
   }  
   
   /**  
    * The horizontal direction.  
    */  
   static class Horizontal implements Direction  
   {  
     /**  
      * Returns the correct part of <code>d</code> for this direction. This will  
      * be <code>d.width</code> for horizontal and <code>d.height</code> for  
      * vertical direction.  
      *  
      * @param d the size as Dimension object  
      *  
      * @return the correct part of <code>d</code> for this direction  
      */  
     public int size(Dimension d)  
     {  
       return d.width;  
     }  
   
     /**  
      * Returns the lower bounds of the {@link Insets} object according to this  
      * direction. This will be <code>insets.top</code> for vertical direction  
      * and <code>insets.left</code> for horizontal direction.  
      *  
      * @param insets the {@link Insets} object from which to return the lower  
      *               bounds  
      *  
      * @return the lower bounds of the {@link Insets} object according to this  
      *     direction  
      */  
     public int lower(Insets insets)  
     {  
       return insets.left;  
     }  
   
     /**  
      * Returns the alignment property according to this direction.  
      *  
      * @param comp the Component for which to return the alignment property  
      *  
      * @return the alignment property according to this direction  
      */  
     public float alignment(Component comp)  
     {  
       return comp.getAlignmentX();  
     }  
   
     /**  
      * Sets the location for Component <code>c</code>. <code>coord1</code>  
      * specifies the coordinate of the location in this direction,  
      * <code>coord2</code> the coordinate of the location in the opposite  
      * direction.  
      *  
      * @param c the Component for which to set the location  
      * @param coord1 the coordinate in this direction  
      * @param coord2 the coordinate in the opposite direction  
      */  
     public void setLocation(Component c, int coord1, int coord2)  
     {  
       c.setLocation(coord1, coord2);  
     }  
   
     /**  
      * Sets the size for Component <code>c</code>. <code>coord1</code>  
      * specifies the size in this direction,  
      * <code>coord2</code> the size in the opposite  
      * direction.  
      *  
      * @param c the Component for which to set the size  
      * @param size1 the size in this direction  
      * @param size2 the size in the opposite direction  
      */  
     public void setSize(Component c, int size1, int size2)  
     {  
       c.setSize(size1, size2);  
     }  
   }  
   /**  
    * The vertical direction.  
    */  
   static class Vertical implements Direction  
   {  
     /**  
      * Returns the correct part of <code>d</code> for this direction. This will  
      * be <code>d.width</code> for horizontal and <code>d.height</code> for  
      * vertical direction.  
      *  
      * @param d the size as Dimension object  
      *  
      * @return the correct part of <code>d</code> for this direction  
      */  
     public int size(Dimension d)  
     {  
       return d.height;  
     }  
   
     /**  
      * Returns the lower bounds of the {@link Insets} object according to this  
      * direction. This will be <code>insets.top</code> for vertical direction  
      * and <code>insets.left</code> for horizontal direction.  
      *  
      * @param insets the {@link Insets} object from which to return the lower  
      *        bounds  
      *  
      * @return the lower bounds of the {@link Insets} object according to this  
      *     direction  
      */  
     public int lower(Insets insets)  
     {  
       return insets.top;  
     }  
   
     /**  
      * Returns the alignment property according to this direction.  
      *  
      * @param comp the Component for which to return the alignment property  
      *  
      * @return the alignment property according to this direction  
      */  
     public float alignment(Component comp)  
     {  
       return comp.getAlignmentY();  
     }  
   
     /**  
      * Sets the location for Component <code>c</code>. <code>coord1</code>  
      * specifies the coordinate of the location in this direction,  
      * <code>coord2</code> the coordinate of the location in the opposite  
      * direction.  
      *  
      * @param c the Component for which to set the location  
      * @param coord1 the coordinate in this direction  
      * @param coord2 the coordinate in the opposite direction  
      */  
     public void setLocation(Component c, int coord1, int coord2)  
     {  
       c.setLocation(coord2, coord1);  
     }  
   
     /**  
      * Sets the size for Component <code>c</code>. <code>coord1</code>  
      * specifies the size in this direction,  
      * <code>coord2</code> the size in the opposite  
      * direction.  
      *  
      * @param c the Component for which to set the size  
      * @param size1 the size in this direction  
      * @param size2 the size in the opposite direction  
      */  
     public void setSize(Component c, int size1, int size2)  
     {  
       c.setSize(size2, size1);  
     }  
   }  
   
   /**  
    * A helper class that temporarily stores the size specs of a component.  
    */  
   static class SizeReq  
   {  
     int size;  
     int min;  
     int pref;  
     int max;  
     float align;  
     Component comp;  
     SizeReq(Component comp, Direction dir)  
     {  
       this.min = dir.size(comp.getMinimumSize());  
       this.pref = dir.size(comp.getPreferredSize());  
       this.max = dir.size(comp.getMaximumSize());  
       this.size = dir.size(comp.getSize());  
       this.align = dir.alignment(comp);  
       this.comp = comp;  
     }  
   }  
   
   /**  
59     * Specifies that components are laid out left to right.     * Specifies that components are laid out left to right.
60     */     */
61    public static final int X_AXIS = 0;    public static final int X_AXIS = 0;
# Line 339  public class BoxLayout implements Layout Line 90  public class BoxLayout implements Layout
90     */     */
91    private int way = X_AXIS;    private int way = X_AXIS;
92    
   /** Constant for the horizontal direction. */  
   private static final Direction HORIZONTAL = new Horizontal();  
   
   /** Constant for the vertical direction. */  
   private static final Direction VERTICAL = new Vertical();  
   
93    /**    /**
94     * Constructs a <code>BoxLayout</code> object.     * Constructs a <code>BoxLayout</code> object.
95     *     *
# Line 404  public class BoxLayout implements Layout Line 149  public class BoxLayout implements Layout
149      if (parent != container)      if (parent != container)
150        throw new AWTError("invalid parent");        throw new AWTError("invalid parent");
151    
152      Insets insets = parent.getInsets();      // Setup the SizeRequirements for both the X and Y axis.
153      int x = 0;      Component[] children = container.getComponents();
154      int y = 0;      SizeRequirements[] hSizeReqs = new SizeRequirements[children.length];
155        SizeRequirements[] vSizeReqs = new SizeRequirements[children.length];
156      List children = AWTUtilities.getVisibleChildren(parent);      getSizeRequirements(hSizeReqs, vSizeReqs);
157        SizeRequirements hReq;
158      if (isHorizontalIn(parent))      SizeRequirements vReq;
159        {              if (isHorizontalIn(container))
160          x = insets.left + insets.right;        {
161          // sum up preferred widths of components, find maximum of preferred          hReq = SizeRequirements.getTiledSizeRequirements(hSizeReqs);
162          // heights          vReq = SizeRequirements.getAlignedSizeRequirements(vSizeReqs);
         for (Iterator i = children.iterator(); i.hasNext();)  
           {  
             Component comp = (Component) i.next();  
             Dimension sz = comp.getPreferredSize();  
             x += sz.width;  
             y = Math.max(y, sz.height);  
           }  
         y += insets.bottom + insets.top;  
       }  
     else  
       {          
         y = insets.top + insets.bottom;  
         // sum up preferred heights of components, find maximum of  
         //  preferred widths  
         for (Iterator i = children.iterator(); i.hasNext();)  
           {  
             Component comp = (Component) i.next();  
             Dimension sz = comp.getPreferredSize();  
             y += sz.height;  
             x = Math.max(x, sz.width);  
           }  
         x += insets.left + insets.right;  
163        }        }
164        else
165      return new Dimension(x, y);        {
166            hReq = SizeRequirements.getAlignedSizeRequirements(hSizeReqs);
167            vReq = SizeRequirements.getTiledSizeRequirements(vSizeReqs);
168          }
169        return new Dimension(hReq.preferred, vReq.preferred);
170    }    }
171    
172    /**    /**
# Line 454  public class BoxLayout implements Layout Line 181  public class BoxLayout implements Layout
181      if (parent != container)      if (parent != container)
182        throw new AWTError("invalid parent");        throw new AWTError("invalid parent");
183    
184      Insets insets = parent.getInsets();      // Setup the SizeRequirements for both the X and Y axis.
185      int x = insets.left + insets.right;      Component[] children = container.getComponents();
186      int y = insets.bottom + insets.top;      SizeRequirements[] hSizeReqs = new SizeRequirements[children.length];
187        SizeRequirements[] vSizeReqs = new SizeRequirements[children.length];
188      List children = AWTUtilities.getVisibleChildren(parent);      getSizeRequirements(hSizeReqs, vSizeReqs);
189        SizeRequirements hReq;
190      if (isHorizontalIn(parent))      SizeRequirements vReq;
191        if (isHorizontalIn(container))
192        {        {
193          // sum up preferred widths of components, find maximum of preferred          hReq = SizeRequirements.getTiledSizeRequirements(hSizeReqs);
194          // heights          vReq = SizeRequirements.getAlignedSizeRequirements(vSizeReqs);
         for (Iterator i = children.iterator(); i.hasNext();)  
           {  
             Component comp = (Component) i.next();  
             Dimension sz = comp.getMinimumSize();  
             x += sz.width;  
             y = Math.max(y, sz.height);  
           }  
195        }        }
196      else      else
197        {        {
198          // sum up preferred heights of components, find maximum of          hReq = SizeRequirements.getAlignedSizeRequirements(hSizeReqs);
199          //  preferred widths          vReq = SizeRequirements.getTiledSizeRequirements(vSizeReqs);
         for (Iterator i = children.iterator(); i.hasNext();)  
           {  
             Component comp = (Component) i.next();  
             Dimension sz = comp.getMinimumSize();  
             y += sz.height;  
             x = Math.max(x, sz.width);  
           }  
200        }        }
201            return new Dimension(hReq.minimum, vReq.minimum);
     return new Dimension(x, y);  
202    }    }
203    
204    /**    /**
# Line 495  public class BoxLayout implements Layout Line 208  public class BoxLayout implements Layout
208     */     */
209    public void layoutContainer(Container parent)    public void layoutContainer(Container parent)
210    {    {
211      if (isHorizontalIn(parent))      // Setup the SizeRequirements for both the X and Y axis.
212        layoutAlgorithm(parent, HORIZONTAL, VERTICAL);      Component[] children = container.getComponents();
213        SizeRequirements[] hSizeReqs = new SizeRequirements[children.length];
214        SizeRequirements[] vSizeReqs = new SizeRequirements[children.length];
215        getSizeRequirements(hSizeReqs, vSizeReqs);
216    
217        int[] hSpans = new int[children.length];
218        int[] hOffsets = new int[children.length];
219        int[] vSpans = new int[children.length];
220        int[] vOffsets = new int[children.length];
221    
222        if (isHorizontalIn(container))
223          {
224            SizeRequirements.calculateTiledPositions(container.getWidth(), null,
225                                                     hSizeReqs, hOffsets, hSpans);
226            SizeRequirements.calculateAlignedPositions(container.getHeight(), null,
227                                                     vSizeReqs, vOffsets, vSpans);
228          }
229      else      else
230        layoutAlgorithm(parent, VERTICAL, HORIZONTAL);        {
231            SizeRequirements.calculateTiledPositions(container.getHeight(), null,
232                                                     vSizeReqs, vOffsets, vSpans);
233            SizeRequirements.calculateAlignedPositions(container.getWidth(), null,
234                                                     hSizeReqs, hOffsets, hSpans);
235          }
236    
237        // Set positions and widths of child components.
238        for (int i = 0; i < children.length; i++)
239          {
240            Component child = children[i];
241            child.setBounds(hOffsets[i], vOffsets[i], hSpans[i], vSpans[i]);
242          }
243    }    }
244        
245    /**    /**
# Line 565  public class BoxLayout implements Layout Line 306  public class BoxLayout implements Layout
306      if (parent != container)      if (parent != container)
307        throw new AWTError("invalid parent");        throw new AWTError("invalid parent");
308    
309      Insets insets = parent.getInsets();      // Setup the SizeRequirements for both the X and Y axis.
310      int x = insets.left + insets.right;      Component[] children = container.getComponents();
311      int y = insets.top + insets.bottom;      SizeRequirements[] hSizeReqs = new SizeRequirements[children.length];
312        SizeRequirements[] vSizeReqs = new SizeRequirements[children.length];
313      List children = AWTUtilities.getVisibleChildren(parent);      getSizeRequirements(hSizeReqs, vSizeReqs);
314        SizeRequirements hReq;
315      if (isHorizontalIn(parent))      SizeRequirements vReq;
316        if (isHorizontalIn(container))
317        {        {
318                    hReq = SizeRequirements.getTiledSizeRequirements(hSizeReqs);
319          // sum up preferred widths of components, find maximum of preferred          vReq = SizeRequirements.getAlignedSizeRequirements(vSizeReqs);
         // heights  
         for (Iterator i = children.iterator(); i.hasNext();)  
           {  
             Component comp = (Component) i.next();  
             Dimension sz = comp.getMaximumSize();  
             x += sz.width;  
             // Check for overflow.  
             if (x < 0)  
               x = Integer.MAX_VALUE;  
             y = Math.max(y, sz.height);  
           }  
320        }        }
321      else      else
322        {        {
323          // sum up preferred heights of components, find maximum of          hReq = SizeRequirements.getAlignedSizeRequirements(hSizeReqs);
324          //  preferred widths          vReq = SizeRequirements.getTiledSizeRequirements(vSizeReqs);
325          for (Iterator i = children.iterator(); i.hasNext();)        }
326            {      return new Dimension(hReq.maximum, vReq.maximum);
             Component comp = (Component) i.next();  
             Dimension sz = comp.getMaximumSize();  
             y += sz.height;  
             // Check for overflow  
             if (y < 0)  
               y = Integer.MAX_VALUE;  
             x = Math.max(x, sz.width);  
           }  
       }  
     return new Dimension(x, y);  
327    }    }
328    
329    /**    /**
330     * Lays out the Container <code>c</code> in the layout direction     * Fills arrays of SizeRequirements for the horizontal and vertical
331     * <code>layoutDir</code>. The direction that is crossing the layout     * requirements of the children of component.
    * direction is specified in <code>crossDir</code>.  
332     *     *
333     * @param parent     * @param hSizeReqs the horizontal requirements to be filled by this method
334     * @param layoutDir     * @param vSizeReqs the vertical requirements to be filled by this method
    * @param crossDir  
335     */     */
336    void layoutAlgorithm(Container parent, Direction layoutDir, Direction crossDir)    private void getSizeRequirements(SizeRequirements[] hSizeReqs,
337                                       SizeRequirements[] vSizeReqs)
338    {    {
339      if (parent != container)      Component[] children = container.getComponents();
340        throw new AWTError("invalid parent");      for (int i = 0; i < children.length; i++)
   
     Dimension parentSize = parent.getSize();  
     Insets insets = parent.getInsets();  
     Dimension innerSize = new Dimension(parentSize.width - insets.left  
                                         - insets.right, parentSize.height  
                                         - insets.bottom - insets.top);  
   
     // Set all components to their preferredSizes and sum up the allocated  
     // space. Create SizeReqs for each component and store them in  
     // sizeReqs. Find the maximum size in the crossing direction.  
     List children = AWTUtilities.getVisibleChildren(parent);  
     Vector sizeReqs = new Vector();  
     int allocated = 0;  
     for (Iterator i = children.iterator(); i.hasNext();)  
341        {        {
342          Component c = (Component) i.next();          Component child = children[i];
343          SizeReq sizeReq = new SizeReq(c, layoutDir);          if (! child.isVisible())
344          int preferred = layoutDir.size(c.getPreferredSize());            {
345          sizeReq.size = preferred;              SizeRequirements req = new SizeRequirements();
346          allocated += preferred;              hSizeReqs[i] = req;
347          sizeReqs.add(sizeReq);              vSizeReqs[i] = req;
348        }            }
   
     // Distribute remaining space (may be positive or negative) over components  
     int remainder = layoutDir.size(innerSize) - allocated;  
     distributeSpace(sizeReqs, remainder, layoutDir);  
   
     // Resize and relocate components. If the component can be sized to  
     // take the full space in the crossing direction, then do so, otherwise  
     // align according to its alingnmentX or alignmentY property.  
     int loc = 0;  
     int offset1 = layoutDir.lower(insets);  
     int offset2 = crossDir.lower(insets);  
     for (Iterator i = sizeReqs.iterator(); i.hasNext();)  
       {  
         SizeReq sizeReq = (SizeReq) i.next();  
         Component c = sizeReq.comp;  
         int availCrossSize = crossDir.size(innerSize);  
         int maxCross = crossDir.size(c.getMaximumSize());  
         int crossSize = Math.min(availCrossSize, maxCross);  
         int crossRemainder = availCrossSize - crossSize;  
         int crossLoc = (int) (crossDir.alignment(c) * crossRemainder);  
         layoutDir.setSize(c, sizeReq.size, crossSize);  
         layoutDir.setLocation(c, offset1 + loc, offset2 + crossLoc);  
         loc += sizeReq.size;  
       }  
   }  
   
   /**  
    * Distributes some space over a set of components. This implementation  
    * tries to set the components as close as possible to their  
    * <code>preferredSize</code>s, and respects the components  
    * <code>minimumSize</code> and <code>maximumSize</code>.  
    *  
    * The algorithm is implemented as follows:  
    *  
    * <ul>  
    * <li>The <code>remainder</code> is divided by the number of components  
    * in <code>freeComponents</code>.</li>  
    * <li>The result is added to (or substracted from) the size of each  
    * component.</li>  
    * <li>If the <code>minimumSize</code> or <code>maximumSize</code> of a  
    * component is exceeded, then this component is set to its  
    * <code>minimumSize</code> or <code>maximumSize</code>, it is removed from  
    * <code>freeComponents</code> and the difference is added to a new  
    * remainder.</li>  
    * <li>Finally, if there is a new remainer != 0 and the  
    * <code>freeComponents.size() != 0</code>, then this method is called  
    * recursivly to distribute the newly allocated remaining space.</li>  
    * </ul>  
    *  
    * @param freeComponents a SizeReq collection for components that have space  
    *     left so that they can be moved freely  
    * @param remainder the space that should be distributed between the  
    *     components  
    * @param dir the direction in which we operate  
    */  
   void distributeSpace(Collection freeComponents, int remainder, Direction dir)  
   {  
     // Sum up total available space in components. If the remainder is negative  
     // then we sum up the difference between minSize and size. If remainder  
     // is positive we sum up the difference between maxSize and size.  
     double totalAvailable = 0;  
     for (Iterator i = freeComponents.iterator(); i.hasNext();)  
       {  
         SizeReq sizeReq = (SizeReq) i.next();  
         if (remainder >= 0)  
           totalAvailable += sizeReq.max - sizeReq.size;  
         else  
           totalAvailable += sizeReq.min - sizeReq.size;  
       }  
     if (totalAvailable == 0)  
       if (remainder >= 0)  
         totalAvailable = 1;  
       else  
         totalAvailable = -1;  
   
     int newRemainder = 0;  
     Vector stillFree = new Vector();  
     for (Iterator i = freeComponents.iterator(); i.hasNext();)  
       {  
         // Add/substract share to component.  
         SizeReq sizeReq = (SizeReq) i.next();  
         double available = 0;  
         if (remainder >= 0)  
           available = sizeReq.max - sizeReq.size;  
349          else          else
350            available = sizeReq.min - sizeReq.size;            {
351          int share = (int) ((available / totalAvailable) * remainder);              SizeRequirements hReq =
352          sizeReq.size += share;                new SizeRequirements(child.getMinimumSize().width,
353          // check for min/maximumSize                                     child.getPreferredSize().width,
354          if (sizeReq.size < sizeReq.min)                                     child.getMaximumSize().width,
355            {                                     child.getAlignmentX());
356              newRemainder += sizeReq.size - sizeReq.min;              hSizeReqs[i] = hReq;
357              sizeReq.size = sizeReq.min;              SizeRequirements vReq =
358            }                new SizeRequirements(child.getMinimumSize().height,
359          else if (sizeReq.size > sizeReq.max)                                     child.getPreferredSize().height,
360            {                                     child.getMaximumSize().height,
361              newRemainder += sizeReq.size - sizeReq.max;                                     child.getAlignmentY());
362              sizeReq.size = sizeReq.max;              vSizeReqs[i] = vReq;
363            }            }
         else  
           stillFree.add(sizeReq);  
364        }        }
     // recursivly call this method if necessary  
     if (newRemainder != 0 && stillFree.size() > 0)  
       distributeSpace(stillFree, newRemainder, dir);  
365    }    }
366  }  }

Legend:
Removed from v.1.17  
changed lines
  Added in v.1.18

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26