View Javadoc

1   /*
2      Copyright 2002-2006 Martin van den Bemt
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 org.xulux.guilayer.swing.layouts;
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.HashMap;
26  
27  import javax.swing.JComponent;
28  
29  import org.xulux.api.gui.IWidget;
30  
31  /**
32   * A layout manager that positions it's controls
33   * using the size and the position of the control
34   *
35   * @todo Fix insets problem when more native components are present than 1
36   * The insets seems to tamper with the bounds of native components.
37   * We should have a map or list to maintain processed components, so
38   * on first entry it doesn't do the bounds restore..
39   *
40   * @author <a href="mailto:martin@mvdb.net">Martin van den Bemt</a>
41   * @version $Id: XYLayout.java,v 1.8 2004/10/14 14:34:20 mvdb Exp $
42   */
43  public class XYLayout extends SwingLayoutAbstract implements LayoutManager2, Serializable {
44      /**
45       * the map with widgets
46       */
47      protected HashMap map;
48  
49      /**
50       * Is this the first time the gui is layout?
51       */
52      private boolean firstLayout = true;
53  
54      /**
55       *
56       */
57      public XYLayout() {
58          map = new HashMap();
59      }
60  
61      /**
62       * Use this contructor if used inside nyx.
63       * @param parent the creator of the XYLayout
64       */
65      public XYLayout(IWidget parent) {
66          map = new HashMap();
67          setParent(parent);
68      }
69  
70      /**
71       * The contraints is the widget itself.
72       * @see java.awt.LayoutManager2#addLayoutComponent(Component, Object)
73       */
74      public void addLayoutComponent(Component comp, Object constraints) {
75          map.put(comp, constraints);
76      }
77  
78      /**
79       * @see java.awt.LayoutManager2#getLayoutAlignmentX(Container)
80       */
81      public float getLayoutAlignmentX(Container target) {
82          return 0.5F;
83      }
84  
85      /**
86       * @see java.awt.LayoutManager2#getLayoutAlignmentY(Container)
87       */
88      public float getLayoutAlignmentY(Container target) {
89          return 0.5F;
90      }
91  
92      /**
93       * @see java.awt.LayoutManager2#invalidateLayout(Container)
94       */
95      public void invalidateLayout(Container target) {
96      }
97  
98      /**
99       * @see java.awt.LayoutManager2#maximumLayoutSize(Container)
100      */
101     public Dimension maximumLayoutSize(Container target) {
102         return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
103     }
104 
105     /**
106      * @see java.awt.LayoutManager#addLayoutComponent(String, Component)
107      */
108     public void addLayoutComponent(String name, Component comp) {
109     }
110 
111     /**
112      * @see java.awt.LayoutManager#layoutContainer(Container)
113      */
114     public void layoutContainer(Container parent) {
115         if (parent == null) {
116             return;
117         }
118         synchronized (parent.getTreeLock()) {
119         Insets insets = parent.getInsets();
120         int count = parent.getComponentCount();
121         for (int i = 0; i < count; i++) {
122             Component component = parent.getComponent(i);
123             if (!component.isVisible()) {
124                 continue;
125             }
126             IWidget widget = (IWidget) map.get(component);
127             Rectangle r = null;
128             if (widget != null && widget.isVisible()) {
129                 r = getRectangle(widget, component);
130                 if (component instanceof JComponent) {
131                     ((JComponent) component).setPreferredSize(new Dimension(r.width, r.height));
132                 }
133                 component.setSize(r.width, r.height);
134             } else {
135                 // if component is not a widget
136                 // so layed on top of xulux, try to get all the info from
137                 // the component. It's up to the component
138                 // to set sizes etc and handle all other
139                 // logic.
140                 r = getRectangle(component, insets);
141             }
142             // r cannot be null in this scenario
143             component.setBounds(insets.left + r.x, insets.top + r.y, r.width, r.height);
144         }
145         }
146     }
147 
148     /**
149      * The preferred size of the component is used, when the widget
150      * size isn't really useable...
151      *
152      * @param widget the widget to get the size from
153      * @param component the component to get the size from
154      * @return the rectangle of the component
155      */
156     public Rectangle getRectangle(IWidget widget, Component component) {
157         if (widget == null) {
158             return null;
159         }
160         Rectangle r = widget.getRectangle().getRectangle();
161         if (r.width <= 0 && r.height <= 0) {
162             Dimension d = component.getPreferredSize();
163             if (d != null) {
164               // prevent crashes on bad layoutmanagers.
165               // a layoutmanager which returns null on preferredLayoutSize
166               // would result in a crash here, preventing the a further layout..
167               r.width = d.width;
168               r.height = d.height;
169               widget.getRectangle().setSize(r.width, r.height);
170             }
171         }
172         return r;
173     }
174 
175     /**
176      * This is mainly used for swing components that are
177      * layed "invisibly" on top of nyx.
178      * You should use setLocation(x,y) to position the
179      * Swing component correctly.
180      *
181      * @param component the component
182      * @param insets the insets
183      * @return the rectangle for a native swing component
184      */
185     public Rectangle getRectangle(Component component, Insets insets) {
186 
187         if (component == null) {
188             return null;
189         }
190         Rectangle r = component.getBounds();
191         // we need to correct the insets when the first run alrady
192         // has taken place.
193         if (!isFirstLayout()) {
194             if (insets != null) {
195                 r.x -= insets.left;
196                 r.y -= insets.top;
197                 component.setBounds(r);
198             }
199         } else {
200             setFirstLayout(false);
201         }
202         Dimension d = component.getPreferredSize();
203         r.width = d.width;
204         r.height = d.height;
205         return r;
206     }
207 
208     /**
209      * @see java.awt.LayoutManager#minimumLayoutSize(Container)
210      */
211     public Dimension minimumLayoutSize(Container parent) {
212         return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
213     }
214 
215     /**
216      * @see java.awt.LayoutManager#preferredLayoutSize(Container)
217      */
218     public Dimension preferredLayoutSize(Container parent) {
219         Dimension dim = getLayoutSize(parent);
220         return dim;
221     }
222 
223     /**
224      * is almost the same as layoutContainer,
225      * except using setBounds.
226      * If the size of the widget is not set (0 or less than zero)
227      * it will use the preferredsize of the native component, which
228      * is gotten from getRectangle().
229      * @todo write a helper class to give some feedback to the developer
230      *       on what sizes should be preferred, to have everything fit!
231      *       now it just makes the sizes of eg a panel bigger if the insets
232      *       are bigger than 0
233      * @todo dig into the insets stuff deeper and find scenarios where it can fail
234      * @param parent the parent container
235      * @return the layoutsize
236      */
237     protected Dimension getLayoutSize(Container parent) {
238         Dimension dim = new Dimension(0, 0);
239         IWidget pWidget = (IWidget) map.get(parent);
240         int maxX = 0;
241         int maxY = 0;
242         for (int i = 0; i < parent.getComponentCount(); i++) {
243             Component component = parent.getComponent(i);
244             IWidget widget = (IWidget) map.get(component);
245             if (widget != null && widget.isVisible()) {
246                 Rectangle r = getRectangle(widget, component);
247                 int tmpWidth = r.x + r.width;
248                 if (tmpWidth > maxX) {
249                     maxX = tmpWidth;
250                 }
251                 int tmpHeight = r.y + r.height;
252                 if (tmpHeight > maxY) {
253                     maxY = tmpHeight;
254                 }
255             } else if (widget == null) { //if (widget == null) {
256                 // only process when there is no widget
257                 Dimension compDim = component.getPreferredSize();
258                 maxX += compDim.width;
259                 maxY += compDim.height;
260             }
261         }
262         dim.width = maxX;
263         dim.height = maxY;
264 
265         Insets insets = parent.getInsets();
266         dim.width += insets.left + insets.right;
267         dim.height += insets.top + insets.bottom;
268         return dim;
269     }
270 
271     /**
272      * Set if this is the first time that we layout or not
273      * @param firstLayout true or false
274      */
275     protected void setFirstLayout(boolean firstLayout) {
276         this.firstLayout = firstLayout;
277     }
278 
279     /**
280      * @return if the layout still needs to process it's first layout
281      */
282     protected boolean isFirstLayout() {
283         return this.firstLayout;
284     }
285 
286     /**
287      * @see java.awt.LayoutManager#removeLayoutComponent(Component)
288      */
289     public void removeLayoutComponent(Component comp) {
290         map.remove(comp);
291     }
292 
293     /**
294      * @see org.xulux.gui.IXuluxLayout#destroy()
295      */
296     public void destroy() {
297     }
298 
299     /**
300      * @see org.xulux.api.gui.IXuluxLayout#addWidget(org.xulux.api.gui.IWidget)
301      */
302     public void addWidget(IWidget widget) {
303       Object nativeWidget = widget.getNativeWidget();
304       if (nativeWidget instanceof Component) {
305         addLayoutComponent((Component) nativeWidget, widget);
306       }
307     }
308 
309     /**
310      * @see org.xulux.api.gui.IXuluxLayout#removeWidget(org.xulux.api.gui.IWidget)
311      */
312     public void removeWidget(IWidget widget) {
313       Object nativeWidget = widget.getNativeWidget();
314       if (nativeWidget instanceof Component) {
315         removeLayoutComponent((Component) nativeWidget);
316       }
317     }
318 }