|
1 /* |
|
2 * CDDL HEADER START |
|
3 * |
|
4 * The contents of this file are subject to the terms of the |
|
5 * Common Development and Distribution License (the "License"). |
|
6 * You may not use this file except in compliance with the License. |
|
7 * |
|
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE |
|
9 * or http://www.opensolaris.org/os/licensing. |
|
10 * See the License for the specific language governing permissions |
|
11 * and limitations under the License. |
|
12 * |
|
13 * When distributing Covered Code, include this CDDL HEADER in each |
|
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. |
|
15 * If applicable, add the following below this CDDL HEADER, with the |
|
16 * fields enclosed by brackets "[]" replaced with your own identifying |
|
17 * information: Portions Copyright [yyyy] [name of copyright owner] |
|
18 * |
|
19 * CDDL HEADER END |
|
20 */ |
|
21 |
|
22 /* |
|
23 * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. |
|
24 */ |
|
25 |
|
26 package com.oracle.solaris.vp.util.swing.layout; |
|
27 |
|
28 import java.awt.*; |
|
29 import javax.swing.*; |
|
30 import javax.swing.border.LineBorder; |
|
31 |
|
32 public class UniformLayout extends AbstractLayout { |
|
33 // |
|
34 // Enums |
|
35 // |
|
36 |
|
37 public enum Orientation { |
|
38 HORIZONTAL, |
|
39 VERTICAL, |
|
40 } |
|
41 |
|
42 public enum FillPolicy { |
|
43 RESIZE_COMPONENTS, |
|
44 RESIZE_GAPS, |
|
45 } |
|
46 |
|
47 // |
|
48 // Instance data |
|
49 // |
|
50 |
|
51 private int gap; |
|
52 private Orientation o; |
|
53 private FillPolicy policy; |
|
54 |
|
55 // |
|
56 // Constructors |
|
57 // |
|
58 |
|
59 /** |
|
60 * Constructs a {@code UniformLayout} with the given orientation, gap, |
|
61 * and fill policy. |
|
62 * |
|
63 * @param o |
|
64 * the orientation to use when positioning Components |
|
65 * |
|
66 * @param gap |
|
67 * the gap between each Component |
|
68 * |
|
69 * @param policy |
|
70 * the fill policy, if the Container is longer than necessary |
|
71 */ |
|
72 public UniformLayout(Orientation o, int gap, FillPolicy policy) { |
|
73 this.o = o; |
|
74 this.gap = gap; |
|
75 this.policy = policy; |
|
76 } |
|
77 |
|
78 /** |
|
79 * Constructs a {@code UniformLayout} with the given orientation and |
|
80 * gap, and the default fill policy (FillPolicy.RESIZE_COMPONENTS). |
|
81 * |
|
82 * @param o |
|
83 * the orientation to use when positioning Components |
|
84 * |
|
85 * @param gap |
|
86 * the gap between each Component |
|
87 */ |
|
88 public UniformLayout(Orientation o, int gap) { |
|
89 this(o, gap, FillPolicy.RESIZE_COMPONENTS); |
|
90 } |
|
91 |
|
92 /** |
|
93 * Constructs a {@code UniformLayout} with the given orientation and |
|
94 * the default gap (0) and fill policy (FillPolicy.RESIZE_COMPONENTS). |
|
95 * |
|
96 * @param o |
|
97 * the orientation to use when positioning Components |
|
98 */ |
|
99 public UniformLayout(Orientation o) { |
|
100 this(o, 0); |
|
101 } |
|
102 |
|
103 /** |
|
104 * Constructs a {@code UniformLayout} with the default orientation |
|
105 * (Orientation.HORIZONTAL), gap (0), and fill policy |
|
106 * (FillPolicy.RESIZE_COMPONENTS). |
|
107 */ |
|
108 public UniformLayout() { |
|
109 this(Orientation.HORIZONTAL); |
|
110 } |
|
111 |
|
112 /** |
|
113 * Constructs a {@code UniformLayout} with the given gap, and the default |
|
114 * orientation (Orientation.HORIZONTAL) and fill policy |
|
115 * (FillPolicy.RESIZE_COMPONENTS). |
|
116 */ |
|
117 public UniformLayout(int gap) { |
|
118 this(Orientation.HORIZONTAL, gap); |
|
119 } |
|
120 |
|
121 // |
|
122 // LayoutManager methods |
|
123 // |
|
124 |
|
125 @Override |
|
126 public void layoutContainer(Container container) { |
|
127 Insets insets = translate(container.getInsets()); |
|
128 Dimension cSize = translate(container.getSize()); |
|
129 |
|
130 // The amount of space we have to work with |
|
131 int cWidth = cSize.width - insets.left - insets.right; |
|
132 int cHeight = cSize.height - insets.top - insets.bottom; |
|
133 |
|
134 // Weed out invisible Components |
|
135 Component[] comps = getLayoutComponents(container.getComponents()); |
|
136 |
|
137 // Preferred size of each Component |
|
138 Dimension pSize = translate(getComponentSize(comps, true)); |
|
139 |
|
140 FillPolicy policy = getFillPolicy(); |
|
141 |
|
142 int gap = getGap(); |
|
143 int[] widths = new int[comps.length]; |
|
144 int[] gaps = new int[comps.length]; |
|
145 |
|
146 // Total width |
|
147 int tWidth = 0; |
|
148 for (int i = 0; i < comps.length; i++) { |
|
149 widths[i] = pSize.width; |
|
150 gaps[i] = i == 0 ? 0 : gap; |
|
151 tWidth += widths[i] + gaps[i]; |
|
152 } |
|
153 |
|
154 // Excess/insufficient space |
|
155 int extra = cWidth - tWidth; |
|
156 if (extra != 0) { |
|
157 if (extra < 0) { |
|
158 distributeSpace(extra, widths, null); |
|
159 } else { |
|
160 switch (policy) { |
|
161 default: |
|
162 case RESIZE_COMPONENTS: |
|
163 distributeSpace(extra, widths, null); |
|
164 break; |
|
165 |
|
166 case RESIZE_GAPS: |
|
167 float[] weights = new float[gaps.length]; |
|
168 for (int i = 1; i < comps.length; i++) { |
|
169 weights[i] = 1; |
|
170 } |
|
171 distributeSpace(extra, gaps, weights); |
|
172 break; |
|
173 } |
|
174 } |
|
175 } |
|
176 |
|
177 int left = insets.left; |
|
178 |
|
179 // Lay out components |
|
180 for (int i = 0; i < comps.length; i++) { |
|
181 left += gaps[i]; |
|
182 |
|
183 comps[i].setBounds(translate(new Rectangle( |
|
184 left, 0, widths[i], cHeight))); |
|
185 left += widths[i]; |
|
186 } |
|
187 } |
|
188 |
|
189 // |
|
190 // AbstractLayout methods |
|
191 // |
|
192 |
|
193 @Override |
|
194 protected Dimension getLayoutSize(Container container, boolean preferred) { |
|
195 Component[] components = getLayoutComponents(container.getComponents()); |
|
196 Insets insets = container.getInsets(); |
|
197 |
|
198 int width = insets.left + insets.right; |
|
199 int height = insets.top + insets.bottom; |
|
200 |
|
201 Dimension size = getComponentSize(components, preferred); |
|
202 |
|
203 switch (getOrientation()) { |
|
204 default: |
|
205 case HORIZONTAL: |
|
206 width += components.length * size.width + |
|
207 (components.length - 1) * getGap(); |
|
208 height += size.height; |
|
209 break; |
|
210 |
|
211 case VERTICAL: |
|
212 height += components.length * size.height + |
|
213 (components.length - 1) * getGap(); |
|
214 width += size.width; |
|
215 break; |
|
216 } |
|
217 |
|
218 return new Dimension(width, height); |
|
219 } |
|
220 |
|
221 @Override |
|
222 protected boolean needsLayout(Component c) { |
|
223 return c != null && c.isVisible(); |
|
224 } |
|
225 |
|
226 // |
|
227 // UniformLayout methods |
|
228 // |
|
229 |
|
230 public int getGap() { |
|
231 return gap; |
|
232 } |
|
233 |
|
234 public FillPolicy getFillPolicy() { |
|
235 return policy; |
|
236 } |
|
237 |
|
238 public Orientation getOrientation() { |
|
239 return o; |
|
240 } |
|
241 |
|
242 // |
|
243 // Private methods |
|
244 // |
|
245 |
|
246 private Dimension getComponentSize(Component[] components, |
|
247 boolean preferred) { |
|
248 |
|
249 int width = 0; |
|
250 int height = 0; |
|
251 for (int i = 0; i < components.length; i++) { |
|
252 if (components[i].isVisible()) { |
|
253 Dimension s = preferred ? |
|
254 components[i].getPreferredSize() : |
|
255 components[i].getMinimumSize(); |
|
256 width = Math.max(width, s.width); |
|
257 height = Math.max(height, s.height); |
|
258 } |
|
259 } |
|
260 return new Dimension(width, height); |
|
261 } |
|
262 |
|
263 private Dimension translate(Dimension d) { |
|
264 switch (getOrientation()) { |
|
265 default: |
|
266 case HORIZONTAL: |
|
267 return d; |
|
268 |
|
269 case VERTICAL: |
|
270 return new Dimension(d.height, d.width); |
|
271 } |
|
272 } |
|
273 |
|
274 private Insets translate(Insets i) { |
|
275 switch (getOrientation()) { |
|
276 default: |
|
277 case HORIZONTAL: |
|
278 return i; |
|
279 |
|
280 case VERTICAL: |
|
281 return new Insets(i.left, i.top, i.right, i.bottom); |
|
282 } |
|
283 } |
|
284 |
|
285 private Rectangle translate(Rectangle r) { |
|
286 switch (getOrientation()) { |
|
287 default: |
|
288 case HORIZONTAL: |
|
289 return r; |
|
290 |
|
291 case VERTICAL: |
|
292 return new Rectangle(r.y, r.x, r.height, r.width); |
|
293 } |
|
294 } |
|
295 |
|
296 // |
|
297 // Static methods |
|
298 // |
|
299 |
|
300 /** |
|
301 * Unit test/example usage. |
|
302 */ |
|
303 public static void main(String[] args) { |
|
304 Orientation[] orients = { |
|
305 Orientation.HORIZONTAL, |
|
306 Orientation.VERTICAL, |
|
307 }; |
|
308 |
|
309 FillPolicy[] policies = { |
|
310 FillPolicy.RESIZE_COMPONENTS, |
|
311 FillPolicy.RESIZE_GAPS, |
|
312 }; |
|
313 |
|
314 JFrame frame = new JFrame(); |
|
315 Container contentPane = frame.getContentPane(); |
|
316 contentPane.setBackground(new Color( |
|
317 (int)(Math.random() * 256), |
|
318 (int)(Math.random() * 256), |
|
319 (int)(Math.random() * 256))); |
|
320 frame.setLayout( |
|
321 new GridLayout(orients.length, policies.length, 15, 15)); |
|
322 |
|
323 for (int i = 0; i < orients.length; i++) { |
|
324 for (int j = 0; j < policies.length; j++) { |
|
325 UniformLayout layout = |
|
326 new UniformLayout(orients[i], 0, policies[j]); |
|
327 |
|
328 JPanel p = new JPanel(layout); |
|
329 p.setBackground(new Color( |
|
330 (int)(Math.random() * 256), |
|
331 (int)(Math.random() * 256), |
|
332 (int)(Math.random() * 256))); |
|
333 |
|
334 char[] c = new char[] {'a', 'b', 'c', 'd'}; |
|
335 String text = ""; |
|
336 for (int k = 0; k < c.length; k++) { |
|
337 if (k != 0) { |
|
338 text += "\n"; |
|
339 } |
|
340 for (int l = 0; l < k; l++) { |
|
341 text += c[l]; |
|
342 } |
|
343 JComponent comp = new JTextArea(text); |
|
344 comp.setBorder(new LineBorder(Color.black, 1)); |
|
345 p.add(comp); |
|
346 } |
|
347 |
|
348 contentPane.add(p); |
|
349 } |
|
350 } |
|
351 |
|
352 // frame.pack(); |
|
353 GraphicsEnvironment env = |
|
354 GraphicsEnvironment.getLocalGraphicsEnvironment(); |
|
355 Rectangle bounds = env.getMaximumWindowBounds(); |
|
356 frame.setSize(bounds.width, bounds.height); |
|
357 frame.setVisible(true); |
|
358 } |
|
359 } |