Handle hostnames with upper-case letters
[webmin.git] / file / ToolbarLayout.java
1 import java.awt.*;
2 import java.lang.Math;
3
4 /**
5  * A ToolbarLayout arranges components in a left-to-right flow, much 
6  * like the FlowLayout which is supplied with the JDK.  However, it
7  * fixes the problem with the FlowLayout that occurs when a FlowLayout
8  * is for a North aligned component of a BorderLayout--namely, that
9  * if the window is shrunk so that some of the components within the
10  * FlowLayout wrap to the next line the component does not grow in
11  * height to support this wrapping.  This bug was caused by the library
12  * designers using the preferred size in recalculating, not the size
13  * which is determined by the window width.  As such, the flow layout
14  * would always want to be the height of one row.
15  *
16  * A ToolbarLayout lets each component assume its natural (preferred) size.
17  *
18  * NOTE: This class was initially a subclass of FlowLayout, but we
19  *       encountered problems using that approach.
20  *
21  * @version     0.10, 1999-04-27
22  * @author      Peter Armstrong
23  * @author      Tony Johnson
24  */
25 public class ToolbarLayout implements LayoutManager, java.io.Serializable {
26
27     /**
28      * This value indicates that each row of components
29      * should be left-justified. 
30      */
31     public static final int LEFT        = 0;
32
33     /**
34      * This value indicates that each row of components
35      * should be centered. 
36      */
37     public static final int CENTER      = 1;
38
39     /**
40      * This value indicates that each row of components
41      * should be right-justified. 
42      */
43     public static final int RIGHT       = 2;
44
45     int align;
46     int hgap;
47     int vgap;
48
49
50     /**
51      * Constructs a new ToolbarLayout with a left alignment and a
52      * default 5-unit horizontal and vertical gap.
53      */
54     public ToolbarLayout() {
55                 this(LEFT, 5, 5);
56     }
57
58     /**
59      * Constructs a new ToolbarLayout with the specified alignment and a
60      * default 5-unit horizontal and vertical gap.
61      * The value of the alignment argument must be one of 
62      * <code>ToolbarLayout.LEFT</code>, <code>ToolbarLayout.RIGHT</code>, 
63      * or <code>ToolbarLayout.CENTER</code>.
64      * @param align the alignment value
65      */
66     public ToolbarLayout(int align) {
67                 this(align, 5, 5);
68     }
69
70     /**
71      * Creates a new ToolbarLayout with the indicated alignment 
72      * and the indicated horizontal and vertical gaps. 
73      * <p>
74      * The value of the alignment argument must be one of 
75      * <code>ToolbarLayout.LEFT</code>, <code>ToolbarLayout.RIGHT</code>, 
76      * or <code>ToolbarLayout.CENTER</code>.
77      * @param      align   the alignment value.
78      * @param      hgap    the horizontal gap between components.
79      * @param      vgap    the vertical gap between components.
80      */
81     public ToolbarLayout(int align, int hgap, int vgap) {
82                 this.align = align;
83                 this.hgap = hgap;
84                 this.vgap = vgap;
85     }
86
87     /**
88      * Gets the alignment for this layout.
89      * Possible values are <code>ToolbarLayout.LEFT</code>,  
90      * <code>ToolbarLayout.RIGHT</code>, or <code>ToolbarLayout.CENTER</code>.  
91      * @return     the alignment value for this layout.
92      * @see        ToolbarLayout#setAlignment
93      */
94     public int getAlignment() {
95                 return align;
96     }
97     
98     /**
99      * Sets the alignment for this layout.
100      * Possible values are <code>ToolbarLayout.LEFT</code>,  
101      * <code>ToolbarLayout.RIGHT</code>, and <code>ToolbarLayout.CENTER</code>.  
102      * @param      align the alignment value.
103      * @see        ToolbarLayout#getAlignment
104      */
105     public void setAlignment(int align) {
106                 this.align = align;
107     }
108
109     /**
110      * Gets the horizontal gap between components.
111      * @return     the horizontal gap between components.
112      * @see        ToolbarLayout#setHgap
113      */
114     public int getHgap() {
115                 return hgap;
116     }
117     
118     /**
119      * Sets the horizontal gap between components.
120      * @param hgap the horizontal gap between components
121      * @see        ToolbarLayout#getHgap
122      */
123     public void setHgap(int hgap) {
124                 this.hgap = hgap;
125     }
126     
127     /**
128      * Gets the vertical gap between components.
129      * @return     the vertical gap between components.
130      * @see        ToolbarLayout#setVgap
131      */
132     public int getVgap() {
133                 return vgap;
134     }
135     
136     /**
137      * Sets the vertical gap between components.
138      * @param vgap the vertical gap between components
139      * @see        ToolbarLayout#getVgap
140      */
141     public void setVgap(int vgap) {
142                 this.vgap = vgap;
143     }
144
145     /**
146      * Adds the specified component to the layout.  Sets the orientation to be horizontal.
147      * @param name the name of the component
148      * @param comp the component to be added
149      */
150     public void addLayoutComponent(String name, Component comp) {
151     }
152
153     /**
154      * Removes the specified component from the layout. Not used by
155      * this class.  
156      * @param comp the component to remove
157      * @see       java.awt.Container#removeAll
158      */
159     public void removeLayoutComponent(Component comp) {
160     }
161
162     /**
163      * Returns the preferred dimensions for this layout given the components
164      * in the specified target container.  This method is the difference
165      * between ToolbarLayout and FlowLayout.
166      * @param target the component which needs to be laid out
167      * @return    the preferred dimensions to lay out the 
168      *                    subcomponents of the specified container.
169      * @see Container
170      * @see #minimumLayoutSize
171      * @see     java.awt.Container#getPreferredSize
172      */
173     public Dimension preferredLayoutSize(Container target) {
174                 synchronized (target.getTreeLock()) {
175                         Dimension dim = new Dimension(0, 0);
176                         int nmembers = target.getComponentCount();
177
178                         Insets insets = target.getInsets();
179
180                         int numRows             = 1;                                                    //the number of rows
181                         int rowSumWidth = insets.left + insets.right;   //the width of the row so far
182                         int rowMaxWidth = target.getSize().width;               //the width that the ToolbarLayout is in
183                         int rowHeight   = 0;                                                    //the height of each row
184                         int numOnRow    = 0;                                                    //the number of components on the row
185                         
186                         for (int i = 0 ; i < nmembers ; i++) {
187                             Component m = target.getComponent(i);
188                             if (m.isVisible()) {
189                                         Dimension d = m.getPreferredSize();
190                                         rowHeight = Math.max(rowHeight, d.height);      //make each row the height of the biggest component of all
191                                         if (i > 0) {
192                                                 rowSumWidth += hgap;//add on the pre-spacing if this is not the first component
193                                         }
194                                         rowSumWidth += d.width; //add the width of the component
195                                         
196                                         //if it overflowed and if there are components already on this row then bump this component to next row
197                                         if ((rowSumWidth + hgap) > rowMaxWidth) {
198                                                 if (numOnRow > 0) {
199                                                         numRows++;
200                                                         rowSumWidth = insets.left + insets.right + d.width;
201                                                         numOnRow = 0;//reset the number of components on the next row (we ++ no matter what later)
202                                                 }
203                                         }
204                                         numOnRow++;//add this component to the count of the number on the row
205                         }
206                         }
207                         dim.width = rowMaxWidth;
208                         dim.height = insets.top + insets.bottom + numRows*rowHeight + vgap*(numRows + 1);
209                         return dim;
210                 }
211     }
212      
213     /**
214      * Returns the minimum dimensions needed to layout the components
215      * contained in the specified target container.
216      * @param target the component which needs to be laid out 
217      * @return    the minimum dimensions to lay out the 
218      *                    subcomponents of the specified container.
219      * @see #preferredLayoutSize
220      * @see       java.awt.Container
221      * @see       java.awt.Container#doLayout
222      */
223     public Dimension minimumLayoutSize(Container target) {
224                 synchronized (target.getTreeLock()) {
225                         Dimension dim = new Dimension(0, 0);
226                         int nmembers = target.getComponentCount();
227
228                         for (int i = 0 ; i < nmembers ; i++) {
229                             Component m = target.getComponent(i);
230                             if (m.isVisible()) {
231                                         Dimension d = m.getMinimumSize();
232                                         dim.height = Math.max(dim.height, d.height);
233                                         if (i > 0) {
234                                             dim.width += hgap;
235                                         }
236                                         dim.width += d.width;
237                             }
238                         }
239                         Insets insets = target.getInsets();
240                         dim.width += insets.left + insets.right + hgap*2;
241                         dim.height += insets.top + insets.bottom + vgap*2;
242                         return dim;
243                 }
244     }
245
246     /** 
247      * Centers the elements in the specified row, if there is any slack.
248      * @param target the component which needs to be moved
249      * @param x the x coordinate
250      * @param y the y coordinate
251      * @param width the width dimensions
252      * @param height the height dimensions
253      * @param rowStart the beginning of the row
254      * @param rowEnd the the ending of the row
255      */
256     private void moveComponents(Container target, int x, int y, int width, int height, int rowStart, int rowEnd) {
257                 synchronized (target.getTreeLock()) {
258                         switch (align) {
259                         case LEFT:
260                             break;
261                         case CENTER:
262                             x += width / 2;
263                             break;
264                         case RIGHT:
265                             x += width;
266                             break;
267                         }
268                         for (int i = rowStart ; i < rowEnd ; i++) {
269                             Component m = target.getComponent(i);
270                             if (m.isVisible()) {
271                                         m.setLocation(x, y + (height - m.size().height) / 2);
272                                         x += hgap + m.size().width;
273                             }
274                         }
275                 }
276     }
277
278     /**
279      * Lays out the container. This method lets each component take 
280      * its preferred size by reshaping the components in the 
281      * target container in order to satisfy the constraints of
282      * this <code>ToolbarLayout</code> object. 
283      * @param target the specified component being laid out.
284      * @see Container
285      * @see       java.awt.Container#doLayout
286      */
287     public void layoutContainer(Container target) {
288                 synchronized (target.getTreeLock()) {
289                         Insets insets = target.getInsets();
290                         int maxwidth = target.size().width - (insets.left + insets.right + hgap*2);
291                         int nmembers = target.getComponentCount();
292                         int x = 0, y = insets.top + vgap;
293                         int rowh = 0, start = 0;
294
295                         for (int i = 0 ; i < nmembers ; i++) {
296                                 Component m = target.getComponent(i);
297                             if (m.isVisible()) {
298                                         Dimension d = m.getPreferredSize();
299                                         m.setSize(d.width, d.height);
300                                         if ((x == 0) || ((x + d.width) <= maxwidth)) {
301                                             if (x > 0) {
302                                                         x += hgap;
303                                             }
304                                             x += d.width;
305                                             rowh = Math.max(rowh, d.height);
306                                         } else {
307                                             moveComponents(target, insets.left + hgap, y, maxwidth - x, rowh, start, i);
308                                             x = d.width;
309                                             y += vgap + rowh;
310                                             rowh = d.height;
311                                             start = i;
312                                         }
313                             }
314                         }
315                         moveComponents(target, insets.left + hgap, y, maxwidth - x, rowh, start, nmembers);
316                 }
317     }
318     
319     /**
320      * Returns a string representation of this <code>ToolbarLayout</code>
321      * object and its values.
322      * @return     a string representation of this layout.
323      */
324     public String toString() {
325                 String str = "";
326                 switch (align) {
327                         case LEFT:    str = ",align=left"; break;
328                         case CENTER:  str = ",align=center"; break;
329                         case RIGHT:   str = ",align=right"; break;
330                 }
331                 return getClass().getName() + "[hgap=" + hgap + ",vgap=" + vgap + str + "]";
332     }
333 }