001: /*******************************************************************************
002: * Copyright (c) 2005, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: * Stefan Xenos, IBM - initial implementation, bug 178888
011: * Karsten Stoeckmann - bug 156982
012: *******************************************************************************/package org.eclipse.jface.layout;
013:
014: import org.eclipse.swt.graphics.Point;
015: import org.eclipse.swt.graphics.Rectangle;
016: import org.eclipse.swt.layout.GridLayout;
017: import org.eclipse.swt.widgets.Composite;
018:
019: /**
020: * GridLayoutFactory creates and initializes grid layouts. There are two ways to use GridLayoutFactory.
021: * Normally, it is used as a shorthand for writing "new GridLayout()" and initializing a bunch
022: * of fields. In this case the main benefit is a more concise syntax and the ability to create more
023: * than one identical GridLayout from the same factory. Changing a property of the factory will affect
024: * future layouts created by the factory, but has no effect on layouts that have already been created.
025: *
026: * <p>
027: * GridLayoutFactory can also generate grid data for all the controls in a layout. This is done with
028: * the generateLayout method. To use this feature:
029: * </p>
030: *
031: * <ol>
032: * <li>Create the composite</li>
033: * <li>Create all the controls in the composite</li>
034: * <li>Call generateLayout</li>
035: * </ol>
036: *
037: * <p>
038: * The order here is important. generateLayout must be called after all the child controls have
039: * been created. generateLayout will not change any layout data that has already been attached
040: * to a child control and it will not recurse into nested composites.
041: * </p>
042: *
043: * @since 3.2
044: */
045: public final class GridLayoutFactory {
046:
047: /**
048: * Template layout. The factory will create copies of this layout.
049: */
050: private GridLayout l;
051:
052: /**
053: * Creates a new GridLayoutFactory that will create copies of the given layout.
054: *
055: * @param l layout to copy
056: */
057: private GridLayoutFactory(GridLayout l) {
058: this .l = l;
059: }
060:
061: /**
062: * Creates a factory that creates copies of the given layout.
063: *
064: * @param l layout to copy
065: * @return a new GridLayoutFactory instance that creates copies of the given layout
066: */
067: public static GridLayoutFactory createFrom(GridLayout l) {
068: return new GridLayoutFactory(copyLayout(l));
069: }
070:
071: /**
072: * Creates a copy of the reciever.
073: *
074: * @return a copy of the reciever
075: */
076: public GridLayoutFactory copy() {
077: return new GridLayoutFactory(create());
078: }
079:
080: /**
081: * Creates a GridLayoutFactory that creates GridLayouts with the default SWT
082: * values.
083: *
084: * <p>
085: * Initial values are:
086: * </p>
087: *
088: * <ul>
089: * <li>numColumns(1)</li>
090: * <li>margins(5,5)</li>
091: * <li>extendedMargins(0,0,0,0)</li>
092: * <li>spacing(5,5)</li>
093: * <li>equalWidth(false)</li>
094: * </ul>
095: *
096: * @return a GridLayoutFactory that creates GridLayouts as though created with
097: * their default constructor
098: * @see #fillDefaults
099: */
100: public static GridLayoutFactory swtDefaults() {
101: return new GridLayoutFactory(new GridLayout());
102: }
103:
104: /**
105: * Creates a GridLayoutFactory that creates GridLayouts with no margins and
106: * default dialog spacing.
107: *
108: * <p>
109: * Initial values are:
110: * </p>
111: *
112: * <ul>
113: * <li>numColumns(1)</li>
114: * <li>margins(0,0)</li>
115: * <li>extendedMargins(0,0,0,0)</li>
116: * <li>spacing(LayoutConstants.getSpacing())</li>
117: * <li>equalWidth(false)</li>
118: * </ul>
119: *
120: * @return a GridLayoutFactory that creates GridLayouts as though created with
121: * their default constructor
122: * @see #swtDefaults
123: */
124: public static GridLayoutFactory fillDefaults() {
125: GridLayout layout = new GridLayout();
126: layout.marginWidth = 0;
127: layout.marginHeight = 0;
128: Point defaultSpacing = LayoutConstants.getSpacing();
129: layout.horizontalSpacing = defaultSpacing.x;
130: layout.verticalSpacing = defaultSpacing.y;
131: return new GridLayoutFactory(layout);
132: }
133:
134: /**
135: * Sets whether the columns should be forced to be equal width
136: *
137: * @param equal true iff the columns should be forced to be equal width
138: * @return this
139: */
140: public GridLayoutFactory equalWidth(boolean equal) {
141: l.makeColumnsEqualWidth = equal;
142: return this ;
143: }
144:
145: /**
146: * Sets the spacing for layouts created with this factory. The spacing
147: * is the distance between cells within the layout.
148: *
149: * @param hSpacing horizontal spacing (pixels)
150: * @param vSpacing vertical spacing (pixels)
151: * @return this
152: * @see #margins(Point)
153: * @see #margins(int, int)
154: */
155: public GridLayoutFactory spacing(int hSpacing, int vSpacing) {
156: l.horizontalSpacing = hSpacing;
157: l.verticalSpacing = vSpacing;
158: return this ;
159: }
160:
161: /**
162: * Sets the spacing for layouts created with this factory. The spacing
163: * is the distance between cells within the layout.
164: *
165: * @param spacing space between controls in the layout (pixels)
166: * @return this
167: * @see #margins(Point)
168: * @see #margins(int, int)
169: */
170: public GridLayoutFactory spacing(Point spacing) {
171: l.horizontalSpacing = spacing.x;
172: l.verticalSpacing = spacing.y;
173: return this ;
174: }
175:
176: /**
177: * Sets the margins for layouts created with this factory. The margins
178: * are the distance between the outer cells and the edge of the layout.
179: *
180: * @param margins margin size (pixels)
181: * @return this
182: * @see #spacing(Point)
183: * @see #spacing(int, int)
184: */
185: public GridLayoutFactory margins(Point margins) {
186: l.marginWidth = margins.x;
187: l.marginHeight = margins.y;
188: return this ;
189: }
190:
191: /**
192: * Sets the margins for layouts created with this factory. The margins
193: * specify the number of pixels of horizontal and vertical margin that will
194: * be placed along the left/right and top/bottom edges of the layout. Note
195: * that thes margins will be added to the ones specified by
196: * {@link #extendedMargins(int, int, int, int)}.
197: *
198: * @param width
199: * margin width (pixels)
200: * @param height
201: * margin height (pixels)
202: * @return this
203: * @see #spacing(Point)
204: * * @see #spacing(int, int)
205: */
206: public GridLayoutFactory margins(int width, int height) {
207: l.marginWidth = width;
208: l.marginHeight = height;
209: return this ;
210: }
211:
212: /**
213: * Sets the margins for layouts created with this factory. The margins
214: * specify the number of pixels of horizontal and vertical margin that will
215: * be placed along the left, right, top, and bottom edges of the layout.
216: * Note that thes margins will be added to the ones specified by
217: * {@link #margins(int, int)}.
218: *
219: * @param left
220: * left margin size (pixels)
221: * @param right
222: * right margin size (pixels)
223: * @param top
224: * top margin size (pixels)
225: * @param bottom
226: * bottom margin size (pixels)
227: * @return this
228: * @see #spacing(Point)
229: * @see #spacing(int, int)
230: *
231: * @since 3.3
232: */
233: public GridLayoutFactory extendedMargins(int left, int right,
234: int top, int bottom) {
235: l.marginLeft = left;
236: l.marginRight = right;
237: l.marginTop = top;
238: l.marginBottom = bottom;
239: return this ;
240: }
241:
242: /**
243: * Sets the margins for layouts created with this factory. The margins
244: * specify the number of pixels of horizontal and vertical margin that will
245: * be placed along the left, right, top, and bottom edges of the layout.
246: * Note that thes margins will be added to the ones specified by
247: * {@link #margins(int, int)}.
248: *
249: * <code><pre>
250: * // Construct a GridLayout whose left, right, top, and bottom
251: * // margin sizes are 10, 5, 0, and 15 respectively
252: *
253: * Rectangle margins = Geometry.createDiffRectangle(10,5,0,15);
254: * GridLayoutFactory.fillDefaults().extendedMargins(margins).applyTo(composite1);
255: * </pre></code>
256: *
257: * @param differenceRect rectangle which, when added to the client area of the
258: * layout, returns the outer area of the layout. The x and y values of
259: * the rectangle correspond to the position of the bounds of the
260: * layout with respect to the client area. They should be negative.
261: * The width and height correspond to the relative size of the bounds
262: * of the layout with respect to the client area, and should be positive.
263: * @return this
264: * @see #spacing(Point)
265: * @see #spacing(int, int)
266: *
267: * @since 3.3
268: */
269: public GridLayoutFactory extendedMargins(Rectangle differenceRect) {
270: l.marginLeft = -differenceRect.x;
271: l.marginTop = -differenceRect.y;
272: l.marginBottom = differenceRect.y + differenceRect.height;
273: l.marginRight = differenceRect.x + differenceRect.width;
274: return this ;
275: }
276:
277: /**
278: * Sets the number of columns in the layout
279: *
280: * @param numColumns number of columns in the layout
281: * @return this
282: */
283: public GridLayoutFactory numColumns(int numColumns) {
284: l.numColumns = numColumns;
285: return this ;
286: }
287:
288: /**
289: * Creates a new GridLayout, and initializes it with values from the factory.
290: *
291: * @return a new initialized GridLayout.
292: * @see #applyTo
293: */
294: public GridLayout create() {
295: return copyLayout(l);
296: }
297:
298: /**
299: * Creates a new GridLayout and attaches it to the given composite.
300: * Does not create the GridData of any of the controls in the composite.
301: *
302: * @param c composite whose layout will be set
303: * @see #generateLayout
304: * @see #create
305: * @see GridLayoutFactory
306: */
307: public void applyTo(Composite c) {
308: c.setLayout(copyLayout(l));
309: }
310:
311: /**
312: * Copies the given GridLayout instance
313: *
314: * @param l layout to copy
315: * @return a new GridLayout
316: */
317: public static GridLayout copyLayout(GridLayout l) {
318: GridLayout result = new GridLayout(l.numColumns,
319: l.makeColumnsEqualWidth);
320: result.horizontalSpacing = l.horizontalSpacing;
321: result.marginBottom = l.marginBottom;
322: result.marginHeight = l.marginHeight;
323: result.marginLeft = l.marginLeft;
324: result.marginRight = l.marginRight;
325: result.marginTop = l.marginTop;
326: result.marginWidth = l.marginWidth;
327: result.verticalSpacing = l.verticalSpacing;
328:
329: return result;
330: }
331:
332: /**
333: * Applies this layout to the given composite, and attaches default GridData
334: * to all immediate children that don't have one. The layout is generated using
335: * heuristics based on the widget types. In most cases, it will create exactly the same
336: * layout that would have been hardcoded by the programmer. In any situation
337: * where it does not produce the desired layout, the GridData for any child can be
338: * overridden by attaching the layout data before calling this method. In these cases,
339: * the special-case layout data can be hardcoded and the algorithm can supply defaults
340: * to the rest.
341: *
342: * <p>
343: * This must be called <b>AFTER</b> all of the child controls have been created and their
344: * layouts attached. This method will attach a layout to the given composite. If any new
345: * children are created after calling this method, their GridData must be created manually.
346: * The algorithm does not recurse into child composites. To generate all the layouts in
347: * a widget hierarchy, the method must be called bottom-up for each Composite.
348: * </p>
349: *
350: * <p>
351: * All controls are made to span a single cell. The algorithm tries to classify controls into one
352: * of the following categories:
353: * </p>
354: *
355: * <ul>
356: * <li>Pushbuttons: Set to a constant size large enough to fit their text and no smaller
357: * than the default button size.</li>
358: * <li>Wrapping with text (labels, read-only text boxes, etc.): override the preferred horizontal
359: * size with the default wrapping point, fill horizontally, grab horizontal space, keep the
360: * preferred vertical size</li>
361: * <li>Wrapping without text (toolbars, coolbars, etc.): fill align, don't grab, use the preferred size</li>
362: * <li>Horizontally scrolling controls (anything with horizontal scrollbars or where the user edits
363: * text and can cursor through it from left-to-right): override the preferred horizontal size with
364: * a constant, grab horizontal, fill horizontal.</li>
365: * <li>Vertically scrolling controls (anything with vertical scrollbars or where the user edits
366: * text and can cursor through it up and down): override the preferred vertical size with a constant,
367: * grab vertical, fill vertical</li>
368: * <li>Nested layouts: fill align both directions, grab along any dimension if the layout would
369: * be able to expand along that dimension.</li>
370: * <li>Non-wrapping non-scrollable read-only text: fill horizontally, center vertically, default size, don't grab </li>
371: * <li>Non-wrapping non-scrollable non-text: fill both, default size, don't grab</li>
372: * </ul>
373: *
374: * @param c composite whose layout will be generated
375: */
376: public void generateLayout(Composite c) {
377: applyTo(c);
378: LayoutGenerator.generateLayout(c);
379: }
380: }
|