/******************************************************************************* * 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.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLDecoder; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.help.IContext; import org.eclipse.help.IContextProvider; import org.eclipse.help.IHelpResource; import org.eclipse.help.IIndexEntry; import org.eclipse.help.IToc; import org.eclipse.help.ITopic; import org.eclipse.help.UAContentFilter; import org.eclipse.help.internal.base.BaseHelpSystem; import org.eclipse.help.internal.base.HelpBasePlugin; import org.eclipse.help.internal.base.HelpEvaluationContext; import org.eclipse.help.internal.base.IHelpBaseConstants; import org.eclipse.help.internal.base.MissingContentManager; import org.eclipse.help.internal.base.util.LinkUtil; import org.eclipse.help.internal.protocols.HelpURLConnection; import org.eclipse.help.internal.search.federated.IndexerJob; import org.eclipse.help.internal.util.ProductPreferences; import org.eclipse.help.search.ISearchEngine2; import org.eclipse.help.ui.internal.DefaultHelpUI; 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.jface.action.Action; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IContributionManager; import org.eclipse.jface.action.IMenuListener; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.IStatusLineManager; import org.eclipse.jface.action.IToolBarManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.action.SubMenuManager; import org.eclipse.jface.action.SubStatusLineManager; import org.eclipse.jface.action.SubToolBarManager; import org.eclipse.jface.dialogs.MessageDialogWithToggle; import org.eclipse.jface.operation.IRunnableContext; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.viewers.ISelectionProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerFilter; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.SWT; import org.eclipse.swt.SWTError; import org.eclipse.swt.custom.BusyIndicator; import org.eclipse.swt.events.FocusEvent; import org.eclipse.swt.events.FocusListener; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Layout; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IActionBars; import org.eclipse.ui.IMemento; import org.eclipse.ui.ISharedImages; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.SubActionBars; import org.eclipse.ui.actions.ActionFactory; import org.eclipse.ui.activities.ActivityManagerEvent; import org.eclipse.ui.activities.IActivityManagerListener; import org.eclipse.ui.forms.IFormPart; import org.eclipse.ui.forms.ManagedForm; import org.eclipse.ui.forms.events.HyperlinkEvent; import org.eclipse.ui.forms.widgets.FormText; import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.ui.forms.widgets.ILayoutExtension; import org.eclipse.ui.forms.widgets.ScrolledForm; import com.ibm.icu.text.Collator; public class ReusableHelpPart implements IHelpUIConstants, IActivityManagerListener { public static final int ALL_TOPICS = 1 << 1; public static final int CONTEXT_HELP = 1 << 2; public static final int SEARCH = 1 << 3; public static final int BOOKMARKS = 1 << 4; public static final int INDEX = 1 << 5; public static final Collator SHARED_COLLATOR = Collator.getInstance(); private static final String PROMPT_KEY = "askShowAll"; //$NON-NLS-1$ private static final int STATE_START = 1; private static final int STATE_LT = 2; private static final int STATE_LT_B = 3; private static final int STATE_LT_BR = 4; /* * Used as a bridge from live help actions back (e.g. breadcrumb links) * to the originating help part. */ private static ReusableHelpPart lastActiveInstance; private RoleFilter roleFilter; private UAFilter uaFilter; private ManagedForm mform; private int verticalSpacing = 15; private int bmargin = 5; private String defaultContextHelpText; private ArrayList<IHelpPartPage> pages; private Action backAction; private Action nextAction; private CopyAction copyAction; private Action openInfoCenterAction; private OpenHrefAction openAction; private OpenHrefAction openInHelpAction; private OpenHrefAction bookmarkAction; private Action showAllAction; private ReusableHelpPartHistory history; private HelpPartPage currentPage; private int style; private IMemento memento; private boolean showDocumentsInPlace = true; private int numberOfInPlaceHits = 8; private IRunnableContext runnableContext; private IToolBarManager toolBarManager; private IStatusLineManager statusLineManager; private IActionBars actionBars; private EngineDescriptorManager engineManager; public IMenuManager menuManager; private abstract class BusyRunAction extends Action { public BusyRunAction(String name) { super(name); } @Override public void run() { BusyIndicator.showWhile(getControl().getDisplay(), () -> busyRun()); } protected abstract void busyRun(); } private abstract class OpenHrefAction extends BusyRunAction { private Object target; public OpenHrefAction(String name) { super(name); } public void setTarget(Object target) { this.target = target; } public Object getTarget() { return target; } } private class CopyAction extends Action implements FocusListener, SelectionListener { private FormText target; public CopyAction() { super("copy"); //$NON-NLS-1$ } public void hook(final FormText text) { text.addFocusListener(this); } public void unhook(FormText text) { text.removeFocusListener(this); if (target == text) setTarget(null); } @Override public void focusGained(FocusEvent e) { FormText text = (FormText) e.widget; text.addSelectionListener(this); setTarget(text); } @Override public void focusLost(FocusEvent e) { FormText text = (FormText) e.widget; text.removeSelectionListener(this); setTarget(null); } public void setTarget(FormText target) { this.target = target; updateState(); } private void updateState() { setEnabled(target != null && target.canCopy()); } @Override public void run() { if (target != null) target.copy(); } @Override public void widgetSelected(SelectionEvent e) { FormText text = (FormText) e.widget; if (text == target) { updateState(); } } @Override public void widgetDefaultSelected(SelectionEvent e) { } } private static class PartRec { String id; boolean flexible; boolean grabVertical; IHelpPart part; PartRec(String id, boolean flexible, boolean grabVertical) { this.id = id; this.flexible = flexible; this.grabVertical = grabVertical; } } private class HelpPartPage implements IHelpPartPage { private String id; private String iconId; Action pageAction; private int vspacing = verticalSpacing; private int horizontalMargin = 0; private String text; private SubActionBars bars; private IToolBarManager subToolBarManager; private IMenuManager subMenuManager; protected ArrayList<PartRec> partRecs; private int nflexible; public HelpPartPage(String id, String text) { this.id = id; this.text = text; partRecs = new ArrayList<>(); if (ReusableHelpPart.this.actionBars != null) { // Help View bars = new SubActionBars(ReusableHelpPart.this.actionBars); subToolBarManager = bars.getToolBarManager(); subMenuManager = bars.getMenuManager(); } else { // Help Tray subToolBarManager = new SubToolBarManager( ReusableHelpPart.this.toolBarManager); if (ReusableHelpPart.this.menuManager != null) { subMenuManager = new SubMenuManager( ReusableHelpPart.this.menuManager); } else { subMenuManager = null; } } } public HelpPartPage(String id, String text, String iconId) { this(id, text); this.iconId = iconId; } @Override public void dispose() { if (bars != null) { bars.dispose(); bars = null; subToolBarManager = null; subMenuManager = null; } else { try { ((SubToolBarManager) subToolBarManager).disposeManager(); if (subMenuManager != null) { ((SubMenuManager)subMenuManager).disposeManager(); } } catch (RuntimeException e) { // Bug 218079 } } partRecs = null; } @Override public void setVerticalSpacing(int value) { this.vspacing = value; } @Override public int getVerticalSpacing() { return vspacing; } @Override public void setHorizontalMargin(int value) { this.horizontalMargin = value; } @Override public int getHorizontalMargin() { return horizontalMargin; } @Override public IToolBarManager getToolBarManager() { return subToolBarManager; } @Override public String getId() { return id; } @Override public String getText() { return text; } @Override public String getIconId() { return iconId; } @Override public void addPart(String id, boolean flexible) { addPart(id, flexible, false); } @Override public void addPart(String id, boolean flexible, boolean grabVertical) { partRecs.add(new PartRec(id, flexible, grabVertical)); if (flexible) nflexible++; } public PartRec[] getParts() { return partRecs.toArray(new PartRec[partRecs.size()]); } public void refreshPage() { PartRec parts[] = getParts(); if (parts==null) return; for (int p=0;p<parts.length;p++) if (parts[p]!=null && parts[p].part!=null && parts[p].part.isStale()) parts[p].part.refresh(); } @Override public int getNumberOfFlexibleParts() { return nflexible; } @Override public boolean canOpen() { for (int i = 0; i < partRecs.size(); i++) { PartRec rec = partRecs.get(i); if (rec.id.equals(IHelpUIConstants.HV_BROWSER)) { // Try to create a browser and watch // for 'no-handle' error - it means // that the embedded browser is not // available try { createRecPart(rec); rec.part.setVisible(false); } catch (SWTError error) { // cannot create a browser return false; } } } return true; } @Override public void stop() { for (int i = 0; i < partRecs.size(); i++) { PartRec rec = partRecs.get(i); if (rec.part!=null) rec.part.stop(); } } @Override public void saveState(IMemento memento) { for (int i = 0; i < partRecs.size(); i++) { PartRec rec = partRecs.get(i); if (rec.part!=null) rec.part.saveState(memento); } } @Override public void toggleRoleFilter() { for (int i = 0; i < partRecs.size(); i++) { PartRec rec = partRecs.get(i); if (rec.part != null) rec.part.toggleRoleFilter(); } } @Override public void refilter() { for (int i = 0; i < partRecs.size(); i++) { PartRec rec = partRecs.get(i); if (rec.part != null) rec.part.refilter(); } } @Override public void setVisible(boolean visible) { if (bars != null) bars.clearGlobalActionHandlers(); ArrayList<Control> tabList = new ArrayList<>(); for (int i = 0; i < partRecs.size(); i++) { PartRec rec = partRecs.get(i); if (visible) { createRecPart(rec); hookGlobalAction(ActionFactory.PRINT.getId(), rec.part); hookGlobalAction(ActionFactory.COPY.getId(), rec.part); hookGlobalAction(ActionFactory.DELETE.getId(), rec.part); tabList.add(rec.part.getControl()); } rec.part.setVisible(visible); } Composite parent = mform.getForm().getBody(); parent.setTabList(tabList.toArray(new Control[tabList.size()])); if (actionBars != null) { actionBars.clearGlobalActionHandlers(); if (visible) { Map<String, IAction> handlers = bars.getGlobalActionHandlers(); if (handlers != null) { Set<String> keys = handlers.keySet(); for (Iterator<String> iter = keys.iterator(); iter.hasNext();) { String key = iter.next(); actionBars.setGlobalActionHandler(key, handlers.get(key)); } } } if (pageAction != null) pageAction.setChecked(visible); } if (bars != null) { if (visible) bars.activate(); else bars.deactivate(); bars.updateActionBars(); } else { ((SubToolBarManager) subToolBarManager).setVisible(visible); if (subMenuManager != null) { ((SubMenuManager)subMenuManager).setVisible(visible); } ReusableHelpPart.this.toolBarManager.update(true); getControl().getParent().layout(); } } private void hookGlobalAction(String id, IHelpPart part) { if (bars == null) return; IAction action = part.getGlobalAction(id); if (action != null) bars.setGlobalActionHandler(id, action); } private void createRecPart(PartRec rec) throws SWTError { if (rec.part == null) { rec.part = createPart(rec.id, subToolBarManager, subMenuManager); } } @Override public IHelpPart findPart(String id) { for (int i = 0; i < partRecs.size(); i++) { PartRec rec = partRecs.get(i); if (rec.id.equals(id)) return rec.part; } return null; } @Override public void setFocus() { // Focus on the first part that is not the see also links or missing content link for (int focusPart = 0; focusPart < partRecs.size(); focusPart++) { PartRec rec = partRecs.get(focusPart); String partId = rec.part.getId(); if ( partId != IHelpUIConstants.HV_SEE_ALSO && partId != IHelpUIConstants.HV_MISSING_CONTENT) { rec.part.setFocus(); return; } } } } class HelpPartLayout extends Layout implements ILayoutExtension { @Override public int computeMaximumWidth(Composite parent, boolean changed) { return computeSize(parent, SWT.DEFAULT, SWT.DEFAULT, changed).x; } @Override public int computeMinimumWidth(Composite parent, boolean changed) { return computeSize(parent, 0, SWT.DEFAULT, changed).x; } @Override protected Point computeSize(Composite composite, int wHint, int hHint, boolean flushCache) { if (currentPage == null) return new Point(0, 0); PartRec[] parts = currentPage.getParts(); int hmargin = currentPage.getHorizontalMargin(); int innerWhint = wHint != SWT.DEFAULT ? wHint - 2 * hmargin : wHint; Point result = new Point(0, 0); for (int i = 0; i < parts.length; i++) { PartRec partRec = parts[i]; if (!partRec.flexible) { Control c = partRec.part.getControl(); Point size = c.computeSize(innerWhint, SWT.DEFAULT, flushCache); result.x = Math.max(result.x, size.x); result.y += size.y; } if (i < parts.length - 1) result.y += currentPage.getVerticalSpacing(); } result.x += hmargin * 2; result.y += bmargin; return result; } @Override protected void layout(Composite composite, boolean flushCache) { if (currentPage == null) return; Rectangle clientArea = composite.getClientArea(); PartRec[] parts = currentPage.getParts(); int hmargin = currentPage.getHorizontalMargin(); int nfixedParts = parts.length - currentPage.getNumberOfFlexibleParts(); Point[] fixedSizes = new Point[nfixedParts]; int fixedHeight = 0; int index = 0; int innerWidth = clientArea.width - hmargin * 2; for (int i = 0; i < parts.length; i++) { PartRec partRec = parts[i]; if (!partRec.flexible) { Control c = partRec.part.getControl(); Point size = c.computeSize(innerWidth, SWT.DEFAULT, false); fixedSizes[index++] = size; if (!partRec.grabVertical) fixedHeight += size.y; } if (i < parts.length - 1) fixedHeight += currentPage.getVerticalSpacing(); } fixedHeight += bmargin; int flexHeight = clientArea.height - fixedHeight; int flexPortion = 0; if (currentPage.getNumberOfFlexibleParts() > 0) flexPortion = flexHeight / currentPage.getNumberOfFlexibleParts(); int usedFlexHeight = 0; int y = 0; index = 0; int nflexParts = 0; for (int i = 0; i < parts.length; i++) { PartRec partRec = parts[i]; Control c = partRec.part.getControl(); if (partRec.flexible) { int height; if (++nflexParts == currentPage.getNumberOfFlexibleParts()) height = flexHeight - usedFlexHeight; else { height = flexPortion; usedFlexHeight += height; } c.setBounds(0, y, clientArea.width, height); } else { Point fixedSize = fixedSizes[index++]; if (fixedSize.y < flexHeight && partRec.grabVertical) c.setBounds(hmargin, y, innerWidth, flexHeight); else c.setBounds(hmargin, y, innerWidth, fixedSize.y); } if (i < parts.length - 1) y += c.getSize().y + currentPage.getVerticalSpacing(); } } } class RoleFilter extends ViewerFilter { @Override public boolean select(Viewer viewer, Object parentElement, Object element) { IHelpResource res = (IHelpResource) element; String href = res.getHref(); if (href == null) return true; return HelpBasePlugin.getActivitySupport().isEnabled(href); } } class UAFilter extends ViewerFilter { @Override public boolean select(Viewer viewer, Object parentElement, Object element) { return !UAContentFilter.isFiltered(element, HelpEvaluationContext.getContext()); } } public ReusableHelpPart(IRunnableContext runnableContext) { this(runnableContext, getDefaultStyle()); } public ReusableHelpPart(IRunnableContext runnableContext, int style) { this.runnableContext = runnableContext; history = new ReusableHelpPartHistory(); this.style = style; ensureHelpIndexed(); PlatformUI.getWorkbench().getActivitySupport().getActivityManager() .addActivityManagerListener(this); } /* * Used as a bridge from live help actions back (e.g. breadcrumb links) * to the originating help part. */ public static ReusableHelpPart getLastActiveInstance() { return lastActiveInstance; } private void ensureHelpIndexed() { // make sure we have the index but // don't schedule the indexer job if one is // already running Job[] jobs = Job.getJobManager().find(IndexerJob.FAMILY); if (jobs.length == 0) { IndexerJob indexerJob = new IndexerJob(); indexerJob.schedule(); } } /** * Adds the given page to this part. * * @param page the page to add */ public void addPage(IHelpPartPage page) { pages.add(page); } /** * Adds the given part to this one. The part can then be used inside * any page and referred to by id. * * @param id the part's unique id * @param part the part to add */ public void addPart(String id, IHelpPart part) { part.init(this, id, memento); mform.addPart(part); } /** * Creates a new page for this part. * * @param id the page's unique id * @param text the page's heading, or null for none * @param iconId the page's icon * @return the newly created page */ public IHelpPartPage createPage(String id, String text, String iconId) { return new HelpPartPage(id, text, iconId); } private void definePages() { pages = new ArrayList<>(); // federated search page HelpPartPage page = new HelpPartPage(HV_FSEARCH_PAGE, Messages.ReusableHelpPart_searchPage_name, IHelpUIConstants.IMAGE_HELP_SEARCH); page.setVerticalSpacing(0); page.addPart(HV_SEE_ALSO, false); page.addPart(HV_MISSING_CONTENT, false); page.addPart(HV_FSEARCH, false); page.addPart(HV_FSEARCH_RESULT, true); pages.add(page); // all topics page page = new HelpPartPage(HV_ALL_TOPICS_PAGE, Messages.ReusableHelpPart_allTopicsPage_name, IHelpUIConstants.IMAGE_ALL_TOPICS); page.setVerticalSpacing(0); page.setHorizontalMargin(0); page.addPart(HV_SEE_ALSO, false); page.addPart(HV_MISSING_CONTENT, false); page.addPart(HV_SCOPE_SELECT, false); page.addPart(HV_TOPIC_TREE, true); pages.add(page); // bookmarks page page = new HelpPartPage(HV_BOOKMARKS_PAGE, Messages.ReusableHelpPart_bookmarksPage_name, IHelpUIConstants.IMAGE_BOOKMARKS); page.setVerticalSpacing(0); page.setHorizontalMargin(0); page.addPart(HV_SEE_ALSO, false); page.addPart(HV_BOOKMARKS_HEADER, false); page.addPart(HV_BOOKMARKS_TREE, true); pages.add(page); // browser page page = new HelpPartPage(HV_BROWSER_PAGE, null); page.setVerticalSpacing(0); page.addPart(HV_SEE_ALSO, false); page.addPart(HV_BROWSER, true); pages.add(page); // context help page page = new HelpPartPage(HV_CONTEXT_HELP_PAGE, Messages.ReusableHelpPart_contextHelpPage_name, IHelpUIConstants.IMAGE_RELATED_TOPICS); // page.addPart(HV_CONTEXT_HELP, false); // page.addPart(HV_SEARCH_RESULT, false, true); page.setVerticalSpacing(0); page.setHorizontalMargin(0); page.addPart(HV_SEE_ALSO, false); page.addPart(HV_MISSING_CONTENT, false); page.addPart(HV_RELATED_TOPICS, true); pages.add(page); // index page page = new HelpPartPage(HV_INDEX_PAGE, Messages.ReusableHelpPart_indexPage_name, IHelpUIConstants.IMAGE_INDEX); page.setVerticalSpacing(0); page.addPart(HV_SEE_ALSO, false); page.addPart(HV_MISSING_CONTENT, false); page.addPart(HV_SCOPE_SELECT, false); page.addPart(HV_INDEX_TYPEIN, false); page.addPart(HV_INDEX, true); pages.add(page); } public void init(IActionBars bars, IToolBarManager toolBarManager, IStatusLineManager statusLineManager, IMenuManager menuManager, IMemento memento) { this.memento = memento; this.actionBars = bars; this.toolBarManager = toolBarManager; this.menuManager = menuManager; this.statusLineManager = statusLineManager; definePages(); makeActions(); } private void makeActions() { backAction = new Action("back") { //$NON-NLS-1$ @Override public void run() { doBack(); } }; backAction.setImageDescriptor(PlatformUI.getWorkbench() .getSharedImages().getImageDescriptor( ISharedImages.IMG_TOOL_BACK)); backAction.setDisabledImageDescriptor(PlatformUI.getWorkbench() .getSharedImages().getImageDescriptor( ISharedImages.IMG_TOOL_BACK_DISABLED)); backAction.setEnabled(false); backAction.setText(Messages.ReusableHelpPart_back_label); backAction.setToolTipText(Messages.ReusableHelpPart_back_tooltip); backAction.setId("back"); //$NON-NLS-1$ nextAction = new Action("next") { //$NON-NLS-1$ @Override public void run() { doNext(); } }; nextAction.setText(Messages.ReusableHelpPart_forward_label); nextAction.setImageDescriptor(PlatformUI.getWorkbench() .getSharedImages().getImageDescriptor( ISharedImages.IMG_TOOL_FORWARD)); nextAction.setDisabledImageDescriptor(PlatformUI.getWorkbench() .getSharedImages().getImageDescriptor( ISharedImages.IMG_TOOL_FORWARD_DISABLED)); nextAction.setEnabled(false); nextAction.setToolTipText(Messages.ReusableHelpPart_forward_tooltip); nextAction.setId("next"); //$NON-NLS-1$ toolBarManager.add(backAction); toolBarManager.add(nextAction); openInfoCenterAction = new BusyRunAction("openInfoCenter") { //$NON-NLS-1$ @Override protected void busyRun() { PlatformUI.getWorkbench().getHelpSystem().displayHelp(); } }; openInfoCenterAction .setText(Messages.ReusableHelpPart_openInfoCenterAction_label); openAction = new OpenHrefAction("open") { //$NON-NLS-1$ @Override protected void busyRun() { doOpen(getTarget(), getShowDocumentsInPlace()); } }; openAction.setText(Messages.ReusableHelpPart_openAction_label); openInHelpAction = new OpenHrefAction("") {//$NON-NLS-1$ @Override protected void busyRun() { doOpenInHelp(getTarget()); } }; openInHelpAction .setText(Messages.ReusableHelpPart_openInHelpContentsAction_label); copyAction = new CopyAction(); copyAction.setText(Messages.ReusableHelpPart_copyAction_label); bookmarkAction = new OpenHrefAction("bookmark") { //$NON-NLS-1$ @Override protected void busyRun() { doBookmark(getTarget()); } }; bookmarkAction.setText(Messages.ReusableHelpPart_bookmarkAction_label); bookmarkAction.setImageDescriptor(HelpUIResources .getImageDescriptor(IHelpUIConstants.IMAGE_ADD_BOOKMARK)); if (actionBars != null && actionBars.getMenuManager() != null) contributeToDropDownMenu(actionBars.getMenuManager()); roleFilter = new RoleFilter(); uaFilter = new UAFilter(); if (HelpBasePlugin.getActivitySupport().isUserCanToggleFiltering()) { showAllAction = new Action() { @Override public void run() { BusyIndicator.showWhile(getControl().getDisplay(), () -> toggleShowAll(showAllAction.isChecked())); } }; showAllAction.setImageDescriptor(HelpUIResources .getImageDescriptor(IHelpUIConstants.IMAGE_SHOW_ALL)); showAllAction .setToolTipText(Messages.AllTopicsPart_showAll_tooltip); toolBarManager.insertBefore("back", showAllAction); //$NON-NLS-1$ toolBarManager.insertBefore("back", new Separator()); //$NON-NLS-1$ showAllAction.setChecked(!HelpBasePlugin.getActivitySupport() .isFilteringEnabled()); } } ViewerFilter getRoleFilter() { return roleFilter; } ViewerFilter getUAFilter() { return uaFilter; } @Override public void activityManagerChanged(ActivityManagerEvent activityManagerEvent) { // pages is null when the activity manager listener is added, and is set to null // prior to the activity manager listener being removed, so very short timeframes in // logic where pages could equals null entering this method if (pages != null){ for (int i = 0; i < pages.size(); i++) { HelpPartPage page = (HelpPartPage) pages.get(i); page.refilter(); } } } boolean isFilteredByRoles() { return HelpBasePlugin.getActivitySupport().isFilteringEnabled(); } private void doBack() { String id = getCurrentPageId(); if (id.equals(IHelpUIConstants.HV_BROWSER_PAGE)) { // stop the browser BrowserPart part = (BrowserPart) findPart(IHelpUIConstants.HV_BROWSER); part.stop(); } HistoryEntry entry = history.prev(); if (entry != null) executeHistoryEntry(entry); } private void doNext() { HistoryEntry entry = history.next(); if (entry != null) executeHistoryEntry(entry); } private void executeHistoryEntry(HistoryEntry entry) { history.setBlocked(true); if (entry.getType() == HistoryEntry.PAGE) { showPage(entry.getTarget(), true); mform.setInput(entry.getData()); } else if (entry.getType() == HistoryEntry.URL) { String relativeUrl = (String) entry.getData(); showURL(relativeUrl != null ? relativeUrl : entry.getTarget(), true); } } public void createControl(Composite parent, FormToolkit toolkit) { ScrolledForm form = toolkit.createScrolledForm(parent); form.getBody().setLayout(new HelpPartLayout()); mform = new ManagedForm(toolkit, form); mform.getForm().setDelayedReflow(false); toolkit.decorateFormHeading(mform.getForm().getForm()); MenuManager manager = new MenuManager(); IMenuListener listener = manager1 -> contextMenuAboutToShow(manager1); manager.setRemoveAllWhenShown(true); manager.addMenuListener(listener); Menu contextMenu = manager.createContextMenu(form.getForm()); form.getForm().setMenu(contextMenu); form.addListener(SWT.Activate, event -> lastActiveInstance = ReusableHelpPart.this); //contributeToDropDownMenu(mform.getForm().getForm().getMenuManager()); } public HelpPartPage showPage(String id) { String currentPageId = currentPage == null ? null : currentPage.getId(); if (id.equals(currentPageId)) return currentPage; // If navigating away from the browser page clear // its contents if (IHelpUIConstants.HV_BROWSER_PAGE.equals(currentPageId)) { BrowserPart part = (BrowserPart) findPart(IHelpUIConstants.HV_BROWSER); part.clearBrowser(); } HelpPartPage page = findPage(id); if (page != null) { page.refreshPage(); boolean success = flipPages(currentPage, page); return success ? page : null; } return null; } public HelpPartPage showPage(String id, boolean setFocus) { HelpPartPage page = this.showPage(id); if (page != null && setFocus) page.setFocus(); return page; } public void startSearch(String phrase) { showPage(IHelpUIConstants.HV_FSEARCH_PAGE, true); SearchPart part = (SearchPart) findPart(IHelpUIConstants.HV_FSEARCH); if (part != null && phrase != null) part.startSearch(phrase); } public void showDynamicHelp(IWorkbenchPart wpart, Control c) { showPage(IHelpUIConstants.HV_CONTEXT_HELP_PAGE, true); RelatedTopicsPart part = (RelatedTopicsPart) findPart(IHelpUIConstants.HV_RELATED_TOPICS); if (part != null) { part.handleActivation(c, wpart); } } private boolean flipPages(HelpPartPage oldPage, HelpPartPage newPage) { if (newPage.canOpen() == false) return false; if (oldPage != null) { oldPage.stop(); oldPage.setVisible(false); } mform.getForm().setText(null); //(newPage.getText()); mform.getForm().getForm().setSeparatorVisible(newPage.getText()!=null); Image newImage=null; //String iconId = newPage.getIconId(); //if (iconId != null) //newImage = HelpUIResources.getImage(iconId); mform.getForm().setImage(newImage); newPage.setVisible(true); toolBarManager.update(true); currentPage = newPage; if (mform.isStale()) mform.refresh(); mform.getForm().getBody().layout(true); mform.reflow(true); if (newPage.getId().equals(IHelpUIConstants.HV_BROWSER_PAGE) == false) { if (!history.isBlocked()) { history.addEntry(new HistoryEntry(HistoryEntry.PAGE, newPage .getId(), null)); } updateNavigation(); } return true; } /* * void addPageHistoryEntry(String id, Object data) { if * (!history.isBlocked()) { history.addEntry(new * HistoryEntry(HistoryEntry.PAGE, id, data)); } updateNavigation(); } */ public HelpPartPage getCurrentPage() { return currentPage; } public String getCurrentPageId() { return currentPage != null ? currentPage.getId() : null; } void browserChanged(String url) { if (!history.isBlocked()) { try { history.addEntry(new HistoryEntry(HistoryEntry.URL, url, BaseHelpSystem.unresolve(new URL(url)))); } catch (MalformedURLException e) { // Do not add to history } } updateNavigation(); } private void updateNavigation() { backAction.setEnabled(history.hasPrev()); nextAction.setEnabled(history.hasNext()); history.setBlocked(false); } public boolean isMonitoringContextHelp() { return currentPage != null && currentPage.getId().equals(HV_CONTEXT_HELP_PAGE); } public Control getControl() { return mform.getForm(); } public ManagedForm getForm() { return mform; } public void reflow() { mform.getForm().getBody().layout(); mform.reflow(true); } public void dispose() { if (lastActiveInstance == this) { lastActiveInstance = null; } for (int i = 0; i < pages.size(); i++) { HelpPartPage page = (HelpPartPage) pages.get(i); page.dispose(); } pages = null; if (mform != null) { mform.dispose(); mform = null; } PlatformUI.getWorkbench().getActivitySupport().getActivityManager() .removeActivityManagerListener(this); } /* * (non-Javadoc) * * @see org.eclipse.ui.internal.intro.impl.parts.IStandbyContentPart#setFocus() */ public void setFocus() { if (currentPage != null) currentPage.setFocus(); else mform.setFocus(); } public void update(IWorkbenchPart part, Control control) { update(null, null, part, control, false); } /** * Called to update the related topics page in response to a * @param provider * @param context * @param part * @param control * @param isExplicitRequest is true if this is the result of a direct user request such as * pressing F1 and false if it is in response to a focus change listener */ public void update(IContextProvider provider, IContext context, IWorkbenchPart part, Control control, boolean isExplicitRequest) { mform.setInput(new ContextHelpProviderInput(provider, context, control, part, isExplicitRequest)); } private IHelpPart createPart(String id, IToolBarManager tbm, IMenuManager menuManager) { IHelpPart part = null; Composite parent = mform.getForm().getBody(); part = findPart(id); if (part != null) return part; if (id.equals(HV_TOPIC_TREE)) { part = new AllTopicsPart(parent, mform.getToolkit(), tbm); } else if (id.equals(HV_CONTEXT_HELP)) { part = new ContextHelpPart(parent, mform.getToolkit()); ((ContextHelpPart) part) .setDefaultText(getDefaultContextHelpText()); } else if (id.equals(HV_RELATED_TOPICS)) { part = new RelatedTopicsPart(parent, mform.getToolkit()); ((RelatedTopicsPart) part) .setDefaultText(getDefaultContextHelpText()); } else if (id.equals(HV_BROWSER)) { part = new BrowserPart(parent, mform.getToolkit(), tbm, menuManager); } else if (id.equals(HV_SEARCH_RESULT)) { part = new DynamicHelpPart(parent, mform.getToolkit()); } else if (id.equals(HV_FSEARCH_RESULT)) { part = new SearchResultsPart(parent, mform.getToolkit(), tbm); } else if (id.equals(HV_SCOPE_SELECT)) { part = new ScopeSelectPart(parent, mform.getToolkit()); } else if (id.equals(HV_SEE_ALSO)) { part = new SeeAlsoPart(parent, mform.getToolkit()); } else if (id.equals(HV_FSEARCH)) { part = new SearchPart(parent, mform.getToolkit()); } else if (id.equals(HV_BOOKMARKS_HEADER)) { part = new BookmarkHeaderPart(parent, mform.getToolkit()); } else if (id.equals(HV_BOOKMARKS_TREE)) { part = new BookmarksPart(parent, mform.getToolkit(), tbm); } else if (id.equals(HV_INDEX)) { part = new IndexPart(parent, mform.getToolkit(), tbm); } else if (id.equals(HV_INDEX_TYPEIN)) { part = new IndexTypeinPart(parent, mform.getToolkit(), tbm); } else if (id.equals(HV_MISSING_CONTENT)) { part = new MissingContentPart(parent, mform.getToolkit()); } if (part != null) { mform.addPart(part); part.init(this, id, memento); } return part; } /** * @return Returns the runnableContext. */ public IRunnableContext getRunnableContext() { return runnableContext; } public boolean isInWorkbenchWindow() { return runnableContext instanceof IWorkbenchWindow; } /** * @return Returns the defaultContextHelpText. */ public String getDefaultContextHelpText() { return defaultContextHelpText; } /** * @param defaultContextHelpText * The defaultContextHelpText to set. */ public void setDefaultContextHelpText(String defaultContextHelpText) { this.defaultContextHelpText = defaultContextHelpText; } public void showURL(final String url) { BusyIndicator.showWhile(getControl().getDisplay(), () -> showURL(url, getShowDocumentsInPlace())); } public void showURL(String url, boolean replace) { if (url == null) return; if (url.startsWith("nw:")) { //$NON-NLS-1$ replace = false; url = url.substring(3); } else if (url.startsWith("open:")) { //$NON-NLS-1$ int col = url.indexOf(':'); int qloc = url.indexOf('?'); String engineId = url.substring(col+1, qloc); EngineDescriptor desc = getEngineManager().findEngine(engineId); if (desc==null) return; HashMap<String, Object> args = new HashMap<>(); HelpURLConnection.parseQuery(url.substring(qloc+1), args); ((ISearchEngine2)desc.getEngine()).open((String)args.get("id")); //$NON-NLS-1$ return; } if (replace) { if (openInternalBrowser(url)) return; } showExternalURL(url); } private boolean openInternalBrowser(String url) { String openMode = Platform.getPreferencesService().getString(HelpBasePlugin.PLUGIN_ID, IHelpBaseConstants.P_KEY_HELP_VIEW_OPEN_MODE, IHelpBaseConstants.P_IN_PLACE, null); boolean openInEditor = IHelpBaseConstants.P_IN_EDITOR.equals(openMode); boolean openInBrowser = IHelpBaseConstants.P_IN_BROWSER.equals(openMode); Shell windowShell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(); Shell helpShell = mform.getForm().getShell(); boolean isDialog = (helpShell != windowShell); if (!isDialog && openInEditor) { return DefaultHelpUI.showInWorkbenchBrowser(url, true); } if (openInBrowser) { BaseHelpSystem.getHelpDisplay().displayHelpResource(url, false); return true; } showPage(IHelpUIConstants.HV_BROWSER_PAGE); BrowserPart bpart = (BrowserPart) findPart(IHelpUIConstants.HV_BROWSER); if (bpart != null) { bpart.showURL(BaseHelpSystem .resolve(url, "/help/ntopic").toString()); //$NON-NLS-1$ return true; } return false; } public void showExternalURL(String url) { if (isHelpResource(url)) PlatformUI.getWorkbench().getHelpSystem().displayHelpResource(url); else { try { String aurl = BaseHelpSystem.resolve(url, true).toString(); /* /* Previous code before fix for Bug 192750 if (aurl.endsWith("&noframes=true") || aurl.endsWith("?noframes=true")) //$NON-NLS-1$ //$NON-NLS-2$ aurl = aurl.substring(0, aurl.length() - 14); DefaultHelpUI.showInWorkbenchBrowser(aurl, false); */ PlatformUI.getWorkbench().getHelpSystem().displayHelpResource(aurl); } catch (Exception e) { HelpUIPlugin.logError("Error opening browser", e); //$NON-NLS-1$ } } } public IHelpPart findPart(String id) { if (mform == null) return null; IFormPart[] parts = mform.getParts(); for (int i = 0; i < parts.length; i++) { IHelpPart part = (IHelpPart) parts[i]; if (part.getId().equals(id)) return part; } return null; } public boolean isHelpResource(String url) { if (url == null || url.indexOf("://") == -1) //$NON-NLS-1$ return true; return false; } private void contextMenuAboutToShow(IMenuManager manager) { IFormPart[] parts = mform.getParts(); boolean hasContext = false; Control focusControl = getControl().getDisplay().getFocusControl(); for (int i = 0; i < parts.length; i++) { IHelpPart part = (IHelpPart) parts[i]; if (part.hasFocusControl(focusControl)) { hasContext = part.fillContextMenu(manager); break; } } if (hasContext) manager.add(new Separator()); manager.add(backAction); manager.add(nextAction); manager.add(new Separator()); manager.add(openInfoCenterAction); } private void contributeToDropDownMenu(IMenuManager manager) { addPageAction(manager, IHelpUIConstants.HV_CONTEXT_HELP_PAGE); addPageAction(manager, IHelpUIConstants.HV_ALL_TOPICS_PAGE); addPageAction(manager, IHelpUIConstants.HV_INDEX_PAGE); addPageAction(manager, IHelpUIConstants.HV_FSEARCH_PAGE); addPageAction(manager, IHelpUIConstants.HV_BOOKMARKS_PAGE); } private void addPageAction(IMenuManager manager, final String pageId) { // String cid = getCurrentPageId(); HelpPartPage page = findPage(pageId); if (page == null) return; Action action = new Action(pageId, IAction.AS_CHECK_BOX) { @Override public void run() { BusyIndicator.showWhile(mform.getForm().getDisplay(), () -> showPage(pageId)); } }; action.setText(page.getText()); String iconId = page.getIconId(); if (iconId != null) action.setImageDescriptor(HelpUIResources .getImageDescriptor(iconId)); manager.add(action); page.pageAction = action; } private HelpPartPage findPage(String id) { for (int i = 0; i < pages.size(); i++) { HelpPartPage page = (HelpPartPage) pages.get(i); if (page.getId().equals(id)) { return page; } } return null; } boolean fillSelectionProviderMenu(ISelectionProvider provider, IMenuManager manager, boolean addBookmarks) { boolean value = fillOpenActions(provider, manager); if (value && addBookmarks) { manager.add(new Separator()); bookmarkAction.setTarget(provider); manager.add(bookmarkAction); } return true; } private boolean fillOpenActions(Object target, IMenuManager manager) { String href = getHref(target); if (href != null && !href.startsWith("__")) { //$NON-NLS-1$ openAction.setTarget(target); manager.add(openAction); if (!href.startsWith("nw:") && !href.startsWith("open:")) { //$NON-NLS-1$ //$NON-NLS-2$ openInHelpAction.setTarget(target); manager.add(openInHelpAction); } return true; } return false; } void hookFormText(FormText text) { copyAction.hook(text); } void unhookFormText(FormText text) { copyAction.unhook(text); } boolean fillFormContextMenu(FormText text, IMenuManager manager) { if (fillOpenActions(text, manager)) manager.add(new Separator()); manager.add(copyAction); copyAction.setTarget(text); if (text.getSelectedLinkHref() != null) { manager.add(new Separator()); manager.add(bookmarkAction); bookmarkAction.setTarget(getResource(text)); } return true; } IAction getCopyAction() { return copyAction; } private String getHref(Object target) { if (target instanceof ISelectionProvider) { ISelectionProvider provider = (ISelectionProvider) target; IStructuredSelection ssel = (IStructuredSelection) provider .getSelection(); Object obj = ssel.getFirstElement(); if (obj instanceof IToc) return null; if (obj instanceof IHelpResource) { IHelpResource res = (IHelpResource) obj; return res.getHref(); } if (obj instanceof IIndexEntry) { /* * if index entry has single topic * it represents the topic by itself */ IHelpResource[] topics = ((IIndexEntry) obj).getTopics(); if (topics.length == 1) return topics[0].getHref(); return null; } } else if (target instanceof FormText) { FormText text = (FormText) target; Object href = text.getSelectedLinkHref(); if (href != null) return href.toString(); } return null; } private IHelpResource getResource(Object target) { if (target instanceof ISelectionProvider) { ISelectionProvider provider = (ISelectionProvider) target; IStructuredSelection ssel = (IStructuredSelection) provider .getSelection(); Object obj = ssel.getFirstElement(); if (obj instanceof ITopic) { return (ITopic) obj; } else if (obj instanceof IIndexEntry) { /* * if index entry has single topic * it represents the topic by itself */ IIndexEntry entry = (IIndexEntry) obj; IHelpResource[] topics = entry.getTopics(); if (topics.length == 1) { final String href = topics[0].getHref(); final String label = entry.getKeyword(); return new IHelpResource() { @Override public String getHref() { return href; } @Override public String getLabel() { return label; } }; } return null; } else if (obj instanceof IHelpResource) { return (IHelpResource) obj; } } else if (target instanceof FormText) { FormText text = (FormText) target; String rawHref = text.getSelectedLinkHref().toString(); final String href = rawHref.startsWith("open") ? rawHref : //$NON-NLS-1$ LinkUtil.stripParams(text.getSelectedLinkHref().toString()); final String label = text.getSelectedLinkText(); if (href != null) { return new IHelpResource() { @Override public String getHref() { return href; } @Override public String getLabel() { return label; } }; } } return null; } private void doBookmark(Object target) { IHelpResource res = null; if (target instanceof IHelpResource) { res = (IHelpResource)target; } else { res = getResource(target); } if (res != null) { BaseHelpSystem.getBookmarkManager().addBookmark(res.getHref(), res.getLabel()); } } /* * private void doOpen(Object target) { String href = getHref(target); if * (href != null) showURL(href, getShowDocumentsInPlace()); } */ private void doOpen(Object target, boolean replace) { String href = getHref(target); if (href != null) showURL(href, replace); } private void doOpenInHelp(Object target) { String href = getHref(target); if (href != null) // WorkbenchHelp.displayHelpResource(href); showURL(href, false); } /** * @return Returns the statusLineManager. */ public IStatusLineManager getStatusLineManager() { return statusLineManager; } /** * @return Returns the showDocumentsInPlace. */ public boolean getShowDocumentsInPlace() { return showDocumentsInPlace; } /** * @param showDocumentsInPlace * The showDocumentsInPlace to set. */ public void setShowDocumentsInPlace(boolean showDocumentsInPlace) { this.showDocumentsInPlace = showDocumentsInPlace; } /** * @return Returns the style. */ public int getStyle() { return style; } public int getNumberOfInPlaceHits() { return numberOfInPlaceHits; } public void setNumberOfInPlaceHits(int numberOfInPlaceHits) { this.numberOfInPlaceHits = numberOfInPlaceHits; } void handleLinkEntered(HyperlinkEvent e) { IStatusLineManager mng = getRoot(getStatusLineManager()); if (mng != null) { String label = e.getLabel(); String href = (String) e.getHref(); if (href != null && href.startsWith("__")) //$NON-NLS-1$ href = null; if (href != null) { try { href = URLDecoder.decode(href, "UTF-8"); //$NON-NLS-1$ } catch (UnsupportedEncodingException ex) { } // Next line unnecessary following fix for Bug 78746 //href = href.replaceAll("&", "&&"); //$NON-NLS-1$ //$NON-NLS-2$ } if (label != null && href != null) { String message = NLS.bind(Messages.ReusableHelpPart_status, label, href); mng.setMessage(message); } else if (label != null) mng.setMessage(label); else mng.setMessage(href); } } private IStatusLineManager getRoot(IStatusLineManager mng) { while (mng != null) { if (mng instanceof SubStatusLineManager) { SubStatusLineManager smng = (SubStatusLineManager) mng; IContributionManager parent = smng.getParent(); if (parent == null) return smng; if (!(parent instanceof IStatusLineManager)) return smng; mng = (IStatusLineManager) parent; } else break; } return mng; } void handleLinkExited(HyperlinkEvent e) { IStatusLineManager mng = getRoot(getStatusLineManager()); if (mng != null) mng.setMessage(null); } private void toggleShowAll(boolean checked) { if (checked) { IPreferenceStore store = HelpUIPlugin.getDefault() .getPreferenceStore(); String value = store.getString(PROMPT_KEY); if (value.length() == 0) { MessageDialogWithToggle dialog = MessageDialogWithToggle .openOkCancelConfirm(null, Messages.AskShowAll_dialogTitle, getShowAllMessage(), Messages.AskShowAll_toggleMessage, false, store, PROMPT_KEY); if (dialog.getReturnCode() != MessageDialogWithToggle.OK) { showAllAction.setChecked(false); return; } } } HelpBasePlugin.getActivitySupport().setFilteringEnabled(!checked); for (int i = 0; i < pages.size(); i++) { HelpPartPage page = (HelpPartPage) pages.get(i); page.toggleRoleFilter(); } } public void saveState(IMemento memento) { for (int i = 0; i < pages.size(); i++) { HelpPartPage page = (HelpPartPage) pages.get(i); page.saveState(memento); } } private String getShowAllMessage() { String message = HelpBasePlugin.getActivitySupport() .getShowAllMessage(); if (message == null) return Messages.AskShowAll_message; StringBuffer buff = new StringBuffer(); int state = STATE_START; for (int i = 0; i < message.length(); i++) { char c = message.charAt(i); switch (state) { case STATE_START: if (c == '<') state = STATE_LT; else buff.append(c); break; case STATE_LT: if (c == 'b' || c == 'B') state = STATE_LT_B; break; case STATE_LT_B: if (c == 'r' || c == 'R') state = STATE_LT_BR; break; case STATE_LT_BR: if (c == '>') { buff.append('\n'); } state = STATE_START; break; default: buff.append(c); } } return buff.toString(); } EngineDescriptorManager getEngineManager() { if (engineManager==null) { engineManager = new EngineDescriptorManager(); } return engineManager; } static public int getDefaultStyle() { int style = ALL_TOPICS | CONTEXT_HELP | SEARCH; if (ProductPreferences.getBoolean(HelpBasePlugin.getDefault(), "indexView")) { //$NON-NLS-1$ style |= INDEX; } if (ProductPreferences.getBoolean(HelpBasePlugin.getDefault(), "bookmarksView")) { //$NON-NLS-1$ style |= BOOKMARKS; } return style; } public void checkRemoteStatus() { clearBrowser(); showURL("/org.eclipse.help.webapp/" + MissingContentManager.REMOTE_STATUS_HELP_VIEW_HREF); //$NON-NLS-1$ updateStatusLinks(); } public void checkPlaceholderStatus() { clearBrowser(); showURL("/org.eclipse.help.webapp/" + MissingContentManager.MISSING_BOOKS_HELP_VIEW_HREF); //$NON-NLS-1$ updateStatusLinks(); } private void clearBrowser() { IHelpPart part = findPart(HV_BROWSER); if ( part == null ) { return; } BrowserPart browserPart = (BrowserPart) part; browserPart.clearBrowser(); } private void updateStatusLinks() { IHelpPart part = findPart(HV_MISSING_CONTENT); if ( part == null ) { return; } MissingContentPart mcPart = (MissingContentPart) part; mcPart.updateStatus(); } }