diff options
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 8c64151b..fea3b625 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 00000000..1e43c176 --- /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 00000000..8664608f --- /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 00000000..c15c4988 --- /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 00000000..b74c42a9 --- /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 fd26202d..12961547 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; } } |