/*******************************************************************************
* Copyright (c) 2011,2017 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
* Ralf M Petter<ralf.petter@gmail.com> - Bug 510241
*******************************************************************************/
package org.eclipse.ui.tests.forms.layout;
import static org.junit.Assert.assertEquals;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.forms.widgets.ColumnLayout;
import org.eclipse.ui.forms.widgets.ColumnLayoutData;
import org.eclipse.ui.internal.forms.widgets.ColumnLayoutUtils;
import org.eclipse.ui.tests.forms.layout.ControlFactory.TestLayout;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class TestColumnWrapLayout {
private final Point p20 = new Point(100, 20);
private final Point p30 = new Point(100, 30);
private final Point p50 = new Point(100, 50);
private final Point p100 = new Point(100, 100);
private final Point p200 = new Point(100, 200);
private Display display;
private Shell shell;
private Composite inner;
private ColumnLayout layout;
@Before
public void setUp() {
display = PlatformUI.getWorkbench().getDisplay();
shell = new Shell(display);
inner = new Composite(shell, SWT.NULL);
inner.setSize(100, 300);
layout = new ColumnLayout();
layout.leftMargin = 0;
layout.rightMargin = 0;
layout.topMargin = 0;
layout.bottomMargin = 0;
layout.horizontalSpacing = 0;
layout.verticalSpacing = 0;
inner.setLayout(layout);
}
@After
public void tearDown() {
shell.dispose();
}
@Test
public void testEqualSizeColumns() {
Point[] sizes = { p20, p30, p30, p20, p20, p30 };
assertEquals(50, ColumnLayoutUtils.computeColumnHeight(3, sizes, 237, 0));
}
@Test
public void testEqualSizeColumnsWithMargins() {
Point[] sizes = { p20, p30, p30, p20, p20, p30 };
assertEquals(60, ColumnLayoutUtils.computeColumnHeight(3, sizes, 200, 10));
}
@Test
public void testVariedSizeColumns() {
Point[] sizes = { p200, p200, p30 };
assertEquals(230, ColumnLayoutUtils.computeColumnHeight(2, sizes, 100, 0));
}
@Test
public void testLastEntryLargest() {
Point[] sizes = { p50, p30, p30, p30, p50, p50, p100 };
assertEquals(100, ColumnLayoutUtils.computeColumnHeight(4, sizes, 100, 0));
}
@Test
public void testLargeMargins() {
Point[] sizes = { p20, p20, p20, p20, p20, p50, p50};
assertEquals(260, ColumnLayoutUtils.computeColumnHeight(3, sizes, 100, 100));
}
/**
* Test that labels with the WRAP property set do indeed wrap.
*/
@Test
public void testColumnLayoutInShell() {
layout.verticalSpacing = 5;
layout.horizontalSpacing = 5;
layout.minNumColumns = 2;
layout.maxNumColumns = 2;
layout.topMargin=2;
layout.bottomMargin=3;
layout.leftMargin = 5;
layout.rightMargin = 5;
ControlFactory.create(inner, 20, 20, 30);
ControlFactory.create(inner, 20, 20, 40);
ControlFactory.create(inner, 20, 20, 20);
Point size = inner.computeSize(SWT.DEFAULT, SWT.DEFAULT);
assertEquals(70, size.y);
inner.setSize(size);
inner.layout(true);
assertEquals(new Rectangle(5, 2, 20, 30), inner.getChildren()[0].getBounds());
assertEquals(new Rectangle(30, 2, 20, 40), inner.getChildren()[1].getBounds());
}
@Test
public void testHorizontalSpacingHasNoEffectWhenOnlyOneColumn() {
layout.horizontalSpacing = 1000;
Composite control = ControlFactory.create(inner, 20, 20, 30);
Point size = inner.computeSize(SWT.DEFAULT, SWT.DEFAULT);
assertEquals(20, size.x);
inner.pack(true);
assertEquals(new Rectangle(0, 0, 20, 30), control.getBounds());
}
@Test
public void testHorizontalSpacing() {
layout.horizontalSpacing = 1000;
ControlFactory.create(inner, 20, 20, 30);
Composite secondControl = ControlFactory.create(inner, 20, 20, 30);
Point size = inner.computeSize(SWT.DEFAULT, SWT.DEFAULT);
assertEquals(1040, size.x);
inner.pack(true);
assertEquals(new Rectangle(1020, 0, 20, 30), secondControl.getBounds());
}
@Test
public void testHorizontalMargins() {
layout.leftMargin = 100;
layout.rightMargin = 10;
Control leftControl = ControlFactory.create(inner, 20, 20, 30);
Control rightControl = ControlFactory.create(inner, 20, 20, 40);
Point size = inner.computeSize(SWT.DEFAULT, SWT.DEFAULT);
assertEquals(150, size.x);
inner.pack(true);
assertEquals(new Rectangle(100, 0, 20, 30), leftControl.getBounds());
assertEquals(new Rectangle(120, 0, 20, 40), rightControl.getBounds());
assertEquals(new Rectangle(0, 0, 150, 40), inner.getBounds());
}
@Test
public void testVerticalSpacingHasNoEffectWhenOnlyOneColumn() {
layout.verticalSpacing = 1000;
Composite control = ControlFactory.create(inner, 20, 20, 30);
Point size = inner.computeSize(SWT.DEFAULT, SWT.DEFAULT);
assertEquals(20, size.x);
inner.pack(true);
assertEquals(new Rectangle(0, 0, 20, 30), control.getBounds());
}
@Test
public void testVerticalSpacing() {
layout.verticalSpacing = 1000;
layout.maxNumColumns = 1;
ControlFactory.create(inner, 20, 20, 30);
Composite secondControl = ControlFactory.create(inner, 20, 20, 30);
Point size = inner.computeSize(SWT.DEFAULT, SWT.DEFAULT);
assertEquals(1060, size.y);
inner.pack(true);
assertEquals(new Rectangle(0, 1030, 20, 30), secondControl.getBounds());
}
@Test
public void testVerticalMargins() {
layout.topMargin = 100;
layout.bottomMargin = 10;
layout.maxNumColumns = 1;
Control control1 = ControlFactory.create(inner, 20, 20, 30);
Control control2 = ControlFactory.create(inner, 20, 20, 40);
Point size = inner.computeSize(SWT.DEFAULT, SWT.DEFAULT);
assertEquals(180, size.y);
inner.pack();
assertEquals(new Rectangle(0, 100, 20, 30), control1.getBounds());
assertEquals(new Rectangle(0, 130, 20, 40), control2.getBounds());
assertEquals(new Rectangle(0, 0, 20, 180), inner.getBounds());
}
@Test
public void testSelectsCorrectNumberOfColumns() {
layout.horizontalSpacing = 10;
layout.leftMargin = 10;
layout.rightMargin = 10;
ControlFactory.create(inner, 21, 30, 50);
ControlFactory.create(inner, 22, 40, 50);
// This last control will have a preferred height of 108 when compressed to its
// minimum width
ControlFactory.create(inner, 23, 50, 50);
// Should always use the maximum number of columns when the width is
// unconstrained, and the preferred size
// should be based on the maximum size of the children
Point size = inner.computeSize(SWT.DEFAULT, SWT.DEFAULT);
assertEquals(190, size.x);
assertEquals(50, size.y);
// Should still use the maximum number of columns if the minimum size of the
// children will fit in the area
size = inner.computeSize(109, SWT.DEFAULT);
assertEquals(109, size.x);
assertEquals(108, size.y);
// Lay out with the default width
inner.pack(true);
assertAllChildrenHaveWidth(50);
for (Control next : inner.getChildren()) {
assertEquals(0, next.getBounds().y);
}
// If we're one pixel less than the minimum size for the children, the number of
// columns should be reduced
size = inner.computeSize(108, SWT.DEFAULT);
assertEquals(108, size.x);
assertEquals(89, size.y);
// Ensure that it falls back to the minimum number of columns when we're
// requesting the minimum width
int minWidth = layout.computeMinimumWidth(inner, false);
assertEquals(43, minWidth);
}
@Test
public void testFillAlignment() {
layout.maxNumColumns = 1;
// Control1 has a min size of 100, a default size of 800, and a width hint of
// 400. When computing the default size of the column, the width hint should be
// used rather than the control's preferred width and the control should end up
// with a size 400x100.
Composite control1 = ControlFactory.create(inner, 100, 800, 200);
ColumnLayoutData data1 = new ColumnLayoutData();
data1.widthHint = 400;
control1.setLayoutData(data1);
// Control2 is narrower than control1, but since it's fill-aligned it should be
// stretched to match the size of control1.
Composite control2 = ControlFactory.create(inner, 50, 100, 1200);
ColumnLayoutData data2 = new ColumnLayoutData();
data2.widthHint = 200;
control2.setLayoutData(data2);
Point size = inner.computeSize(SWT.DEFAULT, SWT.DEFAULT);
// Both control should be resized to match the first control's width hint since
// it's the widest and both are fill-aligned.
assertEquals(400, size.x);
// 400 pixels for the first control, 300 pixels for the second.
assertEquals(700, size.y);
inner.pack();
assertEquals(new Rectangle(0, 0, 400, 400), control1.getBounds());
assertEquals(new Rectangle(0, 400, 400, 300), control2.getBounds());
}
@Test
public void testLeftAlignment() {
layout.maxNumColumns = 1;
// Create a large control to dominate the width of the columns
Composite control1 = ControlFactory.create(inner, 200, 200, 200);
// Control2 is narrower than control1, but since it's fill-aligned it
// should be
// stretched to match the size of control1.
Composite control2 = ControlFactory.create(inner, 10, 100, 100);
ColumnLayoutData data2 = new ColumnLayoutData();
data2.horizontalAlignment = ColumnLayoutData.LEFT;
data2.widthHint = 50;
control2.setLayoutData(data2);
Composite control3 = ControlFactory.create(inner, 10, 50, 100);
ColumnLayoutData data3 = new ColumnLayoutData();
data3.widthHint = 10;
data3.horizontalAlignment = ColumnLayoutData.LEFT;
control3.setLayoutData(data3);
Point size = inner.computeSize(SWT.DEFAULT, SWT.DEFAULT);
assertEquals(200, size.x);
assertEquals(900, size.y);
inner.pack(true);
assertEquals(new Rectangle(0, 0, 200, 200), control1.getBounds());
assertEquals(new Rectangle(0, 200, 50, 200), control2.getBounds());
assertEquals(new Rectangle(0, 400, 10, 500), control3.getBounds());
// Verify that if we shrink a left-aligned wrapping control to a size
// smaller than its preferred width, it will still wrap correctly.
size = inner.computeSize(25, SWT.DEFAULT);
assertEquals(25, size.x);
assertEquals(2500, size.y);
}
@Test
public void testControlsFlushedCorrectly()
{
Composite composite = ControlFactory.create(inner, 200, 200, 200);
TestLayout layout = (TestLayout) composite.getLayout();
// Currently there is one unnecessary recursive flush on startup. Ignore it for
// now.
inner.computeSize(SWT.DEFAULT, SWT.DEFAULT, false);
layout.wasChanged = false;
// Verify that there is no redundant cache flush.
inner.computeSize(SWT.DEFAULT, SWT.DEFAULT, false);
assertEquals(false, layout.wasChanged);
inner.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
assertEquals(true, layout.wasChanged);
layout.wasChanged = false;
inner.layout(false);
assertEquals(false, layout.wasChanged);
inner.layout(true);
assertEquals(true, layout.wasChanged);
}
private void assertAllChildrenHaveWidth(int desiredWidth) {
Control[] children = inner.getChildren();
for (int idx = 0; idx < children.length; idx++) {
Control next = children[idx];
Rectangle bounds = next.getBounds();
assertEquals("Child " + idx + " should have the correct width", desiredWidth, bounds.width);
}
}
}