/******************************************************************************* * 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$ } } }