blob: 98d4182990536172e106d20f5396b1803ce22e6a [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2016 IBM Corporation 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.help.ui.internal.views;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.StringTokenizer;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.IScopeContext;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.help.internal.base.BaseHelpSystem;
import org.eclipse.help.internal.base.HelpBasePlugin;
import org.eclipse.help.internal.base.util.LinkUtil;
import org.eclipse.help.internal.util.URLCoder;
import org.eclipse.help.ui.internal.HelpUIPlugin;
import org.eclipse.help.ui.internal.HelpUIResources;
import org.eclipse.help.ui.internal.IHelpUIConstants;
import org.eclipse.help.ui.internal.Messages;
import org.eclipse.help.ui.internal.util.FontUtils;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IStatusLineManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.swt.SWT;
import org.eclipse.swt.browser.Browser;
import org.eclipse.swt.browser.LocationEvent;
import org.eclipse.swt.browser.LocationListener;
import org.eclipse.swt.browser.ProgressEvent;
import org.eclipse.swt.browser.ProgressListener;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.forms.AbstractFormPart;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.osgi.service.prefs.BackingStoreException;
public class BrowserPart extends AbstractFormPart implements IHelpPart {
private final static String QUERY = "BrowserPartQuery:"; //$NON-NLS-1$
private final static String HIGHLIGHT_ON = "highlight-on"; //$NON-NLS-1$
private final static String HELP_VIEW_SCALE = "help_view_scale"; //$NON-NLS-1$
private final static String EMPTY_PAGE = "<html><head></head><body></body></html>"; //$NON-NLS-1$
private ReusableHelpPart parent;
private Browser browser;
private String id;
private int lastProgress = -1;
private static final int SCALE_MAX = 250;
private static final int SCALE_MIN = 50;
private static final int SCALE_INCREMENT = 10;
private int fontScalePercentage = 100;
private String url;
private Action showExternalAction;
private Action syncTocAction;
private Action highlightAction;
private Action bookmarkAction;
private Action printAction;
private Action magnifyAction;
private Action reduceAction;
private String statusURL;
private String title;
public BrowserPart(final Composite parent, FormToolkit toolkit,
final IToolBarManager tbm, IMenuManager menuManager) {
browser = new Browser(parent, SWT.NULL);
browser.addLocationListener(new LocationListener() {
@Override
public void changing(LocationEvent event) {
if (redirectLink(event.location))
event.doit = false;
if (!event.doit && event.location != null
&& event.location.startsWith("https://")) { //$NON-NLS-1$
try {
BaseHelpSystem.getHelpBrowser(true).displayURL(
event.location);
} catch (Exception exc) {
}
}
}
@Override
public void changed(LocationEvent event) {
String url = event.location;
boolean isResult = url.indexOf("resultof")!=-1; //$NON-NLS-1$
BrowserPart.this.parent.browserChanged(url);
BrowserPart.this.url = url;
updateSyncTocAction();
BrowserPart.this.highlightAction.setEnabled(isResult);
}
});
browser.addProgressListener(new ProgressListener() {
@Override
public void changed(ProgressEvent e) {
if (e.current == e.total)
return;
IStatusLineManager slm = BrowserPart.this.parent
.getStatusLineManager();
IProgressMonitor monitor = slm != null ? slm
.getProgressMonitor() : null;
if (lastProgress == -1) {
lastProgress = 0;
if (monitor != null) {
monitor.beginTask("", e.total); //$NON-NLS-1$
slm.setCancelEnabled(true);
}
} else if (monitor != null && monitor.isCanceled()) {
browser.stop();
return;
}
if (monitor != null)
monitor.worked(e.current - lastProgress);
lastProgress = e.current;
}
@Override
public void completed(ProgressEvent e) {
IStatusLineManager slm = BrowserPart.this.parent
.getStatusLineManager();
IProgressMonitor monitor = slm != null ? slm
.getProgressMonitor() : null;
if (monitor != null) {
slm.setCancelEnabled(false);
monitor.done();
}
lastProgress = -1;
if (fontScalePercentage != 100) {
rescale();
}
String value = executeQuery("document.title"); //$NON-NLS-1$
BrowserPart.this.title = value != null ? value : "N/A"; //$NON-NLS-1$
}
});
browser.addStatusTextListener(event -> {
if (processQuery(event.text))
return;
IStatusLineManager statusLine = BrowserPart.this.parent.getStatusLineManager();
if (statusLine != null)
statusLine.setMessage(event.text);
if (event.text.indexOf("://") != -1) //$NON-NLS-1$
statusURL = event.text;
});
browser.addOpenWindowListener(event -> {
if (statusURL != null) {
try {
String relativeURL = BaseHelpSystem.unresolve(new URL(statusURL));
if (BrowserPart.this.parent.isHelpResource(relativeURL)) {
BrowserPart.this.parent.showExternalURL(relativeURL);
event.required = true;
}
} catch (MalformedURLException e) {
HelpUIPlugin.logError("Malformed URL: " + statusURL, e); //$NON-NLS-1$
}
}
});
contributeToToolBar(tbm);
contributeToMenu(menuManager);
}
private String executeQuery(String domValue) {
return (String)browser.evaluate("return " + domValue + ';'); //$NON-NLS-1$
}
private boolean processQuery(String text) {
if (text.startsWith(QUERY)) {
browser.setData("query", text.substring(QUERY.length())); //$NON-NLS-1$
return true;
}
return false;
}
private void contributeToToolBar(IToolBarManager tbm) {
boolean highlight = Platform.getPreferencesService().getBoolean(HelpBasePlugin.PLUGIN_ID, HIGHLIGHT_ON, true, null);
showExternalAction = new Action() {
@Override
public void run() {
BusyIndicator.showWhile(browser.getDisplay(), () -> {
try {
parent.showExternalURL(BaseHelpSystem.unresolve(new URL(url)));
} catch (MalformedURLException e) {
HelpUIPlugin.logError("Malformed URL: " + statusURL, e); //$NON-NLS-1$
}
});
}
};
showExternalAction
.setToolTipText(Messages.BrowserPart_showExternalTooltip);
showExternalAction.setImageDescriptor(HelpUIResources
.getImageDescriptor(IHelpUIConstants.IMAGE_NW));
syncTocAction = new Action() {
@Override
public void run() {
doSyncToc();
}
};
syncTocAction.setToolTipText(Messages.BrowserPart_syncTocTooltip);
syncTocAction.setImageDescriptor(HelpUIResources
.getImageDescriptor(IHelpUIConstants.IMAGE_SYNC_TOC));
syncTocAction.setEnabled(false);
bookmarkAction = new Action() {
@Override
public void run() {
String href = LinkUtil.stripParams(BaseHelpSystem.unresolve(url));
BaseHelpSystem.getBookmarkManager().addBookmark(href, title);
}
};
bookmarkAction.setToolTipText(Messages.BrowserPart_bookmarkTooltip);
bookmarkAction.setImageDescriptor(HelpUIResources
.getImageDescriptor(IHelpUIConstants.IMAGE_ADD_BOOKMARK));
highlightAction = new Action() {
@Override
public void run() {
IScopeContext instanceScope = InstanceScope.INSTANCE;
IEclipsePreferences prefs = instanceScope.getNode(HelpBasePlugin.PLUGIN_ID);
prefs.putBoolean(HIGHLIGHT_ON, highlightAction.isChecked());
if (browser.getUrl().indexOf("resultof")!=-1) browser.execute("setHighlight(" +highlightAction.isChecked()+");"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
};
highlightAction.setChecked(highlight);
highlightAction.setToolTipText(Messages.BrowserPart_highlightTooltip);
highlightAction.setImageDescriptor(HelpUIResources
.getImageDescriptor(IHelpUIConstants.IMAGE_HIGHLIGHT));
printAction = new Action(ActionFactory.PRINT.getId()) {
@Override
public void run() {
doPrint();
}
};
printAction.setImageDescriptor(HelpUIResources
.getImageDescriptor(IHelpUIConstants.IMAGE_HELP_PRINT));
printAction.setToolTipText(Messages.BrowserPart_printTooltip);
tbm.insertBefore("back", showExternalAction); //$NON-NLS-1$
tbm.insertBefore("back", syncTocAction); //$NON-NLS-1$
tbm.insertBefore("back", printAction); //$NON-NLS-1$
tbm.insertBefore("back", bookmarkAction); //$NON-NLS-1$
tbm.insertBefore("back", highlightAction); //$NON-NLS-1$
tbm.insertBefore("back", new Separator()); //$NON-NLS-1$
enableButtons();
}
private void contributeToMenu(IMenuManager menuManager) {
if (FontUtils.canRescaleHelpView()) {
fontScalePercentage = Platform.getPreferencesService().getInt(HelpBasePlugin.PLUGIN_ID,
HELP_VIEW_SCALE, 100, null);
if (menuManager != null) {
addMenuActions(menuManager);
}
}
}
private void addMenuActions(IMenuManager menuManager) {
magnifyAction = new Action() {
@Override
public void run() {
doMagnify(SCALE_INCREMENT);
}
};
magnifyAction.setToolTipText(Messages.BrowserPart_magnifyTooltip);
magnifyAction.setText(Messages.BrowserPart_magnifyTooltip);
magnifyAction.setImageDescriptor(HelpUIResources
.getImageDescriptor(IHelpUIConstants.IMAGE_MAGNIFY));
magnifyAction.setDisabledImageDescriptor(HelpUIResources
.getImageDescriptor(IHelpUIConstants.IMAGE_D_MAGNIFY));
reduceAction = new Action() {
@Override
public void run() {
doMagnify(-SCALE_INCREMENT);
}
};
reduceAction.setToolTipText(Messages.BrowserPart_reduceTooltip);
reduceAction.setText(Messages.BrowserPart_reduceTooltip);
reduceAction
.setImageDescriptor(HelpUIResources.getImageDescriptor(IHelpUIConstants.IMAGE_REDUCE));
reduceAction.setDisabledImageDescriptor(HelpUIResources
.getImageDescriptor(IHelpUIConstants.IMAGE_D_REDUCE));
menuManager.add(new Separator());
menuManager.add(reduceAction);
menuManager.add(magnifyAction);
}
@Override
public void init(ReusableHelpPart parent, String id, IMemento memento) {
this.parent = parent;
this.id = id;
if (memento != null) {
String href = memento.getString("BrowserPart.url"); //$NON-NLS-1$
if (href != null)
showURL(BaseHelpSystem.resolve(href, "/help/ntopic").toString()); //$NON-NLS-1$
}
}
@Override
public String getId() {
return id;
}
@Override
public Control getControl() {
return browser;
}
@Override
public void setVisible(boolean visible) {
if (browser != null) {
browser.setVisible(visible);
}
}
@Override
public void setFocus() {
if (browser != null)
browser.setFocus();
}
public void showURL(String url) {
if (browser != null && url != null) {
browser.setUrl(url);
}
}
public void clearBrowser() {
if (browser != null) {
browser.setText(EMPTY_PAGE);
}
}
@Override
public void stop() {
if (browser != null && !browser.isDisposed()) {
browser.stop();
}
}
private void doPrint() {
browser.execute("window.print();"); //$NON-NLS-1$
}
private void doSyncToc() {
String href = BaseHelpSystem.unresolve(this.url);
int ix = href.indexOf("?resultof="); //$NON-NLS-1$
if (ix >= 0) {
href = href.substring(0, ix);
}
parent.showPage(IHelpUIConstants.HV_ALL_TOPICS_PAGE);
AllTopicsPart part = (AllTopicsPart) parent
.findPart(IHelpUIConstants.HV_TOPIC_TREE);
if (part != null) {
part.selectReveal(href);
}
}
private void updateSyncTocAction() {
String href = BaseHelpSystem.unresolve(this.url);
syncTocAction.setEnabled(parent.isHelpResource(href));
}
private boolean redirectLink(final String url) {
if (url.indexOf("/topic/") != -1) { //$NON-NLS-1$
if (url.indexOf("noframes") == -1) { //$NON-NLS-1$
return true;
}
} else if (url.indexOf("livehelp/?pluginID=")>0) { //$NON-NLS-1$
processLiveAction(url);
return true;
} else if (url.indexOf("helpview:") == 0) { //$NON-NLS-1$
HelpviewProtocol.handleProtocolCall(url, parent);
return true;
}
return false;
}
private void processLiveAction(String url) {
if (!Platform.getPreferencesService().getBoolean(HelpBasePlugin.PLUGIN_ID, "activeHelp", false, null)) { //$NON-NLS-1$
return;
}
String query = null;
try {
URL u = new URL(url);
query = u.getQuery();
} catch (MalformedURLException mue) {
}
if (query == null)
return;
StringTokenizer st = new StringTokenizer(query, "=&"); //$NON-NLS-1$
if (st.countTokens() < 6) {
return;
}
st.nextToken();
String pluginId = URLCoder.decode(st.nextToken());
st.nextToken();
String className = URLCoder.decode(st.nextToken());
st.nextToken();
String arg = URLCoder.decode(st.nextToken());
if (pluginId == null || className == null || arg == null)
return;
BaseHelpSystem.runLiveHelp(pluginId, className, arg);
}
@Override
public boolean fillContextMenu(IMenuManager manager) {
return false;
}
@Override
public boolean hasFocusControl(Control control) {
return browser.equals(control);
}
@Override
public IAction getGlobalAction(String id) {
if (id.equals(ActionFactory.PRINT.getId()))
return printAction;
return null;
}
private void enableButtons() {
if (magnifyAction != null) {
magnifyAction.setEnabled(fontScalePercentage < SCALE_MAX);
reduceAction.setEnabled(fontScalePercentage > SCALE_MIN);
}
}
private void doMagnify(int percent) {
fontScalePercentage += percent;
IScopeContext instanceScope = InstanceScope.INSTANCE;
IEclipsePreferences prefs = instanceScope.getNode(HelpBasePlugin.PLUGIN_ID);
prefs.putInt(HELP_VIEW_SCALE, fontScalePercentage);
try {
prefs.flush();
} catch (BackingStoreException e) {
}
rescale();
}
public void rescale() {
browser.execute(FontUtils.getRescaleScript(fontScalePercentage));
enableButtons();
}
@Override
public void toggleRoleFilter() {
}
@Override
public void refilter() {
showURL(this.url);
}
@Override
public void saveState(IMemento memento) {
if (url != null) {
String href = BaseHelpSystem.unresolve(url);
memento.putString("BrowserPart.url", href); //$NON-NLS-1$
}
}
}