KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > ui > internal > layout > CellLayout


1 /*******************************************************************************
2  * Copyright (c) 2004, 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11
12 package org.eclipse.ui.internal.layout;
13
14 import java.util.ArrayList JavaDoc;
15 import java.util.List JavaDoc;
16
17 import org.eclipse.swt.SWT;
18 import org.eclipse.swt.graphics.Point;
19 import org.eclipse.swt.graphics.Rectangle;
20 import org.eclipse.swt.widgets.Composite;
21 import org.eclipse.swt.widgets.Control;
22 import org.eclipse.swt.widgets.Layout;
23
24 /**
25  * <p>Instance of this class lay out the control children of a <code>Composite</code>
26  * in a grid, using a simple set of rules and a simple API. This class is
27  * intended to be more predictable than <code>GridLayout</code> and easier to use than
28  * <code>FormLayout</code>, while retaining most of the power of both.</p>
29  *
30  * <p>The power of a <code>CellLayout</code> lies in the ability to control
31  * the size and resizing properties of each row and column. Unlike other layout
32  * classes, complex layouts can be created without attaching any layout data to
33  * individual controls in the layout. </p>
34  *
35  * <p>The various subclasses of <code>IColumnInfo</code>
36  * can be used to create columns with fixed width, columns whose width is computed
37  * from child controls, or width that grows in proportion to the size of other
38  * columns. Layouts can be given a default <code>IColumnInfo</code> that will
39  * be used to set the size of any column whose properties have not been explicitly
40  * set. This is useful for creating layouts where most or all columns have the
41  * same properties. Similarly, the subclasses of <code>IRowInfo</code> can be used to
42  * control the height of individual rows.</p>
43  *
44  * <p>For a finer grain of control, <code>CellData</code> objects can be attached
45  * to individual controls in the layout. These objects serve a similar function as
46  * <code>GridData</code> objects serve for <code>GridLayout</code>. They allow
47  * controls to span multiple rows or columns, set the justification of the control
48  * within its cell, and allow the user to override the preferred size of the control.
49  * </p>
50  *
51  * <p>In many cases, it is not necessary to attach any layout data to controls in
52  * the layout, since the controls can be arranged based on the properties of rows
53  * and columns. However, layout data may be attached to individual controls to
54  * allow them to span multiple columns or to control their justification within
55  * their cell.
56  * </p>
57  *
58  * <p>All the <code>set</code> methods in this class return <code>this</code>, allowing
59  * a layout to be created and initialized in a single line of code. For example: </p>
60  *
61  * <code>
62  * Composite myControl = new Composite(parent, SWT.NONE);
63  * myControl.setLayout(new CellLayout(2).setMargins(10,10).setSpacing(5,5));
64  * </code>
65  *
66  * @since 3.0
67  */

68 public class CellLayout extends Layout {
69
70     /**
71      * Object used to compute the height of rows whose properties have not been
72      * explicitly set.
73      */

74     private Row defaultRowSettings = new Row(false);
75
76     /**
77      * Object used to compute the width of columns whose properties have not been
78      * explicitly set.
79      */

80     private Row defaultColSettings = new Row(true);
81
82     /**
83      * horizontalSpacing specifies the number of pixels between the right
84      * edge of one cell and the left edge of its neighbouring cell to
85      * the right.
86      *
87      * The default value is 5.
88      */

89     int horizontalSpacing = 5;
90
91     /**
92      * verticalSpacing specifies the number of pixels between the bottom
93      * edge of one cell and the top edge of its neighbouring cell underneath.
94      *
95      * The default value is 5.
96      */

97     int verticalSpacing = 5;
98
99     /**
100      * marginWidth specifies the number of pixels of horizontal margin
101      * that will be placed along the left and right edges of the layout.
102      *
103      * The default value is 0.
104      */

105     public int marginWidth = 5;
106
107     /**
108      * marginHeight specifies the number of pixels of vertical margin
109      * that will be placed along the top and bottom edges of the layout.
110      *
111      * The default value is 0.
112      */

113     public int marginHeight = 5;
114
115     /**
116      * Number of columns in this layout, or 0 indicating that the whole layout
117      * should be on a single row.
118      */

119     private int numCols;
120
121     /**
122      * List of IColumnInfo. The nth object is used to compute the width of the
123      * nth column, or null indicating that the default column should be used.
124      */

125     private List JavaDoc cols;
126
127     /**
128      * List of RowInfo. The nth object is used to compute the height of the
129      * nth row, or null indicating that the default row should be used.
130      */

131     private List JavaDoc rows = new ArrayList JavaDoc(16);
132
133     // Cached information
134
private GridInfo gridInfo = new GridInfo();
135
136     private int[] cachedRowMin = null;
137
138     private int[] cachedColMin = null;
139
140     public static int cacheMisses;
141
142     public static int cacheHits;
143
144     private LayoutCache cache = new LayoutCache();
145
146     // End of cached control sizes
147

148     /**
149      * Creates the layout
150      *
151      * @param numCols the number of columns in this layout,
152      * or 0 indicating that the whole layout should be on one row.
153      */

154     public CellLayout(int numCols) {
155         super();
156         this.numCols = numCols;
157         cols = new ArrayList JavaDoc(numCols == 0 ? 3 : numCols);
158     }
159
160     /**
161      * Sets the amount empty space between cells
162      *
163      * @param newSpacing a point (x,y) corresponding to the number of pixels of
164      * empty space between adjacent columns and rows respectively
165      */

166     public CellLayout setSpacing(int horizontalSpacing, int verticalSpacing) {
167         this.horizontalSpacing = horizontalSpacing;
168         this.verticalSpacing = verticalSpacing;
169
170         return this;
171     }
172
173     /**
174      * Sets the amount empty space between cells
175      *
176      * @param newSpacing a point (x,y) corresponding to the number of pixels of
177      * empty space between adjacent columns and rows respectively
178      */

179     public CellLayout setSpacing(Point newSpacing) {
180         horizontalSpacing = newSpacing.x;
181         verticalSpacing = newSpacing.y;
182         return this;
183     }
184
185     /**
186      * Returns the amount of empty space between adjacent cells
187      *
188      * @return a point (x,y) corresponding to the number of pixels of empty
189      * space between adjacent columns and rows respectively
190      */

191     public Point getSpacing() {
192         return new Point(horizontalSpacing, verticalSpacing);
193     }
194
195     /**
196      * Sets the size of the margin around the outside of the layout.
197      *
198      * @param marginWidth the size of the margin around the top and
199      * bottom of the layout
200      * @param marginHeight the size of the margin on the left and right
201      * of the layout.
202      */

203     public CellLayout setMargins(int marginWidth, int marginHeight) {
204         this.marginWidth = marginWidth;
205         this.marginHeight = marginHeight;
206         return this;
207     }
208
209     /**
210      * Sets the size of the margin around the outside of the layout.
211      *
212      * @param newMargins point indicating the size of the horizontal and vertical
213      * margins, in pixels.
214      */

215     public CellLayout setMargins(Point newMargins) {
216         marginWidth = newMargins.x;
217         marginHeight = newMargins.y;
218         return this;
219     }
220
221     /**
222      * Returns the size of the margins around the outside of the layout.
223      *
224      * @return the size of the outer margins, in pixels.
225      */

226     public Point getMargins() {
227         return new Point(marginWidth, marginHeight);
228     }
229
230     /**
231      * Sets the default column settings. All columns will use these settings unless
232      * they have been explicitly assigned custom settings by setColumn.
233      *
234      * @param info the properties of all default columns
235      * @see setColumn
236      */

237     public CellLayout setDefaultColumn(Row info) {
238         defaultColSettings = info;
239         return this;
240     }
241
242     /**
243      * Sets the column info for the given column number (the leftmost column is column 0).
244      * This replaces any existing info for the column. Note that more than one column
245      * are allowed to share the same IColumnInfo instance if they have identical properties.
246      *
247      * @param colNum the column number to modify
248      * @param info the properties of the column, or null if this column should use the
249      * default properties
250      */

251     public CellLayout setColumn(int colNum, Row info) {
252         while (cols.size() <= colNum) {
253             cols.add(null);
254         }
255
256         cols.set(colNum, info);
257
258         return this;
259     }
260
261     /**
262      * Sets the default row settings for this layout. Unless this is overridden
263      * for an individual row, all rows will use the default settings.
264      *
265      * @param info the row info object that should be used to set the size
266      * of rows, by default.
267      */

268     public CellLayout setDefaultRow(Row info) {
269         defaultRowSettings = info;
270
271         return this;
272     }
273
274     /**
275      * Sets the row info for the given rows. The topmost row is row 0. Multiple
276      * rows are allowed to share the same RowInfo instance.
277      *
278      * @param rowNum the row number to set
279      * @param info the row info that will control the sizing of the given row,
280      * or null if the row should use the default settings for this layout.
281      */

282     public CellLayout setRow(int rowNum, Row info) {
283         while (rows.size() <= rowNum) {
284             rows.add(null);
285         }
286
287         rows.set(rowNum, info);
288
289         return this;
290     }
291
292     /**
293      * Returns the row info that controls the size of the given row. Will return
294      * the default row settings for this layout if no custom row info has been
295      * assigned to the row.
296      *
297      * @param rowNum
298      * @return
299      */

300     private Row getRow(int rowNum, boolean isHorizontal) {
301         if (isHorizontal) {
302             if (rowNum >= rows.size()) {
303                 return defaultRowSettings;
304             }
305
306             Row result = (Row) rows.get(rowNum);
307
308             if (result == null) {
309                 result = defaultRowSettings;
310             }
311
312             return result;
313         } else {
314             if (rowNum >= cols.size()) {
315                 return defaultColSettings;
316             }
317
318             Row result = (Row) cols.get(rowNum);
319
320             if (result == null) {
321                 result = defaultColSettings;
322             }
323
324             return result;
325         }
326     }
327
328     /**
329      * Initializes the gridInfo object.
330      *
331      * @param children controls that are being layed out
332      */

333     private void initGrid(Control[] children) {
334         cache.setControls(children);
335         gridInfo.initGrid(children, this);
336         cachedRowMin = null;
337         cachedColMin = null;
338     }
339
340     /* (non-Javadoc)
341      * @see org.eclipse.swt.widgets.Layout#computeSize(org.eclipse.swt.widgets.Composite, int, int, boolean)
342      */

343     protected Point computeSize(Composite composite, int wHint, int hHint,
344             boolean flushCache) {
345         Control[] children = composite.getChildren();
346         initGrid(children);
347
348         if (flushCache) {
349             cache.flush();
350         }
351
352         // Determine the amount of whitespace (area that cannot be used by controls)
353
Point emptySpace = totalEmptySpace();
354
355         int[] heightConstraints = computeConstraints(true);
356
357         int width;
358         if (wHint == SWT.DEFAULT) {
359             width = preferredSize(heightConstraints, false);
360         } else {
361             width = wHint - emptySpace.x;
362         }
363
364         int height = hHint;
365         if (hHint == SWT.DEFAULT) {
366             height = preferredSize(
367                     computeSizes(heightConstraints, width, false), true);
368         } else {
369             height = hHint - emptySpace.y;
370         }
371
372         Point preferredSize = new Point(width + emptySpace.x, height
373                 + emptySpace.y);
374
375         // At this point we know the layout's preferred size. Now adjust it
376
// if we're smaller than the minimum possible size for the composite.
377

378         // If exactly one dimension of our preferred size is smaller than
379
// the minimum size of our composite, then set that dimension to
380
// the minimum size and recompute the other dimension (for example,
381
// increasing the width to match a shell's minimum width may reduce
382
// the height allocated for a wrapping text widget). There is no
383
// point in doing this if both dimensions are smaller than the
384
// composite's minimum size, since we're already smaller than
385
// we need to be.
386
Point minimumSize = CellLayoutUtil.computeMinimumSize(composite);
387
388         boolean wider = (preferredSize.x >= minimumSize.x);
389         boolean taller = (preferredSize.y >= minimumSize.y);
390
391         if (wider) {
392             if (taller) {
393                 // If we're larger in both dimensions, don't adjust the minimum
394
// size.
395
return preferredSize;
396             } else {
397                 // If our preferred height is smaller than the minimum height,
398
// recompute the preferred width using the minimum height
399
return computeSize(composite, wHint, minimumSize.y, false);
400             }
401         } else {
402             if (taller) {
403                 // If our preferred width is smaller than the minimum width,
404
// recompute the preferred height using the minimum width
405
return computeSize(composite, minimumSize.x, hHint, false);
406             } else {
407                 // If both dimensions are smaller than the minimum size,
408
// use the minimum size as our preferred size.
409
return minimumSize;
410             }
411         }
412     }
413
414     int[] computeSizes(int[] constraints, int availableSpace,
415             boolean computingRows) {
416         int[] result = computeMinSizes(constraints, computingRows);
417
418         int totalFixed = sumOfSizes(result);
419         int denominator = getResizeDenominator(computingRows);
420         int numRows = gridInfo.getNumRows(computingRows);
421
422         if (totalFixed < availableSpace) {
423             int remaining = availableSpace - totalFixed;
424
425             for (int idx = 0; idx < numRows && denominator > 0; idx++) {
426                 Row row = getRow(idx, computingRows);
427
428                 if (row.grows) {
429                     int greed = row.size;
430                     int amount = remaining * greed / denominator;
431
432                     result[idx] += amount;
433                     remaining -= amount;
434                     denominator -= greed;
435                 }
436             }
437         }
438
439         return result;
440     }
441
442     /**
443      * Computes one dimension of the preferred size of the layout.
444      *
445      * @param hint contains the result if already known, or SWT.DEFAULT if it needs to be computed
446      * @param constraints contains constraints along the other dimension, or SWT.DEFAULT if none. For
447      * example, if we are computing the preferred row sizes, this would be an array of known column sizes.
448      * @param computingRows if true, this method returns the height (pixels). Otherwise, it returns the
449      * width (pixels).
450      */

451     int preferredSize(int[] constraints, boolean computingRows) {
452         int[] fixedSizes = computeMinSizes(constraints, computingRows);
453
454         return sumOfSizes(fixedSizes)
455                 + getDynamicSize(constraints, fixedSizes, computingRows);
456     }
457
458     /**
459      * Computes the sum of all integers in the given array. If any of the entries are SWT.DEFAULT,
460      * the result is SWT.DEFAULT.
461      */

462     static int sumOfSizes(int[] input) {
463         return sumOfSizes(input, 0, input.length);
464     }
465
466     static int sumOfSizes(int[] input, int start, int length) {
467         int sum = 0;
468         for (int idx = start; idx < start + length; idx++) {
469             int next = input[idx];
470
471             if (next == SWT.DEFAULT) {
472                 return SWT.DEFAULT;
473             }
474
475             sum += next;
476         }
477
478         return sum;
479     }
480
481     /**
482      * Returns the preferred dynamic width of the layout
483      *
484      * @param constraints
485      * @param fixedSizes
486      * @param computingRows
487      * @return
488      */

489     int getDynamicSize(int[] constraints, int[] fixedSizes,
490             boolean computingRows) {
491         int result = 0;
492         int numerator = getResizeDenominator(computingRows);
493
494         // If no resizable columns, return
495
if (numerator == 0) {
496             return 0;
497         }
498
499         int rowSpacing = computingRows ? verticalSpacing : horizontalSpacing;
500         int colSpacing = computingRows ? horizontalSpacing : verticalSpacing;
501
502         int numControls = gridInfo.controls.length;
503         for (int idx = 0; idx < numControls; idx++) {
504             int controlRowStart = gridInfo.getStartPos(idx, computingRows);
505             int controlRowSpan = getSpan(idx, computingRows);
506             int controlColStart = gridInfo.getStartPos(idx, !computingRows);
507             int controlColSpan = getSpan(idx, !computingRows);
508
509             int denominator = getGrowthRatio(controlRowStart, controlRowSpan,
510                     computingRows);
511
512             if (denominator > 0) {
513
514                 int widthHint = sumOfSizes(constraints, controlColStart,
515                         controlColSpan);
516                 if (widthHint != SWT.DEFAULT) {
517                     widthHint += colSpacing * (controlColSpan - 1);
518                 }
519
520                 // Compute the total control size
521
int controlSize = computeControlSize(idx, widthHint,
522                         computingRows);
523
524                 // Subtract the amount that overlaps fixed-size columns
525
controlSize -= sumOfSizes(fixedSizes, controlRowStart,
526                         controlRowSpan);
527
528                 // Subtract the amount that overlaps spacing between cells
529
controlSize -= (rowSpacing * (controlRowSpan - 1));
530
531                 result = Math
532                         .max(result, controlSize * numerator / denominator);
533             }
534         }
535
536         return result;
537     }
538
539     /**
540      * Computes one dimension of a control's size
541      *
542      * @param control the index of the control being computed
543      * @param constraint the other dimension of the control's size, or SWT.DEFAULT if unknown
544      * @param computingHeight if true, this method returns a height. Else it returns a width
545      * @return the preferred height or width of the control, in pixels
546      */

547     int computeControlSize(int control, int constraint, boolean computingHeight) {
548         CellData data = gridInfo.getCellData(control);
549
550         // If we're looking for the preferred size of the control (without hints)
551
if (constraint == SWT.DEFAULT) {
552             Point result = data.computeSize(cache.getCache(control),
553                     SWT.DEFAULT, SWT.DEFAULT);
554
555             // Return result
556
if (computingHeight) {
557                 return result.y;
558             }
559             return result.x;
560         }
561
562         // Compute a height
563
if (computingHeight) {
564             return data.computeSize(cache.getCache(control), constraint,
565                     SWT.DEFAULT).y;
566         }
567
568         return data.computeSize(cache.getCache(control), SWT.DEFAULT,
569                 constraint).x;
570     }
571
572     /**
573      * Returns the relative amount that a control starting on the given row and spanning
574      * the given length will contribute
575      *
576      * @param start
577      * @param length
578      * @param computingRows
579      * @return
580      */

581     int getGrowthRatio(int start, int length, boolean computingRows) {
582         boolean willGrow = false;
583         int sum = 0;
584
585         int end = start + length;
586         for (int idx = start; idx < end; idx++) {
587             Row row = getRow(idx, computingRows);
588
589             if (row.largerThanChildren && row.grows) {
590                 willGrow = true;
591             }
592
593             sum += row.size;
594         }
595
596         if (!willGrow) {
597             return 0;
598         }
599
600         return sum;
601     }
602
603     int[] computeMinSizes(int[] constraints, boolean computingRows) {
604         // We cache the result of this function since it might be called more than once
605
// for a single size computation
606
int[] result = computingRows ? cachedRowMin : cachedColMin;
607
608         if (result == null) {
609             int columnSpacing;
610             int rowSpacing;
611
612             if (computingRows) {
613                 columnSpacing = horizontalSpacing;
614                 rowSpacing = verticalSpacing;
615             } else {
616                 columnSpacing = verticalSpacing;
617                 rowSpacing = horizontalSpacing;
618             }
619
620             int rowCount = gridInfo.getNumRows(computingRows);
621             result = new int[rowCount];
622             int colCount = gridInfo.getNumRows(!computingRows);
623             int[] rowControls = new int[colCount];
624
625             int lastGrowingRow = -1;
626
627             for (int idx = 0; idx < rowCount; idx++) {
628                 Row row = getRow(idx, computingRows);
629
630                 if (row.grows) {
631                     // There is no minimum size for growing rows
632
lastGrowingRow = idx;
633                     result[idx] = 0;
634                 } else {
635                     result[idx] = row.size;
636
637                     if (row.largerThanChildren) {
638                         // Determine which controls are in this row
639
gridInfo.getRow(rowControls, idx, computingRows);
640
641                         for (int colIdx = 0; colIdx < rowControls.length; colIdx++) {
642                             int control = rowControls[colIdx];
643
644                             // The getRow method will insert -1 into empty cells... skip these.
645
if (control != -1) {
646                                 int controlStart = gridInfo.getStartPos(
647                                         control, computingRows);
648                                 int controlSpan = getSpan(control,
649                                         computingRows);
650
651                                 // If the control ends on this row and does not span any growing rows
652
if (controlStart + controlSpan - 1 == idx
653                                         && controlStart > lastGrowingRow) {
654                                     int controlColStart = gridInfo.getStartPos(
655                                             control, !computingRows);
656                                     int controlColSpan = getSpan(control,
657                                             !computingRows);
658                                     int controlRowSpan = getSpan(control,
659                                             computingRows);
660
661                                     // Compute the width constraint for this control
662
int spannedWidth = sumOfSizes(constraints,
663                                             controlColStart, controlColSpan);
664                                     if (spannedWidth != SWT.DEFAULT) {
665                                         spannedWidth += (columnSpacing * (controlSpan - 1));
666                                     }
667
668                                     int controlHeight = computeControlSize(
669                                             control, spannedWidth,
670                                             computingRows);
671
672                                     // Determine how much of the control spans already allocated columns
673
int allocatedHeight = sumOfSizes(result,
674                                             controlColStart, controlRowSpan - 1)
675                                             + (rowSpacing * (controlRowSpan - 1));
676
677                                     result[idx] = Math.max(result[idx],
678                                             controlHeight - allocatedHeight);
679                                 }
680                             }
681                         }
682                     }
683                 }
684             }
685         }
686
687         // Cache this result
688
if (computingRows) {
689             cachedRowMin = result;
690         } else {
691             cachedColMin = result;
692         }
693
694         return result;
695     }
696
697     /**
698      * Returns the height constraints that should be used when computing column widths. Requires initGrid
699      * to have been called first.
700      *
701      * @param result Will contain the height constraint for row i in the ith position of the array,
702      * or SWT.DEFAULT if there is no constraint on that row.
703      */

704     private int[] computeConstraints(boolean horizontal) {
705         // Initialize the height constraints for each row (basically, these will always be SWT.DEFAULT,
706
// except for rows of type FixedRow, which have a constant height).
707
int numRows = gridInfo.getNumRows(horizontal);
708         int[] result = new int[numRows];
709
710         for (int idx = 0; idx < numRows; idx++) {
711             Row row = getRow(idx, horizontal);
712
713             if (!(row.grows || row.largerThanChildren)) {
714                 result[idx] = row.size;
715             } else {
716                 result[idx] = SWT.DEFAULT;
717             }
718         }
719
720         return result;
721     }
722
723     /**
724      * Computes the total greediness of all rows
725      *
726      * @return the total greediness of all rows
727      */

728     private int getResizeDenominator(boolean horizontal) {
729         int result = 0;
730         int numRows = gridInfo.getNumRows(horizontal);
731
732         for (int idx = 0; idx < numRows; idx++) {
733             Row row = getRow(idx, horizontal);
734
735             if (row.grows) {
736                 result += row.size;
737             }
738         }
739
740         return result;
741     }
742
743     // /**
744
// * Computes the total fixed height of all rows
745
// *
746
// * @param widthConstraints array where the nth entry indicates the known width of the
747
// * nth column, or SWT.DEFAULT if the width is still unknown
748
// *
749
// * @return the total fixed height for all rows
750
// */
751
// private int getMinimumSize(int[] constraints, boolean horizontal) {
752
// Control[] controls = new Control[gridInfo.getRows()];
753
// int result = 0;
754
// int numRows = gridInfo.getRows();
755
//
756
// for (int idx = 0; idx < numRows; idx++) {
757
// result += getRow(idx).getFixedHeight(gridInfo, widthConstraints, idx);
758
// }
759
//
760
// return result;
761
// }
762

763     protected int getSpan(int controlId, boolean isRow) {
764         CellData data = gridInfo.getCellData(controlId);
765
766         if (isRow) {
767             return data.verticalSpan;
768         }
769         return data.horizontalSpan;
770     }
771
772     /**
773      * Returns the total space that will be required for margins and spacing between and
774      * around cells. initGrid(...) must have been called first.
775      *
776      * @return
777      */

778     private Point totalEmptySpace() {
779         int numRows = gridInfo.getRows();
780
781         return new Point((2 * marginWidth)
782                 + ((gridInfo.getCols() - 1) * horizontalSpacing),
783                 (2 * marginHeight) + ((numRows - 1) * verticalSpacing));
784     }
785
786     /**
787      * Returns the absolute positions of each row, given the start position, row sizes,
788      * and row spacing
789      *
790      * @param startPos position of the initial row
791      * @param sizes array of row sizes (pixels)
792      * @param spacing space between each row (pixels)
793      * @return array of row positions. The result size is sizes.length + 1. The last entry is
794      * the position of the end of the layout.
795      */

796     private static int[] computeRowPositions(int startPos, int[] sizes,
797             int spacing) {
798         int[] result = new int[sizes.length + 1];
799
800         result[0] = startPos;
801         for (int idx = 0; idx < sizes.length; idx++) {
802             result[idx + 1] = result[idx] + sizes[idx] + spacing;
803         }
804
805         return result;
806     }
807
808     /* (non-Javadoc)
809      * @see org.eclipse.swt.widgets.Layout#layout(org.eclipse.swt.widgets.Composite, boolean)
810      */

811     protected void layout(Composite composite, boolean flushCache) {
812         Control[] children = composite.getChildren();
813         
814         // If there are no children then this is a NO-OP
815
if (children.length == 0)
816             return;
817             
818         initGrid(children);
819
820         if (flushCache) {
821             cache.flush();
822         }
823
824         Point emptySpace = totalEmptySpace();
825
826         // Compute the area actually available for controls (once the margins and spacing is removed)
827
int availableWidth = composite.getClientArea().width - emptySpace.x;
828         int availableHeight = composite.getClientArea().height - emptySpace.y;
829
830         int[] heights = computeConstraints(true);
831         int[] widths = new int[gridInfo.getCols()];
832
833         // Compute the actual column widths
834
widths = computeSizes(heights, availableWidth, false);
835
836         // Compute the actual row heights (based on the actual column widths)
837
heights = computeSizes(widths, availableHeight, true);
838
839         Rectangle currentCell = new Rectangle(0, 0, 0, 0);
840
841         int[] starty = computeRowPositions(composite.getClientArea().y
842                 + marginHeight, heights, verticalSpacing);
843         int[] startx = computeRowPositions(composite.getClientArea().x
844                 + marginWidth, widths, horizontalSpacing);
845
846         int numChildren = gridInfo.controls.length;
847         for (int controlId = 0; controlId < numChildren; controlId++) {
848             CellData data = gridInfo.getCellData(controlId);
849
850             int row = gridInfo.controlRow[controlId];
851             int col = gridInfo.controlCol[controlId];
852
853             currentCell.x = startx[col];
854             currentCell.width = startx[col + data.horizontalSpan]
855                     - currentCell.x - horizontalSpacing;
856
857             currentCell.y = starty[row];
858             currentCell.height = starty[row + data.verticalSpan]
859                     - currentCell.y - verticalSpacing;
860
861             data.positionControl(cache.getCache(controlId), currentCell);
862         }
863     }
864
865     /**
866      * @return
867      */

868     public int getColumns() {
869         return numCols;
870     }
871
872     public boolean canGrow(Composite composite, boolean horizontally) {
873         initGrid(composite.getChildren());
874
875         int numRows = gridInfo.getNumRows(horizontally);
876
877         for (int idx = 0; idx < numRows; idx++) {
878             Row row = getRow(idx, horizontally);
879
880             if (row.grows) {
881                 return true;
882             }
883         }
884
885         return false;
886
887     }
888 }
889
Popular Tags