45 |
import java.awt.Insets; |
import java.awt.Insets; |
46 |
import java.awt.LayoutManager2; |
import java.awt.LayoutManager2; |
47 |
import java.io.Serializable; |
import java.io.Serializable; |
|
import java.util.Collection; |
|
|
import java.util.Iterator; |
|
|
import java.util.List; |
|
|
import java.util.Vector; |
|
|
|
|
|
import gnu.java.awt.AWTUtilities; |
|
48 |
|
|
49 |
/** |
/** |
50 |
* A layout that stacks the children of a container in a Box, either |
* A layout that stacks the children of a container in a Box, either |
57 |
{ |
{ |
58 |
|
|
59 |
/** |
/** |
|
* This is an abstraction that allows the BoxLayout algorithm to |
|
|
* be applied to both direction (X and Y) without duplicating the |
|
|
* algorithm. It defines several methods that access properties of |
|
|
* a component for a specific direction. |
|
|
*/ |
|
|
static interface Direction |
|
|
{ |
|
|
/** |
|
|
* Returns the correct part of <code>d</code> for this direction. This will |
|
|
* be <code>d.width</code> for horizontal and <code>d.height</code> for |
|
|
* vertical direction. |
|
|
* |
|
|
* @param d the size as Dimension object |
|
|
* |
|
|
* @return the correct part of <code>d</code> for this direction |
|
|
*/ |
|
|
int size(Dimension d); |
|
|
|
|
|
/** |
|
|
* Returns the lower bounds of the {@link Insets} object according to this |
|
|
* direction. This will be <code>insets.top</code> for vertical direction |
|
|
* and <code>insets.left</code> for horizontal direction. |
|
|
* |
|
|
* @param the {@link Insets} object from which to return the lower bounds |
|
|
* |
|
|
* @return the lower bounds of the {@link Insets} object according to this |
|
|
* direction |
|
|
*/ |
|
|
int lower(Insets insets); |
|
|
|
|
|
/** |
|
|
* Returns the alignment property according to this direction. |
|
|
* |
|
|
* @param comp the Component for which to return the alignment property |
|
|
* |
|
|
* @return the alignment property according to this direction |
|
|
*/ |
|
|
float alignment(Component comp); |
|
|
|
|
|
/** |
|
|
* Sets the location for Component <code>c</code>. <code>coord1</code> |
|
|
* specifies the coordinate of the location in this direction, |
|
|
* <code>coord2</code> the coordinate of the location in the opposite |
|
|
* direction. |
|
|
* |
|
|
* @param c the Component for which to set the location |
|
|
* @param coord1 the coordinate in this direction |
|
|
* @param coord2 the coordinate in the opposite direction |
|
|
*/ |
|
|
void setLocation(Component c, int coord1, int coord2); |
|
|
|
|
|
/** |
|
|
* Sets the size for Component <code>c</code>. <code>coord1</code> |
|
|
* specifies the size in this direction, |
|
|
* <code>coord2</code> the size in the opposite |
|
|
* direction. |
|
|
* |
|
|
* @param c the Component for which to set the size |
|
|
* @param size1 the size in this direction |
|
|
* @param size2 the size in the opposite direction |
|
|
*/ |
|
|
void setSize(Component c, int size1, int size2); |
|
|
} |
|
|
|
|
|
/** |
|
|
* The horizontal direction. |
|
|
*/ |
|
|
static class Horizontal implements Direction |
|
|
{ |
|
|
/** |
|
|
* Returns the correct part of <code>d</code> for this direction. This will |
|
|
* be <code>d.width</code> for horizontal and <code>d.height</code> for |
|
|
* vertical direction. |
|
|
* |
|
|
* @param d the size as Dimension object |
|
|
* |
|
|
* @return the correct part of <code>d</code> for this direction |
|
|
*/ |
|
|
public int size(Dimension d) |
|
|
{ |
|
|
return d.width; |
|
|
} |
|
|
|
|
|
/** |
|
|
* Returns the lower bounds of the {@link Insets} object according to this |
|
|
* direction. This will be <code>insets.top</code> for vertical direction |
|
|
* and <code>insets.left</code> for horizontal direction. |
|
|
* |
|
|
* @param insets the {@link Insets} object from which to return the lower |
|
|
* bounds |
|
|
* |
|
|
* @return the lower bounds of the {@link Insets} object according to this |
|
|
* direction |
|
|
*/ |
|
|
public int lower(Insets insets) |
|
|
{ |
|
|
return insets.left; |
|
|
} |
|
|
|
|
|
/** |
|
|
* Returns the alignment property according to this direction. |
|
|
* |
|
|
* @param comp the Component for which to return the alignment property |
|
|
* |
|
|
* @return the alignment property according to this direction |
|
|
*/ |
|
|
public float alignment(Component comp) |
|
|
{ |
|
|
return comp.getAlignmentX(); |
|
|
} |
|
|
|
|
|
/** |
|
|
* Sets the location for Component <code>c</code>. <code>coord1</code> |
|
|
* specifies the coordinate of the location in this direction, |
|
|
* <code>coord2</code> the coordinate of the location in the opposite |
|
|
* direction. |
|
|
* |
|
|
* @param c the Component for which to set the location |
|
|
* @param coord1 the coordinate in this direction |
|
|
* @param coord2 the coordinate in the opposite direction |
|
|
*/ |
|
|
public void setLocation(Component c, int coord1, int coord2) |
|
|
{ |
|
|
c.setLocation(coord1, coord2); |
|
|
} |
|
|
|
|
|
/** |
|
|
* Sets the size for Component <code>c</code>. <code>coord1</code> |
|
|
* specifies the size in this direction, |
|
|
* <code>coord2</code> the size in the opposite |
|
|
* direction. |
|
|
* |
|
|
* @param c the Component for which to set the size |
|
|
* @param size1 the size in this direction |
|
|
* @param size2 the size in the opposite direction |
|
|
*/ |
|
|
public void setSize(Component c, int size1, int size2) |
|
|
{ |
|
|
c.setSize(size1, size2); |
|
|
} |
|
|
} |
|
|
/** |
|
|
* The vertical direction. |
|
|
*/ |
|
|
static class Vertical implements Direction |
|
|
{ |
|
|
/** |
|
|
* Returns the correct part of <code>d</code> for this direction. This will |
|
|
* be <code>d.width</code> for horizontal and <code>d.height</code> for |
|
|
* vertical direction. |
|
|
* |
|
|
* @param d the size as Dimension object |
|
|
* |
|
|
* @return the correct part of <code>d</code> for this direction |
|
|
*/ |
|
|
public int size(Dimension d) |
|
|
{ |
|
|
return d.height; |
|
|
} |
|
|
|
|
|
/** |
|
|
* Returns the lower bounds of the {@link Insets} object according to this |
|
|
* direction. This will be <code>insets.top</code> for vertical direction |
|
|
* and <code>insets.left</code> for horizontal direction. |
|
|
* |
|
|
* @param insets the {@link Insets} object from which to return the lower |
|
|
* bounds |
|
|
* |
|
|
* @return the lower bounds of the {@link Insets} object according to this |
|
|
* direction |
|
|
*/ |
|
|
public int lower(Insets insets) |
|
|
{ |
|
|
return insets.top; |
|
|
} |
|
|
|
|
|
/** |
|
|
* Returns the alignment property according to this direction. |
|
|
* |
|
|
* @param comp the Component for which to return the alignment property |
|
|
* |
|
|
* @return the alignment property according to this direction |
|
|
*/ |
|
|
public float alignment(Component comp) |
|
|
{ |
|
|
return comp.getAlignmentY(); |
|
|
} |
|
|
|
|
|
/** |
|
|
* Sets the location for Component <code>c</code>. <code>coord1</code> |
|
|
* specifies the coordinate of the location in this direction, |
|
|
* <code>coord2</code> the coordinate of the location in the opposite |
|
|
* direction. |
|
|
* |
|
|
* @param c the Component for which to set the location |
|
|
* @param coord1 the coordinate in this direction |
|
|
* @param coord2 the coordinate in the opposite direction |
|
|
*/ |
|
|
public void setLocation(Component c, int coord1, int coord2) |
|
|
{ |
|
|
c.setLocation(coord2, coord1); |
|
|
} |
|
|
|
|
|
/** |
|
|
* Sets the size for Component <code>c</code>. <code>coord1</code> |
|
|
* specifies the size in this direction, |
|
|
* <code>coord2</code> the size in the opposite |
|
|
* direction. |
|
|
* |
|
|
* @param c the Component for which to set the size |
|
|
* @param size1 the size in this direction |
|
|
* @param size2 the size in the opposite direction |
|
|
*/ |
|
|
public void setSize(Component c, int size1, int size2) |
|
|
{ |
|
|
c.setSize(size2, size1); |
|
|
} |
|
|
} |
|
|
|
|
|
/** |
|
|
* A helper class that temporarily stores the size specs of a component. |
|
|
*/ |
|
|
static class SizeReq |
|
|
{ |
|
|
int size; |
|
|
int min; |
|
|
int pref; |
|
|
int max; |
|
|
float align; |
|
|
Component comp; |
|
|
SizeReq(Component comp, Direction dir) |
|
|
{ |
|
|
this.min = dir.size(comp.getMinimumSize()); |
|
|
this.pref = dir.size(comp.getPreferredSize()); |
|
|
this.max = dir.size(comp.getMaximumSize()); |
|
|
this.size = dir.size(comp.getSize()); |
|
|
this.align = dir.alignment(comp); |
|
|
this.comp = comp; |
|
|
} |
|
|
} |
|
|
|
|
|
/** |
|
60 |
* Specifies that components are laid out left to right. |
* Specifies that components are laid out left to right. |
61 |
*/ |
*/ |
62 |
public static final int X_AXIS = 0; |
public static final int X_AXIS = 0; |
86 |
*/ |
*/ |
87 |
private Container container; |
private Container container; |
88 |
|
|
89 |
/* |
/** |
90 |
* Current type of component layouting. Defaults to X_AXIS. |
* Current type of component layouting. Defaults to X_AXIS. |
91 |
*/ |
*/ |
92 |
private int way = X_AXIS; |
private int way = X_AXIS; |
93 |
|
|
94 |
/** Constant for the horizontal direction. */ |
/** |
95 |
private static final Direction HORIZONTAL = new Horizontal(); |
* The size requirements of the containers children for the X direction. |
96 |
|
*/ |
97 |
|
private SizeRequirements[] xChildren; |
98 |
|
|
99 |
|
/** |
100 |
|
* The size requirements of the containers children for the Y direction. |
101 |
|
*/ |
102 |
|
private SizeRequirements[] yChildren; |
103 |
|
|
104 |
|
/** |
105 |
|
* The size requirements of the container to be laid out for the X direction. |
106 |
|
*/ |
107 |
|
private SizeRequirements xTotal; |
108 |
|
|
109 |
|
/** |
110 |
|
* The size requirements of the container to be laid out for the Y direction. |
111 |
|
*/ |
112 |
|
private SizeRequirements yTotal; |
113 |
|
|
114 |
/** Constant for the vertical direction. */ |
/** |
115 |
private static final Direction VERTICAL = new Vertical(); |
* The offsets of the child components in the X direction. |
116 |
|
*/ |
117 |
|
private int[] offsetsX; |
118 |
|
|
119 |
|
/** |
120 |
|
* The offsets of the child components in the Y direction. |
121 |
|
*/ |
122 |
|
private int[] offsetsY; |
123 |
|
|
124 |
|
/** |
125 |
|
* The spans of the child components in the X direction. |
126 |
|
*/ |
127 |
|
private int[] spansX; |
128 |
|
|
129 |
|
/** |
130 |
|
* The spans of the child components in the Y direction. |
131 |
|
*/ |
132 |
|
private int[] spansY; |
133 |
|
|
134 |
/** |
/** |
135 |
* Constructs a <code>BoxLayout</code> object. |
* Constructs a <code>BoxLayout</code> object. |
155 |
*/ |
*/ |
156 |
public void addLayoutComponent(String name, Component component) |
public void addLayoutComponent(String name, Component component) |
157 |
{ |
{ |
158 |
|
// Nothing to do here. |
159 |
} |
} |
160 |
|
|
161 |
/** |
/** |
165 |
*/ |
*/ |
166 |
public void removeLayoutComponent(Component component) |
public void removeLayoutComponent(Component component) |
167 |
{ |
{ |
168 |
|
// Nothing to do here. |
169 |
} |
} |
170 |
|
|
171 |
private boolean isHorizontalIn(Container parent) |
private boolean isHorizontalIn(Container parent) |
189 |
*/ |
*/ |
190 |
public Dimension preferredLayoutSize(Container parent) |
public Dimension preferredLayoutSize(Container parent) |
191 |
{ |
{ |
192 |
if (parent != container) |
synchronized (container.getTreeLock()) |
193 |
throw new AWTError("invalid parent"); |
{ |
194 |
|
if (container != parent) |
195 |
|
throw new AWTError("BoxLayout can't be shared"); |
196 |
|
|
197 |
Insets insets = parent.getInsets(); |
checkTotalRequirements(); |
198 |
int x = 0; |
Insets i = container.getInsets(); |
199 |
int y = 0; |
return new Dimension(xTotal.preferred + i.left + i.right, |
200 |
|
yTotal.preferred + i.top + i.bottom); |
|
List children = AWTUtilities.getVisibleChildren(parent); |
|
|
|
|
|
if (isHorizontalIn(parent)) |
|
|
{ |
|
|
x = insets.left + insets.right; |
|
|
// sum up preferred widths of components, find maximum of preferred |
|
|
// heights |
|
|
for (Iterator i = children.iterator(); i.hasNext();) |
|
|
{ |
|
|
Component comp = (Component) i.next(); |
|
|
Dimension sz = comp.getPreferredSize(); |
|
|
x += sz.width; |
|
|
y = Math.max(y, sz.height); |
|
|
} |
|
|
y += insets.bottom + insets.top; |
|
|
} |
|
|
else |
|
|
{ |
|
|
y = insets.top + insets.bottom; |
|
|
// sum up preferred heights of components, find maximum of |
|
|
// preferred widths |
|
|
for (Iterator i = children.iterator(); i.hasNext();) |
|
|
{ |
|
|
Component comp = (Component) i.next(); |
|
|
Dimension sz = comp.getPreferredSize(); |
|
|
y += sz.height; |
|
|
x = Math.max(x, sz.width); |
|
|
} |
|
|
x += insets.left + insets.right; |
|
201 |
} |
} |
|
|
|
|
return new Dimension(x, y); |
|
202 |
} |
} |
203 |
|
|
204 |
/** |
/** |
210 |
*/ |
*/ |
211 |
public Dimension minimumLayoutSize(Container parent) |
public Dimension minimumLayoutSize(Container parent) |
212 |
{ |
{ |
213 |
if (parent != container) |
synchronized (container.getTreeLock()) |
|
throw new AWTError("invalid parent"); |
|
|
|
|
|
Insets insets = parent.getInsets(); |
|
|
int x = insets.left + insets.right; |
|
|
int y = insets.bottom + insets.top; |
|
|
|
|
|
List children = AWTUtilities.getVisibleChildren(parent); |
|
|
|
|
|
if (isHorizontalIn(parent)) |
|
|
{ |
|
|
// sum up preferred widths of components, find maximum of preferred |
|
|
// heights |
|
|
for (Iterator i = children.iterator(); i.hasNext();) |
|
|
{ |
|
|
Component comp = (Component) i.next(); |
|
|
Dimension sz = comp.getMinimumSize(); |
|
|
x += sz.width; |
|
|
y = Math.max(y, sz.height); |
|
|
} |
|
|
} |
|
|
else |
|
214 |
{ |
{ |
215 |
// sum up preferred heights of components, find maximum of |
if (container != parent) |
216 |
// preferred widths |
throw new AWTError("BoxLayout can't be shared"); |
217 |
for (Iterator i = children.iterator(); i.hasNext();) |
|
218 |
{ |
checkTotalRequirements(); |
219 |
Component comp = (Component) i.next(); |
return new Dimension(xTotal.minimum, yTotal.minimum); |
|
Dimension sz = comp.getMinimumSize(); |
|
|
y += sz.height; |
|
|
x = Math.max(x, sz.width); |
|
|
} |
|
220 |
} |
} |
|
|
|
|
return new Dimension(x, y); |
|
221 |
} |
} |
222 |
|
|
223 |
/** |
/** |
227 |
*/ |
*/ |
228 |
public void layoutContainer(Container parent) |
public void layoutContainer(Container parent) |
229 |
{ |
{ |
230 |
if (isHorizontalIn(parent)) |
synchronized (container.getTreeLock()) |
231 |
layoutAlgorithm(parent, HORIZONTAL, VERTICAL); |
{ |
232 |
else |
if (container != parent) |
233 |
layoutAlgorithm(parent, VERTICAL, HORIZONTAL); |
throw new AWTError("BoxLayout can't be shared"); |
234 |
|
|
235 |
|
checkLayout(); |
236 |
|
Component[] children = container.getComponents(); |
237 |
|
Insets in = container.getInsets(); |
238 |
|
for (int i = 0; i < children.length; i++) |
239 |
|
children[i].setBounds(offsetsX[i] + in.left, offsetsY[i] + in.top, |
240 |
|
spansX[i], spansY[i]); |
241 |
|
} |
242 |
} |
} |
243 |
|
|
244 |
/** |
/** |
245 |
* Adds a component to the layout. Not used in BoxLayout |
* Adds a component to the layout. Not used in BoxLayout |
246 |
* |
* |
249 |
*/ |
*/ |
250 |
public void addLayoutComponent(Component child, Object constraints) |
public void addLayoutComponent(Component child, Object constraints) |
251 |
{ |
{ |
252 |
|
// Nothing to do here. |
253 |
} |
} |
254 |
|
|
255 |
/** |
/** |
261 |
*/ |
*/ |
262 |
public float getLayoutAlignmentX(Container parent) |
public float getLayoutAlignmentX(Container parent) |
263 |
{ |
{ |
264 |
if (parent != container) |
synchronized (container.getTreeLock()) |
265 |
throw new AWTError("invalid parent"); |
{ |
266 |
|
if (container != parent) |
267 |
return 0; |
throw new AWTError("BoxLayout can't be shared"); |
268 |
|
|
269 |
|
checkTotalRequirements(); |
270 |
|
return xTotal.alignment; |
271 |
|
} |
272 |
} |
} |
273 |
|
|
274 |
/** |
/** |
280 |
*/ |
*/ |
281 |
public float getLayoutAlignmentY(Container parent) |
public float getLayoutAlignmentY(Container parent) |
282 |
{ |
{ |
283 |
if (parent != container) |
synchronized (container.getTreeLock()) |
284 |
throw new AWTError("invalid parent"); |
{ |
285 |
|
if (container != parent) |
286 |
return 0; |
throw new AWTError("BoxLayout can't be shared"); |
287 |
|
|
288 |
|
checkTotalRequirements(); |
289 |
|
return yTotal.alignment; |
290 |
|
} |
291 |
} |
} |
292 |
|
|
293 |
/** |
/** |
297 |
*/ |
*/ |
298 |
public void invalidateLayout(Container parent) |
public void invalidateLayout(Container parent) |
299 |
{ |
{ |
300 |
if (parent != container) |
synchronized (container.getTreeLock()) |
301 |
throw new AWTError("invalid parent"); |
{ |
302 |
|
xChildren = null; |
303 |
|
yChildren = null; |
304 |
|
xTotal = null; |
305 |
|
yTotal = null; |
306 |
|
offsetsX = null; |
307 |
|
offsetsY = null; |
308 |
|
spansX = null; |
309 |
|
spansY = null; |
310 |
|
} |
311 |
} |
} |
312 |
|
|
313 |
/** |
/** |
320 |
*/ |
*/ |
321 |
public Dimension maximumLayoutSize(Container parent) |
public Dimension maximumLayoutSize(Container parent) |
322 |
{ |
{ |
323 |
if (parent != container) |
synchronized (container.getTreeLock()) |
324 |
throw new AWTError("invalid parent"); |
{ |
325 |
|
if (container != parent) |
326 |
Insets insets = parent.getInsets(); |
throw new AWTError("BoxLayout can't be shared"); |
|
int x = insets.left + insets.right; |
|
|
int y = insets.top + insets.bottom; |
|
327 |
|
|
328 |
List children = AWTUtilities.getVisibleChildren(parent); |
checkTotalRequirements(); |
329 |
|
return new Dimension(xTotal.maximum, yTotal.maximum); |
330 |
|
} |
331 |
|
} |
332 |
|
|
333 |
if (isHorizontalIn(parent)) |
/** |
334 |
|
* Makes sure that the xTotal and yTotal fields are set up correctly. A call |
335 |
|
* to {@link #invalidateLayout} sets these fields to null and they have to be |
336 |
|
* recomputed. |
337 |
|
*/ |
338 |
|
private void checkTotalRequirements() |
339 |
|
{ |
340 |
|
if (xTotal == null || yTotal == null) |
341 |
{ |
{ |
342 |
|
checkRequirements(); |
343 |
// sum up preferred widths of components, find maximum of preferred |
if (isHorizontalIn(container)) |
|
// heights |
|
|
for (Iterator i = children.iterator(); i.hasNext();) |
|
344 |
{ |
{ |
345 |
Component comp = (Component) i.next(); |
xTotal = SizeRequirements.getTiledSizeRequirements(xChildren); |
346 |
Dimension sz = comp.getMaximumSize(); |
yTotal = SizeRequirements.getAlignedSizeRequirements(yChildren); |
|
x += sz.width; |
|
|
// Check for overflow. |
|
|
if (x < 0) |
|
|
x = Integer.MAX_VALUE; |
|
|
y = Math.max(y, sz.height); |
|
347 |
} |
} |
348 |
} |
else |
|
else |
|
|
{ |
|
|
// sum up preferred heights of components, find maximum of |
|
|
// preferred widths |
|
|
for (Iterator i = children.iterator(); i.hasNext();) |
|
349 |
{ |
{ |
350 |
Component comp = (Component) i.next(); |
xTotal = SizeRequirements.getAlignedSizeRequirements(xChildren); |
351 |
Dimension sz = comp.getMaximumSize(); |
yTotal = SizeRequirements.getTiledSizeRequirements(yChildren); |
|
y += sz.height; |
|
|
// Check for overflow |
|
|
if (y < 0) |
|
|
y = Integer.MAX_VALUE; |
|
|
x = Math.max(x, sz.width); |
|
352 |
} |
} |
353 |
} |
} |
|
return new Dimension(x, y); |
|
354 |
} |
} |
355 |
|
|
356 |
/** |
/** |
357 |
* Lays out the Container <code>c</code> in the layout direction |
* Makes sure that the xChildren and yChildren fields are correctly set up. |
358 |
* <code>layoutDir</code>. The direction that is crossing the layout |
* A call to {@link #invalidateLayout(Container)} sets these fields to null, |
359 |
* direction is specified in <code>crossDir</code>. |
* so they have to be set up again. |
|
* |
|
|
* @param parent |
|
|
* @param layoutDir |
|
|
* @param crossDir |
|
360 |
*/ |
*/ |
361 |
void layoutAlgorithm(Container parent, Direction layoutDir, Direction crossDir) |
private void checkRequirements() |
362 |
{ |
{ |
363 |
if (parent != container) |
if (xChildren == null || yChildren == null) |
|
throw new AWTError("invalid parent"); |
|
|
|
|
|
Dimension parentSize = parent.getSize(); |
|
|
Insets insets = parent.getInsets(); |
|
|
Dimension innerSize = new Dimension(parentSize.width - insets.left |
|
|
- insets.right, parentSize.height |
|
|
- insets.bottom - insets.top); |
|
|
|
|
|
// Set all components to their preferredSizes and sum up the allocated |
|
|
// space. Create SizeReqs for each component and store them in |
|
|
// sizeReqs. Find the maximum size in the crossing direction. |
|
|
List children = AWTUtilities.getVisibleChildren(parent); |
|
|
Vector sizeReqs = new Vector(); |
|
|
int allocated = 0; |
|
|
for (Iterator i = children.iterator(); i.hasNext();) |
|
364 |
{ |
{ |
365 |
Component c = (Component) i.next(); |
Component[] children = container.getComponents(); |
366 |
SizeReq sizeReq = new SizeReq(c, layoutDir); |
xChildren = new SizeRequirements[children.length]; |
367 |
int preferred = layoutDir.size(c.getPreferredSize()); |
yChildren = new SizeRequirements[children.length]; |
368 |
sizeReq.size = preferred; |
for (int i = 0; i < children.length; i++) |
369 |
allocated += preferred; |
{ |
370 |
sizeReqs.add(sizeReq); |
if (! children[i].isVisible()) |
371 |
} |
{ |
372 |
|
xChildren[i] = new SizeRequirements(); |
373 |
// Distribute remaining space (may be positive or negative) over components |
yChildren[i] = new SizeRequirements(); |
374 |
int remainder = layoutDir.size(innerSize) - allocated; |
} |
375 |
distributeSpace(sizeReqs, remainder, layoutDir); |
else |
376 |
|
{ |
377 |
// Resize and relocate components. If the component can be sized to |
xChildren[i] = |
378 |
// take the full space in the crossing direction, then do so, otherwise |
new SizeRequirements(children[i].getMinimumSize().width, |
379 |
// align according to its alingnmentX or alignmentY property. |
children[i].getPreferredSize().width, |
380 |
int loc = 0; |
children[i].getMaximumSize().width, |
381 |
int offset1 = layoutDir.lower(insets); |
children[i].getAlignmentX()); |
382 |
int offset2 = crossDir.lower(insets); |
yChildren[i] = |
383 |
for (Iterator i = sizeReqs.iterator(); i.hasNext();) |
new SizeRequirements(children[i].getMinimumSize().height, |
384 |
{ |
children[i].getPreferredSize().height, |
385 |
SizeReq sizeReq = (SizeReq) i.next(); |
children[i].getMaximumSize().height, |
386 |
Component c = sizeReq.comp; |
children[i].getAlignmentY()); |
387 |
int availCrossSize = crossDir.size(innerSize); |
} |
388 |
int maxCross = crossDir.size(c.getMaximumSize()); |
} |
|
int crossSize = Math.min(availCrossSize, maxCross); |
|
|
int crossRemainder = availCrossSize - crossSize; |
|
|
int crossLoc = (int) (crossDir.alignment(c) * crossRemainder); |
|
|
layoutDir.setSize(c, sizeReq.size, crossSize); |
|
|
layoutDir.setLocation(c, offset1 + loc, offset2 + crossLoc); |
|
|
loc += sizeReq.size; |
|
389 |
} |
} |
390 |
} |
} |
391 |
|
|
392 |
/** |
/** |
393 |
* Distributes some space over a set of components. This implementation |
* Makes sure that the offsetsX, offsetsY, spansX and spansY fields are set |
394 |
* tries to set the components as close as possible to their |
* up correctly. A call to {@link #invalidateLayout} sets these fields |
395 |
* <code>preferredSize</code>s, and respects the components |
* to null and they have to be recomputed. |
396 |
* <code>minimumSize</code> and <code>maximumSize</code>. |
*/ |
397 |
* |
private void checkLayout() |
398 |
* The algorithm is implemented as follows: |
{ |
399 |
* |
if (offsetsX == null || offsetsY == null || spansX == null |
400 |
* <ul> |
|| spansY == null) |
|
* <li>The <code>remainder</code> is divided by the number of components |
|
|
* in <code>freeComponents</code>.</li> |
|
|
* <li>The result is added to (or substracted from) the size of each |
|
|
* component.</li> |
|
|
* <li>If the <code>minimumSize</code> or <code>maximumSize</code> of a |
|
|
* component is exceeded, then this component is set to its |
|
|
* <code>minimumSize</code> or <code>maximumSize</code>, it is removed from |
|
|
* <code>freeComponents</code> and the difference is added to a new |
|
|
* remainder.</li> |
|
|
* <li>Finally, if there is a new remainer != 0 and the |
|
|
* <code>freeComponents.size() != 0</code>, then this method is called |
|
|
* recursivly to distribute the newly allocated remaining space.</li> |
|
|
* </ul> |
|
|
* |
|
|
* @param freeComponents a SizeReq collection for components that have space |
|
|
* left so that they can be moved freely |
|
|
* @param remainder the space that should be distributed between the |
|
|
* components |
|
|
* @param dir the direction in which we operate |
|
|
*/ |
|
|
void distributeSpace(Collection freeComponents, int remainder, Direction dir) |
|
|
{ |
|
|
// Sum up total available space in components. If the remainder is negative |
|
|
// then we sum up the difference between minSize and size. If remainder |
|
|
// is positive we sum up the difference between maxSize and size. |
|
|
double totalAvailable = 0; |
|
|
for (Iterator i = freeComponents.iterator(); i.hasNext();) |
|
|
{ |
|
|
SizeReq sizeReq = (SizeReq) i.next(); |
|
|
if (remainder >= 0) |
|
|
totalAvailable += sizeReq.max - sizeReq.size; |
|
|
else |
|
|
totalAvailable += sizeReq.min - sizeReq.size; |
|
|
} |
|
|
if (totalAvailable == 0) |
|
|
if (remainder >= 0) |
|
|
totalAvailable = 1; |
|
|
else |
|
|
totalAvailable = -1; |
|
|
|
|
|
int newRemainder = 0; |
|
|
Vector stillFree = new Vector(); |
|
|
for (Iterator i = freeComponents.iterator(); i.hasNext();) |
|
401 |
{ |
{ |
402 |
// Add/substract share to component. |
checkRequirements(); |
403 |
SizeReq sizeReq = (SizeReq) i.next(); |
checkTotalRequirements(); |
404 |
double available = 0; |
int len = container.getComponents().length; |
405 |
if (remainder >= 0) |
offsetsX = new int[len]; |
406 |
available = sizeReq.max - sizeReq.size; |
offsetsY = new int[len]; |
407 |
|
spansX = new int[len]; |
408 |
|
spansY = new int[len]; |
409 |
|
|
410 |
|
Insets in = container.getInsets(); |
411 |
|
int width = container.getWidth() - in.left - in.right; |
412 |
|
int height = container.getHeight() - in.top -in.bottom; |
413 |
|
|
414 |
|
if (isHorizontalIn(container)) |
415 |
|
{ |
416 |
|
SizeRequirements.calculateTiledPositions(width, |
417 |
|
xTotal, xChildren, |
418 |
|
offsetsX, spansX); |
419 |
|
SizeRequirements.calculateAlignedPositions(height, |
420 |
|
yTotal, yChildren, |
421 |
|
offsetsY, spansY); |
422 |
|
} |
423 |
else |
else |
424 |
available = sizeReq.min - sizeReq.size; |
{ |
425 |
int share = (int) ((available / totalAvailable) * remainder); |
SizeRequirements.calculateAlignedPositions(width, |
426 |
sizeReq.size += share; |
xTotal, xChildren, |
427 |
// check for min/maximumSize |
offsetsX, spansX); |
428 |
if (sizeReq.size < sizeReq.min) |
SizeRequirements.calculateTiledPositions(height, |
429 |
{ |
yTotal, yChildren, |
430 |
newRemainder += sizeReq.size - sizeReq.min; |
offsetsY, spansY); |
431 |
sizeReq.size = sizeReq.min; |
} |
|
} |
|
|
else if (sizeReq.size > sizeReq.max) |
|
|
{ |
|
|
newRemainder += sizeReq.size - sizeReq.max; |
|
|
sizeReq.size = sizeReq.max; |
|
|
} |
|
|
else |
|
|
stillFree.add(sizeReq); |
|
432 |
} |
} |
|
// recursivly call this method if necessary |
|
|
if (newRemainder != 0 && stillFree.size() > 0) |
|
|
distributeSpace(stillFree, newRemainder, dir); |
|
433 |
} |
} |
434 |
} |
} |