| /*=============================================================================# |
| # Copyright (c) 2009, 2020 Stephan Wahlbrink and others. |
| # |
| # This program and the accompanying materials are made available under the |
| # terms of the Eclipse Public License 2.0 which is available at |
| # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 |
| # which is available at https://www.apache.org/licenses/LICENSE-2.0. |
| # |
| # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 |
| # |
| # Contributors: |
| # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation |
| #=============================================================================*/ |
| |
| package org.eclipse.statet.internal.redocs.tex.r.ui.editors; |
| |
| import static org.eclipse.ui.IWorkbenchCommandConstants.NAVIGATE_EXPAND_ALL; |
| |
| import static org.eclipse.statet.jcommons.lang.ObjectUtils.nonNullAssert; |
| |
| import static org.eclipse.statet.ecommons.ui.actions.UIActions.ADDITIONS_GROUP_ID; |
| import static org.eclipse.statet.ecommons.ui.actions.UIActions.VIEW_EXPAND_GROUP_ID; |
| import static org.eclipse.statet.ecommons.ui.actions.UIActions.VIEW_FILTER_GROUP_ID; |
| |
| import java.util.Collections; |
| import java.util.Map; |
| |
| import org.eclipse.core.commands.AbstractHandler; |
| import org.eclipse.core.commands.ExecutionEvent; |
| import org.eclipse.core.commands.IHandler2; |
| import org.eclipse.jface.action.IMenuListener2; |
| import org.eclipse.jface.action.IMenuManager; |
| import org.eclipse.jface.action.IToolBarManager; |
| import org.eclipse.jface.action.MenuManager; |
| import org.eclipse.jface.action.Separator; |
| import org.eclipse.jface.dialogs.IDialogSettings; |
| import org.eclipse.jface.viewers.TreeViewer; |
| import org.eclipse.ui.IActionBars; |
| import org.eclipse.ui.menus.CommandContributionItem; |
| import org.eclipse.ui.menus.CommandContributionItemParameter; |
| import org.eclipse.ui.part.IPageSite; |
| import org.eclipse.ui.services.IServiceLocator; |
| |
| import org.eclipse.statet.jcommons.lang.NonNullByDefault; |
| import org.eclipse.statet.jcommons.lang.Nullable; |
| |
| import org.eclipse.statet.ecommons.ui.actions.HandlerCollection; |
| import org.eclipse.statet.ecommons.ui.actions.HandlerContributionItem; |
| import org.eclipse.statet.ecommons.ui.dialogs.DialogUtils; |
| import org.eclipse.statet.ecommons.ui.util.UIAccess; |
| import org.eclipse.statet.ecommons.ui.viewers.ViewerUtils; |
| import org.eclipse.statet.ecommons.ui.workbench.ContextHandlers; |
| |
| import org.eclipse.statet.base.ui.IStatetUIMenuIds; |
| import org.eclipse.statet.docmlet.tex.core.commands.TexCommand; |
| import org.eclipse.statet.docmlet.tex.core.model.LtxSourceUnitModelInfo; |
| import org.eclipse.statet.docmlet.tex.core.model.TexModel; |
| import org.eclipse.statet.docmlet.tex.core.model.TexSourceElement; |
| import org.eclipse.statet.docmlet.tex.ui.TexUIResources; |
| import org.eclipse.statet.internal.redocs.tex.r.RedocsTexRPlugin; |
| import org.eclipse.statet.internal.redocs.tex.r.ui.sourceediting.DocROutlineContentProvider; |
| import org.eclipse.statet.ltk.model.core.element.EmbeddingForeignElement; |
| import org.eclipse.statet.ltk.model.core.element.LtkModelElement; |
| import org.eclipse.statet.ltk.model.core.element.LtkModelElementFilter; |
| import org.eclipse.statet.ltk.model.core.element.SourceStructElement; |
| import org.eclipse.statet.ltk.model.core.element.SourceUnitModelInfo; |
| import org.eclipse.statet.ltk.ui.sourceediting.OutlineContentProvider; |
| import org.eclipse.statet.ltk.ui.sourceediting.SourceEditor1; |
| import org.eclipse.statet.ltk.ui.sourceediting.SourceEditor2OutlinePage; |
| import org.eclipse.statet.ltk.ui.util.ViewerDragSupport; |
| import org.eclipse.statet.ltk.ui.util.ViewerDropSupport; |
| import org.eclipse.statet.r.core.model.RModel; |
| import org.eclipse.statet.r.launching.RCodeLaunching; |
| import org.eclipse.statet.redocs.r.ui.RedocsRUIResources; |
| import org.eclipse.statet.redocs.tex.r.ui.TexRweaveLabelProvider; |
| |
| |
| @NonNullByDefault |
| public class LtxRweaveOutlinePage extends SourceEditor2OutlinePage { |
| |
| |
| private static final String EXPAND_ELEMENTS_COMMAND_ID= "org.eclipse.statet.workbench.commands.ExpandElements"; //$NON-NLS-1$ |
| |
| |
| private static boolean isRChunk(final SourceStructElement<?, ?> element) { |
| if (element instanceof EmbeddingForeignElement) { |
| final SourceStructElement<?, ?> foreignElement= ((EmbeddingForeignElement<?, ?>)element).getForeignElement(); |
| if (foreignElement != null && foreignElement.getModelTypeId() == RModel.R_TYPE_ID) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| |
| private static final Map<String, String> SECTION_PARAMETERS= Collections.singletonMap("type", "sections"); //$NON-NLS-1$ //$NON-NLS-2$ |
| private static final Map<String, String> CHAPTER_PARAMETERS= Collections.singletonMap("type", "chapters"); //$NON-NLS-1$ //$NON-NLS-2$ |
| private static final Map<String, String> SUBSECTION_PARAMETERS= Collections.singletonMap("type", "subsections"); //$NON-NLS-1$ //$NON-NLS-2$ |
| private static final Map<String, String> RCHUNK_PARAMETERS= Collections.singletonMap("type", "rchunks"); //$NON-NLS-1$ //$NON-NLS-2$ |
| |
| |
| private class FilterRChunks extends AbstractToggleHandler { |
| |
| public FilterRChunks() { |
| super("filter.r_chunks.enabled", false, null, 0); //$NON-NLS-1$ |
| } |
| |
| @Override |
| protected void apply(final boolean on) { |
| LtxRweaveOutlinePage.this.contentFilter.hideRChunks= on; |
| final TreeViewer viewer= getViewer(); |
| if (viewer == null || !UIAccess.isOkToUse(viewer.getControl())) { |
| return; |
| } |
| viewer.refresh(false); |
| } |
| |
| } |
| |
| public class ExpandElementsContributionItem extends HandlerContributionItem { |
| |
| private final IHandler2 expandElementsHandler; |
| |
| public ExpandElementsContributionItem( |
| final IServiceLocator serviceLocator, final HandlerCollection handlers) { |
| super(new CommandContributionItemParameter(serviceLocator, |
| ".ExpandElements", NAVIGATE_EXPAND_ALL, null, //$NON-NLS-1$ |
| null, null, null, |
| "Expand All", "E", null, |
| HandlerContributionItem.STYLE_PULLDOWN, null, false ), |
| nonNullAssert(handlers.get(NAVIGATE_EXPAND_ALL)) ); |
| this.expandElementsHandler= nonNullAssert(handlers.get(EXPAND_ELEMENTS_COMMAND_ID)); |
| } |
| |
| |
| @Override |
| protected void initDropDownMenu(final MenuManager menuManager) { |
| menuManager.addMenuListener(new IMenuListener2() { |
| @Override |
| public void menuAboutToShow(final IMenuManager manager) { |
| final TreeViewer viewer= getViewer(); |
| if (viewer == null) { |
| return; |
| } |
| final LtxSourceUnitModelInfo modelInfo= getCurrentInputModel(); |
| if (modelInfo == null) { |
| return; |
| } |
| final TexUIResources texResources= TexUIResources.INSTANCE; |
| final RedocsRUIResources sweaveResources= RedocsRUIResources.INSTANCE; |
| if (modelInfo.getMinSectionLevel() > 0) { |
| if (modelInfo.getMinSectionLevel() < TexCommand.CHAPTER_LEVEL |
| && modelInfo.getMaxSectionLevel() >= TexCommand.CHAPTER_LEVEL) { |
| manager.add(new HandlerContributionItem(new CommandContributionItemParameter( |
| getSite(), null, EXPAND_ELEMENTS_COMMAND_ID, CHAPTER_PARAMETERS, |
| texResources.getImageDescriptor(TexUIResources.OBJ_CHAPTER_IMAGE_ID), null, null, |
| "Show all Chapters", "C", null, |
| HandlerContributionItem.STYLE_PUSH, null, false ), |
| ExpandElementsContributionItem.this.expandElementsHandler )); |
| } |
| if (modelInfo.getMinSectionLevel() < TexCommand.SECTION_LEVEL |
| && modelInfo.getMaxSectionLevel() >= TexCommand.SECTION_LEVEL) { |
| manager.add(new HandlerContributionItem(new CommandContributionItemParameter( |
| getSite(), null, EXPAND_ELEMENTS_COMMAND_ID, SECTION_PARAMETERS, |
| texResources.getImageDescriptor(TexUIResources.OBJ_SECTION_IMAGE_ID), null, null, |
| "Show all Sections", "S", null, |
| HandlerContributionItem.STYLE_PUSH, null, false ), |
| ExpandElementsContributionItem.this.expandElementsHandler )); |
| } |
| if (modelInfo.getMinSectionLevel() < TexCommand.SUBSECTION_LEVEL |
| && modelInfo.getMaxSectionLevel() >= TexCommand.SUBSECTION_LEVEL) { |
| manager.add(new HandlerContributionItem(new CommandContributionItemParameter( |
| getSite(), null, EXPAND_ELEMENTS_COMMAND_ID, SUBSECTION_PARAMETERS, |
| texResources.getImageDescriptor(TexUIResources.OBJ_SUBSECTION_IMAGE_ID), null, null, |
| "Show all SubSections", "u", null, |
| HandlerContributionItem.STYLE_PUSH, null, false ), |
| ExpandElementsContributionItem.this.expandElementsHandler )); |
| manager.add(new Separator()); |
| } |
| } |
| if (!LtxRweaveOutlinePage.this.contentFilter.hideRChunks) { |
| manager.add(new HandlerContributionItem(new CommandContributionItemParameter( |
| getSite(), null, EXPAND_ELEMENTS_COMMAND_ID, RCHUNK_PARAMETERS, |
| sweaveResources.getImageDescriptor(RedocsRUIResources.OBJ_RCHUNK_IMAGE_ID), null, null, |
| "Show all R Chunks", "R", null, |
| HandlerContributionItem.STYLE_PUSH, null, false ), |
| ExpandElementsContributionItem.this.expandElementsHandler )); |
| } |
| } |
| @Override |
| public void menuAboutToHide(final IMenuManager manager) { |
| ExpandElementsContributionItem.this.display.asyncExec(new Runnable() { |
| @Override |
| public void run() { |
| menuManager.dispose(); |
| } |
| }); |
| } |
| }); |
| } |
| |
| } |
| |
| public class ExpandElementsHandler extends AbstractHandler { |
| |
| public ExpandElementsHandler() { |
| } |
| |
| @Override |
| public @Nullable Object execute(final ExecutionEvent event) { |
| final String type= event.getParameter("type"); |
| if (type == null) { |
| return null; |
| } |
| final TreeViewer viewer= getViewer(); |
| if (viewer == null || !UIAccess.isOkToUse(viewer.getControl())) { |
| return null; |
| } |
| final SourceUnitModelInfo modelInfo= getModelInfo(viewer.getInput()); |
| if (modelInfo == null) { |
| return null; |
| } |
| final LtkModelElementFilter<? super SourceStructElement<?, ?>> contentFilter= getContentFilter(); |
| final LtkModelElementFilter<? super SourceStructElement<?, ?>> expandFilter; |
| if (type.equals("rchunks")) { //$NON-NLS-1$ |
| expandFilter= new LtkModelElementFilter<SourceStructElement<?, ?>>() { |
| @Override |
| public boolean include(final SourceStructElement<?, ?> element) { |
| if (contentFilter.include(element)) { |
| if ((element.getElementType() & LtkModelElement.MASK_C1) == TexSourceElement.C1_EMBEDDED |
| && isRChunk(element)) { |
| ViewerUtils.expandToLevel(viewer, element, 0); |
| return false; |
| } |
| element.hasSourceChildren(this); |
| return false; |
| } |
| return false; |
| } |
| }; |
| } |
| else { |
| final int sectionLevel; |
| if (type.equals("chapters")) { //$NON-NLS-1$ |
| sectionLevel= TexCommand.CHAPTER_LEVEL; |
| } |
| else if (type.equals("sections")) { //$NON-NLS-1$ |
| sectionLevel= TexCommand.SECTION_LEVEL; |
| } |
| else if (type.equals("subsections")) { //$NON-NLS-1$ |
| sectionLevel= TexCommand.SUBSECTION_LEVEL; |
| } |
| else if (type.equals("subsubsections")) { //$NON-NLS-1$ |
| sectionLevel= TexCommand.SUBSUBSECTION_LEVEL; |
| } |
| else { |
| sectionLevel= 0; |
| } |
| if (sectionLevel < 1 || sectionLevel > 5) { |
| return null; |
| } |
| expandFilter= new LtkModelElementFilter<SourceStructElement<?, ?>>() { |
| private boolean childExpand; |
| @Override |
| public boolean include(final SourceStructElement<?, ?> element) { |
| if (contentFilter.include(element) |
| && (element.getElementType() & LtkModelElement.MASK_C2) == TexSourceElement.C2_SECTIONING) { |
| final int currentLevel= (element.getElementType() & 0xf); |
| if (currentLevel < 1 || currentLevel > sectionLevel) { |
| return false; // nothing to do |
| } |
| if (currentLevel < sectionLevel) { |
| this.childExpand= false; |
| element.hasSourceChildren(this); |
| if (this.childExpand) { |
| return false; // done |
| } |
| } |
| // expand |
| ViewerUtils.expandToLevel(viewer, element, 0); |
| this.childExpand= true; |
| return false; |
| } |
| return false; |
| } |
| }; |
| } |
| modelInfo.getSourceElement().hasSourceChildren(expandFilter); |
| return null; |
| } |
| } |
| |
| |
| private class ContentFilter implements LtkModelElementFilter<SourceStructElement<?, ?>> { |
| |
| private boolean hideRChunks; |
| |
| @Override |
| public boolean include(final SourceStructElement<?, ?> element) { |
| switch ((element.getElementType() & LtkModelElement.MASK_C1)) { |
| case TexSourceElement.C1_EMBEDDED: |
| if (isRChunk(element)) { |
| return !this.hideRChunks; |
| } |
| } |
| return true; |
| } |
| |
| } |
| |
| |
| private final ContentFilter contentFilter= new ContentFilter(); |
| |
| |
| public LtxRweaveOutlinePage(final SourceEditor1 editor) { |
| super(editor, TexModel.LTX_TYPE_ID, LtxRweaveRefactoringFactory.getInstance(), |
| "org.eclipse.statet.redocs.tex.menus.LtxOutlineViewContextMenu"); //$NON-NLS-1$ |
| } |
| |
| |
| @Override |
| protected IDialogSettings getDialogSettings() { |
| return DialogUtils.getDialogSettings(RedocsTexRPlugin.getInstance(), "SweaveOutlineView"); //$NON-NLS-1$ |
| } |
| |
| @Override |
| protected OutlineContentProvider createContentProvider() { |
| return new DocROutlineContentProvider(new PageOutlineContent()); |
| } |
| |
| @Override |
| protected LtkModelElementFilter<? super SourceStructElement<?, ?>> getContentFilter() { |
| return this.contentFilter; |
| } |
| |
| @Override |
| protected void configureViewer(final TreeViewer viewer) { |
| super.configureViewer(viewer); |
| |
| viewer.setLabelProvider(new TexRweaveLabelProvider(0)); |
| |
| final ViewerDropSupport drop= new ViewerDropSupport(viewer, this, |
| getRefactoringFactory() ); |
| drop.init(); |
| final ViewerDragSupport drag= new ViewerDragSupport(viewer); |
| drag.init(); |
| } |
| |
| @Override |
| protected void initActions(final IServiceLocator serviceLocator, |
| final ContextHandlers handlers) { |
| super.initActions(serviceLocator, handlers); |
| |
| handlers.add(".FilterRChunks", new FilterRChunks()); //$NON-NLS-1$ |
| |
| { final IHandler2 handler= new ExpandElementsHandler(); |
| handlers.add(EXPAND_ELEMENTS_COMMAND_ID, handler); |
| // handlerService.activateHandler(EXPAND_ELEMENTS_COMMAND_ID, handler); //$NON-NLS-1$ |
| } |
| } |
| |
| @Override |
| protected void contributeToActionBars(final IServiceLocator serviceLocator, |
| final IActionBars actionBars, final HandlerCollection handlers) { |
| super.contributeToActionBars(serviceLocator, actionBars, handlers); |
| |
| final IToolBarManager toolBarManager= actionBars.getToolBarManager(); |
| final RedocsRUIResources sweaveResources= RedocsRUIResources.INSTANCE; |
| |
| toolBarManager.appendToGroup(VIEW_EXPAND_GROUP_ID, |
| new ExpandElementsContributionItem(serviceLocator, handlers)); |
| |
| // toolBarManager.appendToGroup(ECommonsUI.VIEW_SORT_MENU_ID, |
| // new AlphaSortAction()); |
| toolBarManager.appendToGroup(VIEW_FILTER_GROUP_ID, |
| new HandlerContributionItem(new CommandContributionItemParameter(serviceLocator, |
| null, HandlerContributionItem.NO_COMMAND_ID, null, |
| sweaveResources.getImageDescriptor(RedocsRUIResources.LOCTOOL_FILTERCHUNKS_IMAGE_ID), null, null, |
| "Hide R Chunks", "R", null, |
| HandlerContributionItem.STYLE_CHECK, null, false ), |
| nonNullAssert(handlers.get(".FilterRChunks")) )); //$NON-NLS-1$ |
| // toolBarManager.appendToGroup(ECommonsUI.VIEW_FILTER_MENU_ID, |
| // new FilterLocalDefinitions()); |
| } |
| |
| @Override |
| protected void contextMenuAboutToShow(final IMenuManager m) { |
| super.contextMenuAboutToShow(m); |
| final IPageSite site= getSite(); |
| |
| if (m.find(IStatetUIMenuIds.GROUP_SUBMIT_MENU_ID) == null) { |
| m.insertBefore(ADDITIONS_GROUP_ID, |
| new Separator(IStatetUIMenuIds.GROUP_SUBMIT_MENU_ID) ); |
| } |
| |
| m.appendToGroup(IStatetUIMenuIds.GROUP_SUBMIT_MENU_ID, |
| new CommandContributionItem(new CommandContributionItemParameter( |
| site, null, RCodeLaunching.SUBMIT_SELECTION_COMMAND_ID, null, |
| null, null, null, |
| null, "R", null, //$NON-NLS-1$ |
| CommandContributionItem.STYLE_PUSH, null, false) )); |
| m.appendToGroup(IStatetUIMenuIds.GROUP_SUBMIT_MENU_ID, |
| new CommandContributionItem(new CommandContributionItemParameter( |
| site, null, RCodeLaunching.SUBMIT_UPTO_SELECTION_COMMAND_ID, null, |
| null, null, null, |
| null, "U", null, //$NON-NLS-1$ |
| CommandContributionItem.STYLE_PUSH, null, false) )); |
| |
| m.add(new Separator(IStatetUIMenuIds.GROUP_ADD_MORE_ID)); |
| } |
| |
| protected @Nullable LtxSourceUnitModelInfo getCurrentInputModel() { |
| final TreeViewer viewer= getViewer(); |
| if (viewer == null) { |
| return null; |
| } |
| return (LtxSourceUnitModelInfo)getModelInfo(viewer.getInput()); |
| } |
| |
| } |