Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/gjt/sp/jedit/gui/VariableGridLayout.java


1   /*
2    * VariableGridLayout.java - a grid layout manager with variable cell sizes
3    *
4    * Originally written by Dirk Moebius for the jEdit project. This work has been
5    * placed into the public domain. You may use this work in any way and for any
6    * purpose you wish.
7    *
8    * THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND, NOT EVEN THE
9    * IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR OF THIS SOFTWARE, ASSUMES
10   * _NO_ RESPONSIBILITY FOR ANY CONSEQUENCE RESULTING FROM THE USE, MODIFICATION,
11   * OR REDISTRIBUTION OF THIS SOFTWARE.
12   */
13  
14  package org.gjt.sp.jedit.gui;
15  
16  
17  import java.awt.*;
18  
19  /**
20   * The <code>VariableGridLayout</code> class is a layout manager
21   * that lays out a container's components in a rectangular grid
22   * with variable cell sizes.<p>
23   *
24   * The container is divided into rectangles, and one component is placed
25   * in each rectangle. Each row is as large as the largest component in
26   * that row, and each column is as wide as the widest component in
27   * that column.<p>
28   *
29   * This behavior is basically the same as in
30   * <code>java.awt.GridLayout</code>, but with different row heights and
31   * column widths for each row/column.<p>
32   *
33   * For example, the following is an applet that lays out six buttons
34   * into three rows and two columns:<p>
35   *
36   * <blockquote><pre>
37   * import java.awt.*;
38   * import java.applet.Applet;
39   * public class ButtonGrid extends Applet {
40   *     public void init() {
41   *         setLayout(new VariableGridLayout(VariableGridLayout.FIXED_NUM_COLUMNS, 2));
42   *         add(new Button("1"));
43   *         add(new Button("2"));
44   *         add(new Button("3"));
45   *         add(new Button("4"));
46   *         add(new Button("5"));
47   *         add(new Button("6"));
48   *     }
49   * }
50   * </pre></blockquote><p>
51   *
52   * <b>Programmer's remark:</b> VariableGridLayout could be faster, if it would
53   * reside in the package java.awt, because then it could access some
54   * package private fields of <code>Container</code> or
55   * <code>Component</code>. Instead, it has to call
56   * <code>Component.getSize()</code>,
57   * which allocates memory on the heap.<p>
58   *
59   * <b>Todo:</b>
60   * <ul>
61   * <li>Use alignmentX/Y property if the grid cell is larger than the preferred size of the component.
62   * <li>Ability to span components over more than one cell horizontally
63   * </ul>
64   *
65   * @author Dirk Moebius
66   * @version 1.0
67   * @see java.awt.GridLayout
68   */
69  public class VariableGridLayout implements LayoutManager2, java.io.Serializable
70  {
71  
72    public static final int FIXED_NUM_ROWS = 1;
73    public static final int FIXED_NUM_COLUMNS = 2;
74  
75  
76    public VariableGridLayout(int mode, int size, int hgap, int vgap) {
77      if (mode != FIXED_NUM_ROWS && mode != FIXED_NUM_COLUMNS) {
78        throw new IllegalArgumentException("illegal mode; value is " + mode);
79      }
80      if (size <= 0) {
81        throw new IllegalArgumentException("size cannot be zero or less; value is " + size);
82      }
83      if (hgap < 0) {
84        throw new IllegalArgumentException("hgap cannot be negative; value is " + hgap);
85      }
86      if (vgap < 0) {
87        throw new IllegalArgumentException("vgap cannot be negative; value is " + vgap);
88      }
89      this.mode = mode;
90      this.size = size;
91      this.hgap = hgap;
92      this.vgap = vgap;
93    }
94  
95  
96    /**
97     * Creates a variable grid layout manager with the specified mode
98     * and zero horizontal and vertical gap.
99     */
100   public VariableGridLayout(int mode, int size) {
101     this(mode, size, 0, 0);
102   }
103 
104 
105   /**
106    * Creates a variable grid layout manager with mode FIXED_NUM_ROWS,
107    * number of rows == 1 and zero horizontal and vertical gap.
108    */
109   public VariableGridLayout() {
110     this(FIXED_NUM_ROWS, 1, 0, 0);
111   }
112 
113 
114   /**
115    * Not used in this class.
116    */
117   public void addLayoutComponent(String name, Component component) { }
118 
119 
120   /**
121    * Not used in this class.
122    */
123   public void addLayoutComponent(Component component, Object constraints) { }
124 
125 
126   /**
127    * Not used in this class.
128    */
129   public void removeLayoutComponent(Component component) { }
130 
131 
132   /**
133    * Always returns 0.5.
134    */
135   public float getLayoutAlignmentX(Container container) {
136     return 0.5f;
137   }
138 
139 
140   /**
141    * Always returns 0.5.
142    */
143   public float getLayoutAlignmentY(Container container) {
144     return 0.5f;
145   }
146 
147 
148   public Dimension preferredLayoutSize(Container parent) {
149     return getLayoutSize(parent, 2);
150   }
151 
152 
153   public Dimension minimumLayoutSize(Container parent) {
154     return getLayoutSize(parent, 0);
155   }
156 
157 
158   public Dimension maximumLayoutSize(Container parent) {
159     return getLayoutSize(parent, 1);
160   }
161 
162 
163   public void layoutContainer(Container parent) {
164     synchronized (parent.getTreeLock()) {
165       update(parent);
166 
167       int ncomponents = parent.getComponentCount();
168 
169       if (ncomponents == 0) {
170         return;
171       }
172 
173       // Pass 1: compute preferred row heights / column widths
174       int total_height = 0;
175       for (int r = 0, i = 0; r < nrows; r++) {
176         for (int c = 0; c < ncols; c++, i++) {
177           if (i < ncomponents) {
178             Dimension d = parent.getComponent(i).getPreferredSize();
179             row_heights[r] = Math.max(row_heights[r], d.height);
180             col_widths[c] = Math.max(col_widths[c], d.width);
181           } else {
182             break;
183           }
184         }
185         total_height += row_heights[r];
186       }
187 
188       int total_width = 0;
189       for (int c = 0; c < ncols; c++) {
190         total_width += col_widths[c];
191       }
192 
193       // Pass 2: redistribute free space
194       Dimension parent_size = parent.getSize();
195       Insets insets = parent.getInsets();
196       int free_height = parent_size.height - insets.top - insets.bottom - (nrows - 1) * vgap;
197       int free_width = parent_size.width - insets.left - insets.right - (ncols - 1) * hgap;
198 
199       if (total_height != free_height) {
200         double dy = (double)free_height / (double)total_height;
201         for (int r = 0; r < nrows; r++) {
202           row_heights[r] = (int) ((double)row_heights[r] * dy);
203         }
204       }
205 
206       if (total_width != free_width) {
207         double dx = ((double)free_width) / ((double)total_width);
208         for (int c = 0; c < ncols; c++) {
209           col_widths[c] = (int) ((double)col_widths[c] * dx);
210         }
211       }
212 
213       // Pass 3: layout components
214       for (int r = 0, y = insets.top, i = 0; r < nrows; y += row_heights[r] + vgap, r++) {
215         for (int c = 0, x = insets.left; c < ncols; x += col_widths[c] + hgap, c++, i++) {
216           if (i < ncomponents) {
217             parent.getComponent(i).setBounds(x, y, col_widths[c], row_heights[r]);
218           }
219         }
220       }
221 
222     } // synchronized
223   }
224 
225 
226   public void invalidateLayout(Container container) {}
227 
228 
229   /**
230    * Returns the string representation of this variable grid layout's values.
231    * @return  a string representation of this variable grid layout.
232    */
233   public String toString() {
234     return getClass().getName() + "[mode=" + mode + ",size=" + size
235          + ",hgap=" + hgap + ",vgap=" + vgap + "]";
236   }
237 
238 
239   /**
240    * @param  which  if 0 compute minimum layout size,
241    *        if 1 compute maximum layout size,
242    *        otherwise compute preferred layout size.
243    */
244   private Dimension getLayoutSize(Container parent, int which) {
245     synchronized (parent.getTreeLock()){
246       update(parent);
247 
248       int ncomponents = parent.getComponentCount();
249       int h = 0;
250       int w = 0;
251 
252       for (int r = 0, i = 0; r < nrows; r++) {
253         int row_height = 0;
254         for (int c = 0; c < ncols; c++, i++) {
255           if (i < ncomponents) {
256             switch (which) {
257               case 0:
258                 row_height = Math.max(row_height, parent.getComponent(i).getMinimumSize().height);
259                 break;
260               case 1:
261                 row_height = Math.max(row_height, parent.getComponent(i).getMaximumSize().height);
262                 break;
263               default:
264                 row_height = Math.max(row_height, parent.getComponent(i).getPreferredSize().height);
265                 break;
266             }
267           } else {
268             break;
269           }
270         }
271         h += row_height;
272       }
273 
274       for (int c = 0; c < ncols; c++) {
275         int col_width = 0;
276         for (int r = 0; r < nrows; r++) {
277           int i = r * ncols + c;
278           if (i < ncomponents) {
279             switch (which) {
280               case 0:
281                 col_width = Math.max(col_width, parent.getComponent(i).getMinimumSize().width);
282                 break;
283               case 1:
284                 col_width = Math.max(col_width, parent.getComponent(i).getMaximumSize().width);
285                 break;
286               default:
287                 col_width = Math.max(col_width, parent.getComponent(i).getPreferredSize().width);
288                 break;
289             }
290           } else {
291             break;
292           }
293         }
294         w += col_width;
295       }
296 
297       Insets insets = parent.getInsets();
298       return new Dimension(w + insets.left + insets.right + ((ncols - 1) * hgap),
299                  h + insets.top + insets.bottom + ((nrows - 1) * vgap));
300     }
301   }
302 
303 
304   private void update(Container container) {
305     int ncomponents = container.getComponentCount();
306     int old_nrows = nrows;
307     int old_ncols = ncols;
308     if (this.mode == FIXED_NUM_ROWS) {
309       nrows = this.size;
310       ncols = (ncomponents + nrows - 1) / nrows;
311     } else {
312       ncols = this.size;
313       nrows = (ncomponents + ncols - 1) / ncols;
314     }
315     if (old_nrows != nrows) {
316       row_heights = new int[nrows];
317     }
318     if (old_ncols != ncols) {
319       col_widths = new int[ncols];
320     }
321   }
322 
323 
324   private int mode;
325   private int size;
326   private int hgap;
327   private int vgap;
328   private transient int nrows = -1;
329   private transient int ncols = -1;
330   private transient int[] row_heights = null;
331   private transient int[] col_widths = null;
332 }