View Javadoc

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 }