001: /*******************************************************************************
002: * Copyright (c) 2005, 2006 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: *******************************************************************************/package org.eclipse.jface.layout;
011:
012: import org.eclipse.jface.util.Geometry;
013: import org.eclipse.swt.SWT;
014: import org.eclipse.swt.events.ModifyListener;
015: import org.eclipse.swt.graphics.Point;
016: import org.eclipse.swt.layout.GridData;
017: import org.eclipse.swt.layout.GridLayout;
018: import org.eclipse.swt.widgets.Button;
019: import org.eclipse.swt.widgets.Composite;
020: import org.eclipse.swt.widgets.Control;
021: import org.eclipse.swt.widgets.Layout;
022: import org.eclipse.swt.widgets.Scrollable;
023:
024: /* package */class LayoutGenerator {
025:
026: /**
027: * Default size for controls with varying contents
028: */
029: private static final Point defaultSize = new Point(150, 150);
030:
031: /**
032: * Default wrapping size for wrapped labels
033: */
034: private static final int wrapSize = 350;
035:
036: private static final GridDataFactory nonWrappingLabelData = GridDataFactory
037: .fillDefaults().align(SWT.BEGINNING, SWT.CENTER).grab(
038: false, false);
039:
040: private static boolean hasStyle(Control c, int style) {
041: return (c.getStyle() & style) != 0;
042: }
043:
044: /**
045: * Generates a GridLayout for the given composite by examining its child
046: * controls and attaching layout data to any immediate children that do not
047: * already have layout data.
048: *
049: * @param toGenerate
050: * composite to generate a layout for
051: */
052: public static void generateLayout(Composite toGenerate) {
053: Control[] children = toGenerate.getChildren();
054:
055: for (int i = 0; i < children.length; i++) {
056: Control control = children[i];
057:
058: // Skip any children that already have layout data
059: if (control.getLayoutData() != null) {
060: continue;
061: }
062:
063: applyLayoutDataTo(control);
064: }
065: }
066:
067: private static void applyLayoutDataTo(Control control) {
068: defaultsFor(control).applyTo(control);
069: }
070:
071: /**
072: * Creates default factory for this control types:
073: * <ul>
074: * <li>{@link Button} with {@link SWT#CHECK}</li>
075: * <li>{@link Button}</li>
076: * <li>{@link Composite}</li>
077: * </ul>
078: * @param control the control the factory is search for
079: * @return a default factory for the control
080: */
081: public static GridDataFactory defaultsFor(Control control) {
082: if (control instanceof Button) {
083: Button button = (Button) control;
084:
085: if (hasStyle(button, SWT.CHECK)) {
086: return nonWrappingLabelData.copy();
087: } else {
088: return GridDataFactory.fillDefaults().align(SWT.FILL,
089: SWT.CENTER).hint(
090: Geometry.max(button.computeSize(SWT.DEFAULT,
091: SWT.DEFAULT, true), LayoutConstants
092: .getMinButtonSize()));
093: }
094: }
095:
096: if (control instanceof Scrollable) {
097: Scrollable scrollable = (Scrollable) control;
098:
099: if (scrollable instanceof Composite) {
100: Composite composite = (Composite) control;
101:
102: Layout theLayout = composite.getLayout();
103: if (theLayout instanceof GridLayout) {
104: boolean growsHorizontally = false;
105: boolean growsVertically = false;
106:
107: Control[] children = composite.getChildren();
108: for (int i = 0; i < children.length; i++) {
109: Control child = children[i];
110:
111: GridData data = (GridData) child
112: .getLayoutData();
113:
114: if (data != null) {
115: if (data.grabExcessHorizontalSpace) {
116: growsHorizontally = true;
117: }
118: if (data.grabExcessVerticalSpace) {
119: growsVertically = true;
120: }
121: }
122: }
123:
124: return GridDataFactory.fillDefaults().grab(
125: growsHorizontally, growsVertically);
126: }
127: }
128: }
129:
130: boolean wrapping = hasStyle(control, SWT.WRAP);
131:
132: // Assume any control with the H_SCROLL or V_SCROLL flags are
133: // horizontally or vertically
134: // scrollable, respectively.
135: boolean hScroll = hasStyle(control, SWT.H_SCROLL);
136: boolean vScroll = hasStyle(control, SWT.V_SCROLL);
137:
138: boolean containsText = hasMethod(control,
139: "setText", new Class[] { String.class }); //$NON-NLS-1$
140:
141: // If the control has a setText method, an addModifyListener method, and
142: // does not have
143: // the SWT.READ_ONLY flag, assume it contains user-editable text.
144: boolean userEditable = !hasStyle(control, SWT.READ_ONLY)
145: && containsText
146: && hasMethod(
147: control,
148: "addModifyListener", new Class[] { ModifyListener.class }); //$NON-NLS-1$
149:
150: // For controls containing user-editable text...
151: if (userEditable) {
152: if (hasStyle(control, SWT.MULTI)) {
153: vScroll = true;
154: }
155:
156: if (!wrapping) {
157: hScroll = true;
158: }
159: }
160:
161: // Compute the horizontal hint
162: int hHint = SWT.DEFAULT;
163: boolean grabHorizontal = hScroll;
164:
165: // For horizontally-scrollable controls, override their horizontal
166: // preferred size
167: // with a constant
168: if (hScroll) {
169: hHint = defaultSize.x;
170: } else {
171: // For wrapping controls, there are two cases.
172: // 1. For controls that contain text (like wrapping labels,
173: // read-only text boxes,
174: // etc.) override their preferred size with the preferred wrapping
175: // point and
176: // make them grab horizontal space.
177: // 2. For non-text controls (like wrapping toolbars), assume that
178: // their non-wrapped
179: // size is best.
180:
181: if (wrapping) {
182: if (containsText) {
183: hHint = wrapSize;
184: grabHorizontal = true;
185: }
186: }
187: }
188:
189: int vAlign = SWT.FILL;
190:
191: // Heuristic for labels: Controls that contain non-wrapping read-only
192: // text should be
193: // center-aligned rather than fill-aligned
194: if (!vScroll && !wrapping && !userEditable && containsText) {
195: vAlign = SWT.CENTER;
196: }
197:
198: return GridDataFactory.fillDefaults().grab(grabHorizontal,
199: vScroll).align(SWT.FILL, vAlign).hint(hHint,
200: vScroll ? defaultSize.y : SWT.DEFAULT);
201: }
202:
203: private static boolean hasMethod(Control control, String name,
204: Class[] parameterTypes) {
205: Class c = control.getClass();
206: try {
207: return c.getMethod(name, parameterTypes) != null;
208: } catch (SecurityException e) {
209: return false;
210: } catch (NoSuchMethodException e) {
211: return false;
212: }
213: }
214: }
|