blob: af046ffe21ebde747e24fb4fb6516c5869856b11 [file] [log] [blame]
/***************************************************************************************************
* Copyright (c) 2000, 2016 IBM Corporation 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:
* IBM Corporation - initial API and implementation
* Sebastian Davids <sdavids@gmx.de> - bug 93374
**************************************************************************************************/
package org.eclipse.help.ui.internal;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLEncoder;
import org.eclipse.core.runtime.Platform;
import org.eclipse.help.IContext;
import org.eclipse.help.IHelpResource;
import org.eclipse.help.browser.IBrowser;
import org.eclipse.help.internal.base.BaseHelpSystem;
import org.eclipse.help.internal.base.HelpBasePlugin;
import org.eclipse.help.internal.base.IHelpBaseConstants;
import org.eclipse.help.ui.internal.util.ErrorUtil;
import org.eclipse.help.ui.internal.util.FontUtils;
import org.eclipse.help.ui.internal.views.ContextHelpPart;
import org.eclipse.help.ui.internal.views.HelpTray;
import org.eclipse.help.ui.internal.views.HelpView;
import org.eclipse.help.ui.internal.views.ReusableHelpPart;
import org.eclipse.jface.dialogs.DialogTray;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.TrayDialog;
import org.eclipse.osgi.service.environment.Constants;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.browser.IWebBrowser;
import org.eclipse.ui.browser.IWorkbenchBrowserSupport;
import org.eclipse.ui.help.AbstractHelpUI;
import org.eclipse.ui.intro.IIntroManager;
import org.eclipse.ui.intro.IIntroPart;
/**
* This class is an implementation of the Help UI. In is registered into the helpSupport extension
* point, and is responsible for handling requests to display help. The methods on this class
* interact with the actual UI component handling the display.
* <p>
* Most methods delegate most work to HelpDisplay class; only the UI specific ones implemented in
* place.
* </p>
*/
public class DefaultHelpUI extends AbstractHelpUI {
private ContextHelpDialog f1Dialog = null;
private static DefaultHelpUI instance;
private static boolean openingHelpView = false;
private static final String HELP_VIEW_ID = "org.eclipse.help.ui.HelpView"; //$NON-NLS-1$
class ExternalWorkbenchBrowser implements IBrowser {
public ExternalWorkbenchBrowser() {
}
private IWebBrowser getExternalBrowser() throws PartInitException {
IWorkbenchBrowserSupport support = PlatformUI.getWorkbench().getBrowserSupport();
return support.getExternalBrowser();
}
@Override
public void close() {
}
@Override
public boolean isCloseSupported() {
return false;
}
@Override
public void displayURL(String url) throws Exception {
try {
IWebBrowser browser = getExternalBrowser();
if (browser != null) {
browser.openURL(new URL(url));
}
} catch (PartInitException pie) {
ErrorUtil.displayErrorDialog(pie.getLocalizedMessage());
}
}
@Override
public boolean isSetLocationSupported() {
return false;
}
@Override
public boolean isSetSizeSupported() {
return false;
}
@Override
public void setLocation(int x, int y) {
}
@Override
public void setSize(int width, int height) {
}
}
/**
* Constructor.
*/
public DefaultHelpUI() {
super();
instance = this;
// register external browser. This will cause the help system
// to use workbench external browser instead of its own.
BaseHelpSystem.getInstance().setBrowserInstance(new ExternalWorkbenchBrowser());
}
public static DefaultHelpUI getInstance() {
return instance;
}
/**
* Displays help.
*/
@Override
public void displayHelp() {
BaseHelpSystem.getHelpDisplay().displayHelp(useExternalBrowser(null));
}
/**
* Displays search.
*/
@Override
public void displaySearch() {
search(null);
}
/**
* Displays dynamic help.
*/
@Override
public void displayDynamicHelp() {
IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
Shell activeShell = getActiveShell();
if (window != null && isActiveShell(activeShell, window)) {
setIntroStandby();
IWorkbenchPage page = window.getActivePage();
Control c = activeShell.getDisplay().getFocusControl();
if (page != null) {
IWorkbenchPart activePart = page.getActivePart();
try {
IViewPart part = page.showView(HELP_VIEW_ID, null, IWorkbenchPage.VIEW_ACTIVATE);
if (part != null) {
HelpView view = (HelpView) part;
view.showDynamicHelp(activePart, c);
}
} catch (PartInitException e) {
}
} else {
// check the dialog
Object data = activeShell.getData();
if (data instanceof TrayDialog) {
IContext context = ContextHelpPart.findHelpContext(c);
displayContextAsHelpTray(activeShell, context);
return;
}
warnNoOpenPerspective(window);
}
}
}
/**
* Starts the search.
*/
@Override
public void search(final String expression) {
IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
Shell activeShell = getActiveShell();
if (window != null && isActiveShell(activeShell, window)) {
setIntroStandby();
IWorkbenchPage page = window.getActivePage();
if (page != null) {
boolean searchFromBrowser = Platform.getPreferencesService().getBoolean
(HelpBasePlugin.PLUGIN_ID, IHelpBaseConstants.P_KEY_SEARCH_FROM_BROWSER, false, null);
if (searchFromBrowser) {
String parameters = "tab=search"; //$NON-NLS-1$
if (expression != null) {
try {
parameters += "&searchWord=" + URLEncoder.encode(expression, "UTF-8"); //$NON-NLS-1$ //$NON-NLS-2$
} catch (UnsupportedEncodingException e) {
// Should not happen: UTF-8 is a required encoding for every Java version
}
}
BaseHelpSystem.getHelpDisplay().displayHelpResource(parameters, false);
} else {
try {
IViewPart part = page.showView(HELP_VIEW_ID);
if (part != null) {
HelpView view = (HelpView) part;
view.startSearch(expression);
}
} catch (PartInitException e) {
}
}
} else {
// check the dialog
if (activeShell != null) {
Object data = activeShell.getData();
if (data instanceof TrayDialog) {
displayContextAsHelpTray(activeShell, null);
return;
}
else {
// tried to summon help from a non-tray dialog
// not supported
return;
}
}
warnNoOpenPerspective(window);
}
}
}
public static void showIndex() {
HelpView helpView = getHelpView();
if (helpView != null) {
helpView.showIndex();
}
}
private static HelpView getHelpView() {
HelpView view = null;
IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
Shell activeShell = getActiveShell();
if (window != null && isActiveShell(activeShell, window)) {
setIntroStandby();
IWorkbenchPage page = window.getActivePage();
if (page != null) {
try {
IViewPart part = page.showView(HELP_VIEW_ID);
if (part != null) {
view = (HelpView) part;
}
} catch (PartInitException e) {
}
}
}
return view;
}
private static void setIntroStandby() {
IIntroManager introMng = PlatformUI.getWorkbench().getIntroManager();
IIntroPart intro = introMng.getIntro();
if (intro != null && !introMng.isIntroStandby(intro))
introMng.setIntroStandby(intro, true);
}
private void warnNoOpenPerspective(IWorkbenchWindow window) {
MessageDialog.openInformation(window.getShell(), Messages.DefaultHelpUI_wtitle,
Messages.DefaultHelpUI_noPerspMessage);
}
/**
* Displays a help resource specified as a url.
* <ul>
* <li>a URL in a format that can be returned by
* {@link org.eclipse.help.IHelpResource#getHref() IHelpResource.getHref()}
* <li>a URL query in the format format <em>key=value&amp;key=value ...</em> The valid keys
* are: "tab", "toc", "topic", "contextId". For example,
* <em>toc="/myplugin/mytoc.xml"&amp;topic="/myplugin/references/myclass.html"</em> is valid.
* </ul>
*/
@Override
public void displayHelpResource(String href) {
BaseHelpSystem.getHelpDisplay().displayHelpResource(href, useExternalBrowser(href));
}
/**
* Displays context-sensitive help for specified context
*
* @param context
* the context to display
* @param x
* int positioning information
* @param y
* int positioning information
*/
@Override
public void displayContext(IContext context, int x, int y) {
displayContext(context, x, y, false);
}
void displayContext(IContext context, int x, int y, boolean noInfopop) {
if (context == null)
return;
boolean winfopop = Platform.getPreferencesService().getBoolean
(HelpBasePlugin.PLUGIN_ID, IHelpBaseConstants.P_KEY_WINDOW_INFOPOP, false, null);
boolean dinfopop = Platform.getPreferencesService().getBoolean
(HelpBasePlugin.PLUGIN_ID, IHelpBaseConstants.P_KEY_DIALOG_INFOPOP, false, null) || FontUtils.isFontTooLargeForTray();
IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
Shell activeShell = getActiveShell();
if (window != null && isActiveShell(activeShell, window)) {
IWorkbenchPage page = window.getActivePage();
if (page != null) {
if (!noInfopop && winfopop) {
Control c = window.getShell().getDisplay().getFocusControl();
displayContextAsInfopop(context, x, y, c);
return;
}
try {
/*
* If the context help has no description text and exactly one
* topic, go straight to the topic and skip context help.
*/
String contextText = context.getText();
IHelpResource[] topics = context.getRelatedTopics();
boolean isSingleChoiceWithoutDescription = contextText == null && topics.length == 1;
String openMode = Platform.getPreferencesService().getString
(HelpBasePlugin.PLUGIN_ID, IHelpBaseConstants.P_KEY_HELP_VIEW_OPEN_MODE, IHelpBaseConstants.P_IN_PLACE, null);
if (isSingleChoiceWithoutDescription && IHelpBaseConstants.P_IN_EDITOR.equals(openMode)) {
showInWorkbenchBrowser(topics[0].getHref(), true);
} else if (isSingleChoiceWithoutDescription && IHelpBaseConstants.P_IN_BROWSER.equals(openMode)) {
BaseHelpSystem.getHelpDisplay().displayHelpResource(topics[0].getHref(), true);
} else {
IWorkbenchPart activePart = page.getActivePart();
Control c = window.getShell().getDisplay().getFocusControl();
openingHelpView = true;
IViewPart part = page.showView(HELP_VIEW_ID);
openingHelpView = false;
if (part != null) {
HelpView view = (HelpView) part;
if (isSingleChoiceWithoutDescription) {
view.showHelp(topics[0].getHref());
} else {
view.displayContext(context, activePart, c);
}
}
}
return;
} catch (PartInitException e) {
// ignore the exception and let
// the code default to the context
// help dialog
}
}
}
// check the dialog
if (HelpTray.isAppropriateFor(activeShell) && (!dinfopop || noInfopop)) {
displayContextAsHelpTray(activeShell, context);
return;
}
// we are here either as a fallback or because of the user preferences
displayContextAsInfopop(context, x, y, null);
}
@Override
public URL resolve(String href, boolean documentOnly) {
return BaseHelpSystem.resolve(href, documentOnly);
}
public String unresolve(URL url) {
return BaseHelpSystem.unresolve(url);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.help.AbstractHelpUI#resolve(java.lang.String, boolean)
*/
private static Shell getActiveShell() {
Display display = PlatformUI.getWorkbench().getDisplay();
return display.getActiveShell();
}
static boolean isActiveShell(Shell activeShell, IWorkbenchWindow window) {
// Test if the active shell belongs to this window
return activeShell != null && activeShell.equals(window.getShell());
}
private void displayContextAsInfopop(IContext context, int x, int y, Control c) {
if (f1Dialog != null) {
f1Dialog.close();
}
if (context != null) {
/*
* If the context help has no description text and exactly one
* topic, go straight to the topic and skip context help.
*/
IHelpResource[] topics = context.getRelatedTopics();
if (context.getText() == null && topics.length == 1) {
try {
PlatformUI.getWorkbench().getHelpSystem().displayHelpResource(topics[0].getHref());
}
catch (Exception e) {
// should never happen
}
}
else {
f1Dialog = new ContextHelpDialog(context, x, y);
f1Dialog.open();
}
}
}
private void displayContextAsHelpTray(Shell activeShell, IContext context) {
Control controlInFocus = activeShell.getDisplay().getFocusControl();
TrayDialog dialog = (TrayDialog)activeShell.getData();
DialogTray tray = dialog.getTray();
if (tray == null) {
tray = new HelpTray();
dialog.openTray(tray);
}
if (tray instanceof HelpTray) {
ReusableHelpPart helpPart = ((HelpTray)tray).getHelpPart();
if (context != null) {
IHelpResource[] topics = context.getRelatedTopics();
if (context.getText() == null && topics.length == 1) {
helpPart.showURL(topics[0].getHref());
}
else {
helpPart.showPage(IHelpUIConstants.HV_CONTEXT_HELP_PAGE);
helpPart.update(null, context, null, controlInFocus, true);
}
}
else {
helpPart.showPage(IHelpUIConstants.HV_FSEARCH_PAGE, true);
}
helpPart.setFocus();
}
else {
// someone else was occupying the tray; not supported
}
}
/**
* Returns <code>true</code> if the context-sensitive help window is currently being
* displayed, <code>false</code> if not.
*/
@Override
public boolean isContextHelpDisplayed() {
if (f1Dialog == null) {
return false;
}
return f1Dialog.isShowing();
}
private boolean useExternalBrowser(String url) {
// On non Windows platforms, use external when modal window is displayed
if (!Constants.OS_WIN32.equalsIgnoreCase(Platform.getOS())) {
Display display = Display.getCurrent();
if (display != null) {
if (insideModalParent(display))
return true;
}
}
// Use external when no help frames are to be displayed, otherwise no
// navigation buttons.
if (url != null) {
if (url.indexOf("?noframes=true") > 0 //$NON-NLS-1$
|| url.indexOf("&noframes=true") > 0) { //$NON-NLS-1$
return true;
}
}
return false;
}
private boolean insideModalParent(Display display) {
return isDisplayModal(display.getActiveShell());
}
public static boolean isDisplayModal(Shell activeShell) {
while (activeShell != null) {
if ((activeShell.getStyle() & (SWT.APPLICATION_MODAL | SWT.PRIMARY_MODAL | SWT.SYSTEM_MODAL)) > 0)
return true;
activeShell = (Shell) activeShell.getParent();
}
return false;
}
public static boolean showInWorkbenchBrowser(String url, boolean onlyInternal) {
IWorkbenchBrowserSupport support = PlatformUI.getWorkbench().getBrowserSupport();
if (!onlyInternal || support.isInternalWebBrowserAvailable()) {
try {
IWebBrowser browser = support
.createBrowser(
IWorkbenchBrowserSupport.AS_EDITOR
| IWorkbenchBrowserSupport.NAVIGATION_BAR
| IWorkbenchBrowserSupport.STATUS,
"org.eclipse.help.ui", Messages.ReusableHelpPart_internalBrowserTitle, url); //$NON-NLS-1$
browser.openURL(BaseHelpSystem.resolve(url, "/help/nftopic")); //$NON-NLS-1$
return true;
} catch (PartInitException e) {
HelpUIPlugin.logError(
Messages.ReusableHelpPart_internalWebBrowserError, e);
}
}
return false;
}
/*
* Used to indicate to the HelpView that we are about to pass in a context
*/
public static boolean isOpeningHelpView() {
return openingHelpView;
}
}