|
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) 2004, 2012, Oracle and/or its affiliates. All rights reserved. |
|
24 */ |
|
25 |
|
26 |
|
27 package com.oracle.solaris.vp.panels.usermgr.client.swing; |
|
28 |
|
29 import java.awt.*; |
|
30 import javax.swing.*; |
|
31 import java.util.*; |
|
32 |
|
33 import com.oracle.solaris.vp.util.misc.finder.Finder; |
|
34 |
|
35 /** |
|
36 * SMC code adapted for Visual Panels |
|
37 * |
|
38 * This class provides the <code>DoubleTreesLayout</code> manager used |
|
39 * by the <code>DoubleTrees</code> component. The layout manager assumes |
|
40 * that the <code>DoubleTrees</code> component contains the following |
|
41 * interior components. |
|
42 * <br> |
|
43 * <code> |
|
44 * +---------------------------------------------------+ |
|
45 * | LEFT_LABEL RIGHT_LABEL | |
|
46 * | +----------------+ +----------------+ | |
|
47 * | |LEFT_SCROLLPANE | |RIGHT_SCROLLPANE| | |
|
48 * | | | +-------+ | | | |
|
49 * | | | |BUTTONS| | | | |
|
50 * | | | | | | | | |
|
51 * | | | | | | | | |
|
52 * | | | +-------+ | | | |
|
53 * | | | | | | |
|
54 * | +----------------+ +----------------+ | |
|
55 * | | |
|
56 * +---------------------------------------------------+ |
|
57 * </code> |
|
58 * <br> |
|
59 * Each component is laid out and sized with respect to its own |
|
60 * <code>DoubleTreesConstraints</code> object. |
|
61 * |
|
62 */ |
|
63 public class DoubleTreesLayout implements LayoutManager2, java.io.Serializable { |
|
64 |
|
65 protected final static Dimension ZERO_SIZE = new Dimension(0, 0); |
|
66 protected final static Dimension MAXIMUM_SIZE = |
|
67 new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE); |
|
68 |
|
69 protected Dimension size; |
|
70 protected Dimension minimumSize = new Dimension(400, 250); |
|
71 protected Dimension preferredSize = minimumSize; |
|
72 protected Dimension maximumSize; |
|
73 protected DoubleTreesConstraints defaultConstraints; |
|
74 |
|
75 /** |
|
76 * Constraints location to component map. Location key is wrapped in an |
|
77 * <code>Integer</code>. |
|
78 */ |
|
79 protected HashMap<Integer, Component> componentsMap; |
|
80 |
|
81 /** |
|
82 * Component to constraints map. |
|
83 */ |
|
84 protected HashMap<Component, DoubleTreesConstraints> constraintsMap; |
|
85 |
|
86 // ---------------------------------------------------------------------- |
|
87 |
|
88 /** |
|
89 * Construct a <code>DoubleTreesLayout<code> manager with default values. |
|
90 */ |
|
91 public DoubleTreesLayout() { |
|
92 size = ZERO_SIZE; |
|
93 maximumSize = MAXIMUM_SIZE; |
|
94 defaultConstraints = new DoubleTreesConstraints(); |
|
95 componentsMap = new HashMap<Integer, Component>(); |
|
96 constraintsMap = new HashMap<Component, DoubleTreesConstraints>(); |
|
97 } |
|
98 |
|
99 // ---------------------------------------------------------------------- |
|
100 |
|
101 /** |
|
102 * Set the constraints for a given component. If the component has |
|
103 * not previously been added to the layout, setting the components |
|
104 * constraints will add the component to the layout. |
|
105 * |
|
106 * @param component |
|
107 * Component. |
|
108 * @param constraints |
|
109 * Components constraints. |
|
110 */ |
|
111 public void setConstraints( |
|
112 Component component, |
|
113 DoubleTreesConstraints constraints) { |
|
114 addLayoutComponent(component, constraints); |
|
115 } |
|
116 |
|
117 /** |
|
118 * Get the constraints for a given component. If the component has |
|
119 * not had previously added to the layout the default constraints |
|
120 * are returned. |
|
121 * |
|
122 * @param component |
|
123 * Component. |
|
124 * @param constraints |
|
125 * Components constraints. |
|
126 */ |
|
127 public DoubleTreesConstraints getConstraints(Component component) { |
|
128 if (constraintsMap.containsKey(component)) { |
|
129 return constraintsMap.get(component); |
|
130 } else { |
|
131 return defaultConstraints; |
|
132 } |
|
133 } |
|
134 |
|
135 public void addLayoutComponent(String name, Component component) { |
|
136 // Copied from GridBayLayout. |
|
137 throw new RuntimeException("Not used by this layout manager"); |
|
138 } |
|
139 |
|
140 public void addLayoutComponent(Component component, Object object) { |
|
141 if (object == null) { |
|
142 if (!constraintsMap.containsKey(component)) { |
|
143 // No constraints for component. |
|
144 object = defaultConstraints; |
|
145 } else { |
|
146 // Don't add again. |
|
147 return; |
|
148 } |
|
149 } |
|
150 |
|
151 // Can only deal with our own constraints objects. |
|
152 if (!(object instanceof DoubleTreesConstraints)) { |
|
153 throw new RuntimeException( |
|
154 "Constraints not sub class of DoubleTreesConstraints"); |
|
155 } |
|
156 |
|
157 /** |
|
158 * Clone constraints in case caller is re-using the same constraints |
|
159 * object. |
|
160 */ |
|
161 DoubleTreesConstraints constraints = |
|
162 (DoubleTreesConstraints) ((DoubleTreesConstraints) object).clone(); |
|
163 |
|
164 // Update maps. |
|
165 componentsMap.put(new Integer(constraints.location), component); |
|
166 constraintsMap.put(component, constraints); |
|
167 |
|
168 } |
|
169 |
|
170 public void removeLayoutComponent(Component component) { |
|
171 DoubleTreesConstraints constraints = |
|
172 constraintsMap.get(component); |
|
173 |
|
174 if (constraints != null) { |
|
175 componentsMap.remove(new Integer(constraints.location)); |
|
176 } |
|
177 |
|
178 constraintsMap.remove(component); |
|
179 } |
|
180 |
|
181 public Dimension preferredLayoutSize(Container parent) { |
|
182 return preferredSize; |
|
183 } |
|
184 |
|
185 public Dimension minimumLayoutSize(Container parent) { |
|
186 return minimumSize; |
|
187 } |
|
188 |
|
189 public Dimension maximumLayoutSize(Container parent) { |
|
190 return maximumSize; |
|
191 } |
|
192 |
|
193 public float getLayoutAlignmentX(Container parent) { |
|
194 return 0.5f; |
|
195 } |
|
196 |
|
197 public float getLayoutAlignmentY(Container parent) { |
|
198 return 0.5f; |
|
199 } |
|
200 |
|
201 public void invalidateLayout(Container target) { |
|
202 } |
|
203 |
|
204 public void layoutContainer(Container parent) { |
|
205 synchronized (parent.getTreeLock()) { |
|
206 doLayoutContainer(parent); |
|
207 } |
|
208 } |
|
209 |
|
210 /** |
|
211 * Layout the components. |
|
212 * |
|
213 * @param parent |
|
214 * Container component where the <code>DoubleTrees</code> component |
|
215 * resides. |
|
216 */ |
|
217 private void doLayoutContainer(Container parent) { |
|
218 size = parent.getSize(); |
|
219 |
|
220 JComponent ll = (JComponent) componentsMap.get( |
|
221 new Integer(DoubleTreesConstraints.LEFT_LABEL)); |
|
222 DoubleTreesConstraints llc = |
|
223 constraintsMap.get(ll); |
|
224 |
|
225 JComponent rl = (JComponent) componentsMap.get( |
|
226 new Integer(DoubleTreesConstraints.RIGHT_LABEL)); |
|
227 DoubleTreesConstraints rlc = constraintsMap.get(rl); |
|
228 |
|
229 Component b = componentsMap.get( |
|
230 new Integer(DoubleTreesConstraints.BUTTONS)); |
|
231 DoubleTreesConstraints bc = constraintsMap.get(b); |
|
232 |
|
233 Component ls = componentsMap.get( |
|
234 new Integer(DoubleTreesConstraints.LEFT_SCROLLPANE)); |
|
235 DoubleTreesConstraints lsc = constraintsMap.get(ls); |
|
236 |
|
237 Component rs = componentsMap.get( |
|
238 new Integer(DoubleTreesConstraints.RIGHT_SCROLLPANE)); |
|
239 DoubleTreesConstraints rsc = constraintsMap.get(rs); |
|
240 |
|
241 double pw = parent.getSize().getWidth(); |
|
242 double ph = parent.getSize().getHeight(); |
|
243 |
|
244 double llw = ll.getPreferredSize().getWidth(); |
|
245 double llh = ll.getPreferredSize().getHeight(); |
|
246 |
|
247 double lsw = ls.getPreferredSize().getWidth(); |
|
248 double lsh = ls.getPreferredSize().getHeight(); |
|
249 |
|
250 double rlw = rl.getPreferredSize().getWidth(); |
|
251 double rlh = rl.getPreferredSize().getHeight(); |
|
252 |
|
253 double rsw = rs.getPreferredSize().getWidth(); |
|
254 double rsh = rs.getPreferredSize().getHeight(); |
|
255 |
|
256 double bw = b.getPreferredSize().getWidth(); |
|
257 double bh = b.getPreferredSize().getHeight(); |
|
258 |
|
259 // button w and h inc. insets |
|
260 |
|
261 bw += bc.insets.left + bc.insets.right; |
|
262 bh += bc.insets.top + bc.insets.bottom; |
|
263 |
|
264 // leave button w fixed, give rest of parent w to scroll panes |
|
265 |
|
266 lsw = rsw = (pw - bw) / 2.0; |
|
267 |
|
268 // left label w must not exceed left scroll pane w |
|
269 |
|
270 ls.setSize(new Dimension((int) lsw, (int) lsh)); |
|
271 |
|
272 ll.setMaximumSize(setDimensionAxis(ll.getMaximumSize(), lsw, true)); |
|
273 |
|
274 llw = lsw - llc.insets.left - llc.insets.right; |
|
275 |
|
276 ll.setSize(setDimensionAxis(ll.getSize(), llw, true)); |
|
277 |
|
278 llw = ll.getPreferredSize().getWidth(); |
|
279 llh = ll.getPreferredSize().getHeight(); |
|
280 |
|
281 // right label w must not exceed right scroll pane w |
|
282 |
|
283 rs.setSize(new Dimension((int) rsw, (int) rsh)); |
|
284 |
|
285 rl.setMaximumSize(setDimensionAxis(ll.getMaximumSize(), rsw, true)); |
|
286 |
|
287 llw = lsw - llc.insets.left - llc.insets.right; |
|
288 |
|
289 rl.setSize(setDimensionAxis(rl.getSize(), rlw, true)); |
|
290 |
|
291 rlw = rl.getPreferredSize().getWidth(); |
|
292 rlh = rl.getPreferredSize().getHeight(); |
|
293 |
|
294 // both label h must be equal and accomodate both labels |
|
295 |
|
296 double lh = Math.max( |
|
297 llh + llc.insets.top + llc.insets.bottom, |
|
298 rlh + rlc.insets.top + rlc.insets.bottom); |
|
299 |
|
300 ll.setSize(new Dimension((int) lsw, (int) lh)); |
|
301 |
|
302 rl.setSize(new Dimension((int) rsw, (int) lh)); |
|
303 |
|
304 // both label w must not exceed scroll pane w |
|
305 |
|
306 llw = lsw; |
|
307 rlw = rsw; |
|
308 |
|
309 // scroll pane h gets rest of parent h after label h allocated |
|
310 |
|
311 lsh = rsh = ph - lh; |
|
312 |
|
313 ls.setSize(new Dimension((int) lsw, (int) lsh)); |
|
314 rs.setSize(new Dimension((int) rsw, (int) rsh)); |
|
315 b.setSize(new Dimension((int) bw, (int) bh)); |
|
316 |
|
317 // see if we have a preferred size > minimum size |
|
318 |
|
319 if (preferredSize == minimumSize) { |
|
320 int w = (int) (lsw + bw + rsw); |
|
321 int h = (int) (lh + lsh); |
|
322 |
|
323 w = Math.max(w, (int) minimumSize.getWidth()); |
|
324 h = Math.max(h, (int) minimumSize.getHeight()); |
|
325 |
|
326 preferredSize = new Dimension(w, h); |
|
327 } |
|
328 |
|
329 // set locations for labels, scroll panes and buttons |
|
330 |
|
331 int llx = 0; |
|
332 int lly = 0; |
|
333 |
|
334 int lsx = 0; |
|
335 int lsy = lly + (int) lh; |
|
336 |
|
337 int bx = lsx + (int) lsw; |
|
338 int by = (int) (lh + (lsh - bh) / 2); |
|
339 |
|
340 int rlx = bx + (int) bw; |
|
341 int rly = 0; |
|
342 |
|
343 int rsx = bx + (int) bw; |
|
344 int rsy = rly + (int) lh; |
|
345 |
|
346 ll.setLocation(llx, lly); |
|
347 ls.setLocation(lsx, lsy); |
|
348 rs.setLocation(rsx, rsy); |
|
349 rl.setLocation(rlx, rly); |
|
350 b.setLocation(bx, by); |
|
351 |
|
352 // adjust size and locations to accomodate insets |
|
353 |
|
354 includeInsets(ll, llc.insets); |
|
355 includeInsets(rl, rlc.insets); |
|
356 includeInsets(ls, lsc.insets); |
|
357 includeInsets(rs, rsc.insets); |
|
358 includeInsets(b, bc.insets); |
|
359 } |
|
360 |
|
361 /** |
|
362 * Adjust components size and location to accomodate an <code>Inset</code>. |
|
363 * |
|
364 * @param component |
|
365 * Component to be resized and relocated. |
|
366 * @param insets |
|
367 * Inserts that must surround the component. |
|
368 */ |
|
369 private void includeInsets(Component component, Insets insets) { |
|
370 Point location = component.getLocation(); |
|
371 Dimension size = component.getSize(); |
|
372 |
|
373 double x = location.getX(); |
|
374 double y = location.getY(); |
|
375 double width = size.getWidth(); |
|
376 double height = size.getHeight(); |
|
377 |
|
378 component.setLocation( |
|
379 (int) (x + insets.left), |
|
380 (int) (y + insets.top)); |
|
381 component.setSize( |
|
382 (int) (width - insets.left - insets.right), |
|
383 (int) (height - insets.top - insets.bottom)); |
|
384 } |
|
385 |
|
386 // ---------------------------------------------------------------------- |
|
387 |
|
388 /** |
|
389 * Get axis of a <code>Dimension</code>. |
|
390 * |
|
391 * @param dimension |
|
392 * <code>Dimension</code> being inspected. |
|
393 * @param xAxis |
|
394 * True if the width (X axis) is required, otherwise false if the |
|
395 * height (Y axis) is required. |
|
396 * @return |
|
397 * Required axis value. |
|
398 */ |
|
399 private double getDimensionAxis(Dimension dimension, boolean xAxis) { |
|
400 if (xAxis) { |
|
401 return dimension.getWidth(); |
|
402 } else { |
|
403 return dimension.getHeight(); |
|
404 } |
|
405 } |
|
406 |
|
407 /** |
|
408 * Set axis of a <code>Dimension</code>. |
|
409 * |
|
410 * @param dimension |
|
411 * <code>Dimension</code> being modified. |
|
412 * @param value |
|
413 * New axis value. |
|
414 * @param xAxis |
|
415 * True if the width (X axis) is required, otherwise false if the |
|
416 * height (Y axis) is required. |
|
417 * @return |
|
418 * The modified <code>Dimension</code>. |
|
419 */ |
|
420 private Dimension setDimensionAxis( |
|
421 Dimension dimension, |
|
422 double value, |
|
423 boolean xAxis) { |
|
424 if (xAxis) { |
|
425 dimension.setSize(value, dimension.getHeight()); |
|
426 } else { |
|
427 dimension.setSize(dimension.getWidth(), value); |
|
428 } |
|
429 |
|
430 return dimension; |
|
431 } |
|
432 |
|
433 /** |
|
434 * Set axis of a <code>Dimension</code>. |
|
435 * |
|
436 * @param dimension |
|
437 * <code>Dimension</code> being modified. |
|
438 * @param value |
|
439 * New axis value. |
|
440 * @param xAxis |
|
441 * True if the width (X axis) is required, otherwise false if the |
|
442 * height (Y axis) is required. |
|
443 * @return |
|
444 * The modified <code>Dimension</code>. |
|
445 */ |
|
446 private Dimension setDimensionAxis( |
|
447 Dimension dimension, |
|
448 int value, |
|
449 boolean xAxis) { |
|
450 return setDimensionAxis(dimension, (double) value, xAxis); |
|
451 } |
|
452 |
|
453 } |