~ubuntu-branches/ubuntu/trusty/libjgoodies-forms-java/trusty

« back to all changes in this revision

Viewing changes to src/main/com/jgoodies/forms/layout/CellConstraints.java

  • Committer: Bazaar Package Importer
  • Author(s): Eric Lavarde
  • Date: 2006-03-23 20:54:19 UTC
  • Revision ID: james.westby@ubuntu.com-20060323205419-emo7oazp2lspvl3b
Tags: upstream-1.0.5
ImportĀ upstreamĀ versionĀ 1.0.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2002-2004 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.Component;
 
34
import java.awt.Insets;
 
35
import java.awt.Rectangle;
 
36
import java.io.Serializable;
 
37
import java.util.StringTokenizer;
 
38
 
 
39
/**
 
40
 * Defines constraints for components that are layed out with the FormLayout.
 
41
 * Defines the components display area: grid x, grid y, 
 
42
 * grid width (column span), grid height (row span), horizontal alignment 
 
43
 * and vertical alignment.<p>
 
44
 * 
 
45
 * Most methods return <em>this</em> object to enable method chaining.<p>
 
46
 * 
 
47
 * You can set optional insets in a constructor. This is useful if you
 
48
 * need to use a pixel-size insets to align perceived component bounds
 
49
 * with pixel data, for example an icon. Anyway, this is rarely used.
 
50
 * The insets don't affect the size computation for columns and rows.
 
51
 * I consider renaming the insets to offsets to better indicate the
 
52
 * motivation for this option.<p>
 
53
 * 
 
54
 * <strong>Examples</strong>:<br>
 
55
 * The following cell constraints locate a component in the third
 
56
 * column of the fifth row; column and row span are 1; the component
 
57
 * will be aligned with the column's right-hand side and the row's
 
58
 * bottom.
 
59
 * <pre>
 
60
 * CellConstraints cc = new CellConstraints();
 
61
 * cc.xy  (3, 5);
 
62
 * cc.xy  (3, 5, CellConstraints.RIGHT, CellConstraints.BOTTOM);
 
63
 * cc.xy  (3, 5, "right, bottom");
 
64
 * 
 
65
 * cc.xyw (3, 5, 1);
 
66
 * cc.xyw (3, 5, 1, CellConstraints.RIGHT, CellConstraints.BOTTOM);
 
67
 * cc.xyw (3, 5, 1, "right, bottom");
 
68
 *  
 
69
 * cc.xywh(3, 5, 1, 1);
 
70
 * cc.xywh(3, 5, 1, 1, CellConstraints.RIGHT, CellConstraints.BOTTOM);
 
71
 * cc.xywh(3, 5, 1, 1, "right, bottom"); 
 
72
 * </pre>
 
73
 * See also the examples in the {@link FormLayout} class comment.<p>
 
74
 * 
 
75
 * TODO: Consider renaming the inset to offsets.
 
76
 *
 
77
 * @author      Karsten Lentzsch
 
78
 * @version $Revision: 1.13 $
 
79
 */
 
80
public final class CellConstraints implements Cloneable, Serializable {
 
81
    
 
82
    // Alignment Constants *************************************************
 
83
    
 
84
    /*
 
85
     * Implementation Note: Do not change the order of the following constants.
 
86
     * The serialization of class Alignment is ordinal-based and relies on it.
 
87
     */
 
88
    
 
89
    /**
 
90
     * Use the column's or row's default alignment.
 
91
     */
 
92
    public static final Alignment DEFAULT =
 
93
        new Alignment("default", Alignment.BOTH);
 
94
 
 
95
    /**
 
96
     * Fill the cell either horizontally or vertically.
 
97
     */
 
98
    public static final Alignment FILL = 
 
99
        new Alignment("fill", Alignment.BOTH);
 
100
 
 
101
    /**
 
102
     * Put the component in the left.
 
103
     */
 
104
    public static final Alignment LEFT =
 
105
        new Alignment("left", Alignment.HORIZONTAL);
 
106
 
 
107
    /**
 
108
     * Put the component in the right.
 
109
     */
 
110
    public static final Alignment RIGHT =
 
111
        new Alignment("right", Alignment.HORIZONTAL);
 
112
    
 
113
    /**
 
114
     * Put the component in the center.
 
115
     */
 
116
    public static final Alignment CENTER =
 
117
        new Alignment("center", Alignment.BOTH);
 
118
 
 
119
    /**
 
120
     * Put the component in the top.
 
121
     */
 
122
    public static final Alignment TOP =
 
123
        new Alignment("top", Alignment.VERTICAL);
 
124
 
 
125
    /**
 
126
     * Put the component in the bottom.
 
127
     */
 
128
    public static final Alignment BOTTOM =
 
129
        new Alignment("bottom", Alignment.VERTICAL);
 
130
 
 
131
    /**
 
132
     * An array of all enumeration values used to canonicalize 
 
133
     * deserialized alignments.
 
134
     */
 
135
    private static final Alignment[] VALUES = 
 
136
        { DEFAULT, FILL, LEFT, RIGHT, CENTER, TOP, BOTTOM };
 
137
    
 
138
    /**
 
139
     * A reusable <code>Insets</code> object to reduce object instantiation.
 
140
     */
 
141
    private static final Insets EMPTY_INSETS = 
 
142
        new Insets(0, 0, 0, 0);
 
143
    
 
144
    
 
145
    // Fields ***************************************************************
 
146
    
 
147
    /**
 
148
     * Describes the component's horizontal grid origin (starts at 1).
 
149
     */
 
150
    public int gridX;
 
151
 
 
152
    /**
 
153
     * Describes the component's vertical grid origin (starts at 1).
 
154
     */
 
155
    public int gridY;
 
156
 
 
157
    /**
 
158
     * Describes the component's horizontal grid extend (number of cells).
 
159
     */
 
160
    public int gridWidth;
 
161
 
 
162
    /**
 
163
     * Describes the component's vertical grid extent (number of cells).
 
164
     */
 
165
    public int gridHeight;
 
166
    
 
167
    /**
 
168
     * Describes the component's horizontal alignment.
 
169
     */
 
170
    public Alignment hAlign;
 
171
    
 
172
    /**
 
173
     * Describes the component's vertical alignment.
 
174
     */
 
175
    public Alignment vAlign;
 
176
    
 
177
    /**
 
178
     * Describes the component's <code>Insets</code> in it's display area.
 
179
     */
 
180
    public Insets insets;
 
181
    
 
182
    
 
183
    // Instance Creation ****************************************************
 
184
    
 
185
    /**
 
186
     * Constructs a default instance of <code>CellConstraints</code>.
 
187
     */
 
188
    public CellConstraints() {
 
189
        this(1, 1);
 
190
    }
 
191
    
 
192
 
 
193
    /**
 
194
     * Constructs an instance of <code>CellConstraints</code> for the given
 
195
     * cell position.<p>
 
196
     * 
 
197
     * <strong>Examples:</strong><pre>
 
198
     * new CellConstraints(1, 3);
 
199
     * new CellConstraints(1, 3);
 
200
     * </pre>
 
201
     * 
 
202
     * @param gridX     the component's horizontal grid origin
 
203
     * @param gridY     the component's vertical grid origin
 
204
     */
 
205
    public CellConstraints(int gridX, int gridY) {
 
206
        this(gridX, gridY, 1, 1);
 
207
    }
 
208
    
 
209
 
 
210
    /**
 
211
     * Constructs an instance of <code>CellConstraints</code> for the given
 
212
     * cell position, anchor, and fill.<p>
 
213
     * 
 
214
     * <strong>Examples:</strong><pre>
 
215
     * new CellConstraints(1, 3, CellConstraints.LEFT,   CellConstraints.BOTTOM);
 
216
     * new CellConstraints(1, 3, CellConstraints.CENTER, CellConstraints.FILL);
 
217
     * </pre>
 
218
     * 
 
219
     * @param gridX     the component's horizontal grid origin
 
220
     * @param gridY     the component's vertical grid origin
 
221
     * @param hAlign    the component's horizontal alignment
 
222
     * @param vAlign    the component's vertical alignment
 
223
     */
 
224
    public CellConstraints(int gridX, int gridY, 
 
225
                            Alignment hAlign, Alignment vAlign) {
 
226
        this(gridX, gridY, 1, 1, hAlign, vAlign, EMPTY_INSETS);
 
227
    }
 
228
 
 
229
    
 
230
    /**
 
231
     * Constructs an instance of <code>CellConstraints</code> for the given
 
232
     * cell position and size.<p>
 
233
     * 
 
234
     * <strong>Examples:</strong><pre>
 
235
     * new CellConstraints(1, 3, 2, 1);
 
236
     * new CellConstraints(1, 3, 7, 3);
 
237
     * </pre>
 
238
     * 
 
239
     * @param gridX             the component's horizontal grid origin
 
240
     * @param gridY             the component's vertical grid origin
 
241
     * @param gridWidth the component's horizontal extent
 
242
     * @param gridHeight        the component's vertical extent
 
243
     */
 
244
    public CellConstraints(int gridX, int gridY, int gridWidth, int gridHeight) {
 
245
        this(gridX, gridY, gridWidth, gridHeight, DEFAULT, DEFAULT);
 
246
    }
 
247
    
 
248
 
 
249
    /**
 
250
     * Constructs an instance of <code>CellConstraints</code> for the given
 
251
     * cell position and size, anchor, and fill.<p>
 
252
     * 
 
253
     * <strong>Examples:</strong><pre>
 
254
     * new CellConstraints(1, 3, 2, 1, CellConstraints.LEFT,   CellConstraints.BOTTOM);
 
255
     * new CellConstraints(1, 3, 7, 3, CellConstraints.CENTER, CellConstraints.FILL);
 
256
     * </pre>
 
257
     * 
 
258
     * @param gridX             the component's horizontal grid origin
 
259
     * @param gridY             the component's vertical grid origin
 
260
     * @param gridWidth the component's horizontal extent
 
261
     * @param gridHeight        the component's vertical extent
 
262
     * @param hAlign            the component's horizontal alignment
 
263
     * @param vAlign            the component's vertical alignment
 
264
     */
 
265
    public CellConstraints(int gridX, int gridY, int gridWidth, int gridHeight,
 
266
                            Alignment hAlign, Alignment vAlign) {
 
267
        this(gridX, gridY, gridWidth, gridHeight, hAlign, vAlign, EMPTY_INSETS);
 
268
    }
 
269
    
 
270
 
 
271
    /**
 
272
     * Constructs an instance of <code>CellConstraints</code> for 
 
273
     * the complete set of available properties.<p>
 
274
     * 
 
275
     * <strong>Examples:</strong><pre>
 
276
     * new CellConstraints(1, 3, 2, 1, CellConstraints.LEFT,   CellConstraints.BOTTOM, new Insets(0, 1, 0, 3));
 
277
     * new CellConstraints(1, 3, 7, 3, CellConstraints.CENTER, CellConstraints.FILL,   new Insets(0, 1, 0, 0));
 
278
     * </pre>
 
279
     * 
 
280
     * @param gridX             the component's horizontal grid origin
 
281
     * @param gridY             the component's vertical grid origin
 
282
     * @param gridWidth         the component's horizontal extent
 
283
     * @param gridHeight        the component's vertical extent
 
284
     * @param hAlign            the component's horizontal alignment
 
285
     * @param vAlign            the component's vertical alignment
 
286
     * @param insets            the component's display area <code>Insets</code>
 
287
     * @throws IndexOutOfBoundsException if the grid origin or extent is negative
 
288
     * @throws NullPointerException if the horizontal or vertical alignment is null
 
289
     * @throws IllegalArgumentException if an alignment orientation is invalid
 
290
     */
 
291
    public CellConstraints(int gridX, int gridY, int gridWidth, int gridHeight, 
 
292
                            Alignment hAlign, Alignment vAlign, Insets insets) {
 
293
                this.gridX      = gridX;
 
294
        this.gridY      = gridY;
 
295
        this.gridWidth  = gridWidth;
 
296
        this.gridHeight = gridHeight;
 
297
        this.hAlign     = hAlign;
 
298
        this.vAlign     = vAlign;
 
299
        this.insets     = insets;
 
300
        if (gridX <= 0)
 
301
            throw new IndexOutOfBoundsException("The grid x must be a positive number.");
 
302
        if (gridY <= 0)
 
303
            throw new IndexOutOfBoundsException("The grid y must be a positive number.");
 
304
        if (gridWidth <= 0)
 
305
            throw new IndexOutOfBoundsException("The grid width must be a positive number.");
 
306
        if (gridHeight <= 0)
 
307
            throw new IndexOutOfBoundsException("The grid height must be a positive number.");
 
308
        if (hAlign == null)
 
309
            throw new NullPointerException("The horizontal alignment must not be null.");
 
310
        if (vAlign == null)
 
311
            throw new NullPointerException("The vertical alignment must not be null.");
 
312
        ensureValidOrientations(hAlign, vAlign);
 
313
    }
 
314
    
 
315
    
 
316
    /**
 
317
     * Constructs an instance of <code>CellConstraints</code> from
 
318
     * the given encoded string properties.<p>
 
319
     * 
 
320
     * <strong>Examples:</strong><pre>
 
321
     * new CellConstraints("1, 3");
 
322
     * new CellConstraints("1, 3, left, bottom");
 
323
     * new CellConstraints("1, 3, 2, 1, left, bottom");
 
324
     * new CellConstraints("1, 3, 2, 1, l, b");
 
325
     * </pre>
 
326
     * 
 
327
     * @param encodedConstraints        the constraints encoded as string
 
328
     */
 
329
    public CellConstraints(String encodedConstraints) {
 
330
        this();
 
331
        initFromConstraints(encodedConstraints);
 
332
    }        
 
333
        
 
334
 
 
335
    // Setters **************************************************************
 
336
 
 
337
    /**
 
338
     * Sets row and column origins; sets width and height to 1; 
 
339
     * uses the default alignments.<p>
 
340
     * 
 
341
     * <strong>Examples:</strong><pre>
 
342
     * cc.xy(1, 1);
 
343
     * cc.xy(1, 3);
 
344
     * </pre>
 
345
     * 
 
346
     * @param col     the new column index
 
347
     * @param row     the new row index
 
348
     * @return this
 
349
     */
 
350
    public CellConstraints xy(int col, int row) {
 
351
        return xywh(col, row, 1, 1);
 
352
    }
 
353
    
 
354
        
 
355
    /**
 
356
     * Sets row and column origins; sets width and height to 1; 
 
357
     * decodes horizontal and vertical alignments from the given string.<p>
 
358
     * 
 
359
     * <strong>Examples:</strong><pre>
 
360
     * cc.xy(1, 3, "left, bottom");
 
361
     * cc.xy(1, 3, "l, b");
 
362
     * cc.xy(1, 3, "center, fill");
 
363
     * cc.xy(1, 3, "c, f");
 
364
     * </pre>
 
365
     * 
 
366
     * @param col                the new column index
 
367
     * @param row                the new row index
 
368
     * @param encodedAlignments  describes the horizontal and vertical alignments
 
369
     * @return this
 
370
     * @throws IllegalArgumentException if an alignment orientation is invalid
 
371
     */
 
372
    public CellConstraints xy(int col, int row, String encodedAlignments) {
 
373
        return xywh(col, row, 1, 1, encodedAlignments);
 
374
    }
 
375
 
 
376
    /**
 
377
     * Sets the row and column origins; sets width and height to 1;
 
378
     * set horizontal and vertical alignment using the specified objects.<p>
 
379
     * 
 
380
     * <strong>Examples:</strong><pre>
 
381
     * cc.xy(1, 3, CellConstraints.LEFT,   CellConstraints.BOTTOM);
 
382
     * cc.xy(1, 3, CellConstraints.CENTER, CellConstraints.FILL);
 
383
     * </pre>
 
384
     *
 
385
     * @param col       the new column index
 
386
     * @param row       the new row index
 
387
     * @param colAlign  horizontal component alignment
 
388
     * @param rowAlign  vertical component alignment     
 
389
     * @return this
 
390
     */
 
391
    public CellConstraints xy(int col, int row, 
 
392
                              Alignment colAlign, Alignment rowAlign) {
 
393
        return xywh(col, row, 1, 1, colAlign, rowAlign);
 
394
    }
 
395
    
 
396
 
 
397
    /**
 
398
     * Sets the row, column, width, and height; uses a height (row span) of 1 
 
399
     * and the horizontal and vertical default alignments.<p>
 
400
     * 
 
401
     * <strong>Examples:</strong><pre>
 
402
     * cc.xyw(1, 3, 7);
 
403
     * cc.xyw(1, 3, 2);
 
404
     * </pre>
 
405
     * 
 
406
     * @param col      the new column index
 
407
     * @param row      the new row index
 
408
     * @param colSpan  the column span or grid width
 
409
     * @return this
 
410
     */
 
411
    public CellConstraints xyw(int col, int row, int colSpan) {
 
412
        return xywh(col, row, colSpan, 1, DEFAULT, DEFAULT);
 
413
    }
 
414
        
 
415
 
 
416
    /**
 
417
     * Sets the row, column, width, and height; 
 
418
     * decodes the horizontal and vertical alignments from the given string.
 
419
     * The row span (height) is set to 1.<p>
 
420
     * 
 
421
     * <strong>Examples:</strong><pre>
 
422
     * cc.xyw(1, 3, 7, "left, bottom");
 
423
     * cc.xyw(1, 3, 7, "l, b");
 
424
     * cc.xyw(1, 3, 2, "center, fill");
 
425
     * cc.xyw(1, 3, 2, "c, f");
 
426
     * </pre>
 
427
     *  
 
428
     * @param col                the new column index
 
429
     * @param row                the new row index
 
430
     * @param colSpan            the column span or grid width
 
431
     * @param encodedAlignments  describes the horizontal and vertical alignments
 
432
     * @return this
 
433
     * @throws IllegalArgumentException if an alignment orientation is invalid
 
434
     */
 
435
    public CellConstraints xyw(int col, int row, int colSpan,  
 
436
                                 String encodedAlignments) {
 
437
        return xywh(col, row, colSpan, 1, encodedAlignments);
 
438
    }
 
439
 
 
440
    
 
441
    /**
 
442
     * Sets the row, column, width, and height; sets the horizontal 
 
443
     * and vertical aligment using the specified alignment objects.
 
444
     * The row span (height) is set to 1.<p>
 
445
     * 
 
446
     * <strong>Examples:</strong><pre>
 
447
     * cc.xyw(1, 3, 2, CellConstraints.LEFT,   CellConstraints.BOTTOM);
 
448
     * cc.xyw(1, 3, 7, CellConstraints.CENTER, CellConstraints.FILL);
 
449
     * </pre>
 
450
     *
 
451
     * @param col       the new column index
 
452
     * @param row       the new row index
 
453
     * @param colSpan   the column span or grid width
 
454
     * @param colAlign  horizontal component alignment
 
455
     * @param rowAlign  vertical component alignment     
 
456
     * @return this
 
457
     * @throws IllegalArgumentException if an alignment orientation is invalid
 
458
     */
 
459
    public CellConstraints xyw(int col, int row, int colSpan, 
 
460
                                 Alignment colAlign, Alignment rowAlign) {
 
461
        return xywh(col, row, colSpan, 1, colAlign, rowAlign);
 
462
    }
 
463
    
 
464
 
 
465
    /**
 
466
     * Sets the row, column, width, and height; uses default alignments.<p>
 
467
     * 
 
468
     * <strong>Examples:</strong><pre>
 
469
     * cc.xywh(1, 3, 2, 1);
 
470
     * cc.xywh(1, 3, 7, 3);
 
471
     * </pre>
 
472
     * 
 
473
     * @param col      the new column index
 
474
     * @param row      the new row index
 
475
     * @param colSpan  the column span or grid width
 
476
     * @param rowSpan  the row span or grid height
 
477
     * @return this
 
478
     */
 
479
    public CellConstraints xywh(int col, int row, int colSpan, int rowSpan) {
 
480
        return xywh(col, row, colSpan, rowSpan, DEFAULT, DEFAULT);
 
481
    }
 
482
    
 
483
 
 
484
    /**
 
485
     * Sets the row, column, width, and height; 
 
486
     * decodes the horizontal and vertical alignments from the given string.<p>
 
487
     * 
 
488
     * <strong>Examples:</strong><pre>
 
489
     * cc.xywh(1, 3, 2, 1, "left, bottom");
 
490
     * cc.xywh(1, 3, 2, 1, "l, b");
 
491
     * cc.xywh(1, 3, 7, 3, "center, fill");
 
492
     * cc.xywh(1, 3, 7, 3, "c, f");
 
493
     * </pre>
 
494
     *  
 
495
     * @param col                the new column index
 
496
     * @param row                the new row index
 
497
     * @param colSpan            the column span or grid width
 
498
     * @param rowSpan            the row span or grid height
 
499
     * @param encodedAlignments  describes the horizontal and vertical alignments
 
500
     * @return this
 
501
     * @throws IllegalArgumentException if an alignment orientation is invalid
 
502
     */
 
503
    public CellConstraints xywh(int col, int row, int colSpan, int rowSpan, 
 
504
                                 String encodedAlignments) {
 
505
        CellConstraints result = xywh(col, row, colSpan, rowSpan);
 
506
        result.setAlignments(encodedAlignments);
 
507
        return result;
 
508
    }
 
509
 
 
510
    
 
511
    /**
 
512
     * Sets the row, column, width, and height; sets the horizontal 
 
513
     * and vertical aligment using the specified alignment objects.<p>
 
514
     * 
 
515
     * <strong>Examples:</strong><pre>
 
516
     * cc.xywh(1, 3, 2, 1, CellConstraints.LEFT,   CellConstraints.BOTTOM);
 
517
     * cc.xywh(1, 3, 7, 3, CellConstraints.CENTER, CellConstraints.FILL);
 
518
     * </pre>
 
519
     *
 
520
     * @param col       the new column index
 
521
     * @param row       the new row index
 
522
     * @param colSpan   the column span or grid width
 
523
     * @param rowSpan   the row span or grid height
 
524
     * @param colAlign  horizontal component alignment
 
525
     * @param rowAlign  vertical component alignment     
 
526
     * @return this
 
527
     * @throws IllegalArgumentException if an alignment orientation is invalid
 
528
     */
 
529
    public CellConstraints xywh(int col, int row, int colSpan, int rowSpan, 
 
530
                                 Alignment colAlign, Alignment rowAlign) {
 
531
        this.gridX      = col;
 
532
        this.gridY      = row;
 
533
        this.gridWidth  = colSpan;
 
534
        this.gridHeight = rowSpan;
 
535
        this.hAlign     = colAlign;
 
536
        this.vAlign     = rowAlign;
 
537
        ensureValidOrientations(hAlign, vAlign);
 
538
        return this;
 
539
    }
 
540
    
 
541
 
 
542
    // Parsing and Decoding String Descriptions *****************************
 
543
    
 
544
    /**
 
545
     * Decodes and returns the grid bounds and alignments for this 
 
546
     * constraints as an array of six integers. The string representation
 
547
     * is a comma separated sequence, one of
 
548
     * <pre>
 
549
     * "x, y"
 
550
     * "x, y, w, h"
 
551
     * "x, y, hAlign, vAlign"
 
552
     * "x, y, w, h, hAlign, vAlign"
 
553
     * </pre> 
 
554
     * 
 
555
     * @param encodedConstraints represents horizontal and vertical alignment
 
556
     * @throws IllegalArgumentException if the encoded constraints do not
 
557
     *     follow the constraint syntax
 
558
     */
 
559
    private void initFromConstraints(String encodedConstraints) {
 
560
        StringTokenizer tokenizer = new StringTokenizer(encodedConstraints, " ,");
 
561
        int argCount = tokenizer.countTokens();
 
562
        if (!(argCount == 2 || argCount == 4 || argCount == 6))
 
563
           throw new IllegalArgumentException(
 
564
                    "You must provide 2, 4 or 6 arguments.");
 
565
        
 
566
        Integer nextInt = decodeInt(tokenizer.nextToken());
 
567
        if (nextInt == null) { 
 
568
            throw new IllegalArgumentException(
 
569
                    "First cell constraint element must be a number.");
 
570
        }
 
571
        gridX = nextInt.intValue();
 
572
        if (gridX <= 0)
 
573
            throw new IndexOutOfBoundsException("The grid x must be a positive number.");
 
574
            
 
575
        nextInt = decodeInt(tokenizer.nextToken());
 
576
        if (nextInt == null) {
 
577
            throw new IllegalArgumentException(
 
578
                    "Second cell constraint element must be a number.");
 
579
        }
 
580
        gridY = nextInt.intValue();
 
581
        if (gridY <= 0)
 
582
            throw new IndexOutOfBoundsException(
 
583
                    "The grid y must be a positive number.");
 
584
 
 
585
        if (!tokenizer.hasMoreTokens())
 
586
            return;
 
587
            
 
588
        String token = tokenizer.nextToken();
 
589
        nextInt = decodeInt(token);
 
590
        if (nextInt != null) {
 
591
            // Case: "x, y, w, h" or
 
592
            //       "x, y, w, h, hAlign, vAlign"
 
593
            gridWidth = nextInt.intValue();
 
594
            if (gridWidth <= 0)
 
595
                throw new IndexOutOfBoundsException(
 
596
                    "The grid width must be a positive number.");
 
597
            nextInt = decodeInt(tokenizer.nextToken());
 
598
            if (nextInt == null)
 
599
                throw new IllegalArgumentException(
 
600
                    "Fourth cell constraint element must be like third.");
 
601
            gridHeight = nextInt.intValue();
 
602
            if (gridHeight <= 0)
 
603
                throw new IndexOutOfBoundsException(
 
604
                    "The grid height must be a positive number.");
 
605
 
 
606
            if (!tokenizer.hasMoreTokens())
 
607
                return;
 
608
            token = tokenizer.nextToken();
 
609
        }
 
610
            
 
611
        hAlign = decodeAlignment(token);
 
612
        vAlign = decodeAlignment(tokenizer.nextToken());
 
613
        ensureValidOrientations(hAlign, vAlign);
 
614
    }
 
615
    
 
616
    
 
617
    /**
 
618
     * Decodes a string description for the horizontal and vertical 
 
619
     * alignment and set the alignment values.
 
620
     * <p>
 
621
     * Valid horizontal aligmnents are: left, middle, right, default, and fill.
 
622
     * Valid vertical alignments are: top, center, bottom, default, and fill.
 
623
     * The anchor's string representation abbreviates the alignment:
 
624
     * l, m, r, d, f, t, c, and b. 
 
625
     * <p>
 
626
     * Anchor examples:
 
627
     * "mc" is centered, "lt" is northwest, "mt" is north, "rc" east.
 
628
     * "md" is horizontally centered and uses the row's default alignment.
 
629
     * "dt" is on top of the cell and uses the column's default alignment.
 
630
     * <p>
 
631
     *
 
632
     * @param encodedAlignments represents horizontal and vertical alignment
 
633
     * @throws IllegalArgumentException if an alignment orientation is invalid
 
634
     */
 
635
    private void setAlignments(String encodedAlignments) {
 
636
        StringTokenizer tokenizer = new StringTokenizer(encodedAlignments, " ,");
 
637
        hAlign = decodeAlignment(tokenizer.nextToken());
 
638
        vAlign = decodeAlignment(tokenizer.nextToken());
 
639
        ensureValidOrientations(hAlign, vAlign);
 
640
    }
 
641
    
 
642
 
 
643
    /**
 
644
     * Decodes an integer string representation and returns the
 
645
     * associated Integer or null in case of an invalid number format.
 
646
     * 
 
647
     * @param token             the encoded integer
 
648
     * @return the decoded Integer or null
 
649
     */
 
650
    private Integer decodeInt(String token) {
 
651
        try {
 
652
            return Integer.decode(token);
 
653
        } catch (NumberFormatException e) {
 
654
            return null;
 
655
        }
 
656
    }
 
657
    
 
658
    
 
659
    /**
 
660
     * Parses an alignment string description and 
 
661
     * returns the corresponding alignment value.
 
662
     * 
 
663
     * @param encodedAlignment  the encoded alignment
 
664
     * @return the associated <code>Alignment</code> instance
 
665
     */
 
666
    private Alignment decodeAlignment(String encodedAlignment) {
 
667
        return Alignment.valueOf(encodedAlignment);
 
668
    }
 
669
 
 
670
    
 
671
    /**
 
672
     * Checks and verifies that this constraints object has valid grid 
 
673
     * index values, i. e. the display area cells are inside the form's grid. 
 
674
     * 
 
675
     * @param colCount  number of columns in the grid
 
676
     * @param rowCount  number of rows in the grid
 
677
     * @throws IndexOutOfBoundsException if the display area described
 
678
     *     by this constraints object is not inside the grid
 
679
     */
 
680
    void ensureValidGridBounds(int colCount, int rowCount) {
 
681
        if (gridX <= 0) {
 
682
            throw new IndexOutOfBoundsException(
 
683
                "The column index " + gridX + " must be positive.");
 
684
        }
 
685
        if (gridX > colCount) {
 
686
            throw new IndexOutOfBoundsException(
 
687
                "The column index " + gridX + " must be less than or equal to " 
 
688
                    + colCount + ".");
 
689
        }
 
690
        if (gridX + gridWidth - 1 > colCount) {
 
691
            throw new IndexOutOfBoundsException(
 
692
                "The grid width " + gridWidth + " must be less than or equal to "
 
693
                    + (colCount - gridX + 1) + ".");
 
694
        }
 
695
        if (gridY <= 0) {
 
696
            throw new IndexOutOfBoundsException(
 
697
                "The row index " + gridY + " must be positive.");
 
698
        }
 
699
        if (gridY > rowCount) {
 
700
            throw new IndexOutOfBoundsException(
 
701
                "The row index " + gridY + " must be less than or equal to "
 
702
                    + rowCount + ".");
 
703
        }
 
704
        if (gridY + gridHeight - 1 > rowCount) {
 
705
            throw new IndexOutOfBoundsException(
 
706
                "The grid height " + gridHeight + " must be less than or equal to "
 
707
                    + (rowCount - gridY + 1) + ".");
 
708
        }
 
709
    }
 
710
    
 
711
    
 
712
    /**
 
713
     * Checks and verifies that the horizontal alignment is a horizontal
 
714
     * and the vertical alignment is vertical. 
 
715
     * 
 
716
     * @param horizontalAlignment  the horizontal alignment
 
717
     * @param verticalAlignment    the vertical alignment
 
718
     * @throws IllegalArgumentException if an alignment is invalid
 
719
     */
 
720
    private void ensureValidOrientations(Alignment horizontalAlignment, Alignment verticalAlignment) {
 
721
        if (!horizontalAlignment.isHorizontal())
 
722
            throw new IllegalArgumentException("The horizontal alignment must be one of: left, center, right, fill, default.");
 
723
        if (!verticalAlignment.isVertical())
 
724
            throw new IllegalArgumentException("The vertical alignment must be one of: top, center, botto, fill, default.");
 
725
    }
 
726
    
 
727
    
 
728
    // Settings Component Bounds ********************************************
 
729
    
 
730
    /**
 
731
     * Sets the component's bounds using the given component and cell bounds.
 
732
     * 
 
733
     * @param c                           the component to set bounds
 
734
     * @param layout             the FormLayout instance that computes the bounds
 
735
     * @param cellBounds                  the cell's bounds
 
736
     * @param minWidthMeasure     measures the minimum width
 
737
     * @param minHeightMeasure    measures the minimum height
 
738
     * @param prefWidthMeasure    measures the preferred width
 
739
     * @param prefHeightMeasure  measures the preferred height
 
740
     */
 
741
    void setBounds(Component c, FormLayout layout, 
 
742
                   Rectangle cellBounds, 
 
743
                   FormLayout.Measure minWidthMeasure,
 
744
                   FormLayout.Measure minHeightMeasure,
 
745
                   FormLayout.Measure prefWidthMeasure,
 
746
                   FormLayout.Measure prefHeightMeasure) {
 
747
        ColumnSpec colSpec = gridWidth  == 1 ? layout.getColumnSpec(gridX) : null;
 
748
        RowSpec    rowSpec = gridHeight == 1 ? layout.getRowSpec(gridY) : null;
 
749
        Alignment concreteHAlign = concreteAlignment(this.hAlign, colSpec);
 
750
        Alignment concreteVAlign = concreteAlignment(this.vAlign, rowSpec);
 
751
        Insets concreteInsets = this.insets != null ? this.insets : EMPTY_INSETS;
 
752
        int cellX = cellBounds.x + concreteInsets.left;
 
753
        int cellY = cellBounds.y + concreteInsets.top;
 
754
        int cellW = cellBounds.width  - concreteInsets.left - concreteInsets.right;
 
755
        int cellH = cellBounds.height - concreteInsets.top  - concreteInsets.bottom;
 
756
        int compW = componentSize(c, colSpec, cellW, minWidthMeasure,
 
757
                                                     prefWidthMeasure);
 
758
        int compH = componentSize(c, rowSpec, cellH, minHeightMeasure,
 
759
                                                     prefHeightMeasure);
 
760
        int x = origin(concreteHAlign, cellX, cellW, compW); 
 
761
        int y = origin(concreteVAlign, cellY, cellH, compH);
 
762
        int w = extent(concreteHAlign, cellW, compW);
 
763
        int h = extent(concreteVAlign, cellH, compH);
 
764
        c.setBounds(x, y, w, h);
 
765
    }
 
766
    
 
767
    
 
768
    /**
 
769
     * Computes and returns the concrete alignment. Takes into account
 
770
     * the cell alignment and <i>the</i> <code>FormSpec</code> if applicable.<p>
 
771
     * 
 
772
     * If this constraints object doesn't belong to a single column or row,
 
773
     * the <code>formSpec</code> parameter is <code>null</code>.
 
774
     * In this case the cell alignment is answered, but <code>DEFAULT</code>
 
775
     * is mapped to <code>FILL</code>.<p>
 
776
     * 
 
777
     * If the cell belongs to a single column or row, we use the cell
 
778
     * alignment, unless it is <code>DEFAULT</code>, where the alignment 
 
779
     * is inherited from the column or row resp.
 
780
     * 
 
781
     * @param cellAlignment   this cell's aligment
 
782
     * @param formSpec        the associated column or row specification
 
783
     * @return the concrete alignment
 
784
     */
 
785
    private Alignment concreteAlignment(Alignment cellAlignment, FormSpec formSpec) {
 
786
        return formSpec == null 
 
787
            ? (cellAlignment == DEFAULT ? FILL : cellAlignment)
 
788
            : usedAlignment(cellAlignment, formSpec);
 
789
    }
 
790
 
 
791
    
 
792
    /**
 
793
     * Returns the alignment used for a given form constraints object.
 
794
     * The cell alignment overrides the column or row default, unless
 
795
     * it is <code>DEFAULT</code>. In the latter case, we use the
 
796
     * column or row alignment.
 
797
     * 
 
798
     * @param cellAlignment   this cell constraint's alignment
 
799
     * @param formSpec        the associated column or row specification
 
800
     * @return the alignment used
 
801
     */
 
802
    private Alignment usedAlignment(Alignment cellAlignment, FormSpec formSpec) {
 
803
        if (cellAlignment != CellConstraints.DEFAULT) {
 
804
            // Cell alignments other than DEFAULT override col/row alignments 
 
805
            return cellAlignment;
 
806
        }
 
807
        FormSpec.DefaultAlignment defaultAlignment = formSpec.getDefaultAlignment();
 
808
        if (defaultAlignment == FormSpec.FILL_ALIGN) 
 
809
            return FILL;
 
810
        if (defaultAlignment == ColumnSpec.LEFT) 
 
811
            return LEFT;
 
812
        else if (defaultAlignment == FormSpec.CENTER_ALIGN)
 
813
            return CENTER;
 
814
        else if (defaultAlignment == ColumnSpec.RIGHT) 
 
815
            return RIGHT;
 
816
        else if (defaultAlignment == RowSpec.TOP) 
 
817
            return TOP;
 
818
        else 
 
819
            return BOTTOM;    
 
820
    }
 
821
    
 
822
    
 
823
    /**
 
824
     * Computes and returns the pixel size of the given component using the
 
825
     * given form specification, measures, and cell size.
 
826
     * 
 
827
     * @param component the component to measure 
 
828
     * @param formSpec          the specification of the component's column/row
 
829
     * @param minMeasure        the measure for the minimum size
 
830
     * @param prefMeasure       the measure for the preferred size
 
831
     * @param cellSize          the cell size
 
832
     * @return the component size as measured or a constant
 
833
     */
 
834
    private int componentSize(Component component,
 
835
                               FormSpec formSpec,
 
836
                               int cellSize,
 
837
                               FormLayout.Measure minMeasure,
 
838
                               FormLayout.Measure prefMeasure) {
 
839
        if (formSpec == null) {
 
840
            return prefMeasure.sizeOf(component);
 
841
        } else if (formSpec.getSize() == Sizes.MINIMUM) {
 
842
            return minMeasure.sizeOf(component);
 
843
        } else if (formSpec.getSize() == Sizes.PREFERRED) {
 
844
            return prefMeasure.sizeOf(component);
 
845
        } else {  // default mode
 
846
            return Math.min(cellSize, prefMeasure.sizeOf(component)); 
 
847
        }
 
848
    }
 
849
    
 
850
    
 
851
    /**
 
852
     * Computes and returns the component's pixel origin.
 
853
     * 
 
854
     * @param alignment         the component's alignment
 
855
     * @param cellOrigin                the origin of the display area
 
856
     * @param cellSize                  the extent of the display area
 
857
     * @param componentSize
 
858
     * @return the component's pixel origin
 
859
     */
 
860
    private int origin(Alignment alignment, 
 
861
                        int cellOrigin, 
 
862
                        int cellSize, 
 
863
                        int componentSize) {
 
864
        if (alignment == RIGHT || alignment == BOTTOM) {
 
865
            return cellOrigin + cellSize - componentSize;
 
866
        } else if (alignment == CENTER) {
 
867
            return cellOrigin + (cellSize - componentSize) / 2;
 
868
        } else {  // left, top, fill
 
869
            return cellOrigin;
 
870
        }
 
871
    }
 
872
    
 
873
    
 
874
    /**
 
875
     * Returns the component's pixel extent.
 
876
     * 
 
877
     * @param alignment         the component's alignment
 
878
     * @param cellSize                  the size of the display area
 
879
     * @param componentSize     the component's size
 
880
     * @return the component's pixel extent
 
881
     */
 
882
    private int extent(Alignment alignment, int cellSize, int componentSize) {
 
883
        return alignment == FILL
 
884
                    ? cellSize
 
885
                    : componentSize;
 
886
    }
 
887
    
 
888
    
 
889
    // Misc *****************************************************************
 
890
    
 
891
    /**
 
892
     * Creates a copy of this cell constraints object.
 
893
     * 
 
894
     * @return          a copy of this cell constraints object
 
895
     */
 
896
    public Object clone() {
 
897
        try {
 
898
            CellConstraints c = (CellConstraints) super.clone();
 
899
            c.insets = (Insets) insets.clone();
 
900
            return c;
 
901
        } catch (CloneNotSupportedException e) {
 
902
            // This shouldn't happen, since we are Cloneable.
 
903
            throw new InternalError();
 
904
        }
 
905
    }
 
906
    
 
907
    
 
908
    /**
 
909
     * Constructs and returns a string representation of this constraints object.
 
910
     * 
 
911
     * @return  string representation of this constraints object
 
912
     */
 
913
    public String toString() {
 
914
        StringBuffer buffer = new StringBuffer("CellConstraints");
 
915
        buffer.append("[x=");
 
916
        buffer.append(gridX);
 
917
        buffer.append("; y=");
 
918
        buffer.append(gridY);
 
919
        buffer.append("; w=");
 
920
        buffer.append(gridWidth);
 
921
        buffer.append("; h=");
 
922
        buffer.append(gridHeight);
 
923
        buffer.append("; hAlign=");
 
924
        buffer.append(hAlign);
 
925
        buffer.append("; vAlign=");
 
926
        buffer.append(vAlign);
 
927
        if (!(EMPTY_INSETS.equals(insets))) {
 
928
          buffer.append("; insets=");
 
929
          buffer.append(insets);
 
930
        }
 
931
        
 
932
        buffer.append(']');
 
933
        return buffer.toString();
 
934
    }  
 
935
    
 
936
    
 
937
    /**
 
938
     * Returns a short string representation of this constraints object.
 
939
     * 
 
940
     * @return a short string representation of this constraints object
 
941
     */
 
942
    public String toShortString() {
 
943
        return toShortString(null);
 
944
    }
 
945
    
 
946
    
 
947
    /**
 
948
     * Returns a short string representation of this constraints object.
 
949
     * This method can use the given <code>FormLayout</code> 
 
950
     * to display extra information how default alignments
 
951
     * are mapped to concrete alignments. Therefore it asks the 
 
952
     * related column and row as specified by this constraints object. 
 
953
     * 
 
954
     * @param layout  the layout to be presented as a string
 
955
     * @return a short string representation of this constraints object
 
956
     */
 
957
    public String toShortString(FormLayout layout) {
 
958
        StringBuffer buffer = new StringBuffer("(");
 
959
        buffer.append(formatInt(gridX));
 
960
        buffer.append(", ");
 
961
        buffer.append(formatInt(gridY));
 
962
        buffer.append(", ");
 
963
        buffer.append(formatInt(gridWidth));
 
964
        buffer.append(", ");
 
965
        buffer.append(formatInt(gridHeight));
 
966
        buffer.append(", \"");
 
967
        buffer.append(hAlign.abbreviation());
 
968
        if (hAlign == DEFAULT && layout != null) {
 
969
            buffer.append('=');
 
970
            ColumnSpec colSpec = gridWidth == 1
 
971
                ? layout.getColumnSpec(gridX)
 
972
                : null;
 
973
            buffer.append(concreteAlignment(hAlign, colSpec).abbreviation());
 
974
        }
 
975
        buffer.append(", ");
 
976
        buffer.append(vAlign.abbreviation());
 
977
        if (vAlign == DEFAULT && layout != null) {
 
978
            buffer.append('=');
 
979
            RowSpec rowSpec = gridHeight == 1
 
980
                ? layout.getRowSpec(gridY)
 
981
                : null;
 
982
            buffer.append(concreteAlignment(vAlign, rowSpec).abbreviation());
 
983
        }
 
984
        buffer.append("\"");
 
985
        if (!(EMPTY_INSETS.equals(insets))) {
 
986
          buffer.append(", ");
 
987
          buffer.append(insets);
 
988
        }
 
989
        
 
990
        buffer.append(')');
 
991
        return buffer.toString();
 
992
    }  
 
993
    
 
994
    
 
995
    // Helper Class *********************************************************
 
996
    
 
997
    /**
 
998
     * An ordinal-based serializable typesafe enumeration for component 
 
999
     * alignment types as used by the {@link FormLayout}.
 
1000
     */
 
1001
    public static final class Alignment implements Serializable {
 
1002
        
 
1003
        private static final int HORIZONTAL = 0;
 
1004
        private static final int VERTICAL   = 1;
 
1005
        private static final int BOTH       = 2;
 
1006
        
 
1007
        private final transient String name;
 
1008
        private final transient int    orientation;
 
1009
        
 
1010
        private Alignment(String name, int orientation) { 
 
1011
            this.name        = name; 
 
1012
            this.orientation = orientation;
 
1013
        }
 
1014
        
 
1015
        static Alignment valueOf(String nameOrAbbreviation) {
 
1016
            String str = nameOrAbbreviation.toLowerCase();
 
1017
            if (str.equals("d") || str.equals("default"))
 
1018
                return DEFAULT;
 
1019
            else if (str.equals("f") || str.equals("fill"))
 
1020
                return FILL;
 
1021
            else if (str.equals("c") || str.equals("center"))
 
1022
                return CENTER;
 
1023
            else if (str.equals("l") || str.equals("left"))
 
1024
                return LEFT;
 
1025
            else if (str.equals("r") || str.equals("right"))
 
1026
                return RIGHT;
 
1027
            else if (str.equals("t") || str.equals("top"))
 
1028
                return TOP;
 
1029
            else if (str.equals("b") || str.equals("bottom"))
 
1030
                return BOTTOM;
 
1031
            else
 
1032
                throw new IllegalArgumentException(
 
1033
                    "Invalid alignment " + nameOrAbbreviation
 
1034
                    + ". Must be one of: left, center, right, top, bottom, "
 
1035
                    + "fill, default, l, c, r, t, b, f, d.");
 
1036
        }
 
1037
 
 
1038
        /**
 
1039
         * Returns this Alignment's name.
 
1040
         * 
 
1041
         * @return this alignment's name.
 
1042
         */
 
1043
        public String toString() {
 
1044
            return name;
 
1045
        }
 
1046
 
 
1047
        /**
 
1048
         * Returns the first character of this Alignment's name.
 
1049
         * Used to identify it in short format strings.
 
1050
         * 
 
1051
         * @return the name's first character.
 
1052
         */
 
1053
        public char abbreviation() {
 
1054
            return name.charAt(0);
 
1055
        }
 
1056
        
 
1057
        private boolean isHorizontal() {
 
1058
            return orientation != VERTICAL;
 
1059
        }
 
1060
 
 
1061
        private boolean isVertical() {
 
1062
            return orientation != HORIZONTAL;
 
1063
        }
 
1064
 
 
1065
        
 
1066
        // Serialization *********************************************************
 
1067
        
 
1068
        private static int nextOrdinal = 0;
 
1069
        
 
1070
        private final int ordinal = nextOrdinal++;
 
1071
        
 
1072
        private Object readResolve() {
 
1073
            return VALUES[ordinal];  // Canonicalize
 
1074
        }
 
1075
 
 
1076
    }
 
1077
 
 
1078
 
 
1079
    /**
 
1080
     * Returns an integer that has a minimum of two characters.
 
1081
     * 
 
1082
     * @param number   the number to format
 
1083
     * @return a string representation for a number with a minum of two chars
 
1084
     */
 
1085
        private String formatInt(int number) {
 
1086
        String str = Integer.toString(number);
 
1087
        return number < 10 ? " " + str : str;
 
1088
    }
 
1089
    
 
1090
}
 
1091