2
* Copyright (c) 2002-2004 JGoodies Karsten Lentzsch. All Rights Reserved.
4
* Redistribution and use in source and binary forms, with or without
5
* modification, are permitted provided that the following conditions are met:
7
* o Redistributions of source code must retain the above copyright notice,
8
* this list of conditions and the following disclaimer.
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.
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.
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.
31
package com.jgoodies.forms.layout;
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;
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>
45
* Most methods return <em>this</em> object to enable method chaining.<p>
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>
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
60
* CellConstraints cc = new CellConstraints();
62
* cc.xy (3, 5, CellConstraints.RIGHT, CellConstraints.BOTTOM);
63
* cc.xy (3, 5, "right, bottom");
66
* cc.xyw (3, 5, 1, CellConstraints.RIGHT, CellConstraints.BOTTOM);
67
* cc.xyw (3, 5, 1, "right, bottom");
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");
73
* See also the examples in the {@link FormLayout} class comment.<p>
75
* TODO: Consider renaming the inset to offsets.
77
* @author Karsten Lentzsch
78
* @version $Revision: 1.13 $
80
public final class CellConstraints implements Cloneable, Serializable {
82
// Alignment Constants *************************************************
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.
90
* Use the column's or row's default alignment.
92
public static final Alignment DEFAULT =
93
new Alignment("default", Alignment.BOTH);
96
* Fill the cell either horizontally or vertically.
98
public static final Alignment FILL =
99
new Alignment("fill", Alignment.BOTH);
102
* Put the component in the left.
104
public static final Alignment LEFT =
105
new Alignment("left", Alignment.HORIZONTAL);
108
* Put the component in the right.
110
public static final Alignment RIGHT =
111
new Alignment("right", Alignment.HORIZONTAL);
114
* Put the component in the center.
116
public static final Alignment CENTER =
117
new Alignment("center", Alignment.BOTH);
120
* Put the component in the top.
122
public static final Alignment TOP =
123
new Alignment("top", Alignment.VERTICAL);
126
* Put the component in the bottom.
128
public static final Alignment BOTTOM =
129
new Alignment("bottom", Alignment.VERTICAL);
132
* An array of all enumeration values used to canonicalize
133
* deserialized alignments.
135
private static final Alignment[] VALUES =
136
{ DEFAULT, FILL, LEFT, RIGHT, CENTER, TOP, BOTTOM };
139
* A reusable <code>Insets</code> object to reduce object instantiation.
141
private static final Insets EMPTY_INSETS =
142
new Insets(0, 0, 0, 0);
145
// Fields ***************************************************************
148
* Describes the component's horizontal grid origin (starts at 1).
153
* Describes the component's vertical grid origin (starts at 1).
158
* Describes the component's horizontal grid extend (number of cells).
160
public int gridWidth;
163
* Describes the component's vertical grid extent (number of cells).
165
public int gridHeight;
168
* Describes the component's horizontal alignment.
170
public Alignment hAlign;
173
* Describes the component's vertical alignment.
175
public Alignment vAlign;
178
* Describes the component's <code>Insets</code> in it's display area.
180
public Insets insets;
183
// Instance Creation ****************************************************
186
* Constructs a default instance of <code>CellConstraints</code>.
188
public CellConstraints() {
194
* Constructs an instance of <code>CellConstraints</code> for the given
197
* <strong>Examples:</strong><pre>
198
* new CellConstraints(1, 3);
199
* new CellConstraints(1, 3);
202
* @param gridX the component's horizontal grid origin
203
* @param gridY the component's vertical grid origin
205
public CellConstraints(int gridX, int gridY) {
206
this(gridX, gridY, 1, 1);
211
* Constructs an instance of <code>CellConstraints</code> for the given
212
* cell position, anchor, and fill.<p>
214
* <strong>Examples:</strong><pre>
215
* new CellConstraints(1, 3, CellConstraints.LEFT, CellConstraints.BOTTOM);
216
* new CellConstraints(1, 3, CellConstraints.CENTER, CellConstraints.FILL);
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
224
public CellConstraints(int gridX, int gridY,
225
Alignment hAlign, Alignment vAlign) {
226
this(gridX, gridY, 1, 1, hAlign, vAlign, EMPTY_INSETS);
231
* Constructs an instance of <code>CellConstraints</code> for the given
232
* cell position and size.<p>
234
* <strong>Examples:</strong><pre>
235
* new CellConstraints(1, 3, 2, 1);
236
* new CellConstraints(1, 3, 7, 3);
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
244
public CellConstraints(int gridX, int gridY, int gridWidth, int gridHeight) {
245
this(gridX, gridY, gridWidth, gridHeight, DEFAULT, DEFAULT);
250
* Constructs an instance of <code>CellConstraints</code> for the given
251
* cell position and size, anchor, and fill.<p>
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);
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
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);
272
* Constructs an instance of <code>CellConstraints</code> for
273
* the complete set of available properties.<p>
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));
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
291
public CellConstraints(int gridX, int gridY, int gridWidth, int gridHeight,
292
Alignment hAlign, Alignment vAlign, Insets insets) {
295
this.gridWidth = gridWidth;
296
this.gridHeight = gridHeight;
297
this.hAlign = hAlign;
298
this.vAlign = vAlign;
299
this.insets = insets;
301
throw new IndexOutOfBoundsException("The grid x must be a positive number.");
303
throw new IndexOutOfBoundsException("The grid y must be a positive number.");
305
throw new IndexOutOfBoundsException("The grid width must be a positive number.");
307
throw new IndexOutOfBoundsException("The grid height must be a positive number.");
309
throw new NullPointerException("The horizontal alignment must not be null.");
311
throw new NullPointerException("The vertical alignment must not be null.");
312
ensureValidOrientations(hAlign, vAlign);
317
* Constructs an instance of <code>CellConstraints</code> from
318
* the given encoded string properties.<p>
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");
327
* @param encodedConstraints the constraints encoded as string
329
public CellConstraints(String encodedConstraints) {
331
initFromConstraints(encodedConstraints);
335
// Setters **************************************************************
338
* Sets row and column origins; sets width and height to 1;
339
* uses the default alignments.<p>
341
* <strong>Examples:</strong><pre>
346
* @param col the new column index
347
* @param row the new row index
350
public CellConstraints xy(int col, int row) {
351
return xywh(col, row, 1, 1);
356
* Sets row and column origins; sets width and height to 1;
357
* decodes horizontal and vertical alignments from the given string.<p>
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");
366
* @param col the new column index
367
* @param row the new row index
368
* @param encodedAlignments describes the horizontal and vertical alignments
370
* @throws IllegalArgumentException if an alignment orientation is invalid
372
public CellConstraints xy(int col, int row, String encodedAlignments) {
373
return xywh(col, row, 1, 1, encodedAlignments);
377
* Sets the row and column origins; sets width and height to 1;
378
* set horizontal and vertical alignment using the specified objects.<p>
380
* <strong>Examples:</strong><pre>
381
* cc.xy(1, 3, CellConstraints.LEFT, CellConstraints.BOTTOM);
382
* cc.xy(1, 3, CellConstraints.CENTER, CellConstraints.FILL);
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
391
public CellConstraints xy(int col, int row,
392
Alignment colAlign, Alignment rowAlign) {
393
return xywh(col, row, 1, 1, colAlign, rowAlign);
398
* Sets the row, column, width, and height; uses a height (row span) of 1
399
* and the horizontal and vertical default alignments.<p>
401
* <strong>Examples:</strong><pre>
406
* @param col the new column index
407
* @param row the new row index
408
* @param colSpan the column span or grid width
411
public CellConstraints xyw(int col, int row, int colSpan) {
412
return xywh(col, row, colSpan, 1, DEFAULT, DEFAULT);
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>
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");
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
433
* @throws IllegalArgumentException if an alignment orientation is invalid
435
public CellConstraints xyw(int col, int row, int colSpan,
436
String encodedAlignments) {
437
return xywh(col, row, colSpan, 1, encodedAlignments);
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>
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);
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
457
* @throws IllegalArgumentException if an alignment orientation is invalid
459
public CellConstraints xyw(int col, int row, int colSpan,
460
Alignment colAlign, Alignment rowAlign) {
461
return xywh(col, row, colSpan, 1, colAlign, rowAlign);
466
* Sets the row, column, width, and height; uses default alignments.<p>
468
* <strong>Examples:</strong><pre>
469
* cc.xywh(1, 3, 2, 1);
470
* cc.xywh(1, 3, 7, 3);
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
479
public CellConstraints xywh(int col, int row, int colSpan, int rowSpan) {
480
return xywh(col, row, colSpan, rowSpan, DEFAULT, DEFAULT);
485
* Sets the row, column, width, and height;
486
* decodes the horizontal and vertical alignments from the given string.<p>
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");
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
501
* @throws IllegalArgumentException if an alignment orientation is invalid
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);
512
* Sets the row, column, width, and height; sets the horizontal
513
* and vertical aligment using the specified alignment objects.<p>
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);
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
527
* @throws IllegalArgumentException if an alignment orientation is invalid
529
public CellConstraints xywh(int col, int row, int colSpan, int rowSpan,
530
Alignment colAlign, Alignment rowAlign) {
533
this.gridWidth = colSpan;
534
this.gridHeight = rowSpan;
535
this.hAlign = colAlign;
536
this.vAlign = rowAlign;
537
ensureValidOrientations(hAlign, vAlign);
542
// Parsing and Decoding String Descriptions *****************************
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
551
* "x, y, hAlign, vAlign"
552
* "x, y, w, h, hAlign, vAlign"
555
* @param encodedConstraints represents horizontal and vertical alignment
556
* @throws IllegalArgumentException if the encoded constraints do not
557
* follow the constraint syntax
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.");
566
Integer nextInt = decodeInt(tokenizer.nextToken());
567
if (nextInt == null) {
568
throw new IllegalArgumentException(
569
"First cell constraint element must be a number.");
571
gridX = nextInt.intValue();
573
throw new IndexOutOfBoundsException("The grid x must be a positive number.");
575
nextInt = decodeInt(tokenizer.nextToken());
576
if (nextInt == null) {
577
throw new IllegalArgumentException(
578
"Second cell constraint element must be a number.");
580
gridY = nextInt.intValue();
582
throw new IndexOutOfBoundsException(
583
"The grid y must be a positive number.");
585
if (!tokenizer.hasMoreTokens())
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();
595
throw new IndexOutOfBoundsException(
596
"The grid width must be a positive number.");
597
nextInt = decodeInt(tokenizer.nextToken());
599
throw new IllegalArgumentException(
600
"Fourth cell constraint element must be like third.");
601
gridHeight = nextInt.intValue();
603
throw new IndexOutOfBoundsException(
604
"The grid height must be a positive number.");
606
if (!tokenizer.hasMoreTokens())
608
token = tokenizer.nextToken();
611
hAlign = decodeAlignment(token);
612
vAlign = decodeAlignment(tokenizer.nextToken());
613
ensureValidOrientations(hAlign, vAlign);
618
* Decodes a string description for the horizontal and vertical
619
* alignment and set the alignment values.
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.
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.
632
* @param encodedAlignments represents horizontal and vertical alignment
633
* @throws IllegalArgumentException if an alignment orientation is invalid
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);
644
* Decodes an integer string representation and returns the
645
* associated Integer or null in case of an invalid number format.
647
* @param token the encoded integer
648
* @return the decoded Integer or null
650
private Integer decodeInt(String token) {
652
return Integer.decode(token);
653
} catch (NumberFormatException e) {
660
* Parses an alignment string description and
661
* returns the corresponding alignment value.
663
* @param encodedAlignment the encoded alignment
664
* @return the associated <code>Alignment</code> instance
666
private Alignment decodeAlignment(String encodedAlignment) {
667
return Alignment.valueOf(encodedAlignment);
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.
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
680
void ensureValidGridBounds(int colCount, int rowCount) {
682
throw new IndexOutOfBoundsException(
683
"The column index " + gridX + " must be positive.");
685
if (gridX > colCount) {
686
throw new IndexOutOfBoundsException(
687
"The column index " + gridX + " must be less than or equal to "
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) + ".");
696
throw new IndexOutOfBoundsException(
697
"The row index " + gridY + " must be positive.");
699
if (gridY > rowCount) {
700
throw new IndexOutOfBoundsException(
701
"The row index " + gridY + " must be less than or equal to "
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) + ".");
713
* Checks and verifies that the horizontal alignment is a horizontal
714
* and the vertical alignment is vertical.
716
* @param horizontalAlignment the horizontal alignment
717
* @param verticalAlignment the vertical alignment
718
* @throws IllegalArgumentException if an alignment is invalid
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.");
728
// Settings Component Bounds ********************************************
731
* Sets the component's bounds using the given component and cell bounds.
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
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,
758
int compH = componentSize(c, rowSpec, cellH, minHeightMeasure,
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);
769
* Computes and returns the concrete alignment. Takes into account
770
* the cell alignment and <i>the</i> <code>FormSpec</code> if applicable.<p>
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>
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.
781
* @param cellAlignment this cell's aligment
782
* @param formSpec the associated column or row specification
783
* @return the concrete alignment
785
private Alignment concreteAlignment(Alignment cellAlignment, FormSpec formSpec) {
786
return formSpec == null
787
? (cellAlignment == DEFAULT ? FILL : cellAlignment)
788
: usedAlignment(cellAlignment, formSpec);
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.
798
* @param cellAlignment this cell constraint's alignment
799
* @param formSpec the associated column or row specification
800
* @return the alignment used
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;
807
FormSpec.DefaultAlignment defaultAlignment = formSpec.getDefaultAlignment();
808
if (defaultAlignment == FormSpec.FILL_ALIGN)
810
if (defaultAlignment == ColumnSpec.LEFT)
812
else if (defaultAlignment == FormSpec.CENTER_ALIGN)
814
else if (defaultAlignment == ColumnSpec.RIGHT)
816
else if (defaultAlignment == RowSpec.TOP)
824
* Computes and returns the pixel size of the given component using the
825
* given form specification, measures, and cell size.
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
834
private int componentSize(Component component,
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));
852
* Computes and returns the component's pixel origin.
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
860
private int origin(Alignment alignment,
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
875
* Returns the component's pixel extent.
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
882
private int extent(Alignment alignment, int cellSize, int componentSize) {
883
return alignment == FILL
889
// Misc *****************************************************************
892
* Creates a copy of this cell constraints object.
894
* @return a copy of this cell constraints object
896
public Object clone() {
898
CellConstraints c = (CellConstraints) super.clone();
899
c.insets = (Insets) insets.clone();
901
} catch (CloneNotSupportedException e) {
902
// This shouldn't happen, since we are Cloneable.
903
throw new InternalError();
909
* Constructs and returns a string representation of this constraints object.
911
* @return string representation of this constraints object
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);
933
return buffer.toString();
938
* Returns a short string representation of this constraints object.
940
* @return a short string representation of this constraints object
942
public String toShortString() {
943
return toShortString(null);
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.
954
* @param layout the layout to be presented as a string
955
* @return a short string representation of this constraints object
957
public String toShortString(FormLayout layout) {
958
StringBuffer buffer = new StringBuffer("(");
959
buffer.append(formatInt(gridX));
961
buffer.append(formatInt(gridY));
963
buffer.append(formatInt(gridWidth));
965
buffer.append(formatInt(gridHeight));
966
buffer.append(", \"");
967
buffer.append(hAlign.abbreviation());
968
if (hAlign == DEFAULT && layout != null) {
970
ColumnSpec colSpec = gridWidth == 1
971
? layout.getColumnSpec(gridX)
973
buffer.append(concreteAlignment(hAlign, colSpec).abbreviation());
976
buffer.append(vAlign.abbreviation());
977
if (vAlign == DEFAULT && layout != null) {
979
RowSpec rowSpec = gridHeight == 1
980
? layout.getRowSpec(gridY)
982
buffer.append(concreteAlignment(vAlign, rowSpec).abbreviation());
985
if (!(EMPTY_INSETS.equals(insets))) {
987
buffer.append(insets);
991
return buffer.toString();
995
// Helper Class *********************************************************
998
* An ordinal-based serializable typesafe enumeration for component
999
* alignment types as used by the {@link FormLayout}.
1001
public static final class Alignment implements Serializable {
1003
private static final int HORIZONTAL = 0;
1004
private static final int VERTICAL = 1;
1005
private static final int BOTH = 2;
1007
private final transient String name;
1008
private final transient int orientation;
1010
private Alignment(String name, int orientation) {
1012
this.orientation = orientation;
1015
static Alignment valueOf(String nameOrAbbreviation) {
1016
String str = nameOrAbbreviation.toLowerCase();
1017
if (str.equals("d") || str.equals("default"))
1019
else if (str.equals("f") || str.equals("fill"))
1021
else if (str.equals("c") || str.equals("center"))
1023
else if (str.equals("l") || str.equals("left"))
1025
else if (str.equals("r") || str.equals("right"))
1027
else if (str.equals("t") || str.equals("top"))
1029
else if (str.equals("b") || str.equals("bottom"))
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.");
1039
* Returns this Alignment's name.
1041
* @return this alignment's name.
1043
public String toString() {
1048
* Returns the first character of this Alignment's name.
1049
* Used to identify it in short format strings.
1051
* @return the name's first character.
1053
public char abbreviation() {
1054
return name.charAt(0);
1057
private boolean isHorizontal() {
1058
return orientation != VERTICAL;
1061
private boolean isVertical() {
1062
return orientation != HORIZONTAL;
1066
// Serialization *********************************************************
1068
private static int nextOrdinal = 0;
1070
private final int ordinal = nextOrdinal++;
1072
private Object readResolve() {
1073
return VALUES[ordinal]; // Canonicalize
1080
* Returns an integer that has a minimum of two characters.
1082
* @param number the number to format
1083
* @return a string representation for a number with a minum of two chars
1085
private String formatInt(int number) {
1086
String str = Integer.toString(number);
1087
return number < 10 ? " " + str : str;