KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > jgoodies > forms > layout > FormSpec


1 /*
2  * Copyright (c) 2003 JGoodies Karsten Lentzsch. All Rights Reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * o Redistributions of source code must retain the above copyright notice,
8  * this list of conditions and the following disclaimer.
9  *
10  * o Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13  *
14  * o Neither the name of JGoodies Karsten Lentzsch nor the names of
15  * its contributors may be used to endorse or promote products derived
16  * from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
22  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
27  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */

30
31 package com.jgoodies.forms.layout;
32
33 import java.awt.Container JavaDoc;
34 import java.util.List JavaDoc;
35 import java.util.StringTokenizer JavaDoc;
36
37
38 /**
39  * Specifies columns and rows in {@link FormLayout} by their default
40  * alignment, start size and resizing behavior.
41  *
42  * @author Karsten Lentzsch
43  * @version $Revision: 1.4 $
44  * @see FormLayout
45  * @see CellConstraints
46  */

47 abstract class FormSpec {
48     
49     
50     // Horizontal and Vertical Default Alignments ***************************
51

52     /**
53      * By default put components in the left.
54      */

55     static final DefaultAlignment LEFT_ALIGN = new DefaultAlignment("left");
56
57     /**
58      * By default put components in the right.
59      */

60     static final DefaultAlignment RIGHT_ALIGN = new DefaultAlignment("right");
61
62     /**
63      * By default put the components in the top.
64      */

65     static final DefaultAlignment TOP_ALIGN = new DefaultAlignment("top");
66
67     /**
68      * By default put the components in the bottom.
69      */

70     static final DefaultAlignment BOTTOM_ALIGN = new DefaultAlignment("bottom");
71
72     /**
73      * By default put the components in the center.
74      */

75     static final DefaultAlignment CENTER_ALIGN = new DefaultAlignment("center");
76
77     /**
78      * By default fill the column or row.
79      */

80     static final DefaultAlignment FILL_ALIGN = new DefaultAlignment("fill");
81
82
83     // Resizing Weights *****************************************************
84

85     /**
86      * Gives a column or row a fixed size.
87      */

88     public static final double NO_GROW = 0.0d;
89
90     /**
91      * The default resize weight.
92      */

93     public static final double DEFAULT_GROW = 1.0d;
94     
95
96     // Fields ***************************************************************
97

98     /**
99      * Holds the default alignment that will be used if a cell does not
100      * override this default.
101      */

102     private DefaultAlignment defaultAlignment;
103     
104     /**
105      * Holds the size that describes how to size this column or row.
106      */

107     private Size size;
108     
109     /**
110      * Holds the resize weight; is 0 if not used.
111      */

112     private double resizeWeight;
113     
114     
115     // Instance Creation ****************************************************
116

117     /**
118      * Constructs a <code>FormSpec</code> for the given default alignment,
119      * size, and resize weight. The resize weight must be a non-negative
120      * double; you can use <code>NONE</code> as a convenience value for no
121      * resize.
122      *
123      * @param defaultAlignment the spec's default alignment
124      * @param size a constant, component or bounded size
125      * @param resizeWeight the spec resize weight
126      * @throws IllegalArgumentException if the resize weight is negative
127      */

128     protected FormSpec(DefaultAlignment defaultAlignment,
129                         Size size,
130                         double resizeWeight) {
131         this.defaultAlignment = defaultAlignment;
132         this.size = size;
133         this.resizeWeight = resizeWeight;
134         if (resizeWeight < 0)
135             throw new IllegalArgumentException JavaDoc("The resize weight must be non-negative.");
136     }
137     
138     /**
139      * Constructs a <code>FormSpec</code> from the specified encoded
140      * description. The description will be parsed to set initial values.
141      *
142      * @param defaultAlignment the default alignment
143      * @param encodedDescription the encoded description
144      */

145     protected FormSpec(DefaultAlignment defaultAlignment, String JavaDoc encodedDescription) {
146         this(defaultAlignment, Sizes.DEFAULT, NO_GROW);
147         parseAndInitValues(encodedDescription.toLowerCase());
148     }
149     
150
151     // Public API ***********************************************************
152

153     /**
154      * Answers the default alignment.
155      */

156     public final DefaultAlignment getDefaultAlignment() {
157         return defaultAlignment;
158     }
159     
160     /**
161      * Sets the default alignment.
162      *
163      * @param newDefaultAlignment the new default alignment
164      */

165     public void setDefaultAlignment(DefaultAlignment newDefaultAlignment) {
166         defaultAlignment = newDefaultAlignment;
167     }
168     
169     /**
170      * Returns the size.
171      *
172      * @return the size
173      */

174     public final Size getSize() {
175         return size;
176     }
177     
178     /**
179      * Sets the size.
180      *
181      * @param size the new size
182      */

183     public void setSize(Size size) {
184         this.size = size;
185     }
186     
187     
188     /**
189      * Answers the current resize weight.
190      *
191      * @return the resize weight.
192      */

193     public final double getResizeWeight() {
194         return resizeWeight;
195     }
196     
197     /**
198      * Sets a new resize weight.
199      *
200      * @param weight the new resize weight
201      */

202     public void setResizeWeight(double weight) {
203         resizeWeight = weight;
204     }
205     
206     
207     /**
208      * Checks and answers whether this spec can grow or not.
209      * That is the case if and only if the resize weight is
210      * != <code>NO_GROW</code>.
211      *
212      * @return true if it can grow, false if it can't grow
213      */

214     final boolean canGrow() {
215         return getResizeWeight() != NO_GROW;
216     }
217
218
219     // Parsing **************************************************************
220

221     /**
222      * Parses an encoded form spec and initializes all required fields.
223      * The encoded description must be in lower case.
224      *
225      * @throws IllegalArgumentException if the string is empty, has no size,
226      * or is otherwise invalid
227      */

228     private void parseAndInitValues(String JavaDoc encodedDescription) {
229         StringTokenizer JavaDoc tokenizer = new StringTokenizer JavaDoc(encodedDescription, ":");
230         if (!tokenizer.hasMoreTokens()) {
231             throw new IllegalArgumentException JavaDoc(
232                                     "The form spec must not be empty.");
233         }
234         String JavaDoc token = tokenizer.nextToken();
235         
236         // Check if the first token is an orientation.
237
DefaultAlignment alignment = DefaultAlignment.valueOf(token, isHorizontal());
238         if (alignment != null) {
239             setDefaultAlignment(alignment);
240             if (!tokenizer.hasMoreTokens()) {
241                 throw new IllegalArgumentException JavaDoc(
242                                     "The form spec must provide a size.");
243             }
244             token = tokenizer.nextToken();
245         }
246         
247         parseAndInitSize(token);
248         
249         if (tokenizer.hasMoreTokens()) {
250             setResizeWeight(decodeResize(tokenizer.nextToken()));
251         }
252     }
253     
254
255     /**
256      * Parses an encoded size spec and initializes the size fields.
257      *
258      * @param token a token that represents a size, either bounded or plain
259      */

260     private void parseAndInitSize(String JavaDoc token) {
261         if (token.startsWith("max(") && token.endsWith(")")) {
262             setSize(parseAndInitBoundedSize(token, false));
263             return;
264         }
265         if (token.startsWith("min(") && token.endsWith(")")) {
266             setSize(parseAndInitBoundedSize(token, true));
267             return;
268         }
269         setSize(decodeAtomicSize(token));
270     }
271
272
273     /**
274      * Parses an encoded compound size and sets the size fields.
275      * The compound size has format:
276      * max(<atomic size>;<atomic size2>) | min(<atomic size1>;<atomic size2>)
277      * One of the two atomic sizes must be a logical size, the other must
278      * be a size constant.
279      * @param token a token for a bounded size, e.g. "max(50dlu; pref)"
280      * @param setMax if true we set a maximum size, otherwise a minimum size
281      */

282     private Size parseAndInitBoundedSize(String JavaDoc token, boolean setMax) {
283         int semicolonIndex = token.indexOf(';');
284         String JavaDoc sizeToken1 = token.substring(4, semicolonIndex);
285         String JavaDoc sizeToken2 = token.substring(semicolonIndex+1, token.length()-1);
286         
287         Size size1 = decodeAtomicSize(sizeToken1);
288         Size size2 = decodeAtomicSize(sizeToken2);
289         
290         // Check valid combinations and set min or max.
291
if (size1 instanceof ConstantSize) {
292             if (size2 instanceof Sizes.ComponentSize) {
293                 return new BoundedSize(size2, setMax ? null : size1,
294                                                setMax ? size1 : null);
295             } else
296                 throw new IllegalArgumentException JavaDoc(
297                                 "Bounded sizes must not be both constants.");
298         } else {
299             if (size2 instanceof ConstantSize) {
300                 return new BoundedSize(size1, setMax ? null : size2,
301                                                setMax ? size2 : null);
302             } else
303                 throw new IllegalArgumentException JavaDoc(
304                                 "Bounded sizes must not be both logical.");
305         }
306     }
307     
308     
309     /**
310      * Decodes and answers an atomic size that is either a constant size or a
311      * component size.
312      * @param token the encoded size
313      * @return the decoded size either a constant or component size
314      */

315     private Size decodeAtomicSize(String JavaDoc token) {
316         Sizes.ComponentSize componentSize = Sizes.ComponentSize.valueOf(token);
317         if (componentSize != null)
318             return componentSize;
319         else
320             return ConstantSize.valueOf(token, isHorizontal());
321     }
322     
323     
324     /**
325      * Decodes an encoded resize mode and resize weight and answers
326      * the resize weight.
327      * @param token the encoded resize weight
328      * @return the decoded resize weight
329      * @throws IllegalArgumentException if the string description is an
330      * invalid string representation
331      */

332     private double decodeResize(String JavaDoc token) {
333         if (token.equals("g") || token.equals("grow")) {
334             return DEFAULT_GROW;
335         }
336         if (token.equals("n") || token.equals("nogrow") || token.equals("none")) {
337             return NO_GROW;
338         }
339         // Must have format: grow(<double>)
340
if ((token.startsWith("grow(") || token.startsWith("g("))
341              && token.endsWith(")")) {
342             int leftParen = token.indexOf('(');
343             int rightParen = token.indexOf(')');
344             String JavaDoc substring = token.substring(leftParen + 1, rightParen);
345             return Double.parseDouble(substring);
346         } else {
347             throw new IllegalArgumentException JavaDoc(
348                     "The resize argument '" + token + "' is invalid. " +
349                     " Must be one of: grow, g, none, n, grow(<double>), g(<double>)");
350         }
351     }
352     
353     
354     // Misc *****************************************************************
355

356     /**
357      * Returns a string representation of this form specification.
358      * The string representation consists of three elements separated by
359      * a colon (<tt>":"</tt>), first the alignment, second the size,
360      * and third the resize spec.
361      *
362      * @return a string representation of the form specification.
363      */

364     public final String JavaDoc toString() {
365         StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
366         buffer.append(defaultAlignment);
367         
368         buffer.append(":");
369         buffer.append(size.toString());
370         buffer.append(':');
371         if (resizeWeight == NO_GROW) {
372             buffer.append("noGrow");
373         } else if (resizeWeight == DEFAULT_GROW) {
374             buffer.append("grow");
375         } else {
376             buffer.append("grow(");
377             buffer.append(resizeWeight);
378             buffer.append(')');
379         }
380         return buffer.toString();
381     }
382     
383     /**
384      * Returns a string representation of this form specification.
385      * The string representation consists of three elements separated by
386      * a colon (<tt>":"</tt>), first the alignment, second the size,
387      * and third the resize spec.
388      *
389      * @return a string representation of the form specification.
390      */

391     public final String JavaDoc toShortString() {
392         StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
393         buffer.append(defaultAlignment.abbreviation());
394         
395         buffer.append(":");
396         buffer.append(size.toString());
397         buffer.append(':');
398         if (resizeWeight == NO_GROW) {
399             buffer.append("n");
400         } else if (resizeWeight == DEFAULT_GROW) {
401             buffer.append("g");
402         } else {
403             buffer.append("g(");
404             buffer.append(resizeWeight);
405             buffer.append(')');
406         }
407         return buffer.toString();
408     }
409     
410     
411     // Abstract Behavior ****************************************************
412

413     /**
414      * Returns if this is a horizontal specification (vs. vertical).
415      * Used to distinct between horizontal and vertical dialog units,
416      * which have different conversion factors.
417      * @return true for horizontal, false for vertical
418      */

419     abstract boolean isHorizontal();
420
421
422     // Helper Code **********************************************************
423

424     /**
425      * Computes the maximum size for the given list of components, using
426      * this form spec and the specified measure.
427      * <p>
428      * Invoked by FormLayout to determine the size of one of my elements
429      */

430     final int maximumSize(Container JavaDoc container,
431                     List JavaDoc components,
432                     FormLayout.Measure minMeasure,
433                     FormLayout.Measure prefMeasure,
434                     FormLayout.Measure defaultMeasure) {
435         return size.maximumSize(container,
436                                  components,
437                                  minMeasure,
438                                  prefMeasure,
439                                  defaultMeasure);
440     }
441     
442     
443     /**
444      * A typesafe enumeration for the column and row default alignment types.
445      */

446     public static final class DefaultAlignment {
447         
448         private final String JavaDoc name;
449
450         private DefaultAlignment(String JavaDoc name) {
451             this.name = name;
452         }
453
454         /**
455          * Answers a DefaultAlignment that corresponds to the specified
456          * string, null if no such aignment exists.
457          * @param str the encoded alignment
458          * @param isHorizontal indicates the values orientation
459          * @return the corresponding DefaultAlignment or null
460          */

461         static DefaultAlignment valueOf(String JavaDoc str, boolean isHorizontal) {
462             if (str.equals("f") || str.equals("fill"))
463                 return FILL_ALIGN;
464             else if (str.equals("c") || str.equals("center"))
465                 return CENTER_ALIGN;
466             else if (isHorizontal) {
467                 if (str.equals("r") || str.equals("right"))
468                     return RIGHT_ALIGN;
469                 else if (str.equals("l") || str.equals("left"))
470                     return LEFT_ALIGN;
471                 else
472                     return null;
473             } else {
474                 if (str.equals("t") || str.equals("top"))
475                     return TOP_ALIGN;
476                 else if (str.equals("b") || str.equals("bottom"))
477                     return BOTTOM_ALIGN;
478                 else
479                     return null;
480             }
481         }
482
483         public String JavaDoc toString() { return name; }
484
485         public char abbreviation() { return name.charAt(0); }
486
487     }
488     
489     
490 }
491
492
Popular Tags