View Javadoc

1   /*
2    * Copyright (c) 1998, 2005 Gargoyle Software Inc. 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    * 1. Redistributions of source code must retain the above copyright notice,
8    *    this list of conditions and the following disclaimer.
9    * 2. Redistributions in binary form must reproduce the above copyright notice,
10   *    this list of conditions and the following disclaimer in the documentation
11   *    and/or other materials provided with the distribution.
12   * 3. The end-user documentation included with the redistribution, if any, must
13   *    include the following acknowledgment:
14   *
15   *       "This product includes software developed by Gargoyle Software Inc.
16   *        (http://www.GargoyleSoftware.com/)."
17   *
18   *    Alternately, this acknowledgment may appear in the software itself, if
19   *    and wherever such third-party acknowledgments normally appear.
20   * 4. The name "Gargoyle Software" must not be used to endorse or promote
21   *    products derived from this software without prior written permission.
22   *    For written permission, please contact info@GargoyleSoftware.com.
23   * 5. Products derived from this software may not be called "GSBase", nor may
24   *    "GSBase" appear in their name, without prior written permission of
25   *    Gargoyle Software Inc.
26   *
27   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
28   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
29   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GARGOYLE
30   * SOFTWARE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
31   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
33   * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34   * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35   * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
36   * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37   */
38  package com.gargoylesoftware.base.gui;
39  
40  import com.gargoylesoftware.base.util.DetailedIllegalArgumentException;
41  import com.gargoylesoftware.base.util.DetailedNullPointerException;
42  import java.io.Serializable;
43  
44  /***
45   * This object contains all the constraints that apply to a specific
46   * component inside a TableLayout.
47   * <p>
48   * We use the convention of specifying row before column to conform with the
49   * swing standards.  This seems counterintuitive when specifying x,y
50   * (actually y,x) co-ordinates however we felt it was more important to
51   * conform to existing java layout standards.
52   *
53   * @version $Revision: 1.6 $
54   * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
55   */
56  public class TableLayoutConstraints implements Serializable {
57  
58      // Required for serialization - do not remove or modify.
59      private static final long serialVersionUID = 4323958798646824406L;
60  
61      private boolean isImmutable_ = false;
62  
63      // Note that the default value for obeyMaximumSize is FALSE
64      private boolean obeyMaximumSize_ = false;
65  
66      private boolean obeyMinimumSize_ = true;
67  
68      private int row_;
69      private int column_;
70      private int rowSpan_;
71      private int columnSpan_;
72      private int verticalAlignment_;
73      private boolean verticalStretch_;
74      private int horizontalAlignment_;
75      private boolean horizontalStretch_;
76  
77      /***
78       * Create a new instance.
79       * @param row The starting row.
80       * @param column The starting column.
81       */
82      public TableLayoutConstraints( final int row,
83                                     final int column ) {
84  
85          setRow(row);
86          setColumn(column);
87  
88          setRowSpan(1);
89          setColumnSpan(1);
90          setVerticalAlignment( TableLayout.CENTER );
91          setHorizontalAlignment( TableLayout.LEFT );
92          setVerticalStretch( false );
93          setHorizontalStretch( false );
94      }
95  
96      /***
97       * Return a string representation of this object.
98       * @return Return a string representation of this object.
99       */
100     public final String toString() {
101         return getClass().getName()
102         + "] row_=[" + row_
103         + "] rowSpan_=[" + rowSpan_
104         + "] column_=[" + column_
105         + "] columnSpan_=[" + columnSpan_
106         + "] verticalAlignment_=[" + verticalAlignment_
107         + "] verticalStretch_=["+ verticalStretch_
108         + "] horizontalAlignment_=[" + horizontalAlignment_
109         + "] horizontalStretch_=["+ horizontalStretch_
110         + "] isImmutable_=["+ isImmutable_
111         + "] obeyMinimumSize_=["+ obeyMinimumSize_
112         + "] obeyMaximumSize_=["+ obeyMaximumSize_
113         + "]";
114 
115     }
116 
117     /***
118      * Make this object immutable.
119      */
120     public final void setImmutable() {
121         isImmutable_ = true;
122     }
123 
124     /***
125      * Return true if this object is immutable.
126      * @return Return true if this object is immutable.
127      */
128     public final boolean isImmutable() {
129         return isImmutable_;
130     }
131 
132     /***
133      * Check to make sure that we are allowed to modify this object.  If not, throw an
134      * exception.
135      * @throws IllegalArgumentException If the object is immutable
136      */
137     private void ensureMutable() throws IllegalArgumentException {
138         if( isImmutable_ == true ) {
139             throw new IllegalArgumentException("This object is now immutable and cannot be modified");
140         }
141     }
142 
143     /***
144      * Set the row.
145      * @param row The row.
146      */
147     public final void setRow( final int row ) {
148         ensureMutable();
149         if( row < 0 ) {
150             throw new DetailedIllegalArgumentException("row", new Integer(row), "Is less than zero");
151         }
152         row_ = row;
153     }
154 
155     /***
156      * Return the row.
157      * @return The row.
158      */
159     public final int getRow() {
160         return row_;
161     }
162 
163     /***
164      * Set the column.
165      * @param column The new column.
166      */
167     public final void setColumn( final int column ) {
168         ensureMutable();
169         if( column < 0 ) {
170             throw new DetailedIllegalArgumentException("column", new Integer(column), "Is less than zero");
171         }
172         column_ = column;
173     }
174 
175     /***
176      * Return the column.
177      * @return The column.
178      */
179     public final int getColumn() {
180         return column_;
181     }
182 
183     /***
184      * Set the number of rows that this component will span.  The new span
185      * must be greater than or equal to one.
186      * @param span The new row span.
187      */
188     public final void setRowSpan( final int span ) {
189         ensureMutable();
190         if( span < 1 ) {
191             throw new DetailedIllegalArgumentException("span", span, "Is less than one");
192         }
193         rowSpan_ = span;
194     }
195 
196     /***
197      * Return the number of rows this component will span.
198      * @return The row span.
199      */
200     public final int getRowSpan() {
201         return rowSpan_;
202     }
203 
204     /***
205      * Set the number of columns that this component will span.  The new span
206      * must be greater than or equal to one.
207      * @param span The new span.
208      */
209     public final void setColumnSpan( final int span ) {
210         ensureMutable();
211         if( span < 1 ) {
212             throw new DetailedIllegalArgumentException("span", new Integer(span), "Is less than one");
213         }
214         columnSpan_ = span;
215     }
216 
217     /***
218      * Return the number of columns this component will span.
219      * @return the column span.
220      */
221     public final int getColumnSpan() {
222         return columnSpan_;
223     }
224 
225     /***
226      * Set the vertical alignment of the component within the specified area.
227      * Possible values are
228      * <ul>
229      * <li>TableLayout.TOP
230      * <li>TableLayout.BOTTOM
231      * <li>TableLayout.CENTER
232      * </ul>
233      * @param alignment The new alignment.
234      */
235     public final void setVerticalAlignment( final int alignment ) {
236         ensureMutable();
237         switch( alignment ) {
238         case TableLayout.TOP:
239         case TableLayout.BOTTOM:
240         case TableLayout.CENTER:
241             // Legal values
242             break;
243 
244         default:
245             throw new DetailedIllegalArgumentException("alignment", alignment);
246         }
247 
248         verticalAlignment_ = alignment;
249     }
250 
251     /***
252      * Return the vertical alignment.
253      * @return Return the vertical alignment.
254      */
255     public final int getVerticalAlignment() {
256         return verticalAlignment_;
257     }
258 
259     /***
260      * Set the horizontal alignment of the component within the specified
261      * area. Possible values are
262      * <ul>
263      * <li>TableLayout.LEFT
264      * <li>TableLayout.RIGHT
265      * <li>TableLayout.CENTER
266      * </ul>
267      * @param alignment The new alignment.
268      */
269     public final void setHorizontalAlignment( final int alignment ) {
270         ensureMutable();
271 
272         switch( alignment ) {
273         case TableLayout.LEFT:
274         case TableLayout.RIGHT:
275         case TableLayout.CENTER:
276             // Legal values
277             break;
278 
279         default:
280             throw new DetailedIllegalArgumentException("alignment", alignment);
281         }
282 
283         horizontalAlignment_ = alignment;
284     }
285 
286     /***
287      * Return the horizontalAlignment.
288      * @return Return the horizontalAlignment.
289      */
290     public final int getHorizontalAlignment() {
291         return horizontalAlignment_;
292     }
293 
294     /***
295      * Set whether or not this component can be stretched vertically.
296      * @param stretch true if the component will stretch vertically.
297      */
298     public final void setVerticalStretch( final boolean stretch ) {
299         ensureMutable();
300         verticalStretch_ = stretch;
301     }
302 
303     /***
304      * Return true if this component can be stretched vertically.
305      * @return Return true if this component can be stretched vertically.
306      */
307     public final boolean getVerticalStretch() {
308         return verticalStretch_;
309     }
310 
311     /***
312      * Set whether or not this component can be stretched horizontally.
313      * @param stretch true if the component will stretch horizontally.
314      */
315     public final void setHorizontalStretch( final boolean stretch ) {
316         ensureMutable();
317         horizontalStretch_ = stretch;
318     }
319 
320     /***
321      * Return true if this component can be stretched horizontally.
322      * @return Return true if this component can be stretched horizontally.
323      */
324     public final boolean getHorizontalStretch() {
325         return horizontalStretch_;
326     }
327 
328     /***
329      * Set whether or not the component should obey it's maximum size.  Most components
330      * do not provide sensible maximum values so always obeying these values, ends up
331      * with very strange layouts.  The default value is false.
332      * @param obey true if we are to obey the maximum size.
333      */
334     public final void setObeyMaximumSize( final boolean obey ) {
335         ensureMutable();
336         obeyMaximumSize_ = obey;
337     }
338 
339     /***
340      * Return true if we are obeying the maximum size.
341      * @return Return true if we are obeying the maximum size.
342      */
343     public final boolean getObeyMaximumSize() {
344         return obeyMaximumSize_;
345     }
346 
347     /***
348      * Set whether or not we should obey the minimum size of the component.  Default is true.
349      * @param obey true if we are to obey the minimum size.
350      */
351     public final void setObeyMinimumSize( final boolean obey ) {
352         ensureMutable();
353         obeyMinimumSize_ = obey;
354     }
355 
356     /***
357      * Return true if we are obeying the minimum size.
358      * @return Return true if we are obeying the minimum size.
359      */
360     public final boolean getObeyMinimumSize() {
361         return obeyMinimumSize_;
362     }
363 
364     /***
365      * Create an instance of TableLayoutConstraints from the specified string.
366      * Format: "1,1"
367      * @param constraintString The constraints string.
368      * @return A new TableLayoutConstraints object.
369      */
370     public static TableLayoutConstraints makeConstraints( final String constraintString ) {
371         assertNotNull("constraintString", constraintString);
372         if( constraintString.length() == 0 ) {
373             throw new DetailedIllegalArgumentException("constraintString", constraintString, "May not be empty");
374         }
375 
376         final int commaIndex = constraintString.indexOf(',');
377         if( commaIndex == -1 ) {
378             throw new DetailedIllegalArgumentException("constraintString", constraintString, "Missing a comma");
379         }
380 
381         final TableLayoutConstraints constraints = new TableLayoutConstraints(0,0);
382         parseConstraintString( constraints, constraintString.substring(0, commaIndex), true );
383         parseConstraintString( constraints, constraintString.substring(commaIndex+1), false );
384 
385         return constraints;
386     }
387 
388     /***
389      * Parse the constraint string.
390      * @param constraints The new constraints object
391      * @param constraintString The constraints as an input string
392      * @param isRow true if these constraints are for a row
393      */
394     private static void parseConstraintString( final TableLayoutConstraints constraints,
395                                                final String constraintString,
396                                                final boolean isRow ) {
397 
398         final int stringLength = constraintString.length();
399 
400         if( stringLength == 0 ) {
401             throw new DetailedIllegalArgumentException("constraintString", constraintString, "May not be empty");
402         }
403 
404         int index = 0;
405         while( index < stringLength && Character.isDigit( constraintString.charAt(index) ) ) {
406             index++;
407         }
408 
409         final int number = Integer.parseInt( constraintString.substring(0,index) );
410         if( isRow ) {
411             constraints.setRow(number);
412         }
413         else {
414             constraints.setColumn(number);
415         }
416 
417         char nextChar;
418 
419         for( ;index < stringLength; index++ ) {
420             nextChar = constraintString.charAt(index);
421 
422             switch(nextChar) {
423                 case 's':
424                     if( isRow ) {
425                         constraints.setVerticalStretch(true);
426                     }
427                     else {
428                         constraints.setHorizontalStretch(true);
429                     }
430                     break;
431 
432                 case '+':
433                     index++;
434                     final int startIndex = index;
435                     while( index < stringLength && Character.isDigit( constraintString.charAt(index) ) ) {
436                         index++;
437                     }
438 
439                     final int span = Integer.parseInt( constraintString.substring(startIndex,index) );
440                     if( isRow ) {
441                         constraints.setRowSpan(span);
442                     }
443                     else {
444                         constraints.setColumnSpan(span);
445                     }
446                     index--;
447                     break;
448 
449                 default:
450                     throw new IllegalArgumentException("Unexpected command ["+nextChar+"]");
451             }
452         }
453     }
454 
455 
456     /***
457      * Verify that the specified value is not null.  If it is then throw an exception
458      *
459      * @param fieldName The name of the field to check
460      * @param fieldValue The value of the field to check
461      * @exception DetailedNullPointerException If fieldValue is null
462      */
463     protected static final void assertNotNull( final String fieldName, final Object fieldValue )
464         throws DetailedNullPointerException {
465 
466         if( fieldValue == null ) {
467             throw new DetailedNullPointerException(fieldName);
468         }
469     }
470 }
471