KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > swing > SizeRequirements


1 /*
2  * @(#)SizeRequirements.java 1.32 03/12/19
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7 package javax.swing;
8
9
10 import java.awt.*;
11 import java.io.Serializable JavaDoc;
12
13 /**
14  * For the convenience of layout managers,
15  * calculates information about the size and position of components.
16  * All size and position calculation methods are class methods
17  * that take arrays of SizeRequirements as arguments.
18  * The SizeRequirements class supports two types of layout:
19  *
20  * <blockquote>
21  * <dl>
22  * <dt> tiled
23  * <dd> The components are placed end-to-end,
24  * starting either at coordinate 0 (the leftmost or topmost position)
25  * or at the coordinate representing the end of the allocated span
26  * (the rightmost or bottommost position).
27  *
28  * <dt> aligned
29  * <dd> The components are aligned as specified
30  * by each component's X or Y alignment value.
31  * </dl>
32  * </blockquote>
33  *
34  * <p>
35  *
36  * Each SizeRequirements object contains information
37  * about either the width (and X alignment)
38  * or height (and Y alignment)
39  * of a single component or a group of components:
40  *
41  * <blockquote>
42  * <dl>
43  * <dt> <code>minimum</code>
44  * <dd> The smallest reasonable width/height of the component
45  * or component group, in pixels.
46  *
47  * <dt> <code>preferred</code>
48  * <dd> The natural width/height of the component
49  * or component group, in pixels.
50  *
51  * <dt> <code>maximum</code>
52  * <dd> The largest reasonable width/height of the component
53  * or component group, in pixels.
54  *
55  * <dt> <code>alignment</code>
56  * <dd> The X/Y alignment of the component
57  * or component group.
58  * </dl>
59  * </blockquote>
60  * <p>
61  * <strong>Warning:</strong>
62  * Serialized objects of this class will not be compatible with
63  * future Swing releases. The current serialization support is
64  * appropriate for short term storage or RMI between applications running
65  * the same version of Swing. As of 1.4, support for long term storage
66  * of all JavaBeans<sup><font size="-2">TM</font></sup>
67  * has been added to the <code>java.beans</code> package.
68  * Please see {@link java.beans.XMLEncoder}.
69  *
70  * @see Component#getMinimumSize
71  * @see Component#getPreferredSize
72  * @see Component#getMaximumSize
73  * @see Component#getAlignmentX
74  * @see Component#getAlignmentY
75  *
76  * @version 1.32 12/19/03
77  * @author Timothy Prinzing
78  */

79 public class SizeRequirements implements Serializable JavaDoc {
80
81     /**
82      * The minimum size required.
83      * For a component <code>comp</code>, this should be equal to either
84      * <code>comp.getMinimumSize().width</code> or
85      * <code>comp.getMinimumSize().height</code>.
86      */

87     public int minimum;
88
89     /**
90      * The preferred (natural) size.
91      * For a component <code>comp</code>, this should be equal to either
92      * <code>comp.getPreferredSize().width</code> or
93      * <code>comp.getPreferredSize().height</code>.
94      */

95     public int preferred;
96
97     /**
98      * The maximum size allowed.
99      * For a component <code>comp</code>, this should be equal to either
100      * <code>comp.getMaximumSize().width</code> or
101      * <code>comp.getMaximumSize().height</code>.
102      */

103     public int maximum;
104
105     /**
106      * The alignment, specified as a value between 0.0 and 1.0,
107      * inclusive.
108      * To specify centering, the alignment should be 0.5.
109      */

110     public float alignment;
111
112     /**
113      * Creates a SizeRequirements object with the minimum, preferred,
114      * and maximum sizes set to zero and an alignment value of 0.5
115      * (centered).
116      */

117     public SizeRequirements() {
118     minimum = 0;
119     preferred = 0;
120     maximum = 0;
121     alignment = 0.5f;
122     }
123
124     /**
125      * Creates a SizeRequirements object with the specified minimum, preferred,
126      * and maximum sizes and the specified alignment.
127      *
128      * @param min the minimum size >= 0
129      * @param pref the preferred size >= 0
130      * @param max the maximum size >= 0
131      * @param a the alignment >= 0.0f && <= 1.0f
132      */

133     public SizeRequirements(int min, int pref, int max, float a) {
134     minimum = min;
135     preferred = pref;
136     maximum = max;
137     alignment = a > 1.0f ? 1.0f : a < 0.0f ? 0.0f : a;
138     }
139
140     /**
141      * Returns a string describing the minimum, preferred, and maximum
142      * size requirements, along with the alignment.
143      *
144      * @return the string
145      */

146     public String JavaDoc toString() {
147     return "[" + minimum + "," + preferred + "," + maximum + "]@" + alignment;
148     }
149
150     /**
151      * Determines the total space necessary to
152      * place a set of components end-to-end. The needs
153      * of each component in the set are represented by an entry in the
154      * passed-in SizeRequirements array.
155      * The returned SizeRequirements object has an alignment of 0.5
156      * (centered). The space requirement is never more than
157      * Integer.MAX_VALUE.
158      *
159      * @param children the space requirements for a set of components.
160      * The vector may be of zero length, which will result in a
161      * default SizeRequirements object instance being passed back.
162      * @return the total space requirements.
163      */

164     public static SizeRequirements JavaDoc getTiledSizeRequirements(SizeRequirements JavaDoc[]
165                                 children) {
166     SizeRequirements JavaDoc total = new SizeRequirements JavaDoc();
167     for (int i = 0; i < children.length; i++) {
168         SizeRequirements JavaDoc req = children[i];
169         total.minimum = (int) Math.min((long) total.minimum + (long) req.minimum, Integer.MAX_VALUE);
170         total.preferred = (int) Math.min((long) total.preferred + (long) req.preferred, Integer.MAX_VALUE);
171         total.maximum = (int) Math.min((long) total.maximum + (long) req.maximum, Integer.MAX_VALUE);
172     }
173     return total;
174     }
175
176     /**
177      * Determines the total space necessary to
178      * align a set of components. The needs
179      * of each component in the set are represented by an entry in the
180      * passed-in SizeRequirements array. The total space required will
181      * never be more than Integer.MAX_VALUE.
182      *
183      * @param children the set of child requirements. If of zero length,
184      * the returns result will be a default instance of SizeRequirements.
185      * @return the total space requirements.
186      */

187     public static SizeRequirements JavaDoc getAlignedSizeRequirements(SizeRequirements JavaDoc[]
188                                   children) {
189     SizeRequirements JavaDoc totalAscent = new SizeRequirements JavaDoc();
190     SizeRequirements JavaDoc totalDescent = new SizeRequirements JavaDoc();
191     for (int i = 0; i < children.length; i++) {
192         SizeRequirements JavaDoc req = children[i];
193
194         int ascent = (int) (req.alignment * req.minimum);
195         int descent = req.minimum - ascent;
196         totalAscent.minimum = Math.max(ascent, totalAscent.minimum);
197         totalDescent.minimum = Math.max(descent, totalDescent.minimum);
198
199         ascent = (int) (req.alignment * req.preferred);
200         descent = req.preferred - ascent;
201         totalAscent.preferred = Math.max(ascent, totalAscent.preferred);
202         totalDescent.preferred = Math.max(descent, totalDescent.preferred);
203
204         ascent = (int) (req.alignment * req.maximum);
205         descent = req.maximum - ascent;
206         totalAscent.maximum = Math.max(ascent, totalAscent.maximum);
207         totalDescent.maximum = Math.max(descent, totalDescent.maximum);
208     }
209     int min = (int) Math.min((long) totalAscent.minimum + (long) totalDescent.minimum, Integer.MAX_VALUE);
210     int pref = (int) Math.min((long) totalAscent.preferred + (long) totalDescent.preferred, Integer.MAX_VALUE);
211     int max = (int) Math.min((long) totalAscent.maximum + (long) totalDescent.maximum, Integer.MAX_VALUE);
212     float alignment = 0.0f;
213     if (min > 0) {
214         alignment = (float) totalAscent.minimum / min;
215         alignment = alignment > 1.0f ? 1.0f : alignment < 0.0f ? 0.0f : alignment;
216     }
217     return new SizeRequirements JavaDoc(min, pref, max, alignment);
218     }
219
220     /**
221      * Creates a set of offset/span pairs representing how to
222      * lay out a set of components end-to-end.
223      * This method requires that you specify
224      * the total amount of space to be allocated,
225      * the size requirements for each component to be placed
226      * (specified as an array of SizeRequirements), and
227      * the total size requirement of the set of components.
228      * You can get the total size requirement
229      * by invoking the getTiledSizeRequirements method. The components
230      * will be tiled in the forward direction with offsets increasing from 0.
231      *
232      * @param allocated the total span to be allocated >= 0.
233      * @param total the total of the children requests. This argument
234      * is optional and may be null.
235      * @param children the size requirements for each component.
236      * @param offsets the offset from 0 for each child where
237      * the spans were allocated (determines placement of the span).
238      * @param spans the span allocated for each child to make the
239      * total target span.
240      */

241     public static void calculateTiledPositions(int allocated,
242                            SizeRequirements JavaDoc total,
243                                SizeRequirements JavaDoc[] children,
244                                int[] offsets,
245                            int[] spans) {
246         calculateTiledPositions(allocated, total, children, offsets, spans, true);
247     }
248
249     /**
250      * Creates a set of offset/span pairs representing how to
251      * lay out a set of components end-to-end.
252      * This method requires that you specify
253      * the total amount of space to be allocated,
254      * the size requirements for each component to be placed
255      * (specified as an array of SizeRequirements), and
256      * the total size requirement of the set of components.
257      * You can get the total size requirement
258      * by invoking the getTiledSizeRequirements method.
259      *
260      * This method also requires a flag indicating whether components
261      * should be tiled in the forward direction (offsets increasing
262      * from 0) or reverse direction (offsets decreasing from the end
263      * of the allocated space). The forward direction represents
264      * components tiled from left to right or top to bottom. The
265      * reverse direction represents components tiled from right to left
266      * or bottom to top.
267      *
268      * @param allocated the total span to be allocated >= 0.
269      * @param total the total of the children requests. This argument
270      * is optional and may be null.
271      * @param children the size requirements for each component.
272      * @param offsets the offset from 0 for each child where
273      * the spans were allocated (determines placement of the span).
274      * @param spans the span allocated for each child to make the
275      * total target span.
276      * @param forward tile with offsets increasing from 0 if true
277      * and with offsets decreasing from the end of the allocated space
278      * if false.
279      */

280     public static void calculateTiledPositions(int allocated,
281                            SizeRequirements JavaDoc total,
282                                SizeRequirements JavaDoc[] children,
283                                int[] offsets,
284                            int[] spans,
285                                                boolean forward) {
286     // The total argument turns out to be a bad idea since the
287
// total of all the children can overflow the integer used to
288
// hold the total. The total must therefore be calculated and
289
// stored in long variables.
290
long min = 0;
291     long pref = 0;
292     long max = 0;
293     for (int i = 0; i < children.length; i++) {
294         min += children[i].minimum;
295         pref += children[i].preferred;
296         max += children[i].maximum;
297     }
298     if (allocated >= pref) {
299         expandedTile(allocated, min, pref, max, children, offsets, spans, forward);
300     } else {
301         compressedTile(allocated, min, pref, max, children, offsets, spans, forward);
302     }
303     }
304
305     private static void compressedTile(int allocated, long min, long pref, long max,
306                        SizeRequirements JavaDoc[] request,
307                        int[] offsets, int[] spans,
308                                        boolean forward) {
309
310     // ---- determine what we have to work with ----
311
float totalPlay = Math.min(pref - allocated, pref - min);
312     float factor = (pref - min == 0) ? 0.0f : totalPlay / (pref - min);
313
314     // ---- make the adjustments ----
315
int totalOffset;
316         if( forward ) {
317             // lay out with offsets increasing from 0
318
totalOffset = 0;
319             for (int i = 0; i < spans.length; i++) {
320                 offsets[i] = totalOffset;
321                 SizeRequirements JavaDoc req = request[i];
322                 float play = factor * (req.preferred - req.minimum);
323                 spans[i] = (int)(req.preferred - play);
324                 totalOffset = (int) Math.min((long) totalOffset + (long) spans[i], Integer.MAX_VALUE);
325             }
326     } else {
327             // lay out with offsets decreasing from the end of the allocation
328
totalOffset = allocated;
329             for (int i = 0; i < spans.length; i++) {
330                 SizeRequirements JavaDoc req = request[i];
331                 float play = factor * (req.preferred - req.minimum);
332                 spans[i] = (int)(req.preferred - play);
333                 offsets[i] = totalOffset - spans[i];
334                 totalOffset = (int) Math.max((long) totalOffset - (long) spans[i], 0);
335             }
336         }
337     }
338
339     private static void expandedTile(int allocated, long min, long pref, long max,
340                      SizeRequirements JavaDoc[] request,
341                      int[] offsets, int[] spans,
342                                      boolean forward) {
343
344     // ---- determine what we have to work with ----
345
float totalPlay = Math.min(allocated - pref, max - pref);
346     float factor = (max - pref == 0) ? 0.0f : totalPlay / (max - pref);
347
348     // ---- make the adjustments ----
349
int totalOffset;
350         if( forward ) {
351             // lay out with offsets increasing from 0
352
totalOffset = 0;
353             for (int i = 0; i < spans.length; i++) {
354                 offsets[i] = totalOffset;
355                 SizeRequirements JavaDoc req = request[i];
356                 int play = (int)(factor * (req.maximum - req.preferred));
357                 spans[i] = (int) Math.min((long) req.preferred + (long) play, Integer.MAX_VALUE);
358                 totalOffset = (int) Math.min((long) totalOffset + (long) spans[i], Integer.MAX_VALUE);
359             }
360         } else {
361             // lay out with offsets decreasing from the end of the allocation
362
totalOffset = allocated;
363             for (int i = 0; i < spans.length; i++) {
364                 SizeRequirements JavaDoc req = request[i];
365                 int play = (int)(factor * (req.maximum - req.preferred));
366                 spans[i] = (int) Math.min((long) req.preferred + (long) play, Integer.MAX_VALUE);
367                 offsets[i] = totalOffset - spans[i];
368                 totalOffset = (int) Math.max((long) totalOffset - (long) spans[i], 0);
369             }
370         }
371     }
372
373     /**
374      * Creates a bunch of offset/span pairs specifying how to
375      * lay out a set of components with the specified alignments.
376      * The resulting span allocations will overlap, with each one
377      * fitting as well as possible into the given total allocation.
378      * This method requires that you specify
379      * the total amount of space to be allocated,
380      * the size requirements for each component to be placed
381      * (specified as an array of SizeRequirements), and
382      * the total size requirements of the set of components
383      * (only the alignment field of which is actually used).
384      * You can get the total size requirement by invoking
385      * getAlignedSizeRequirements.
386      *
387      * Normal alignment will be done with an alignment value of 0.0f
388      * representing the left/top edge of a component.
389      *
390      * @param allocated the total span to be allocated >= 0.
391      * @param total the total of the children requests.
392      * @param children the size requirements for each component.
393      * @param offsets the offset from 0 for each child where
394      * the spans were allocated (determines placement of the span).
395      * @param spans the span allocated for each child to make the
396      * total target span.
397      */

398     public static void calculateAlignedPositions(int allocated,
399                                                  SizeRequirements JavaDoc total,
400                                  SizeRequirements JavaDoc[] children,
401                                  int[] offsets,
402                          int[] spans) {
403         calculateAlignedPositions( allocated, total, children, offsets, spans, true );
404     }
405
406     /**
407      * Creates a set of offset/span pairs specifying how to
408      * lay out a set of components with the specified alignments.
409      * The resulting span allocations will overlap, with each one
410      * fitting as well as possible into the given total allocation.
411      * This method requires that you specify
412      * the total amount of space to be allocated,
413      * the size requirements for each component to be placed
414      * (specified as an array of SizeRequirements), and
415      * the total size requirements of the set of components
416      * (only the alignment field of which is actually used)
417      * You can get the total size requirement by invoking
418      * getAlignedSizeRequirements.
419      *
420      * This method also requires a flag indicating whether normal or
421      * reverse alignment should be performed. With normal alignment
422      * the value 0.0f represents the left/top edge of the component
423      * to be aligned. With reverse alignment, 0.0f represents the
424      * right/bottom edge.
425      *
426      * @param allocated the total span to be allocated >= 0.
427      * @param total the total of the children requests.
428      * @param children the size requirements for each component.
429      * @param offsets the offset from 0 for each child where
430      * the spans were allocated (determines placement of the span).
431      * @param spans the span allocated for each child to make the
432      * total target span.
433      * @param normal when true, the alignment value 0.0f means
434      * left/top; when false, it means right/bottom.
435      */

436     public static void calculateAlignedPositions(int allocated,
437                                                  SizeRequirements JavaDoc total,
438                                  SizeRequirements JavaDoc[] children,
439                                  int[] offsets,
440                          int[] spans,
441                                                  boolean normal) {
442         float totalAlignment = normal ? total.alignment : 1.0f - total.alignment;
443         int totalAscent = (int)(allocated * totalAlignment);
444         int totalDescent = allocated - totalAscent;
445         for (int i = 0; i < children.length; i++) {
446             SizeRequirements JavaDoc req = children[i];
447             float alignment = normal ? req.alignment : 1.0f - req.alignment;
448             int maxAscent = (int)(req.maximum * alignment);
449             int maxDescent = req.maximum - maxAscent;
450             int ascent = Math.min(totalAscent, maxAscent);
451             int descent = Math.min(totalDescent, maxDescent);
452             
453             offsets[i] = totalAscent - ascent;
454             spans[i] = (int) Math.min((long) ascent + (long) descent, Integer.MAX_VALUE);
455         }
456     }
457
458     // This method was used by the JTable - which now uses a different technique.
459
/**
460      * Adjust a specified array of sizes by a given amount.
461      *
462      * @param delta an int specifying the size difference
463      * @param children an array of SizeRequirements objects
464      * @return an array of ints containing the final size for each item
465      */

466     public static int[] adjustSizes(int delta, SizeRequirements JavaDoc[] children) {
467       return new int[0];
468     }
469 }
470
Popular Tags