1 /* BoxLayout.java -- A layout for swing components.
2    Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc.
3 
4 This file is part of GNU Classpath.
5 
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 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 package javax.swing;
39 
40 import java.awt.AWTError;
41 import java.awt.Component;
42 import java.awt.ComponentOrientation;
43 import java.awt.Container;
44 import java.awt.Dimension;
45 import java.awt.Insets;
46 import java.awt.LayoutManager2;
47 import java.io.Serializable;
48 
49 /**
50  * A layout that stacks the children of a container in a Box, either
51  * horizontally or vertically.
52  *
53  * @author Ronald Veldema (rveldema@cs.vu.nl)
54  * @author Roman Kennke (roman@kennke.org)
55  */
56 public class BoxLayout implements LayoutManager2, Serializable
57 {
58 
59   /**
60    * Specifies that components are laid out left to right.
61    */
62   public static final int X_AXIS = 0;
63 
64   /**
65    * Specifies that components are laid out top to bottom.
66    */
67   public static final int Y_AXIS = 1;
68 
69   /**
70    * Specifies that components are laid out in the direction of a line of text.
71    */
72   public static final int LINE_AXIS = 2;
73 
74   /**
75    * Sepcifies that components are laid out in the direction of the line flow.
76    */
77   public static final int PAGE_AXIS = 3;
78 
79   /*
80    * Needed for serialization.
81    */
82   private static final long serialVersionUID = -2474455742719112368L;
83 
84   /*
85    * The container given to the constructor.
86    */
87   private Container container;
88 
89   /**
90    * Current type of component layouting. Defaults to X_AXIS.
91    */
92   private int way = X_AXIS;
93 
94   /**
95    * The size requirements of the containers children for the X direction.
96    */
97   private SizeRequirements[] xChildren;
98 
99   /**
100    * The size requirements of the containers children for the Y direction.
101    */
102   private SizeRequirements[] yChildren;
103 
104   /**
105    * The size requirements of the container to be laid out for the X direction.
106    */
107   private SizeRequirements xTotal;
108 
109   /**
110    * The size requirements of the container to be laid out for the Y direction.
111    */
112   private SizeRequirements yTotal;
113 
114   /**
115    * The offsets of the child components in the X direction.
116    */
117   private int[] offsetsX;
118 
119   /**
120    * The offsets of the child components in the Y direction.
121    */
122   private int[] offsetsY;
123 
124   /**
125    * The spans of the child components in the X direction.
126    */
127   private int[] spansX;
128 
129   /**
130    * The spans of the child components in the Y direction.
131    */
132   private int[] spansY;
133 
134   /**
135    * Constructs a <code>BoxLayout</code> object.
136    *
137    * @param container The container that needs to be laid out.
138    * @param way The orientation of the components.
139    *
140    * @exception AWTError If way has an invalid value.
141    */
BoxLayout(Container container, int way)142   public BoxLayout(Container container, int way)
143   {
144     if (way != X_AXIS && way != Y_AXIS && way != LINE_AXIS && way != PAGE_AXIS)
145       throw new AWTError("Invalid axis");
146 
147     int width = 0;
148     int height = 0;
149     this.container = container;
150     this.way = way;
151   }
152 
153   /**
154    * Adds a component to the layout. Not used in BoxLayout.
155    *
156    * @param name The name of the component to add.
157    * @param component the component to add to the layout.
158    */
addLayoutComponent(String name, Component component)159   public void addLayoutComponent(String name, Component component)
160   {
161     // Nothing to do here.
162   }
163 
164   /**
165    * Removes a component from the layout. Not used in BoxLayout.
166    *
167    * @param component The component to remove from the layout.
168    */
removeLayoutComponent(Component component)169   public void removeLayoutComponent(Component component)
170   {
171     // Nothing to do here.
172   }
173 
isHorizontalIn(Container parent)174   private boolean isHorizontalIn(Container parent)
175   {
176     ComponentOrientation orientation = parent.getComponentOrientation();
177     return this.way == X_AXIS
178       || (this.way == LINE_AXIS
179           && orientation.isHorizontal())
180       || (this.way == PAGE_AXIS
181           && (!orientation.isHorizontal()));
182   }
183 
184 
185 
186   /**
187    * Returns the preferred size of the layout.
188    *
189    * @param parent The container that needs to be laid out.
190    *
191    * @return The dimension of the layout.
192    */
preferredLayoutSize(Container parent)193   public Dimension preferredLayoutSize(Container parent)
194   {
195     synchronized (container.getTreeLock())
196       {
197         if (container != parent)
198           throw new AWTError("BoxLayout can't be shared");
199 
200         checkTotalRequirements();
201         Insets i = container.getInsets();
202         return new Dimension(xTotal.preferred + i.left + i.right,
203                              yTotal.preferred + i.top + i.bottom);
204       }
205   }
206 
207   /**
208    * Returns the minimum size of the layout.
209    *
210    * @param parent The container that needs to be laid out.
211    *
212    * @return The dimension of the layout.
213    */
minimumLayoutSize(Container parent)214   public Dimension minimumLayoutSize(Container parent)
215   {
216     synchronized (container.getTreeLock())
217       {
218         if (container != parent)
219           throw new AWTError("BoxLayout can't be shared");
220 
221         checkTotalRequirements();
222         Insets i = container.getInsets();
223         return new Dimension(xTotal.minimum + i.left + i.right,
224                              yTotal.minimum + i.top + i.bottom);
225       }
226   }
227 
228   /**
229    * Lays out the specified container using this layout.
230    *
231    * @param parent The container that needs to be laid out.
232    */
layoutContainer(Container parent)233   public void layoutContainer(Container parent)
234   {
235     synchronized (container.getTreeLock())
236       {
237         if (container != parent)
238           throw new AWTError("BoxLayout can't be shared");
239 
240         checkLayout();
241         Component[] children = container.getComponents();
242         Insets in = container.getInsets();
243         for (int i = 0; i < children.length; i++)
244           children[i].setBounds(offsetsX[i] + in.left, offsetsY[i] + in.top,
245                                 spansX[i], spansY[i]);
246       }
247   }
248 
249   /**
250    * Adds a component to the layout. Not used in BoxLayout
251    *
252    * @param child The component to add to the layout.
253    * @param constraints The constraints for the component in the layout.
254    */
addLayoutComponent(Component child, Object constraints)255   public void addLayoutComponent(Component child, Object constraints)
256   {
257     // Nothing to do here.
258   }
259 
260   /**
261    * Returns the alignment along the X axis for the container.
262    *
263    * @param parent The container that needs to be laid out.
264    *
265    * @return The alignment.
266    */
getLayoutAlignmentX(Container parent)267   public float getLayoutAlignmentX(Container parent)
268   {
269     synchronized (container.getTreeLock())
270       {
271         if (container != parent)
272           throw new AWTError("BoxLayout can't be shared");
273 
274         checkTotalRequirements();
275         return xTotal.alignment;
276       }
277   }
278 
279   /**
280    * Returns the alignment along the Y axis for the container.
281    *
282    * @param parent The container that needs to be laid out.
283    *
284    * @return The alignment.
285    */
getLayoutAlignmentY(Container parent)286   public float getLayoutAlignmentY(Container parent)
287   {
288     synchronized (container.getTreeLock())
289       {
290         if (container != parent)
291           throw new AWTError("BoxLayout can't be shared");
292 
293         checkTotalRequirements();
294         return yTotal.alignment;
295       }
296   }
297 
298   /**
299    * Invalidates the layout.
300    *
301    * @param parent The container that needs to be laid out.
302    */
invalidateLayout(Container parent)303   public void invalidateLayout(Container parent)
304   {
305     if (container != parent)
306       throw new AWTError("BoxLayout can't be shared");
307 
308     synchronized (container.getTreeLock())
309       {
310         xChildren = null;
311         yChildren = null;
312         xTotal = null;
313         yTotal = null;
314         offsetsX = null;
315         offsetsY = null;
316         spansX = null;
317         spansY = null;
318       }
319   }
320 
321   /**
322    * Returns the maximum size of the layout gived the components
323    * in the given container.
324    *
325    * @param parent The container that needs to be laid out.
326    *
327    * @return The dimension of the layout.
328    */
maximumLayoutSize(Container parent)329   public Dimension maximumLayoutSize(Container parent)
330   {
331     synchronized (container.getTreeLock())
332       {
333         if (container != parent)
334           throw new AWTError("BoxLayout can't be shared");
335 
336         checkTotalRequirements();
337         Insets i = container.getInsets();
338         return new Dimension(xTotal.maximum + i.left + i.right,
339                              yTotal.maximum + i.top + i.bottom);
340       }
341   }
342 
343   /**
344    * Makes sure that the xTotal and yTotal fields are set up correctly. A call
345    * to {@link #invalidateLayout} sets these fields to null and they have to be
346    * recomputed.
347    */
checkTotalRequirements()348   private void checkTotalRequirements()
349   {
350     if (xTotal == null || yTotal == null)
351       {
352         checkRequirements();
353         if (isHorizontalIn(container))
354           {
355             xTotal = SizeRequirements.getTiledSizeRequirements(xChildren);
356             yTotal = SizeRequirements.getAlignedSizeRequirements(yChildren);
357           }
358         else
359           {
360             xTotal = SizeRequirements.getAlignedSizeRequirements(xChildren);
361             yTotal = SizeRequirements.getTiledSizeRequirements(yChildren);
362           }
363       }
364   }
365 
366   /**
367    * Makes sure that the xChildren and yChildren fields are correctly set up.
368    * A call to {@link #invalidateLayout(Container)} sets these fields to null,
369    * so they have to be set up again.
370    */
checkRequirements()371   private void checkRequirements()
372   {
373     if (xChildren == null || yChildren == null)
374       {
375         Component[] children = container.getComponents();
376         xChildren = new SizeRequirements[children.length];
377         yChildren = new SizeRequirements[children.length];
378         for (int i = 0; i < children.length; i++)
379           {
380             if (! children[i].isVisible())
381               {
382                 xChildren[i] = new SizeRequirements();
383                 yChildren[i] = new SizeRequirements();
384               }
385             else
386               {
387                 xChildren[i] =
388                   new SizeRequirements(children[i].getMinimumSize().width,
389                                        children[i].getPreferredSize().width,
390                                        children[i].getMaximumSize().width,
391                                        children[i].getAlignmentX());
392                 yChildren[i] =
393                   new SizeRequirements(children[i].getMinimumSize().height,
394                                        children[i].getPreferredSize().height,
395                                        children[i].getMaximumSize().height,
396                                        children[i].getAlignmentY());
397               }
398           }
399       }
400   }
401 
402   /**
403    * Makes sure that the offsetsX, offsetsY, spansX and spansY fields are set
404    * up correctly. A call to {@link #invalidateLayout} sets these fields
405    * to null and they have to be recomputed.
406    */
checkLayout()407   private void checkLayout()
408   {
409     if (offsetsX == null || offsetsY == null || spansX == null
410         || spansY == null)
411       {
412         checkRequirements();
413         checkTotalRequirements();
414         int len = container.getComponents().length;
415         offsetsX = new int[len];
416         offsetsY = new int[len];
417         spansX = new int[len];
418         spansY = new int[len];
419 
420         Insets in = container.getInsets();
421         int width = container.getWidth() - in.left - in.right;
422         int height = container.getHeight() - in.top -in.bottom;
423 
424         if (isHorizontalIn(container))
425           {
426             SizeRequirements.calculateTiledPositions(width,
427                                                      xTotal, xChildren,
428                                                      offsetsX, spansX);
429             SizeRequirements.calculateAlignedPositions(height,
430                                                        yTotal, yChildren,
431                                                        offsetsY, spansY);
432           }
433         else
434           {
435             SizeRequirements.calculateAlignedPositions(width,
436                                                        xTotal, xChildren,
437                                                        offsetsX, spansX);
438             SizeRequirements.calculateTiledPositions(height,
439                                                      yTotal, yChildren,
440                                                      offsetsY, spansY);
441           }
442       }
443   }
444 }
445