/*=============================================================================# # Copyright (c) 2014-2016 Stephan Wahlbrink (WalWare.de) 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: # Stephan Wahlbrink - initial API and implementation #=============================================================================*/ package de.walware.docmlet.base.internal.ui.markuphelp; import java.io.IOException; import java.net.URL; import java.util.List; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.resource.FontDescriptor; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.osgi.util.NLS; 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.OpenWindowListener; import org.eclipse.swt.browser.WindowEvent; import org.eclipse.swt.graphics.FontData; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.ui.IActionBars; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IPartListener2; import org.eclipse.ui.IViewSite; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.IWorkbenchPartReference; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.browser.IWebBrowser; import org.eclipse.ui.browser.IWorkbenchBrowserSupport; import org.eclipse.ui.part.ViewPart; import org.eclipse.ui.services.IServiceLocator; import org.eclipse.ui.statushandlers.StatusManager; import de.walware.ecommons.ui.actions.HandlerCollection; import de.walware.ecommons.ui.actions.SimpleContributionItem; import de.walware.ecommons.ui.util.LayoutUtil; import de.walware.ecommons.ui.util.UIAccess; import de.walware.docmlet.base.internal.ui.DocBaseUIPlugin; import de.walware.docmlet.base.ui.DocBaseUI; import de.walware.docmlet.base.ui.markuphelp.IMarkupHelpContextProvider; import de.walware.docmlet.base.ui.markuphelp.IMarkupHelpView; import de.walware.docmlet.base.ui.markuphelp.MarkupHelpContent; public class MarkupHelpView extends ViewPart implements IMarkupHelpView { private static void appendCssColor(final StringBuilder sb, final RGB color) { sb.append('#'); String s = Integer.toHexString(color.red); if (s.length() == 1) { sb.append('0'); } sb.append(s); s = Integer.toHexString(color.green); if (s.length() == 1) { sb.append('0'); } sb.append(s); s = Integer.toHexString(color.blue); if (s.length() == 1) { sb.append('0'); } sb.append(s); } private Browser browser; private IPartListener2 partListener; private String lastHtml; public MarkupHelpView() { } @Override public void createPartControl(final Composite parent) { parent.setLayout(LayoutUtil.applySashDefaults(new GridLayout(), 1)); this.browser= new Browser(parent, SWT.NONE); this.browser.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); final Display display= this.browser.getDisplay(); this.browser.setForeground(display.getSystemColor(SWT.COLOR_INFO_FOREGROUND)); this.browser.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND)); this.browser.addOpenWindowListener(new OpenWindowListener() { @Override public void open(final WindowEvent event) { event.browser= MarkupHelpView.this.browser; // event.required= true; // Cancel opening of new windows } }); this.browser.addLocationListener(new LocationListener() { @Override public void changing(final LocationEvent event) { if (event.location != null && !event.location.startsWith("about:")) { //$NON-NLS-1$ openExternal(event.location); event.doit= false; } } @Override public void changed(final LocationEvent event) { } }); final IViewSite site= getViewSite(); initActions(site, null); contributeToActionBars(site, site.getActionBars(), null); initLinking(); } private void initLinking() { this.partListener= new IPartListener2() { @Override public void partVisible(final IWorkbenchPartReference partRef) { } @Override public void partOpened(final IWorkbenchPartReference partRef) { } @Override public void partInputChanged(final IWorkbenchPartReference partRef) { } @Override public void partHidden(final IWorkbenchPartReference partRef) { } @Override public void partDeactivated(final IWorkbenchPartReference partRef) { } @Override public void partClosed(final IWorkbenchPartReference partRef) { } @Override public void partBroughtToTop(final IWorkbenchPartReference partRef) { } @Override public void partActivated(final IWorkbenchPartReference partRef) { final IWorkbenchPart part= partRef.getPart(false); if (part instanceof IEditorPart) { activated((IEditorPart) part); } } }; getSite().getPage().addPartListener(this.partListener); UIAccess.getDisplay().asyncExec(new Runnable() { @Override public void run() { activated(getSite().getPage().getActiveEditor()); } }); } protected void initActions(final IServiceLocator serviceLocator, final HandlerCollection handlers) { } protected void contributeToActionBars(final IServiceLocator serviceLocator, final IActionBars actionBars, final HandlerCollection handlers) { final IMenuManager menuManager= actionBars.getMenuManager(); { final List<MarkupHelpContent> topics= DocBaseUIPlugin.getInstance().getMarkupHelpManager().getTopicList(); for (final MarkupHelpContent topic : topics) { menuManager.add(new SimpleContributionItem(topic.getTitle(), null) { final String topicId= topic.getId(); @Override protected void execute(final Event event) throws ExecutionException { show(this.topicId); } }); } } } @Override public void dispose() { if (this.partListener != null) { getSite().getPage().removePartListener(this.partListener); this.partListener= null; } super.dispose(); } private void activated(final IEditorPart editor) { final IMarkupHelpContextProvider contextProvider= (IMarkupHelpContextProvider) editor.getAdapter(IMarkupHelpContextProvider.class); if (contextProvider != null) { show(contextProvider.getHelpContentId()); } } @Override public void setFocus() { this.browser.setFocus(); } @Override public void show(final String id) { final MarkupHelpContent content= DocBaseUIPlugin.getInstance().getMarkupHelpManager().getContent(id); if (content != null) { setContent(content); } } private void setContent(final MarkupHelpContent content) { String html; try { html= content.getContent(); } catch (final IOException e) { StatusManager.getManager().handle(new Status(IStatus.ERROR, DocBaseUI.PLUGIN_ID, 0, NLS.bind("An error occurred while loading markup help content {0}).", content), e )); DocBaseUIPlugin.getInstance().getMarkupHelpManager().disable(content.getId()); return; } html= style(html); if (!html.equals(this.lastHtml)) { this.lastHtml= html; this.browser.setText(html); } } private String style(final String html) { final StringBuilder sb= new StringBuilder(html.length() + 200); final int idx= html.indexOf("</head>"); //$NON-NLS-1$ sb.append(html, 0, idx); sb.append("<style type=\"text/css\">\n"); collectCss(sb); sb.append("</style>"); sb.append(html, idx, html.length()); return sb.toString(); } private void collectCss(final StringBuilder sb) { final RGB foregroundColor = JFaceResources.getColorRegistry().getRGB("de.walware.workbench.themes.DocViewColor"); //$NON-NLS-1$ final RGB docBackgroundColor = JFaceResources.getColorRegistry().getRGB("de.walware.workbench.themes.DocViewBackgroundColor"); //$NON-NLS-1$ final FontDescriptor docFontDescr = JFaceResources.getFontDescriptor("de.walware.workbench.themes.DocViewFont"); //$NON-NLS-1$ final FontData fontData = docFontDescr.getFontData()[0]; { sb.append("body { font-family: '"); //$NON-NLS-1$ sb.append(fontData.getName()); sb.append("'; font-size: "); //$NON-NLS-1$ sb.append(fontData.getHeight()); sb.append("pt; color: "); //$NON-NLS-1$ appendCssColor(sb, foregroundColor); sb.append("; background: "); //$NON-NLS-1$ appendCssColor(sb, docBackgroundColor); sb.append("; }\n"); //$NON-NLS-1$ } { sb.append("body { margin: "); //$NON-NLS-1$ sb.append(LayoutUtil.defaultVSpacing()); sb.append("px "); //$NON-NLS-1$ sb.append(LayoutUtil.defaultHSpacing()); sb.append("px; }\n"); //$NON-NLS-1$ } { sb.append("table, tr, th, td { font-size: "); //$NON-NLS-1$ sb.append(fontData.getHeight()); sb.append("pt; }\n"); //$NON-NLS-1$ } { sb.append("h4 { margin-bottom: 0.66em; }"); //$NON-NLS-1$ sb.append("pre { margin-top: 0.66em; margin-bottom: 0.66em; }"); //$NON-NLS-1$ } } private void openExternal(final String location) { final IWorkbenchBrowserSupport browserSupport = PlatformUI.getWorkbench().getBrowserSupport(); try { final IWebBrowser externalBrowser = browserSupport.createBrowser( IWorkbenchBrowserSupport.LOCATION_BAR | IWorkbenchBrowserSupport.NAVIGATION_BAR | IWorkbenchBrowserSupport.STATUS, "de.walware.docmlet.base.MarkupHelp", null, null); final URL url = new URL(location); externalBrowser.openURL(url); } catch (final Exception e) { StatusManager.getManager().handle(new Status(IStatus.ERROR, DocBaseUI.PLUGIN_ID, 0, "An error occurred while opening the page in an external browser.", e )); } } }