PageRenderTime 104ms CodeModel.GetById 41ms app.highlight 34ms RepoModel.GetById 16ms app.codeStats 0ms

/jEdit/tags/jedit-4-0-pre5/org/gjt/sp/jedit/gui/VariableGridLayout.java

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