1 /*
2  * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 package javax.swing;
26 
27 
28 import java.awt.*;
29 import java.beans.ConstructorProperties;
30 import java.io.Serializable;
31 
32 /**
33  * A layout manager to arrange components over the top
34  * of each other.  The requested size of the container
35  * will be the largest requested size of the children,
36  * taking alignment needs into consideration.
37  *
38  * The alignment is based upon what is needed to properly
39  * fit the children in the allocation area.  The children
40  * will be placed such that their alignment points are all
41  * on top of each other.
42  * <p>
43  * <strong>Warning:</strong>
44  * Serialized objects of this class will not be compatible with
45  * future Swing releases. The current serialization support is
46  * appropriate for short term storage or RMI between applications running
47  * the same version of Swing.  As of 1.4, support for long term storage
48  * of all JavaBeans
49  * has been added to the <code>java.beans</code> package.
50  * Please see {@link java.beans.XMLEncoder}.
51  *
52  * @author   Timothy Prinzing
53  * @since 1.2
54  */
55 @SuppressWarnings("serial") // Same-version serialization only
56 public class OverlayLayout implements LayoutManager2,Serializable {
57 
58     /**
59      * Constructs a layout manager that performs overlay
60      * arrangement of the children.  The layout manager
61      * created is dedicated to the given container.
62      *
63      * @param target  the container to do layout against
64      */
65     @ConstructorProperties({"target"})
OverlayLayout(Container target)66     public OverlayLayout(Container target) {
67         this.target = target;
68     }
69 
70     /**
71      * Returns the container that uses this layout manager.
72      *
73      * @return the container that uses this layout manager
74      *
75      * @since 1.6
76      */
getTarget()77     public final Container getTarget() {
78         return this.target;
79     }
80 
81     /**
82      * Indicates a child has changed its layout related information,
83      * which causes any cached calculations to be flushed.
84      *
85      * @param target the container
86      */
invalidateLayout(Container target)87     public void invalidateLayout(Container target) {
88         checkContainer(target);
89         xChildren = null;
90         yChildren = null;
91         xTotal = null;
92         yTotal = null;
93     }
94 
95     /**
96      * Adds the specified component to the layout. Used by
97      * this class to know when to invalidate layout.
98      *
99      * @param name the name of the component
100      * @param comp the component to be added
101      */
addLayoutComponent(String name, Component comp)102     public void addLayoutComponent(String name, Component comp) {
103         invalidateLayout(comp.getParent());
104     }
105 
106     /**
107      * Removes the specified component from the layout. Used by
108      * this class to know when to invalidate layout.
109      *
110      * @param comp the component to remove
111      */
removeLayoutComponent(Component comp)112     public void removeLayoutComponent(Component comp) {
113         invalidateLayout(comp.getParent());
114     }
115 
116     /**
117      * Adds the specified component to the layout, using the specified
118      * constraint object. Used by this class to know when to invalidate
119      * layout.
120      *
121      * @param comp the component to be added
122      * @param constraints  where/how the component is added to the layout.
123      */
addLayoutComponent(Component comp, Object constraints)124     public void addLayoutComponent(Component comp, Object constraints) {
125         invalidateLayout(comp.getParent());
126     }
127 
128     /**
129      * Returns the preferred dimensions for this layout given the components
130      * in the specified target container.  Recomputes the layout if it
131      * has been invalidated.  Factors in the current inset setting returned
132      * by getInsets().
133      *
134      * @param target the component which needs to be laid out
135      * @return a Dimension object containing the preferred dimensions
136      * @see #minimumLayoutSize
137      */
preferredLayoutSize(Container target)138     public Dimension preferredLayoutSize(Container target) {
139         checkContainer(target);
140         checkRequests();
141 
142         Dimension size = new Dimension(xTotal.preferred, yTotal.preferred);
143         Insets insets = target.getInsets();
144         size.width += insets.left + insets.right;
145         size.height += insets.top + insets.bottom;
146         return size;
147     }
148 
149     /**
150      * Returns the minimum dimensions needed to lay out the components
151      * contained in the specified target container.  Recomputes the layout
152      * if it has been invalidated, and factors in the current inset setting.
153      *
154      * @param target the component which needs to be laid out
155      * @return a Dimension object containing the minimum dimensions
156      * @see #preferredLayoutSize
157      */
minimumLayoutSize(Container target)158     public Dimension minimumLayoutSize(Container target) {
159         checkContainer(target);
160         checkRequests();
161 
162         Dimension size = new Dimension(xTotal.minimum, yTotal.minimum);
163         Insets insets = target.getInsets();
164         size.width += insets.left + insets.right;
165         size.height += insets.top + insets.bottom;
166         return size;
167     }
168 
169     /**
170      * Returns the maximum dimensions needed to lay out the components
171      * contained in the specified target container.  Recomputes the
172      * layout if it has been invalidated, and factors in the inset setting
173      * returned by <code>getInset</code>.
174      *
175      * @param target the component that needs to be laid out
176      * @return a <code>Dimension</code> object containing the maximum
177      *         dimensions
178      * @see #preferredLayoutSize
179      */
maximumLayoutSize(Container target)180     public Dimension maximumLayoutSize(Container target) {
181         checkContainer(target);
182         checkRequests();
183 
184         Dimension size = new Dimension(xTotal.maximum, yTotal.maximum);
185         Insets insets = target.getInsets();
186         size.width += insets.left + insets.right;
187         size.height += insets.top + insets.bottom;
188         return size;
189     }
190 
191     /**
192      * Returns the alignment along the x axis for the container.
193      *
194      * @param target the container
195      * @return the alignment &gt;= 0.0f &amp;&amp; &lt;= 1.0f
196      */
getLayoutAlignmentX(Container target)197     public float getLayoutAlignmentX(Container target) {
198         checkContainer(target);
199         checkRequests();
200         return xTotal.alignment;
201     }
202 
203     /**
204      * Returns the alignment along the y axis for the container.
205      *
206      * @param target the container
207      * @return the alignment &gt;= 0.0f &amp;&amp; &lt;= 1.0f
208      */
getLayoutAlignmentY(Container target)209     public float getLayoutAlignmentY(Container target) {
210         checkContainer(target);
211         checkRequests();
212         return yTotal.alignment;
213     }
214 
215     /**
216      * Called by the AWT when the specified container needs to be laid out.
217      *
218      * @param target  the container to lay out
219      *
220      * @exception AWTError  if the target isn't the container specified to the
221      *                      constructor
222      */
layoutContainer(Container target)223     public void layoutContainer(Container target) {
224         checkContainer(target);
225         checkRequests();
226 
227         int nChildren = target.getComponentCount();
228         int[] xOffsets = new int[nChildren];
229         int[] xSpans = new int[nChildren];
230         int[] yOffsets = new int[nChildren];
231         int[] ySpans = new int[nChildren];
232 
233         // determine the child placements
234         Dimension alloc = target.getSize();
235         Insets in = target.getInsets();
236         alloc.width -= in.left + in.right;
237         alloc.height -= in.top + in.bottom;
238         SizeRequirements.calculateAlignedPositions(alloc.width, xTotal,
239                                                    xChildren, xOffsets,
240                                                    xSpans);
241         SizeRequirements.calculateAlignedPositions(alloc.height, yTotal,
242                                                    yChildren, yOffsets,
243                                                    ySpans);
244 
245         // flush changes to the container
246         for (int i = 0; i < nChildren; i++) {
247             Component c = target.getComponent(i);
248             c.setBounds(in.left + xOffsets[i], in.top + yOffsets[i],
249                         xSpans[i], ySpans[i]);
250         }
251     }
252 
checkContainer(Container target)253     void checkContainer(Container target) {
254         if (this.target != target) {
255             throw new AWTError("OverlayLayout can't be shared");
256         }
257     }
258 
checkRequests()259     void checkRequests() {
260         if (xChildren == null || yChildren == null) {
261             // The requests have been invalidated... recalculate
262             // the request information.
263             int n = target.getComponentCount();
264             xChildren = new SizeRequirements[n];
265             yChildren = new SizeRequirements[n];
266             for (int i = 0; i < n; i++) {
267                 Component c = target.getComponent(i);
268                 Dimension min = c.getMinimumSize();
269                 Dimension typ = c.getPreferredSize();
270                 Dimension max = c.getMaximumSize();
271                 xChildren[i] = new SizeRequirements(min.width, typ.width,
272                                                     max.width,
273                                                     c.getAlignmentX());
274                 yChildren[i] = new SizeRequirements(min.height, typ.height,
275                                                     max.height,
276                                                     c.getAlignmentY());
277             }
278 
279             xTotal = SizeRequirements.getAlignedSizeRequirements(xChildren);
280             yTotal = SizeRequirements.getAlignedSizeRequirements(yChildren);
281         }
282     }
283 
284     private Container target;
285     private SizeRequirements[] xChildren;
286     private SizeRequirements[] yChildren;
287     private SizeRequirements xTotal;
288     private SizeRequirements yTotal;
289 
290 }
291