/******************************************************************************* * Copyright (c) 2005, 2015 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation * Stefan Xenos, IBM - initial implementation, bug 178888 *******************************************************************************/ package org.eclipse.jface.layout; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Control; /** * This class provides a convienient shorthand for creating and initializing * GridData. This offers several benefits over creating GridData normal way: * * <ul> * <li>The same factory can be used many times to create several GridData instances</li> * <li>The setters on GridDataFactory all return "this", allowing them to be chained</li> * <li>GridDataFactory uses vector setters (it accepts Points), making it easy to * set X and Y values together</li> * </ul> * * <p> * GridDataFactory instances are created using one of the static methods on this class. * </p> * * <p> * Example usage: * </p> * <code><pre> * * //////////////////////////////////////////////////////////// * // Example 1: Typical grid data for a non-wrapping label * * // GridDataFactory version * GridDataFactory.fillDefaults().applyTo(myLabel); * * // Equivalent SWT version * GridData labelData = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_FILL); * myLabel.setLayoutData(labelData); * * /////////////////////////////////////////////////////////// * // Example 2: Typical grid data for a wrapping label * * // GridDataFactory version * GridDataFactory.fillDefaults() * .align(SWT.FILL, SWT.CENTER) * .hint(150, SWT.DEFAULT) * .grab(true, false) * .applyTo(wrappingLabel); * * // Equivalent SWT version * GridData wrappingLabelData = new GridData(GridData.FILL_HORIZONTAL | GridData.VERTICAL_ALIGN_CENTER); * wrappingLabelData.minimumWidth = 1; * wrappingLabelData.widthHint = 150; * wrappingLabel.setLayoutData(wrappingLabelData); * * ////////////////////////////////////////////////////////////// * // Example 3: Typical grid data for a scrollable control (a list box, tree, table, etc.) * * // GridDataFactory version * GridDataFactory.fillDefaults().grab(true, true).hint(150, 150).applyTo(listBox); * * // Equivalent SWT version * GridData listBoxData = new GridData(GridData.FILL_BOTH); * listBoxData.widthHint = 150; * listBoxData.heightHint = 150; * listBoxData.minimumWidth = 1; * listBoxData.minimumHeight = 1; * listBox.setLayoutData(listBoxData); * * ///////////////////////////////////////////////////////////// * // Example 4: Typical grid data for a button * * // GridDataFactory version * Point preferredSize = button.computeSize(SWT.DEFAULT, SWT.DEFAULT, false); * Point hint = Geometry.max(LayoutConstants.getMinButtonSize(), preferredSize); * GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).hint(hint).applyTo(button); * * // Equivalent SWT version * Point preferredSize = button.computeSize(SWT.DEFAULT, SWT.DEFAULT, false); * Point hint = Geometry.max(LayoutConstants.getMinButtonSize(), preferredSize); * GridData buttonData = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_CENTER); * buttonData.widthHint = hint.x; * buttonData.heightHint = hint.y; * button.setLayoutData(buttonData); * * ///////////////////////////////////////////////////////////// * // Example 5: Generated GridData * * // Generates GridData a wrapping label that spans 2 columns * GridDataFactory.generate(wrappingLabel, 2, 1); * * // Generates GridData for a listbox. and adjusts the preferred size to 300x400 pixels * GridDataFactory.defaultsFor(listBox).hint(300, 400).applyTo(listBox); * * // Generates GridData equivalent to example 4 * GridDataFactory.generate(button, 1, 1); * * </pre></code> * * @since 3.2 */ public final class GridDataFactory { private GridData data; /** * Creates a GridDataFactory that creates copes of the given GridData. * * @param d template GridData to copy */ private GridDataFactory(GridData d) { this.data = d; } /** * Creates a new GridDataFactory initialized with the SWT defaults. * This factory will generate GridData that is equivalent to * "new GridData()". * * <p> * Initial values are: * </p> * * <ul> * <li>align(SWT.BEGINNING, SWT.CENTER)</li> * <li>exclude(false)</li> * <li>grab(false, false)</li> * <li>hint(SWT.DEFAULT, SWT.DEFAULT)</li> * <li>indent(0,0)</li> * <li>minSize(0,0)</li> * <li>span(1,1)</li> * </ul> * * @return a new GridDataFactory instance * @see #fillDefaults() */ public static GridDataFactory swtDefaults() { return new GridDataFactory(new GridData()); } /** * Creates a new GridDataFactory that creates copies of the given GridData * by default. * * @param data GridData to copy * @return a new GridDataFactory that creates copies of the argument by default */ public static GridDataFactory createFrom(GridData data) { return new GridDataFactory(copyData(data)); } /** * Creates a GridDataFactory initialized with defaults that will cause * the control to fill its cell. The minimum size is set to the smallest possible * minimum size supported by SWT. Currently, the smallest supported minimum size * is (1,1) so this is the default. If GridLayout ever adds support for grid data * with no minimum size, this will be changed to 0,0 in the future. * * <p> * Initial values are: * </p> * * <ul> * <li>align(SWT.FILL, SWT.FILL)</li> * <li>exclude(false)</li> * <li>grab(false, false)</li> * <li>hint(SWT.DEFAULT, SWT.DEFAULT)</li> * <li>indent(0,0)</li> * <li>minSize(1,1)</li> * <li>span(1,1)</li> * </ul> * * @return a GridDataFactory that makes controls fill their grid by default * * @see #swtDefaults() */ public static GridDataFactory fillDefaults() { GridData data = new GridData(); data.minimumWidth = 1; data.minimumHeight = 1; data.horizontalAlignment = SWT.FILL; data.verticalAlignment = SWT.FILL; return new GridDataFactory(data); } /** * Returns a GridDataFactory initialized with heuristicly generated defaults for the given control. * To be precise, this method picks the default values that GridLayoutFactory.generateLayout * would have assigned to the control. Does not attach GridData to the control. Callers must * additionally call applyTo(theControl) if they wish to use the generated values. * * <p> * This method is intended for situations where generateLayout is generating layout data * for a particular control that is not quite right for the desired layout. * This allows callers to start with the generated values and tweak one or two settings * before applying the GridData to the control. * </p> * * @see GridLayoutFactory#generateLayout(org.eclipse.swt.widgets.Composite) * @param theControl * @return a GridLayoutFactory initialized with defaults that GridLayoutFactory would have * @since 3.3 */ public static GridDataFactory defaultsFor(Control theControl) { return LayoutGenerator.defaultsFor(theControl); } /** * Generates layout data to the given control, given the number of cells * spanned by the control. Attaches a GridData to the control. This method * allows generated layout data to be used with controls that span multiple cells. * <p> * The generated layout data is the same as what would be generated by * GridLayoutFactory.generateLayout, except that the span is configurable * </p> * * @see GridLayoutFactory#generateLayout(org.eclipse.swt.widgets.Composite) * @param theControl * @param hSpan number of columns spanned by the control * @param vSpan number of rows spanned by the control * @since 3.3 */ public static void generate(Control theControl, int hSpan, int vSpan) { defaultsFor(theControl).span(hSpan, vSpan).applyTo(theControl); } /** * Generates layout data to the given control, given the number of cells * spanned by the control. Attaches GridData to the control. This method * allows generated layout data to be used with controls that span multiple cells. * <p> * The generated layout data is the same as what would be generated by * GridLayoutFactory.generateLayout, except that the span is configurable * </p> * * @see GridLayoutFactory#generateLayout(org.eclipse.swt.widgets.Composite) * @param theControl * @param span The x coordinate indicates the number of * columns spanned, and the y coordinate indicates the number of rows. * @since 3.3 */ public static void generate(Control theControl, Point span) { defaultsFor(theControl).span(span).applyTo(theControl); } /** * Sets the GridData span. The span controls how many cells * are filled by the control. * * @param hSpan number of columns spanned by the control * @param vSpan number of rows spanned by the control * @return this */ public GridDataFactory span(int hSpan, int vSpan) { data.horizontalSpan = hSpan; data.verticalSpan = vSpan; return this; } /** * Sets the GridData span. The span controls how many cells * are filled by the control. * * @param span the new span. The x coordinate indicates the number of * columns spanned, and the y coordinate indicates the number of rows. * @return this */ public GridDataFactory span(Point span) { data.horizontalSpan = span.x; data.verticalSpan = span.y; return this; } /** * Sets the width and height hints. The width and height hints override * the control's preferred size. If either hint is set to SWT.DEFAULT, * the control's preferred size is used. * * @param xHint horizontal hint (pixels), or SWT.DEFAULT to use the control's preferred size * @param yHint vertical hint (pixels), or SWT.DEFAULT to use the control's preferred size * @return this */ public GridDataFactory hint(int xHint, int yHint) { data.widthHint = xHint; data.heightHint = yHint; return this; } /** * Sets the width and height hints. The width and height hints override * the control's preferred size. If either hint is set to SWT.DEFAULT, * the control's preferred size is used. * * @param hint size (pixels) to be used instead of the control's preferred size. If * the x or y values are set to SWT.DEFAULT, the control's computeSize() method will * be used to obtain that dimension of the preferred size. * @return this */ public GridDataFactory hint(Point hint) { data.widthHint = hint.x; data.heightHint = hint.y; return this; } /** * Sets the alignment of the control within its cell. * * @param hAlign horizontal alignment. One of SWT.BEGINNING, SWT.CENTER, SWT.END, or SWT.FILL. * @param vAlign vertical alignment. One of SWT.BEGINNING, SWT.CENTER, SWT.END, or SWT.FILL. * @return this */ public GridDataFactory align(int hAlign, int vAlign) { if (hAlign != SWT.BEGINNING && hAlign != SWT.CENTER && hAlign != GridData.CENTER && hAlign != SWT.END && hAlign != GridData.END && hAlign != SWT.FILL && hAlign != SWT.LEFT && hAlign != SWT.RIGHT) { throw new IllegalArgumentException(); } if (vAlign != SWT.BEGINNING && vAlign != SWT.CENTER && vAlign != GridData.CENTER && vAlign != SWT.END && vAlign != GridData.END && vAlign != SWT.FILL && vAlign != SWT.TOP && vAlign != SWT.BOTTOM) { throw new IllegalArgumentException(); } data.horizontalAlignment = hAlign; data.verticalAlignment = vAlign; return this; } /** * Sets the indent of the control within the cell. Moves the position of the control * by the given number of pixels. Positive values move toward the lower-right, negative * values move toward the upper-left. * * @param hIndent distance to move to the right (negative values move left) * @param vIndent distance to move down (negative values move up) * @return this */ public GridDataFactory indent(int hIndent, int vIndent) { data.horizontalIndent = hIndent; data.verticalIndent = vIndent; return this; } /** * Sets the indent of the control within the cell. Moves the position of the control * by the given number of pixels. Positive values move toward the lower-right, negative * values move toward the upper-left. * * @param indent offset to move the control * @return this */ public GridDataFactory indent(Point indent) { data.horizontalIndent = indent.x; data.verticalIndent = indent.y; return this; } /** * Determines whether extra horizontal or vertical space should be allocated to * this control's column when the layout resizes. If any control in the column * is set to grab horizontal then the whole column will grab horizontal space. * If any control in the row is set to grab vertical then the whole row will grab * vertical space. * * @param horizontal true if the control's column should grow horizontally * @param vertical true if the control's row should grow vertically * @return this */ public GridDataFactory grab(boolean horizontal, boolean vertical) { data.grabExcessHorizontalSpace = horizontal; data.grabExcessVerticalSpace = vertical; return this; } /** * Sets the minimum size for the control. The control will not be permitted * to shrink below this size. Note: GridLayout treats a minimum size of 0 * as an undocumented special value, so the smallest possible minimum size * is a size of 1. A minimum size of SWT.DEFAULT indicates that the result * of computeSize(int, int, boolean) should be used as the control's minimum * size. * * * @param minX minimum a value of 1 or more is a horizontal size of the control (pixels). * SWT.DEFAULT indicates that the control's preferred size should be used. A size * of 0 has special semantics defined by GridLayout. * @param minY minimum a value of 1 or more is a vertical size of the control (pixels). SWT.DEFAULT * indicates that the control's preferred size should be used. A size * of 0 has special semantics defined by GridLayout. * @return this */ public GridDataFactory minSize(int minX, int minY) { data.minimumWidth = minX; data.minimumHeight = minY; return this; } /** * Sets the minimum size for the control. The control will not be permitted * to shrink below this size. Note: GridLayout treats a minimum size of 0 * as an undocumented special value, so the smallest possible minimum size * is a size of 1. A minimum size of SWT.DEFAULT indicates that the result * of computeSize(int, int, boolean) should be used as the control's minimum * size. * * @param min minimum size of the control * @return this */ public GridDataFactory minSize(Point min) { data.minimumWidth = min.x; data.minimumHeight = min.y; return this; } /** * Instructs the GridLayout to ignore this control when performing layouts. * * @param shouldExclude true iff the control should be excluded from layouts * @return this */ public GridDataFactory exclude(boolean shouldExclude) { data.exclude = shouldExclude; return this; } /** * Creates a new GridData instance. All attributes of the GridData instance * will be initialized by the factory. * * @return a new GridData instance */ public GridData create() { return copyData(data); } /** * Creates a copy of the receiver. * * @return a copy of the receiver */ public GridDataFactory copy() { return new GridDataFactory(create()); } /** * Returns a copy of the given GridData * * @param data GridData to copy * @return a copy of the argument */ public static GridData copyData(GridData data) { GridData newData = new GridData(data.horizontalAlignment, data.verticalAlignment, data.grabExcessHorizontalSpace, data.grabExcessVerticalSpace, data.horizontalSpan, data.verticalSpan); newData.exclude = data.exclude; newData.heightHint = data.heightHint; newData.horizontalIndent = data.horizontalIndent; newData.minimumHeight = data.minimumHeight; newData.minimumWidth = data.minimumWidth; newData.verticalIndent = data.verticalIndent; newData.widthHint = data.widthHint; return newData; } /** * Sets the layout data on the given control. Creates a new GridData instance and * assigns it to the control by calling control.setLayoutData. * * @param control control whose layout data will be initialized */ public void applyTo(Control control) { control.setLayoutData(create()); } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("GridDataFactory.fillDefaults()\n"); //$NON-NLS-1$ if (data.exclude) { builder.append(" .exclude(true)\n"); //$NON-NLS-1$ } if (data.grabExcessHorizontalSpace || data.grabExcessVerticalSpace) { builder.append(" .grab("); //$NON-NLS-1$ builder.append(data.grabExcessHorizontalSpace); builder.append(", "); //$NON-NLS-1$ builder.append(data.grabExcessVerticalSpace); builder.append(")\n"); //$NON-NLS-1$ } if (data.horizontalAlignment != SWT.FILL || data.verticalAlignment != SWT.FILL) { builder.append(" .align("); //$NON-NLS-1$ builder.append(getAlignmentString(data.horizontalAlignment)); builder.append(", "); //$NON-NLS-1$ builder.append(getAlignmentString(data.verticalAlignment)); builder.append(")\n"); //$NON-NLS-1$ } if (data.horizontalIndent != 0 || data.verticalIndent != 0) { builder.append(" .indent("); //$NON-NLS-1$ builder.append(data.horizontalIndent); builder.append(", "); //$NON-NLS-1$ builder.append(data.verticalIndent); builder.append(")\n"); //$NON-NLS-1$ } if (data.horizontalSpan != 1 || data.verticalSpan != 1) { builder.append(" .span("); //$NON-NLS-1$ builder.append(data.horizontalSpan); builder.append(", "); //$NON-NLS-1$ builder.append(data.verticalSpan); builder.append(")\n"); //$NON-NLS-1$ } if (data.minimumHeight != 1 || data.minimumWidth != 1) { builder.append(" .minSize("); //$NON-NLS-1$ builder.append(data.minimumWidth); builder.append(", "); //$NON-NLS-1$ builder.append(data.minimumHeight); builder.append(")\n"); //$NON-NLS-1$ } if (data.widthHint != SWT.DEFAULT || data.heightHint != SWT.DEFAULT) { builder.append(" .hint("); //$NON-NLS-1$ builder.append(getHintString(data.widthHint)); builder.append(", "); //$NON-NLS-1$ builder.append(getHintString(data.heightHint)); builder.append(")\n"); //$NON-NLS-1$ } return builder.toString(); } private String getHintString(int widthHint) { if (widthHint == -1) { return "SWT.DEFAULT"; //$NON-NLS-1$ } return Integer.toString(widthHint); } private String getAlignmentString(int alignment) { switch (alignment) { case SWT.BEGINNING: return "SWT.BEGINNING"; //$NON-NLS-1$ case SWT.END: return "SWT.END"; //$NON-NLS-1$ case SWT.LEFT: return "SWT.LEFT"; //$NON-NLS-1$ case SWT.RIGHT: return "SWT.RIGHT"; //$NON-NLS-1$ case SWT.TOP: return "SWT.TOP"; //$NON-NLS-1$ case SWT.BOTTOM: return "SWT.BOTTOM"; //$NON-NLS-1$ case SWT.CENTER: return "SWT.CENTER"; //$NON-NLS-1$ case SWT.FILL: return "SWT.FILL"; //$NON-NLS-1$ default: return Integer.toString(alignment); } } }