View Javadoc

1   /*
2    * Copyright (c) 2007 Creative Sphere Limited.
3    * All rights reserved. This program and the accompanying materials
4    * are made available under the terms of the Eclipse Public License v1.0
5    * which accompanies this distribution, and is available at
6    * http://www.eclipse.org/legal/epl-v10.html
7    *
8    * Contributors:
9    *
10   *   Creative Sphere - initial API and implementation
11   *
12   */
13  package org.abstracthorizon.aequo.gui;
14  
15  import java.awt.Component;
16  import java.awt.Container;
17  import java.awt.Dimension;
18  import java.awt.Insets;
19  import java.awt.LayoutManager2;
20  import java.util.HashMap;
21  import java.util.Map;
22  
23  /**
24   * A layout that sorts elements in columns taking the largest width in a column
25   * for column's width.
26   * 
27   * @author Daniel Sendula
28   */
29  public class TableFormLayout implements LayoutManager2 {
30  
31      /** Default horizontal gap */
32      public static final int DEFAULT_HGAP = 5;
33  
34      /** Default vertical gap */
35      public static final int DEFAULT_VGAP = 5;
36  
37      /** Vertical gap */
38      private int vgap;
39  
40      /** Horizontal gap */
41      private int hgap;
42  
43      /** Columns */
44      private int columns;
45  
46      /** Calculated minimum width */
47      private int minWidth = 0;
48  
49      /** Calculated minimum height */
50      private int minHeight = 0;
51  
52      /** Calculated preferred width */
53      private int preferredWidth = 0;
54  
55      /** Calculated preferred height */
56      private int preferredHeight = 0;
57  
58      /** Did we calculate side? */
59      private boolean sizeUnknown = true;
60  
61      /** Preferred widths for columns */
62      int[] preferredWidths;
63  
64      /** Preferred heights for rows */
65      int[] preferredHeights;
66  
67      /** Minimum widths for columns */
68      int[] minWidths;
69  
70      /** Map of constraints */
71      protected Map<Component, Object> constraints = new HashMap<Component, Object>();
72  
73      /**
74       * Constructor
75       * 
76       * @param columns columns
77       */
78      public TableFormLayout(int columns) {
79          this(columns, DEFAULT_HGAP, DEFAULT_VGAP);
80      }
81  
82      /**
83       * Constructor
84       * 
85       * @param columns columns
86       * @param hgap horizontal gap
87       * @param vgap vertical gap
88       */
89      public TableFormLayout(int columns, int hgap, int vgap) {
90          this.columns = columns;
91          this.hgap = hgap;
92          this.vgap = vgap;
93  
94          preferredWidths = new int[columns];
95          minWidths = new int[columns];
96      }
97  
98      /**
99       * Not implemented
100      * 
101      * @param name name
102      * @param component component
103      */
104     public void addLayoutComponent(String name, Component comp) {
105     }
106 
107     /**
108      * Not implemented
109      * 
110      * @param comp component
111      */
112     public void removeLayoutComponent(Component comp) {
113     }
114 
115     /**
116      * Calculates size of parent container
117      * 
118      * @param parent parent container
119      */
120     private void setSizes(Container parent) {
121         int nComps = parent.getComponentCount();
122         Dimension d = null;
123 
124         preferredWidth = 0;
125         preferredHeight = 0;
126         minWidth = 0;
127         minHeight = 0;
128         int maxHeight = 0;
129 
130         for (int i = 0; i < columns; i++) {
131             preferredWidths[i] = 0;
132             minWidths[i] = 0;
133         }
134 
135         int column = 0;
136 
137         int[] prefHeights = new int[100];
138         int rows = 0;
139 
140         for (int i = 0; i < nComps; i++) {
141             Component c = parent.getComponent(i);
142             if (c.isVisible()) {
143                 d = c.getPreferredSize();
144 
145                 Object constraint = constraints.get(c);
146                 int span = 1;
147                 if (constraint instanceof ColumnSpan) {
148                     span = ((ColumnSpan) constraint).span;
149                 }
150 
151                 if (preferredWidths[column] != 0) {
152                     preferredHeight = preferredHeight + vgap;
153                     minHeight = minHeight + vgap;
154                 }
155 
156                 if (span == 1) {
157                     if (d.width > preferredWidths[column]) {
158                         preferredWidths[column] = d.width;
159                     }
160                 }
161 
162                 if (maxHeight < d.height) {
163                     maxHeight = maxHeight + d.height;
164                 }
165 
166                 d = c.getMinimumSize();
167                 if (span == 1) {
168                     if (d.width > minWidths[column]) {
169                         minWidths[column] = d.width;
170                     }
171                 }
172 
173                 column = column + span;
174                 if (column >= columns) {
175                     column = 0;
176                     prefHeights[rows] = maxHeight;
177                     preferredHeight = preferredHeight + maxHeight;
178                     rows = rows + 1;
179                     maxHeight = 0;
180                 }
181             }
182         }
183         if (column != 0) {
184             prefHeights[rows] = maxHeight;
185             preferredHeight = preferredHeight + maxHeight;
186             rows = rows + 1;
187         }
188 
189         preferredHeights = new int[nComps];
190         System.arraycopy(prefHeights, 0, preferredHeights, 0, rows);
191 
192         for (int i = 0; i < columns; i++) {
193             if (i > 0) {
194                 preferredWidth = preferredWidth + hgap;
195                 minWidth = minWidth + hgap;
196             }
197             preferredWidth = preferredWidth + preferredWidths[i];
198             minWidth = minWidth + minWidths[i];
199         }
200     }
201 
202     /**
203      * Returns preferred layout size
204      * 
205      * @param parent parent container
206      * @return preferred layout size
207      */
208     public Dimension preferredLayoutSize(Container parent) {
209         Dimension dim = new Dimension(0, 0);
210 
211         setSizes(parent);
212 
213         // Always add the container's insets!
214         Insets insets = parent.getInsets();
215         dim.width = preferredWidth + insets.left + insets.right;
216         dim.height = preferredHeight + insets.top + insets.bottom;
217 
218         sizeUnknown = false;
219 
220         return dim;
221     }
222 
223     /**
224      * Returns minimum layout size
225      * 
226      * @param parent parent container
227      * @return minimum layout size
228      */
229     public Dimension minimumLayoutSize(Container parent) {
230         Dimension dim = new Dimension(0, 0);
231 
232         // Always add the container's insets!
233         Insets insets = parent.getInsets();
234         dim.width = minWidth + insets.left + insets.right;
235         dim.height = minHeight + insets.top + insets.bottom;
236 
237         sizeUnknown = false;
238 
239         return dim;
240     }
241 
242     /**
243      * Lays out container
244      * 
245      * @param parent parent container
246      */
247     public void layoutContainer(Container parent) {
248         Insets insets = parent.getInsets();
249 
250         int nComps = parent.getComponentCount();
251 
252         int x = insets.left;
253         int y = insets.top;
254 
255         if (sizeUnknown) {
256             setSizes(parent);
257         }
258 
259         int counter = 0;
260         int row = 0;
261 
262         for (int i = 0; i < nComps; i++) {
263             Component c = parent.getComponent(i);
264             if (c.isVisible()) {
265                 Dimension d = c.getPreferredSize();
266 
267                 Object constraint = constraints.get(c);
268                 int span = 1;
269                 if (constraint instanceof ColumnSpan) {
270                     span = ((ColumnSpan) constraint).span;
271                 }
272 
273                 int yo = 0;
274                 if (d.height < preferredHeights[row]) {
275                     yo = (preferredHeights[row] - d.height) / 2;
276                 }
277 
278                 int pWidth = 0;
279                 while ((span > 0) && (counter < columns)) {
280                     span = span - 1;
281                     pWidth = pWidth + preferredWidths[counter];
282                     counter = counter + 1;
283                     if ((counter < columns) && (span > 0)) {
284                         pWidth = pWidth + hgap;
285                     }
286                 }
287 
288                 // Set the component's size and position.
289                 c.setBounds(x, y + yo, pWidth, d.height);
290 
291                 x = x + hgap + pWidth;
292 
293                 if (counter >= columns) {
294                     counter = 0;
295                     x = insets.left;
296                     y = y + vgap + preferredHeights[row];
297                     row = row + 1;
298                 }
299             }
300         }
301     }
302 
303     /**
304      * Returns number of columns
305      * 
306      * @return number of columns
307      */
308     public int getColumns() {
309         return columns;
310     }
311 
312     /**
313      * Adds layout component.
314      * @param comp component
315      * @param constraints constraints
316      */
317     public void addLayoutComponent(Component comp, Object constraints) {
318         if (constraints != null) {
319             this.constraints.put(comp, constraints);
320         }
321     }
322 
323     /**
324      * Returns <code>null</code>
325      * @return <code>null</code>
326      */
327     public Dimension maximumLayoutSize(Container target) {
328         return null;
329     }
330 
331     /**
332      * Returns 0
333      * @return 0
334      */
335     public float getLayoutAlignmentX(Container target) {
336         return 0;
337     }
338 
339     /**
340      * Returns 0
341      * @return 0
342      */
343     public float getLayoutAlignmentY(Container target) {
344         return 0;
345     }
346 
347     /**
348      * Sets sizes
349      * @param target container
350      */
351     public void invalidateLayout(Container target) {
352         setSizes(target);
353     }
354 
355     /**
356      * Class that contains column span info
357      */
358     public static class ColumnSpan {
359         protected int span;
360 
361         /**
362          * Constructor
363          * @param span column span
364          */
365         public ColumnSpan(int span) {
366             this.span = span;
367         }
368     }
369 }