summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteffen Pingel2012-01-31 16:30:20 (EST)
committerSteffen Pingel2012-01-31 16:30:20 (EST)
commitf0b67e6dda1c8d76a6b9a56e7535b8301f7a7b5a (patch)
tree7a3d24243ac096dab79cb360ea869d0230a581f1
parent918ef2a3b3e64750e8758bd756125b9193cfbea5 (diff)
downloadorg.eclipse.mylyn.commons-f0b67e6dda1c8d76a6b9a56e7535b8301f7a7b5a.zip
org.eclipse.mylyn.commons-f0b67e6dda1c8d76a6b9a56e7535b8301f7a7b5a.tar.gz
org.eclipse.mylyn.commons-f0b67e6dda1c8d76a6b9a56e7535b8301f7a7b5a.tar.bz2
NEW - bug 346046: [api] provide an extension point for registering URL
handlers (was: Hyperlinks to builds should open in task editor) https://bugs.eclipse.org/bugs/show_bug.cgi?id=346046 Change-Id: I11f0da1023da9e0aabb2f870d68551450f50c2ce
-rw-r--r--org.eclipse.mylyn.commons.workbench/build.properties3
-rw-r--r--org.eclipse.mylyn.commons.workbench/plugin.xml15
-rw-r--r--org.eclipse.mylyn.commons.workbench/schema/urlHandlers.exsd85
-rw-r--r--org.eclipse.mylyn.commons.workbench/src/org/eclipse/mylyn/commons/workbench/EditorHandle.java116
-rw-r--r--org.eclipse.mylyn.commons.workbench/src/org/eclipse/mylyn/commons/workbench/browser/AbstractUrlHandler.java24
-rw-r--r--org.eclipse.mylyn.commons.workbench/src/org/eclipse/mylyn/commons/workbench/browser/BrowserUtil.java176
6 files changed, 382 insertions, 37 deletions
diff --git a/org.eclipse.mylyn.commons.workbench/build.properties b/org.eclipse.mylyn.commons.workbench/build.properties
index 8c64151..fea3b62 100644
--- a/org.eclipse.mylyn.commons.workbench/build.properties
+++ b/org.eclipse.mylyn.commons.workbench/build.properties
@@ -14,5 +14,6 @@ bin.includes = META-INF/,\
.,\
about.html,\
plugin.properties,\
- icons/
+ icons/,\
+ plugin.xml
src.includes = about.html
diff --git a/org.eclipse.mylyn.commons.workbench/plugin.xml b/org.eclipse.mylyn.commons.workbench/plugin.xml
new file mode 100644
index 0000000..1e43c17
--- /dev/null
+++ b/org.eclipse.mylyn.commons.workbench/plugin.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.0"?>
+<!--
+ Copyright (c) 2012 Tasktop Technologies 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:
+ Tasktop Technologies - initial API and implementation
+ -->
+<plugin>
+ <extension-point id="urlHandlers" name="URL Handlers" schema="schema/urlHandlers.exsd"/>
+</plugin>
diff --git a/org.eclipse.mylyn.commons.workbench/schema/urlHandlers.exsd b/org.eclipse.mylyn.commons.workbench/schema/urlHandlers.exsd
new file mode 100644
index 0000000..8664608
--- /dev/null
+++ b/org.eclipse.mylyn.commons.workbench/schema/urlHandlers.exsd
@@ -0,0 +1,85 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.mylyn.commons.workbench" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+ <appinfo>
+ <meta.schema plugin="org.eclipse.mylyn.commons.workbench" id="urlHandlers" name="URL Handlers"/>
+ </appinfo>
+ <documentation>
+ Provides an extension point for handling URLs.
+ </documentation>
+ </annotation>
+
+ <element name="extension">
+ <annotation>
+ <appinfo>
+ <meta.element />
+ </appinfo>
+ </annotation>
+ <complexType>
+ <choice>
+ <element ref="handler" minOccurs="1" maxOccurs="unbounded"/>
+ </choice>
+ <attribute name="point" type="string" use="required">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="id" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="name" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ <appinfo>
+ <meta.attribute translatable="true"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="handler">
+ <complexType>
+ <attribute name="class" type="string" use="required">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ <appinfo>
+ <meta.attribute kind="java" basedOn="org.eclipse.mylyn.commons.workbench.browser.AbstractUrlHandler:"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ <attribute name="id" type="string" use="required">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="since"/>
+ </appinfo>
+ <documentation>
+ 3.7
+ </documentation>
+ </annotation>
+
+
+
+
+
+</schema>
diff --git a/org.eclipse.mylyn.commons.workbench/src/org/eclipse/mylyn/commons/workbench/EditorHandle.java b/org.eclipse.mylyn.commons.workbench/src/org/eclipse/mylyn/commons/workbench/EditorHandle.java
new file mode 100644
index 0000000..c15c498
--- /dev/null
+++ b/org.eclipse.mylyn.commons.workbench/src/org/eclipse/mylyn/commons/workbench/EditorHandle.java
@@ -0,0 +1,116 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Tasktop Technologies 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:
+ * Tasktop Technologies - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylyn.commons.workbench;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.ui.IWorkbenchPart;
+
+/**
+ * Provides a hook for accessing the part when opening an element in an editor. This class should only be accessed from
+ * the SWT thread.
+ *
+ * @author Steffen Pingel
+ */
+public class EditorHandle implements IAdaptable {
+
+ private Object item;
+
+ private IWorkbenchPart part;
+
+ private IStatus status;
+
+ private final CountDownLatch progressLatch = new CountDownLatch(1);
+
+ /**
+ * Constructs a handle with a status.
+ *
+ * @param status
+ * specifies the result of opening the editor
+ * @see #getStatus()
+ */
+ public EditorHandle(IStatus status) {
+ this.status = status;
+ }
+
+ public EditorHandle() {
+ }
+
+ public Object getAdapter(@SuppressWarnings("rawtypes")
+ Class adapter) {
+ return Platform.getAdapterManager().getAdapter(this, adapter);
+ }
+
+ /**
+ * Returns the item that was opened.
+ *
+ * @return null, if no item is associated with the editor
+ */
+ public Object getItem() {
+ return item;
+ }
+
+ /**
+ * Returns the editor part.
+ *
+ * @return the editor or null if the editor is not open, yet, or does not a workbench part
+ */
+ public IWorkbenchPart getPart() {
+ return part;
+ }
+
+ /**
+ * Returns the result of opening the editor.
+ *
+ * @return a severity of {@link IStatus#OK} indicates that the operation was successful.
+ */
+ public IStatus getStatus() {
+ return status;
+ }
+
+ /**
+ * Sets the item that was opened.
+ *
+ * @see {@link #getItem()}
+ */
+ public void setItem(Object item) {
+ this.item = item;
+ }
+
+ /**
+ * Sets the editor part that was opened.
+ *
+ * @see {@link #getPart()}
+ */
+ public void setPart(IWorkbenchPart part) {
+ this.part = part;
+ }
+
+ /**
+ * Sets the result of the open operation.
+ *
+ * @see {@link #getStatus()}
+ */
+ public void setStatus(IStatus status) {
+ this.status = status;
+ this.progressLatch.countDown();
+ }
+
+ public boolean await(long timeout, TimeUnit unit) throws InterruptedException {
+ return this.progressLatch.await(timeout, unit);
+ }
+
+}
diff --git a/org.eclipse.mylyn.commons.workbench/src/org/eclipse/mylyn/commons/workbench/browser/AbstractUrlHandler.java b/org.eclipse.mylyn.commons.workbench/src/org/eclipse/mylyn/commons/workbench/browser/AbstractUrlHandler.java
new file mode 100644
index 0000000..b74c42a
--- /dev/null
+++ b/org.eclipse.mylyn.commons.workbench/src/org/eclipse/mylyn/commons/workbench/browser/AbstractUrlHandler.java
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Tasktop Technologies 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:
+ * Tasktop Technologies - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylyn.commons.workbench.browser;
+
+import org.eclipse.mylyn.commons.workbench.EditorHandle;
+import org.eclipse.ui.IWorkbenchPage;
+
+/**
+ * @author SteffenPingel
+ */
+public abstract class AbstractUrlHandler {
+
+ public abstract EditorHandle openUrl(IWorkbenchPage page, String location, int customFlags);
+
+}
diff --git a/org.eclipse.mylyn.commons.workbench/src/org/eclipse/mylyn/commons/workbench/browser/BrowserUtil.java b/org.eclipse.mylyn.commons.workbench/src/org/eclipse/mylyn/commons/workbench/browser/BrowserUtil.java
index fd26202..1296154 100644
--- a/org.eclipse.mylyn.commons.workbench/src/org/eclipse/mylyn/commons/workbench/browser/BrowserUtil.java
+++ b/org.eclipse.mylyn.commons.workbench/src/org/eclipse/mylyn/commons/workbench/browser/BrowserUtil.java
@@ -14,16 +14,24 @@ package org.eclipse.mylyn.commons.workbench.browser;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Calendar;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+import org.eclipse.core.runtime.ISafeRunnable;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.util.SafeRunnable;
import org.eclipse.mylyn.commons.core.CoreUtil;
+import org.eclipse.mylyn.commons.core.ExtensionPointReader;
+import org.eclipse.mylyn.commons.core.StatusHandler;
+import org.eclipse.mylyn.commons.workbench.EditorHandle;
import org.eclipse.mylyn.commons.workbench.WorkbenchUtil;
import org.eclipse.mylyn.internal.commons.workbench.CommonsWorkbenchPlugin;
import org.eclipse.mylyn.internal.commons.workbench.Messages;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
+import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.browser.IWebBrowser;
@@ -38,61 +46,89 @@ import org.eclipse.ui.internal.browser.WorkbenchBrowserSupport;
*/
public class BrowserUtil {
+ static class BrowserHandle extends EditorHandle {
+
+ private final IWebBrowser browser;
+
+ public BrowserHandle(IWebBrowser browser) {
+ super(Status.OK_STATUS);
+ this.browser = browser;
+ }
+
+ @Override
+ public Object getAdapter(@SuppressWarnings("rawtypes")
+ Class adapter) {
+ if (adapter == IWebBrowser.class) {
+ return browser;
+ }
+ return super.getAdapter(adapter);
+ }
+
+ }
+
+ static class UrlHandlerInitializer {
+
+ private static List<AbstractUrlHandler> handlers;
+
+ static {
+ ExtensionPointReader<AbstractUrlHandler> reader = new ExtensionPointReader<AbstractUrlHandler>(
+ CommonsWorkbenchPlugin.ID_PLUGIN, "urlHandlers", "handler", AbstractUrlHandler.class); //$NON-NLS-1$ //$NON-NLS-2$
+ IStatus status = reader.read();
+ if (!status.isOK()) {
+ StatusHandler.log(status);
+ }
+ handlers = reader.getItems();
+ }
+
+ }
+
/**
- * Opens <code>location</code> in a web-browser according to the Eclipse workbench preferences.
+ * Opens <code>location</code> in a rich editor if applicable or web-browser according to the workbench preferences.
*
* @param location
* the url to open
- * @see #openUrl(String, int)
+ * @see #openUrl(IWorkbenchPage, String, int)
*/
public static void openUrl(String location) {
openUrl(location, SWT.NONE);
}
/**
- * Opens <code>location</code> in a web-browser according to the Eclipse workbench preferences.
+ * Opens <code>location</code> in a rich editor if applicable or in a web-browser according to the workbench
+ * preferences.
*
* @param location
* the url to open
* @param customFlags
* additional flags that are passed to {@link IWorkbenchBrowserSupport}, pass
* {@link IWorkbenchBrowserSupport#AS_EXTERNAL} to force opening external browser
+ * @see #openUrl(IWorkbenchPage, String, int)
*/
public static void openUrl(String location, int customFlags) {
- try {
- URL url = null;
- if (location != null) {
- url = new URL(location);
- }
- if (WebBrowserPreference.getBrowserChoice() == WebBrowserPreference.EXTERNAL
- || (customFlags & IWorkbenchBrowserSupport.AS_EXTERNAL) != 0) {
- try {
- IWorkbenchBrowserSupport support = PlatformUI.getWorkbench().getBrowserSupport();
- support.getExternalBrowser().openURL(url);
- } catch (PartInitException e) {
- Status status = new Status(IStatus.ERROR, CommonsWorkbenchPlugin.ID_PLUGIN,
- Messages.WorkbenchUtil_Browser_Initialization_Failed);
- CommonsWorkbenchPlugin.getDefault().getLog().log(status);
- if (!CoreUtil.TEST_MODE) {
- MessageDialog.openError(WorkbenchUtil.getShell(), Messages.WorkbenchUtil_Open_Location_Title,
- status.getMessage());
- }
- }
- } else {
- IWebBrowser browser = null;
- int flags = customFlags;
- if (WorkbenchBrowserSupport.getInstance().isInternalWebBrowserAvailable()) {
- flags |= IWorkbenchBrowserSupport.AS_EDITOR | IWorkbenchBrowserSupport.LOCATION_BAR
- | IWorkbenchBrowserSupport.NAVIGATION_BAR;
- } else {
- flags |= IWorkbenchBrowserSupport.AS_EXTERNAL | IWorkbenchBrowserSupport.LOCATION_BAR
- | IWorkbenchBrowserSupport.NAVIGATION_BAR;
- }
+ IWorkbenchPage page = null;
+ if (PlatformUI.getWorkbench().getActiveWorkbenchWindow() != null) {
+ page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
+ }
+ openUrl(page, location, customFlags);
+ }
- String generatedId = "org.eclipse.mylyn.web.browser-" + Calendar.getInstance().getTimeInMillis(); //$NON-NLS-1$
- browser = WorkbenchBrowserSupport.getInstance().createBrowser(flags, generatedId, null, null);
- browser.openURL(url);
- }
+ /**
+ * Opens <code>location</code> in a rich editor if applicable or in a web-browser according to the workbench
+ * preferences.
+ *
+ * @param page
+ * the workbench page to open the editor in
+ * @param location
+ * the url to open
+ * @param customFlags
+ * additional flags that are passed to {@link IWorkbenchBrowserSupport}, pass
+ * {@link IWorkbenchBrowserSupport#AS_EXTERNAL} to force opening external browser
+ * @return a handle that describes the editor or browser that was opened; if {@link EditorHandle#getStatus()}
+ * returns an error status the operation was not successful
+ */
+ public static EditorHandle openUrl(IWorkbenchPage page, String location, int customFlags) {
+ try {
+ return openUrlInternal(page, location, customFlags);
} catch (PartInitException e) {
Status status = new Status(IStatus.ERROR, CommonsWorkbenchPlugin.ID_PLUGIN,
Messages.WorkbenchUtil_Browser_Initialization_Failed, e);
@@ -101,6 +137,7 @@ public class BrowserUtil {
MessageDialog.openError(WorkbenchUtil.getShell(), Messages.WorkbenchUtil_Open_Location_Title,
status.getMessage());
}
+ return new EditorHandle(status);
} catch (MalformedURLException e) {
if (location != null && location.trim().equals("")) { //$NON-NLS-1$
Status status = new Status(IStatus.WARNING, CommonsWorkbenchPlugin.ID_PLUGIN,
@@ -111,6 +148,7 @@ public class BrowserUtil {
} else {
CommonsWorkbenchPlugin.getDefault().getLog().log(status);
}
+ return new EditorHandle(status);
} else {
Status status = new Status(IStatus.ERROR, CommonsWorkbenchPlugin.ID_PLUGIN, NLS.bind(
Messages.WorkbenchUtil_Invalid_URL_Error, location), e);
@@ -120,8 +158,74 @@ public class BrowserUtil {
} else {
CommonsWorkbenchPlugin.getDefault().getLog().log(status);
}
+ return new EditorHandle(status);
+ }
+ }
+ }
+
+ private static EditorHandle openUrlInternal(IWorkbenchPage page, String location, int customFlags)
+ throws MalformedURLException, PartInitException {
+ if (location != null && (customFlags & IWorkbenchBrowserSupport.AS_EXTERNAL) == 0) {
+ // delegate to handler
+ if (page != null) {
+ EditorHandle handle = openUrlByHandler(page, location, customFlags);
+ if (handle != null) {
+ return handle;
+ }
+ }
+ }
+
+ URL url = null;
+ if (location != null) {
+ url = new URL(location);
+ }
+
+ if (WebBrowserPreference.getBrowserChoice() == WebBrowserPreference.EXTERNAL
+ || (customFlags & IWorkbenchBrowserSupport.AS_EXTERNAL) != 0) {
+ // open in external browser
+ IWorkbenchBrowserSupport support = PlatformUI.getWorkbench().getBrowserSupport();
+ final IWebBrowser browser = support.getExternalBrowser();
+ browser.openURL(url);
+ return new BrowserHandle(browser);
+ } else {
+ // open in internal browser
+ int flags = customFlags;
+ if (WorkbenchBrowserSupport.getInstance().isInternalWebBrowserAvailable()) {
+ flags |= IWorkbenchBrowserSupport.AS_EDITOR | IWorkbenchBrowserSupport.LOCATION_BAR
+ | IWorkbenchBrowserSupport.NAVIGATION_BAR;
+ } else {
+ flags |= IWorkbenchBrowserSupport.AS_EXTERNAL | IWorkbenchBrowserSupport.LOCATION_BAR
+ | IWorkbenchBrowserSupport.NAVIGATION_BAR;
+ }
+ String generatedId = "org.eclipse.mylyn.web.browser-" + Calendar.getInstance().getTimeInMillis(); //$NON-NLS-1$
+ IWebBrowser browser = WorkbenchBrowserSupport.getInstance().createBrowser(flags, generatedId, null, null);
+ browser.openURL(url);
+ return new BrowserHandle(browser);
+ }
+ }
+
+ private static EditorHandle openUrlByHandler(final IWorkbenchPage page, final String location, final int customFlags) {
+ for (final AbstractUrlHandler handler : UrlHandlerInitializer.handlers) {
+ final AtomicReference<EditorHandle> result = new AtomicReference<EditorHandle>();
+ SafeRunnable.run(new ISafeRunnable() {
+ public void run() throws Exception {
+ result.set(handler.openUrl(page, location, customFlags));
+ }
+
+ public void handleException(Throwable exception) {
+ CommonsWorkbenchPlugin.getDefault()
+ .getLog()
+ .log(new Status(IStatus.ERROR, CommonsWorkbenchPlugin.ID_PLUGIN, NLS.bind(
+ "Unexpected error in {0} while opening URL ''{1}''", handler.getClass(), location))); //$NON-NLS-1$
+ }
+ });
+
+ if (result.get() != null) {
+ // success
+ return result.get();
}
}
+ return null;
}
}