Bug 578716 - Make p2's UIServices implementation work without a
workbench
In ValidationDialogServiceUI, provide a way to specify the Display to be
used and allow the way links are opened to be specialized so that it
does not rely on the workbench.
Change-Id: Ia5c76233b4084365c4dfb315048e24f76ff3cb52
Signed-off-by: Ed Merks <ed.merks@gmail.com>
Reviewed-on: https://git.eclipse.org/r/c/equinox/rt.equinox.p2/+/190747
diff --git a/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/ValidationDialogServiceUI.java b/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/ValidationDialogServiceUI.java
index b29ebfc..d801b1c 100644
--- a/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/ValidationDialogServiceUI.java
+++ b/bundles/org.eclipse.equinox.p2.ui/src/org/eclipse/equinox/internal/p2/ui/ValidationDialogServiceUI.java
@@ -20,6 +20,7 @@
import java.util.*;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.bouncycastle.openpgp.PGPPublicKey;
@@ -52,6 +53,20 @@
private final IProvisioningAgent agent;
+ private Display display;
+
+ private Consumer<String> linkHandler = link -> {
+ if (PlatformUI.isWorkbenchRunning()) {
+ try {
+ URL url = new URL(link);
+ PlatformUI.getWorkbench().getBrowserSupport().getExternalBrowser().openURL(url);
+ } catch (Exception x) {
+ ProvUIActivator.getDefault().getLog()
+ .log(new Status(IStatus.ERROR, ProvUIActivator.PLUGIN_ID, x.getMessage(), x));
+ }
+ }
+ };
+
public ValidationDialogServiceUI() {
this(null);
}
@@ -62,12 +77,15 @@
static final class MessageDialogWithLink extends MessageDialog {
private final String linkText;
+ private final Consumer<String> linkOpener;
MessageDialogWithLink(Shell parentShell, String dialogTitle, Image dialogTitleImage, String dialogMessage,
- int dialogImageType, String[] dialogButtonLabels, int defaultIndex, String linkText) {
+ int dialogImageType, String[] dialogButtonLabels, int defaultIndex, String linkText,
+ Consumer<String> linkOpener) {
super(parentShell, dialogTitle, dialogTitleImage, dialogMessage, dialogImageType, dialogButtonLabels,
defaultIndex);
this.linkText = linkText;
+ this.linkOpener = linkOpener;
}
@Override
@@ -78,13 +96,7 @@
Link link = new Link(parent, SWT.NONE);
link.setText(linkText);
link.addSelectionListener(SelectionListener.widgetSelectedAdapter(e -> {
- try {
- URL url = new URL(e.text);
- PlatformUI.getWorkbench().getBrowserSupport().getExternalBrowser().openURL(url);
- } catch (Exception x) {
- ProvUIActivator.getDefault().getLog().log(//
- new Status(IStatus.ERROR, ProvUIActivator.PLUGIN_ID, x.getMessage(), x));
- }
+ linkOpener.accept(e.text);
}));
return link;
}
@@ -114,7 +126,7 @@
final AuthenticationInfo[] result = new AuthenticationInfo[1];
if (!suppressAuthentication() && !isHeadless()) {
- PlatformUI.getWorkbench().getDisplay().syncExec(() -> {
+ getDisplay().syncExec(() -> {
Shell shell = ProvUI.getDefaultParentShell();
String message = NLS.bind(ProvUIMessages.ServiceUI_LoginDetails, location);
UserValidationDialog dialog = new UserValidationDialog(shell, ProvUIMessages.ServiceUI_LoginRequired,
@@ -159,7 +171,7 @@
// detail should be trusted
if (!isHeadless() && unsignedDetail != null && unsignedDetail.length > 0) {
final boolean[] result = new boolean[] { false };
- PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() {
+ getDisplay().syncExec(new Runnable() {
@Override
public void run() {
Shell shell = ProvUI.getDefaultParentShell();
@@ -214,7 +226,7 @@
if (input.length != 0) {
trustUnsigned = unsignedArtifacts == null || unsignedArtifacts.isEmpty();
List<Object> result = new ArrayList<>();
- PlatformUI.getWorkbench().getDisplay().syncExec(() -> {
+ getDisplay().syncExec(() -> {
Shell shell = ProvUI.getDefaultParentShell();
TrustCertificateDialog trustCertificateDialog = new TrustCertificateDialog(shell, input);
if (trustCertificateDialog.open() == Window.OK) {
@@ -319,7 +331,7 @@
public AuthenticationInfo getUsernamePassword(final String location, final AuthenticationInfo previousInfo) {
final AuthenticationInfo[] result = new AuthenticationInfo[1];
if (!suppressAuthentication() && !isHeadless()) {
- PlatformUI.getWorkbench().getDisplay().syncExec(() -> {
+ getDisplay().syncExec(() -> {
Shell shell = ProvUI.getDefaultParentShell();
String message = null;
if (previousInfo.saveResult())
@@ -346,18 +358,76 @@
super.showInformationMessage(title, text, linkText);
return;
}
- PlatformUI.getWorkbench().getDisplay().syncExec(() -> {
+ getDisplay().syncExec(() -> {
MessageDialog dialog = new MessageDialogWithLink(ProvUI.getDefaultParentShell(), title, null, text,
- MessageDialog.INFORMATION, new String[] { IDialogConstants.OK_LABEL }, 0, linkText);
+ MessageDialog.INFORMATION, new String[] { IDialogConstants.OK_LABEL }, 0, linkText, linkHandler);
dialog.open();
});
}
+ /**
+ * Returns a handler (used by
+ * {@link #showInformationMessage(String, String, String)}) to open a link in an
+ * external browser.
+ *
+ * @return a handler to open a link in an external browser.
+ *
+ * @since 2.7.400
+ */
+ public Consumer<String> getLinkHandler() {
+ return linkHandler;
+ }
+
+ /**
+ * Sets the handler used by
+ * {@link #showInformationMessage(String, String, String)} to open a link in an
+ * external browser.
+ *
+ * @param linkHandler the handler for opening links in an external browser.
+ *
+ * @since 2.7.400
+ */
+ public void setLinkHandler(Consumer<String> linkHandler) {
+ this.linkHandler = linkHandler;
+ }
+
+ /**
+ * Returns the display of the workbench or the display set by
+ * {@link #setDisplay(Display)} in a non-workbench application.
+ *
+ * @since 2.7.400
+ */
+ public Display getDisplay() {
+ if (display == null && PlatformUI.isWorkbenchRunning()) {
+ display = PlatformUI.getWorkbench().getDisplay();
+ }
+ return display;
+ }
+
+ /**
+ * Can be called once to set the display in a non-workbench application.
+ *
+ * @throws IllegalStateException if there is a workbench running or the display
+ * has already been set differently.
+ *
+ * @since 2.7.400
+ */
+ public void setDisplay(Display display) {
+ if (this.display != null && this.display != display) {
+ throw new IllegalStateException("Cannot change the display"); //$NON-NLS-1$
+ }
+ this.display = display;
+ }
+
private boolean isHeadless() {
// If there is no UI available and we are still the IServiceUI,
// assume that the operation should proceed. See
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=291049
- return !PlatformUI.isWorkbenchRunning();
+ //
+ // But we shouldn't just assume that no workbench mean no display and no head.
+ // It should be possible to reuse this class in an application without a
+ // workbench, e.g., the Eclipse Installer.
+ return getDisplay() == null;
}
private static class ExtendedTreeNode extends TreeNode implements IAdaptable {