Bug 551589: SectionFactory
Change-Id: If990664a5651052dc660940c42a8cb0b429a9a38
Signed-off-by: Marcus Hoepfner <marcus.hoepfner@sap.com>
diff --git a/bundles/org.eclipse.jface/src/org/eclipse/jface/widgets/AbstractCompositeFactory.java b/bundles/org.eclipse.jface/src/org/eclipse/jface/widgets/AbstractCompositeFactory.java
index b83a7bf..88375a0 100644
--- a/bundles/org.eclipse.jface/src/org/eclipse/jface/widgets/AbstractCompositeFactory.java
+++ b/bundles/org.eclipse.jface/src/org/eclipse/jface/widgets/AbstractCompositeFactory.java
@@ -36,7 +36,7 @@
* @param factoryClass
* @param controlCreator
*/
- AbstractCompositeFactory(Class<F> factoryClass, WidgetSupplier<C, Composite> controlCreator) {
+ protected AbstractCompositeFactory(Class<F> factoryClass, WidgetSupplier<C, Composite> controlCreator) {
super(factoryClass, controlCreator);
}
diff --git a/bundles/org.eclipse.ui.forms/META-INF/MANIFEST.MF b/bundles/org.eclipse.ui.forms/META-INF/MANIFEST.MF
index cffba61..be580af 100644
--- a/bundles/org.eclipse.ui.forms/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.ui.forms/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
Bundle-ManifestVersion: 2
Bundle-Name: %name
Bundle-SymbolicName: org.eclipse.ui.forms;singleton:=true
-Bundle-Version: 3.9.200.qualifier
+Bundle-Version: 3.10.0.qualifier
Bundle-Vendor: %provider-name
Bundle-Localization: plugin
Export-Package: org.eclipse.ui.forms,
diff --git a/bundles/org.eclipse.ui.forms/src/org/eclipse/ui/forms/widgets/SectionFactory.java b/bundles/org.eclipse.ui.forms/src/org/eclipse/ui/forms/widgets/SectionFactory.java
new file mode 100644
index 0000000..1c916e6
--- /dev/null
+++ b/bundles/org.eclipse.ui.forms/src/org/eclipse/ui/forms/widgets/SectionFactory.java
@@ -0,0 +1,164 @@
+/*******************************************************************************
+ * Copyright (c) 2020 SAP SE and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Marcus Hoepfner (SAP SE) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ui.forms.widgets;
+
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+import org.eclipse.jface.widgets.AbstractCompositeFactory;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.forms.events.ExpansionEvent;
+import org.eclipse.ui.forms.events.IExpansionListener;
+
+/**
+ * This class provides a convenient shorthand for creating and initializing
+ * {@link Section}. This offers several benefits over creating Section normal
+ * way:
+ *
+ * <ul>
+ * <li>The same factory can be used many times to create several Section
+ * instances</li>
+ * <li>The setters on SectionFactory all return "this", allowing them to be
+ * chained</li>
+ * <li>SectionFactory accepts a Lambda for {@link ExpansionEvent} (see
+ * {@link #onExpanded(Consumer)}) and {@link #onExpanding(Consumer)}</li>
+ * </ul>
+ *
+ * Example usage:
+ *
+ * <pre>
+ * Section section = SectionFactory.newSection(Section.TWISTIE | Section.DESCRIPTION) //
+ * .title("My Section") //
+ * .description("My section created with a factory") //
+ * .onExpand(event -> sectionExpanded(event)) //
+ * .create(parent);
+ * </pre>
+ * <p>
+ * The above example creates a section with a title, a description, registers an
+ * IExpansionListener and finally creates the section in "parent".
+ * </p>
+ *
+ * <pre>
+ * SectionFactory sectionFactory = SectionFactory.newSection(Section.TWISTIE);
+ * sectionFactory.title("Section 1").create(parent);
+ * sectionFactory.title("Section 2").create(parent);
+ * sectionFactory.title("Section 3").create(parent);
+ * </pre>
+ * <p>
+ * The above example creates three section using the same instance of
+ * SectionFactory.
+ * </p>
+ *
+ * @since 3.10
+ *
+ */
+public final class SectionFactory extends AbstractCompositeFactory<SectionFactory, Section> {
+
+ private SectionFactory(int style) {
+ super(SectionFactory.class, (Composite parent) -> new Section(parent, style));
+ }
+
+ /**
+ * Creates a new SectionFactory with the given style. Refer to
+ * {@link Section#Section(Composite, int)} for possible styles.
+ *
+ * @param style
+ * @return a new SectionFactory instance
+ */
+ public static SectionFactory newSection(int style) {
+ return new SectionFactory(style);
+ }
+
+ /**
+ * Sets the title of the section. The title will act as a hyperlink and
+ * activating it will toggle the client between expanded and collapsed state.
+ *
+ * @param title the new title string
+ *
+ * @see Section#setText(String)
+ */
+ public SectionFactory title(String title) {
+ addProperty(section -> section.setText(title));
+ return this;
+ }
+
+ /**
+ * Sets the description text. Has no effect if DESCRIPTION style was not used in
+ * {@link #create(Composite)}
+ *
+ * @param description new description text; not <code>null</code>
+ *
+ * @see Section#setDescription(String)
+ */
+ public SectionFactory description(String description) {
+ addProperty(section -> section.setDescription(description));
+ return this;
+ }
+
+ /**
+ * Sets a function which must provide a description control for the given
+ * Section. The control must not be <samp>null</samp> and must be a direct child
+ * of the section.
+ *
+ * <p>
+ * This method and <code>DESCRIPTION</code> style are mutually exclusive. Use
+ * the method only if you want to create the description control yourself.
+ * </p>
+ *
+ * @param controlFunction the function to create the description control
+ *
+ * @see Section#setDescriptionControl(Control)
+ */
+ public SectionFactory description(Function<Section, Control> controlFunction) {
+ addProperty(section -> section.setDescriptionControl(controlFunction.apply(section)));
+ return this;
+ }
+
+ /**
+ * Creates an {@link IExpansionListener} and registers it for the
+ * expansionStateChanged event. If the section <i>was</i> expanded by the user
+ * the given consumer is invoked. The {@link ExpansionEvent} is passed to the
+ * consumer.
+ *
+ * @param consumer the consumer whose accept method is called
+ * @return this
+ *
+ * @see Section#addExpansionListener(IExpansionListener)
+ * @see IExpansionListener#expansionStateChanged(ExpansionEvent)
+ */
+ public SectionFactory onExpanded(Consumer<ExpansionEvent> consumer) {
+ addProperty(
+ section -> section.addExpansionListener(IExpansionListener.expansionStateChangingAdapter(consumer)));
+ return this;
+ }
+
+ /**
+ * Creates an {@link IExpansionListener} and registers it for the
+ * expansionStateChanging event. If the section <i>is</i> expanded by the user
+ * the given consumer is invoked. The {@link ExpansionEvent} is passed to the
+ * consumer.
+ *
+ * @param consumer the consumer whose accept method is called
+ * @return this
+ *
+ * @see Section#addExpansionListener(IExpansionListener)
+ * @see IExpansionListener#expansionStateChanging(ExpansionEvent)
+ */
+ public SectionFactory onExpanding(Consumer<ExpansionEvent> consumer) {
+ addProperty(
+ section -> section.addExpansionListener(IExpansionListener.expansionStateChangingAdapter(consumer)));
+ return this;
+ }
+}
\ No newline at end of file
diff --git a/tests/org.eclipse.ui.tests.forms/META-INF/MANIFEST.MF b/tests/org.eclipse.ui.tests.forms/META-INF/MANIFEST.MF
index 746c9ac..4675ab6 100755
--- a/tests/org.eclipse.ui.tests.forms/META-INF/MANIFEST.MF
+++ b/tests/org.eclipse.ui.tests.forms/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
Bundle-ManifestVersion: 2
Bundle-Name: Forms Test
Bundle-SymbolicName: org.eclipse.ui.tests.forms;singleton:=true
-Bundle-Version: 3.8.0.qualifier
+Bundle-Version: 3.8.100.qualifier
Require-Bundle: org.eclipse.ui,
org.eclipse.core.runtime,
org.eclipse.test.performance,
diff --git a/tests/org.eclipse.ui.tests.forms/forms/org/eclipse/ui/tests/forms/widgets/SectionFactoryTest.java b/tests/org.eclipse.ui.tests.forms/forms/org/eclipse/ui/tests/forms/widgets/SectionFactoryTest.java
new file mode 100644
index 0000000..bc3c65d
--- /dev/null
+++ b/tests/org.eclipse.ui.tests.forms/forms/org/eclipse/ui/tests/forms/widgets/SectionFactoryTest.java
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * Copyright (c) 2020 SAP SE and others.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which accompanies this distribution,
+ * and is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors: Marcus Hoepfner (SAP SE) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ui.tests.forms.widgets;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.forms.events.ExpansionEvent;
+import org.eclipse.ui.forms.widgets.Section;
+import org.eclipse.ui.forms.widgets.SectionFactory;
+import org.eclipse.ui.forms.widgets.Twistie;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class SectionFactoryTest {
+ protected static Shell shell;
+
+ @Before
+ public void setup() {
+ shell = new Shell();
+ }
+
+ @After
+ public void tearDown() {
+ shell.dispose();
+ }
+
+ @Test
+ public void createsSection() {
+ Section section = SectionFactory.newSection(SWT.NONE).create(shell);
+ assertEquals(shell, section.getParent());
+ }
+
+ @Test
+ public void createsSectionWithText() {
+ Section section = SectionFactory.newSection(SWT.NONE).title("test").create(shell);
+ assertEquals("test", section.getText());
+ }
+
+ @Test
+ public void createsSectionWithDescription() {
+ Section section = SectionFactory.newSection(Section.DESCRIPTION).description("test").create(shell);
+ assertEquals("test", section.getDescription());
+ }
+
+ @Test
+ public void createsSectionWithDescriptionControl() {
+ Section section = SectionFactory.newSection(SWT.NONE).description(parent -> new Label(parent, SWT.NONE))
+ .create(shell);
+ assertTrue(section.getDescriptionControl() instanceof Label);
+ }
+
+ @Test
+ public void addsSectionExpandListeners() {
+ final ExpansionEvent[] raisedEvents = new ExpansionEvent[1];
+ Section section = SectionFactory.newSection(Section.TWISTIE).onExpanded(e -> raisedEvents[0] = e)
+ .create(shell);
+ Control twistie = section.getChildren()[0];
+ assertTrue("Expected a twistie", twistie instanceof Twistie);
+ click(twistie);
+
+ assertNotNull(raisedEvents[0]);
+ }
+
+ @Test
+ public void addsSectionExpandingListener() {
+ final ExpansionEvent[] raisedEvents = new ExpansionEvent[1];
+ Section section = SectionFactory.newSection(Section.TWISTIE).onExpanding(e -> raisedEvents[0] = e)
+ .create(shell);
+ Control twistie = section.getChildren()[0];
+ assertTrue("Expected a twistie", twistie instanceof Twistie);
+ click(twistie);
+
+ assertNotNull(raisedEvents[0]);
+ }
+
+ private void click(Control twistie) {
+ Event event = new Event();
+ event.keyCode = SWT.ARROW_RIGHT;
+ twistie.notifyListeners(SWT.KeyDown, event);
+ }
+}
\ No newline at end of file
diff --git a/tests/org.eclipse.ui.tests.forms/pom.xml b/tests/org.eclipse.ui.tests.forms/pom.xml
index d1fdaf1..932aa01 100644
--- a/tests/org.eclipse.ui.tests.forms/pom.xml
+++ b/tests/org.eclipse.ui.tests.forms/pom.xml
@@ -20,6 +20,6 @@
</parent>
<groupId>org.eclipse.ui</groupId>
<artifactId>org.eclipse.ui.tests.forms</artifactId>
- <version>3.8.0-SNAPSHOT</version>
+ <version>3.8.100-SNAPSHOT</version>
<packaging>eclipse-test-plugin</packaging>
</project>