Bug 566162 - Add WidgetFactory for Link

Change-Id: I70f6b965a2bf2f626bd7caf48129c0061678668d
Signed-off-by: Lars Vogel <Lars.Vogel@vogella.com>
diff --git a/bundles/org.eclipse.jface/src/org/eclipse/jface/widgets/LinkFactory.java b/bundles/org.eclipse.jface/src/org/eclipse/jface/widgets/LinkFactory.java
new file mode 100644
index 0000000..d1b7bc9
--- /dev/null
+++ b/bundles/org.eclipse.jface/src/org/eclipse/jface/widgets/LinkFactory.java
@@ -0,0 +1,125 @@
+/*******************************************************************************
+* Copyright (c) 2020 vogella GmbH 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:
+*     Lars Vogel - initial version
+******************************************************************************/
+package org.eclipse.jface.widgets;
+
+import java.util.function.Consumer;
+
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Link;
+
+/**
+ * This class provides a convenient shorthand for creating and initializing
+ * {@link Link}. This offers several benefits over creating Link objects via the
+ * new operator:
+ *
+ * <ul>
+ * <li>The same factory can be used many times to create several Link
+ * instances</li>
+ * <li>The setters all return "this", allowing them to be chained</li>
+ * <li>This class accepts a Lambda for {@link SelectionEvent} (see
+ * {@link #onSelect})</li>
+ * </ul>
+ *
+ * Example usage:
+ *
+ * <pre>
+ * Link link = LinkFactory.newLink(SWT.NONE) //
+ * 		.text("Click me!") //
+ * 		.onSelect(event -&gt; clicked(event)) //
+ * 		.layoutData(gridData) //
+ * 		.create(parent);
+ * </pre>
+ * <p>
+ * The above example creates a link with a text, registers a SelectionListener
+ * and finally creates the link in "parent".
+ * </p>
+ *
+ * <pre>
+ * GridDataFactory gridDataFactory = GridDataFactory.swtDefaults();
+ * LinkFactory linkFactory = LinkFactory.newLink(SWT.PUSH).onSelect(event -&gt; clicked(event))
+ * 		.layout(gridDataFactory::create);
+ * linkFactory.text("Link 1").create(parent);
+ * linkFactory.text("Link 2").create(parent);
+ * linkFactory.text("Link 3").create(parent);
+ * </pre>
+ * <p>
+ * The above example creates three objects using the same instance of the
+ * factory. Note the layout method. A Supplier is used to create unique GridData
+ * for every single link.
+ * </p>
+ *
+ * @since 3.21
+ *
+ */
+public final class LinkFactory extends AbstractControlFactory<LinkFactory, Link> {
+
+	private LinkFactory(int style) {
+		super(LinkFactory.class, (Composite parent) -> new Link(parent, style));
+	}
+
+	/**
+	 * Creates a new factory with the given style. Refer to
+	 * {@link Link#Link(Composite, int)} for possible styles.
+	 *
+	 * @param style
+	 * @return a new LinkFactory instance
+	 */
+	public static LinkFactory newLink(int style) {
+		return new LinkFactory(style);
+	}
+
+	/**
+	 * Sets the receiver's text.
+	 * <p>
+	 * This method sets the label. The label may include the mnemonic character but
+	 * must not contain line delimiters.
+	 * </p>
+	 * <p>
+	 * Mnemonics are indicated by an '&amp;' that causes the next character to be
+	 * the mnemonic. When the user presses a key sequence that matches the mnemonic,
+	 * a selection event occurs. On most platforms, the mnemonic appears underlined
+	 * but may be emphasized in a platform specific manner. The mnemonic indicator
+	 * character '&amp;' can be escaped by doubling it in the string, causing a
+	 * single '&amp;' to be displayed.
+	 * </p>
+	 *
+	 * @param text the text
+	 * @return this
+	 *
+	 * @see Link#setText(String)
+	 */
+	public LinkFactory text(String text) {
+		addProperty(l -> l.setText(text));
+		return this;
+	}
+
+	/**
+	 * Creates a {@link SelectionListener} and registers it for the widgetSelected
+	 * event. If the receiver is selected by the user the given consumer is invoked.
+	 * The {@link SelectionEvent} is passed to the consumer.
+	 *
+	 * @param consumer the consumer whose accept method is called
+	 * @return this
+	 *
+	 * @see Link#addSelectionListener(SelectionListener)
+	 * @see SelectionListener#widgetSelectedAdapter(Consumer)
+	 */
+	public LinkFactory onSelect(Consumer<SelectionEvent> consumer) {
+		addProperty(c -> c.addSelectionListener(SelectionListener.widgetSelectedAdapter(consumer)));
+		return this;
+	}
+
+}
\ No newline at end of file
diff --git a/tests/org.eclipse.jface.tests/src/org/eclipse/jface/tests/widgets/AllWidgetTests.java b/tests/org.eclipse.jface.tests/src/org/eclipse/jface/tests/widgets/AllWidgetTests.java
index 90e3300..ead93ff 100644
--- a/tests/org.eclipse.jface.tests/src/org/eclipse/jface/tests/widgets/AllWidgetTests.java
+++ b/tests/org.eclipse.jface.tests/src/org/eclipse/jface/tests/widgets/AllWidgetTests.java
@@ -20,6 +20,7 @@
 		TestUnitControlFactory.class, //
 		TestUnitItemFactory.class, //
 		TestUnitLabelFactory.class, //
+		TestUnitLinkFactory.class, //
 		TestUnitSashFactory.class, //
 		TestUnitSashFormFactory.class, //
 		TestUnitShellFactory.class, //
diff --git a/tests/org.eclipse.jface.tests/src/org/eclipse/jface/tests/widgets/TestUnitLinkFactory.java b/tests/org.eclipse.jface.tests/src/org/eclipse/jface/tests/widgets/TestUnitLinkFactory.java
new file mode 100644
index 0000000..f5fb765
--- /dev/null
+++ b/tests/org.eclipse.jface.tests/src/org/eclipse/jface/tests/widgets/TestUnitLinkFactory.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+* Copyright (c) 2020 vogella GmbH 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:
+*    Lars Vogel - initial version
+******************************************************************************/
+package org.eclipse.jface.tests.widgets;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import org.eclipse.jface.widgets.LinkFactory;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Link;
+import org.junit.Test;
+
+public class TestUnitLinkFactory extends AbstractFactoryTest {
+
+	@Test
+	public void createsLink() {
+		Link link = LinkFactory.newLink(SWT.NONE).create(shell);
+
+		assertEquals(shell, link.getParent());
+		assertEquals(SWT.NONE, link.getStyle() & SWT.NONE);
+	}
+
+	@Test
+	public void createLinksWithAllProperties() {
+		final SelectionEvent[] raisedEvents = new SelectionEvent[1];
+		Link link = LinkFactory.newLink(SWT.NONE).text("Test Link").onSelect(e -> raisedEvents[0] = e).create(shell);
+
+		link.notifyListeners(SWT.Selection, new Event());
+
+		assertEquals("Test Link", link.getText());
+
+		assertEquals(1, link.getListeners(SWT.Selection).length);
+		assertNotNull(raisedEvents[0]);
+	}
+}
\ No newline at end of file