1 /*
2 * Copyright 2006-2016 The JGUIraffe Team.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License")
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package net.sf.jguiraffe.gui.platform.swing.layout;
17
18 import java.awt.Component;
19 import java.awt.Container;
20 import java.awt.Dimension;
21 import java.awt.Insets;
22 import java.awt.LayoutManager2;
23 import java.awt.Rectangle;
24 import java.io.Serializable;
25 import java.util.ArrayList;
26 import java.util.List;
27
28 import net.sf.jguiraffe.gui.layout.PercentLayoutBase;
29 import net.sf.jguiraffe.gui.layout.PercentLayoutPlatformAdapter;
30 import net.sf.jguiraffe.gui.layout.UnitSizeHandler;
31
32 /**
33 * <p>
34 * Implementation of a Swing-specific adapter class for the percent layout
35 * manager.
36 * </p>
37 * <p>
38 * This class implements the percent layout manager for swing. It implements the
39 * <code>LayoutManager2</code> interface and can be used as a standard Swing
40 * layout.
41 * </p>
42 *
43 * @author Oliver Heger
44 * @version $Id: SwingPercentLayoutAdapter.java 205 2012-01-29 18:29:57Z oheger $
45 */
46 public class SwingPercentLayoutAdapter implements LayoutManager2,
47 PercentLayoutPlatformAdapter, Serializable
48 {
49 /**
50 * The serial version UID.
51 */
52 private static final long serialVersionUID = 20090730L;
53
54 /** Stores a reference to the associated percent layout object. */
55 private final PercentLayoutBase percentLayout;
56
57 /** Stores the contained components and their constraints. */
58 private final List<ConstraintsData> components;
59
60 /** Stores the size handler used by this layout. */
61 private final UnitSizeHandler sizeHandler = new SwingSizeHandler();
62
63 /**
64 * Creates a new instance of {@code SwingPercentLayouAdaptert} and sets the
65 * associated percent layout.
66 *
67 * @param percentLayout the percent layout object (must not be <b>null</b>)
68 * @throws IllegalArgumentException if the {@code PercentLayoutBase} object
69 * is <b>null</b>
70 */
71 public SwingPercentLayoutAdapter(PercentLayoutBase percentLayout)
72 {
73 if (percentLayout == null)
74 {
75 throw new IllegalArgumentException(
76 "Percent layout must not be null!");
77 }
78
79 this.percentLayout = percentLayout;
80 percentLayout.setPlatformAdapter(this);
81 components = new ArrayList<ConstraintsData>();
82 }
83
84 /**
85 * Returns a reference to the associated percent layout object.
86 *
87 * @return the percent layout object
88 */
89 public PercentLayoutBase getPercentLayout()
90 {
91 return percentLayout;
92 }
93
94 /**
95 * Returns the layout alignment in X direction.
96 *
97 * @param container the associated container
98 * @return the layout alignment in X direction
99 */
100 public float getLayoutAlignmentX(Container container)
101 {
102 return 0;
103 }
104
105 /**
106 * Returns the layout alignment in Y direction.
107 *
108 * @param container the associated container
109 * @return the layout alignment in Y direction
110 */
111 public float getLayoutAlignmentY(Container container)
112 {
113 return 0;
114 }
115
116 /**
117 * Invalidates this layout. Clears all cached values.
118 *
119 * @param container the associated container
120 */
121 public void invalidateLayout(Container container)
122 {
123 invalidate();
124 }
125
126 /**
127 * Returns the maximum layout size. For this layout type there is no upper
128 * limit.
129 *
130 * @param container the container
131 * @return the maximum layout size
132 */
133 public Dimension maximumLayoutSize(Container container)
134 {
135 return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
136 }
137
138 /**
139 * Adds a component to this layout.
140 *
141 * @param comp the component to add
142 * @param constraints the constraints
143 */
144 public void addLayoutComponent(Component comp, Object constraints)
145 {
146 components.add(new ConstraintsData(comp, constraints));
147 invalidate();
148 }
149
150 /**
151 * Adds a component to this layout manager using the given name as
152 * constraints object.
153 *
154 * @param name the name
155 * @param comp the component
156 */
157 public void addLayoutComponent(String name, Component comp)
158 {
159 addLayoutComponent(comp, name);
160 }
161
162 /**
163 * Removes the specified component from the layout manager.
164 *
165 * @param c the component to remove
166 */
167 public void removeLayoutComponent(Component c)
168 {
169 int index = -1;
170 for (int i = 0; i < components.size() && index < 0; i++)
171 {
172 ConstraintsData cd = components.get(i);
173 if (cd.getComponent().equals(c))
174 {
175 index = i;
176 }
177 }
178
179 if (index >= 0)
180 {
181 components.remove(index);
182 getPercentLayout().removeComponent(c);
183 }
184 }
185
186 /**
187 * Determines the coordinates and sizes of all components that belong to
188 * this layout.
189 *
190 * @param container the associated container
191 */
192 public void layoutContainer(Container container)
193 {
194 synchronized (container.getTreeLock())
195 {
196 Insets insets = container.getInsets();
197 Dimension size = container.getSize();
198 getPercentLayout().performLayout(
199 container,
200 new Rectangle(insets.left, insets.top, insets.right,
201 insets.bottom), size);
202 }
203 }
204
205 /**
206 * Returns the minimum size of this layout. For this layout type this equals
207 * the preferred layout size.
208 *
209 * @param container the associated container
210 * @return the minimum layout size
211 */
212 public Dimension minimumLayoutSize(Container container)
213 {
214 return addInsets(getPercentLayout().calcMinimumLayoutSize(container),
215 container);
216 }
217
218 /**
219 * Returns the preferred size of this layout.
220 *
221 * @param container the associated container
222 * @return the preferred layout size
223 */
224 public Dimension preferredLayoutSize(Container container)
225 {
226 return addInsets(getPercentLayout().calcPreferredLayoutSize(container),
227 container);
228 }
229
230 /**
231 * Returns the size handler used by this layout. This happens to be a swing
232 * size handler.
233 *
234 * @return the size handler
235 */
236 public UnitSizeHandler getSizeHandler()
237 {
238 return sizeHandler;
239 }
240
241 /**
242 * Returns the number of components in this layout.
243 *
244 * @return the number of components
245 */
246 public int getComponentCount()
247 {
248 return components.size();
249 }
250
251 /**
252 * Returns the component with the given index.
253 *
254 * @param index the index
255 * @return the component with this index
256 */
257 public Object getComponent(int index)
258 {
259 return components.get(index).getComponent();
260 }
261
262 /**
263 * Returns the constraints for the component with the given index.
264 *
265 * @param index the index
266 * @return the constraints for the specified component
267 */
268 public Object getConstraints(int index)
269 {
270 return components.get(index).getConstraints();
271 }
272
273 /**
274 * Returns the minimum size of the specified component in the given axis.
275 *
276 * @param component the component
277 * @param vert the flag for the axis
278 * @return the minimum component size
279 */
280 public int getMinimumComponentSize(Object component, boolean vert)
281 {
282 Dimension d = ((Component) component).getMinimumSize();
283 return PercentLayoutBase.getOrientationValue(d.width, d.height, vert);
284 }
285
286 /**
287 * Returns the preferred size of the specified component in the given axis.
288 *
289 * @param component the component
290 * @param vert the flag for the axis
291 * @return the preferred component size
292 */
293 public int getPreferredComponentSize(Object component, boolean vert)
294 {
295 Dimension d = ((Component) component).getPreferredSize();
296 return PercentLayoutBase.getOrientationValue(d.width, d.height, vert);
297 }
298
299 /**
300 * Initializes the bounds for the specified component.
301 *
302 * @param component the component
303 * @param bounds the new bounds
304 */
305 public void setComponentBounds(Object component, Rectangle bounds)
306 {
307 ((Component) component).setBounds(bounds);
308 }
309
310 /**
311 * Invalidates the associated percent layout.
312 */
313 private void invalidate()
314 {
315 getPercentLayout().flushCache();
316 }
317
318 /**
319 * Adds the container's insets to the specified dimension object.
320 *
321 * @param size the dimension object
322 * @param container the container
323 * @return the modified dimensions
324 */
325 private static Dimension addInsets(Dimension size, Container container)
326 {
327 Insets insets = container.getInsets();
328 size.width += insets.left + insets.right;
329 size.height += insets.top + insets.bottom;
330 return size;
331 }
332
333 /**
334 * A helper class for storing information about a component and its
335 * constraints.
336 */
337 static class ConstraintsData implements Serializable
338 {
339 /**
340 * The serial version UID.
341 */
342 private static final long serialVersionUID = 20090730L;
343
344 /** Stores the component. */
345 private final Component component;
346
347 /** Stores the constraints object for this component. */
348 private final Object constraints;
349
350 /**
351 * Creates a new instance of <code>ConstraintsData</code> and
352 * initializes it.
353 *
354 * @param comp the component
355 * @param constr the constraints
356 */
357 public ConstraintsData(Component comp, Object constr)
358 {
359 component = comp;
360 constraints = constr;
361 }
362
363 /**
364 * Returns the component.
365 *
366 * @return the component
367 */
368 public Component getComponent()
369 {
370 return component;
371 }
372
373 /**
374 * Returns the constraints.
375 *
376 * @return the constraints
377 */
378 public Object getConstraints()
379 {
380 return constraints;
381 }
382 }
383 }