1 /* FlowLayout.java -- Grid-based layout engine
2    Copyright (C) 1999, 2000, 2001, 2002, 2004  Free Software Foundation
3 
4 This file is part of GNU Classpath.
5 
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20 
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25 
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37 
38 
39 package java.awt;
40 
41 import java.io.Serializable;
42 
43 /** This class implements a flow-based layout.  Components are laid
44  * out in order from left to right.  When a component cannot be placed
45  * without horizontal clipping, a new row is started.  This class
46  * supports horizontal and vertical gaps.  These are used for spacing
47  * between components.
48  *
49  * @author Tom Tromey (tromey@redhat.com)
50  * @author Aaron M. Renn (arenn@urbanophile.com)
51  */
52 public class FlowLayout implements LayoutManager, Serializable
53 {
54   /** Constant that specifies left alignment.  */
55   public static final int LEFT = 0;
56   /** Constant that specifies center alignment.  */
57   public static final int CENTER = 1;
58   /** Constant that specifies right alignment.  */
59   public static final int RIGHT = 2;
60 
61   /** Constant that specifies alignment to leading edge of container's
62    * orientation.  */
63   public static final int LEADING = 3;
64   /** Constant that specifies alignment to trailing edge of container's
65    * orientation.  */
66   public static final int TRAILING = 4;
67 
68   // Serialization constant
69   private static final long serialVersionUID = -7262534875583282631L;
70 
71   /**
72    * Add a new component to the layout.  This particular implementation
73    * does nothing.
74    *
75    * @param name the name
76    * @param comp the component
77    */
addLayoutComponent(String name, Component comp)78   public void addLayoutComponent (String name, Component comp)
79   {
80     // Nothing.
81   }
82 
83   /**
84    * Returns the current justification value for this object.
85    *
86    * @return The current justification value for this object.
87    */
getAlignment()88   public int getAlignment ()
89   {
90     return align;
91   }
92 
93   /**
94    * Returns the horizontal gap between components.
95    *
96    * @return The horizontal gap between components.
97    */
getHgap()98   public int getHgap ()
99   {
100     return hgap;
101   }
102 
103   /**
104    * Returns the vertical gap between lines of components.
105    *
106    * @return The vertical gap between lines of components.
107    */
getVgap()108   public int getVgap ()
109   {
110     return vgap;
111   }
112 
113   /**
114    * Initializes a new instance of <code>FlowLayout</code> with a center
115    * justification and a default horizontal and vertical gap of 5.
116    */
FlowLayout()117   public FlowLayout ()
118   {
119     this (CENTER, 5, 5);
120   }
121 
122   /**
123    * Initializes a new instance of <code>FlowLayout</code> with the specified
124    * justification and a default horizontal and vertical gap of 5.
125    *
126    * @param align The justification setting, which should be one of the
127    * contants in this class.
128    */
FlowLayout(int align)129   public FlowLayout (int align)
130   {
131     this (align, 5, 5);
132   }
133 
134   /**
135    * Initializes a new instance of <code>FlowLayout</code> with the specified
136    * justification and gap values
137    * @param align Alignment
138    * @param hgap The horizontal gap
139    * @param vgap The vertical gap
140    * @exception IllegalArgumentException If either gap is negative
141    */
FlowLayout(int align, int hgap, int vgap)142   public FlowLayout (int align, int hgap, int vgap)
143   {
144     // Use methods to set fields so that we can have all the checking
145     // in one place.
146     setVgap (vgap);
147     setHgap (hgap);
148     setAlignment (align);
149   }
150 
151   /** Lay out the container's components based on current settings.
152    * @param parent The parent container
153    */
layoutContainer(Container parent)154   public void layoutContainer (Container parent)
155   {
156     synchronized (parent.getTreeLock ())
157       {
158         int num = parent.getComponentCount ();
159         // This is more efficient than calling getComponents().
160         Component[] comps = parent.component;
161 
162         Dimension d = parent.getSize ();
163         Insets ins = parent.getInsets ();
164 
165         ComponentOrientation orient = parent.getComponentOrientation ();
166         boolean left_to_right = orient.isLeftToRight ();
167 
168         int y = ins.top + vgap;
169         int i = 0;
170         while (i < num)
171           {
172             // Find the components which go in the current row.
173             int new_w = ins.left + hgap + ins.right;
174             int new_h = 0;
175             int j;
176             boolean found_one = false;
177             for (j = i; j < num; ++j)
178               {
179                 // Skip invisible items.
180                 if (! comps[j].visible)
181                   continue;
182 
183                 Dimension c = comps[j].getPreferredSize ();
184 
185                 int next_w = new_w + hgap + c.width;
186                 if (next_w <= d.width || ! found_one)
187                   {
188                     new_w = next_w;
189                     new_h = Math.max (new_h, c.height);
190                     found_one = true;
191                   }
192                 else
193                   {
194                     // Must start a new row, and we already found an item
195                     break;
196                   }
197               }
198 
199             // Set the location of each component for this row.
200             int x;
201 
202             int myalign = align;
203             if (align == LEADING)
204               myalign = left_to_right ? LEFT : RIGHT;
205             else if (align == TRAILING)
206               myalign = left_to_right ? RIGHT : LEFT;
207 
208             if (myalign == RIGHT)
209               x = ins.left + (d.width - new_w) + hgap;
210             else if (myalign == CENTER)
211               x = ins.left + (d.width - new_w) / 2 + hgap;
212             else // LEFT and all other values of align.
213               x = ins.left + hgap;
214 
215             for (int k = i; k < j; ++k)
216               {
217                 if (comps[k].visible)
218                   {
219                     Dimension c = comps[k].getPreferredSize ();
220                     comps[k].setBounds (x, y + (new_h - c.height) / 2,
221                                         c.width, c.height);
222                     x += c.width + hgap;
223                   }
224               }
225 
226             // Advance to next row.
227             i = j;
228             y += new_h + vgap;
229           }
230       }
231   }
232 
233   /**
234    * Returns the minimum layout size for the specified container using
235    * this layout.
236    * @param cont The parent container
237    * @return The minimum layout size.
238    */
minimumLayoutSize(Container cont)239   public Dimension minimumLayoutSize (Container cont)
240   {
241     return getSize (cont, true);
242   }
243 
244   /**
245    * Returns the preferred layout size for the specified container using
246    * this layout.
247    * @param cont The parent container
248    * @return The preferred layout size.
249    */
preferredLayoutSize(Container cont)250   public Dimension preferredLayoutSize (Container cont)
251   {
252     return getSize (cont, false);
253   }
254 
255   /** Remove the indicated component from this layout manager.
256    * This particular implementation does nothing.
257    * @param comp The component to remove
258    */
removeLayoutComponent(Component comp)259   public void removeLayoutComponent (Component comp)
260   {
261     // Nothing.
262   }
263 
264   /**
265    * Sets the justification value for this object to the specified value.
266    *
267    * @param align The new justification value for this object, which must
268    * be one of the constants in this class.
269    */
setAlignment(int align)270   public void setAlignment (int align)
271   {
272     // The JDK accepts invalid values and treats them as
273     // LEFT during layout, so do we. The invalid value is even stored,
274     // getAlignment() returns the same invalid value.
275     this.align = align;
276   }
277 
278   /**
279    * Sets the horizontal gap between lines of components to the specified value.
280    * No Exception is thrown if hgap < 0.
281    *
282    * @param hgap The new horizontal gap between components.
283    */
setHgap(int hgap)284   public void setHgap (int hgap)
285   {
286     this.hgap = hgap;
287   }
288 
289   /**
290    * Sets the vertical gap between lines of components to the specified value.
291    * No Exception is thrown if vgap < 0.
292    *
293    * @param vgap The new vertical gap.
294    */
setVgap(int vgap)295   public void setVgap (int vgap)
296   {
297     this.vgap = vgap;
298   }
299 
300   /** Return String description of this object.
301    * @return A string representation of this object.
302    */
toString()303   public String toString ()
304   {
305     return ("[" + getClass ().getName () + ",hgap=" + hgap + ",vgap=" + vgap
306             + ",align=" + align + "]");
307   }
308 
309   // This method is used to compute the various sizes.
getSize(Container parent, boolean is_min)310   private Dimension getSize (Container parent, boolean is_min)
311   {
312     synchronized (parent.getTreeLock ())
313       {
314         int w, h, num = parent.getComponentCount ();
315         // This is more efficient than calling getComponents().
316         Component[] comps = parent.component;
317 
318         w = 0;
319         h = 0;
320         for (int i = 0; i < num; ++i)
321           {
322             if (! comps[i].visible)
323               continue;
324 
325             // FIXME: can we just directly read the fields in Component?
326             // Or will that not work with subclassing?
327             Dimension d;
328 
329             if (is_min)
330               d = comps[i].getMinimumSize ();
331             else
332               d = comps[i].getPreferredSize ();
333 
334             w += d.width;
335             h = Math.max (d.height, h);
336           }
337 
338         Insets ins = parent.getInsets ();
339 
340         if (num == 0)
341           w += 2 * hgap + ins.left + ins.right;
342         else
343           w += (num + 1) * hgap + ins.left + ins.right;
344         h += 2 * vgap + ins.top + ins.bottom;
345 
346         return new Dimension (w, h);
347       }
348   }
349 
350   /**
351    * @serial The justification alignment of the lines of components, which
352    * will be one of the constants defined in this class.
353    */
354   private int align;
355 
356   /**
357    * @serial The horizontal gap between components.
358    */
359   private int hgap;
360 
361   /**
362    * @serial The vertical gap between lines of components.
363    */
364   private int vgap;
365 }
366