| /******************************************************************************* |
| * Copyright (c) 2016 ALL4TEC & CEA LIST. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * ALL4TEC & CEA LIST - initial API and implementation |
| ******************************************************************************/ |
| package org.polarsys.esf.core.common.ui.editor; |
| |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.Map; |
| |
| import org.apache.commons.lang3.StringUtils; |
| import org.eclipse.emf.common.ui.viewer.IViewerProvider; |
| import org.eclipse.emf.edit.domain.EditingDomain; |
| import org.eclipse.emf.edit.domain.IEditingDomainProvider; |
| import org.eclipse.emf.edit.ui.action.DeleteAction; |
| import org.eclipse.emf.edit.ui.action.EditingDomainActionBarContributor; |
| import org.eclipse.emf.edit.ui.action.ValidateAction; |
| import org.eclipse.jface.action.Action; |
| import org.eclipse.jface.action.IAction; |
| import org.eclipse.jface.action.IContributionItem; |
| import org.eclipse.jface.action.IMenuManager; |
| import org.eclipse.jface.action.MenuManager; |
| import org.eclipse.jface.action.Separator; |
| import org.eclipse.jface.action.ToolBarManager; |
| import org.eclipse.jface.resource.ImageDescriptor; |
| import org.eclipse.jface.viewers.AbstractTreeViewer; |
| import org.eclipse.jface.viewers.ISelection; |
| import org.eclipse.jface.viewers.ISelectionChangedListener; |
| import org.eclipse.jface.viewers.ISelectionProvider; |
| import org.eclipse.jface.viewers.IStructuredSelection; |
| import org.eclipse.jface.viewers.SelectionChangedEvent; |
| import org.eclipse.jface.viewers.Viewer; |
| import org.eclipse.ui.IActionBars; |
| import org.eclipse.ui.IEditorPart; |
| import org.eclipse.ui.IPageLayout; |
| import org.eclipse.ui.PartInitException; |
| import org.eclipse.ui.actions.ActionFactory; |
| import org.eclipse.ui.handlers.CollapseAllHandler; |
| import org.eclipse.ui.handlers.ExpandAllHandler; |
| import org.polarsys.esf.core.common.ui.CommonUIActivator; |
| import org.polarsys.esf.core.common.ui.CommonUIActivator.Implementation; |
| import org.polarsys.esf.core.common.ui.actions.ActionBarContributorUtils; |
| import org.polarsys.esf.core.common.ui.provider.IToolBarManagerProvider; |
| |
| /** |
| * This is the abstract action bar contributor used for all the multi pages editors. |
| * |
| * It extends {@link EditingDomainActionBarContributor} which provide the standard mechanisms |
| * to provide the actions on an editing domain. |
| * |
| * It implements {@link ISelectionChangedListener} to be able to react when the selection changed in the |
| * active editor, to update the action linked to the current selection. |
| * |
| * This contributor will populate the editor tool bar with different kind of actions : |
| * <ul> |
| * <li>Actions not linked to the current context (ie: expand / collapse tree)</li> |
| * <li>Actions linked to the current selection when one is set (ie: create children elements)</li> |
| * </ul> |
| * |
| * @author $Author: jdumont $ |
| * @version $Revision: 83 $ |
| */ |
| public abstract class AbstractActionBarContributor |
| extends EditingDomainActionBarContributor |
| implements ISelectionChangedListener { |
| |
| /** Instance of utility class used by the action contributors. */ |
| private ActionBarContributorUtils mActionBarContributorUtils = ActionBarContributorUtils.INSTANCE; |
| |
| /** This keeps track of the active editor on which the actions are applied. */ |
| private IEditorPart mActiveEditorPart = null; |
| |
| /** This keeps track of the current selection provider. */ |
| private ISelectionProvider mSelectionProvider = null; |
| |
| /** This action opens the Properties view. */ |
| private IAction mShowPropertiesViewAction = new Action(ActionBarContributorUtils.SHOW_PROPERTIES_ACTION_LABEL) { |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public void run() { |
| try { |
| getPage().showView(IPageLayout.ID_PROP_SHEET); |
| } catch (final PartInitException pException) { |
| CommonUIActivator.logError( |
| "Error during the opening of the Properties view", //$NON-NLS-1$ |
| pException); |
| } |
| } |
| }; |
| |
| /** This action expands the active editor content, if possible. */ |
| private IAction mExpandAllAction = createExpandAllAction(); |
| |
| /** This action collapse the active editor content, if possible. */ |
| private IAction mCollapseAllAction = createCollapseAllAction(); |
| |
| /** |
| * This action refreshes the viewer of the current editor if the editor |
| * implements {@link org.eclipse.emf.common.ui.viewer.IViewerProvider}. |
| */ |
| private IAction mRefreshViewerAction = new Action(ActionBarContributorUtils.REFRESH_ACTION_LABEL) { |
| |
| /** |
| * {@inheritDoc} |
| * |
| * The action is enabled only if the editor implements {@link IViewerProvider} |
| * to provide its owned viewer. |
| */ |
| @Override |
| public boolean isEnabled() { |
| return mActiveEditorPart instanceof IViewerProvider; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public void run() { |
| if (mActiveEditorPart instanceof IViewerProvider) { |
| final Viewer vViewer = ((IViewerProvider) mActiveEditorPart).getViewer(); |
| if (vViewer != null) { |
| vViewer.refresh(); |
| } |
| } |
| } |
| }; |
| |
| /** |
| * This will contain one {@link org.eclipse.emf.edit.ui.action.CreateChildAction} corresponding to each descriptor |
| * generated for the current selection by the item provider. |
| */ |
| private Collection<IAction> mCreateSelectChildActionsColl = Collections.emptyList(); |
| |
| /** |
| * This will contain a map of {@link org.eclipse.emf.edit.ui.action.CreateChildAction}s, keyed by sub-menu text |
| * for all the create child action relative to the current selection. |
| */ |
| private Map<String, Collection<IAction>> mCreateSelectChildMenuActionsMap = null; |
| |
| /** This is the menu manager into which menu contribution items should be added for CreateChild actions. */ |
| private IMenuManager mCreateSelectChildMenuManager = null; |
| |
| /** |
| * Default constructor. |
| * This creates an instance of the contributor with the default style |
| * {@link EditingDomainActionBarContributor#ADDITIONS_LAST_STYLE}. |
| */ |
| public AbstractActionBarContributor() { |
| // Call the parent constructor and ask to add an 'additions' anchor at the end of the menu |
| super(ADDITIONS_LAST_STYLE); |
| |
| // Create the parent action specific to the editing domain context |
| // NB : The 'load resource' and 'control' actions are not needed |
| validateAction = new ValidateAction(); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * This implementation also call the method to contribute to any toolbar |
| * potentially provided by the active editor. |
| */ |
| @Override |
| public void init(final IActionBars pActionBars) { |
| // Call the parent method |
| super.init(pActionBars); |
| } |
| |
| /** |
| * Contribute to the editor toolbar, if the active editor provide a tool bar manager. |
| * This method may be called only once as it will create all the actions, even the global |
| * actions which doesn't need to change or be updated after their creation. |
| */ |
| public void contributeToEditorToolBar() { |
| |
| // Check if the editor provide a custom toolbar manager |
| if (mActiveEditorPart instanceof IToolBarManagerProvider) { |
| // Get the tool bar manager from the active editor |
| ToolBarManager vEditorToolBarManager = ((IToolBarManagerProvider) mActiveEditorPart).getToolBarManager(); |
| |
| // Use a flag to known if the tool bar content have been modified |
| boolean vNeedToUpdate = false; |
| |
| // Add the expand all action if it's not already in it |
| if (vEditorToolBarManager.find(ActionBarContributorUtils.EXPAND_ALL_ACTION_ID) == null) { |
| vEditorToolBarManager.add(mExpandAllAction); |
| vNeedToUpdate = true; |
| } |
| |
| // Add the collapse all action if it's not already in it |
| if (vEditorToolBarManager.find(ActionBarContributorUtils.COLLAPSE_ALL_ACTION_ID) == null) { |
| vEditorToolBarManager.add(mCollapseAllAction); |
| vNeedToUpdate = true; |
| } |
| |
| // Add the separator for the actions on the selected element, if it's not already in it |
| if (vEditorToolBarManager.find(ActionBarContributorUtils.TOOLBAR_SEP_SELECTION_ACTIONS) == null) { |
| vEditorToolBarManager.add(new Separator(ActionBarContributorUtils.TOOLBAR_SEP_SELECTION_ACTIONS)); |
| vNeedToUpdate = true; |
| } |
| |
| // Add the delete action to the toolbar if it's not already in it |
| // This action will react to the selection change automatically |
| if (vEditorToolBarManager.find(ActionFactory.DELETE.getId()) == null) { |
| vEditorToolBarManager.add(new Separator(ActionBarContributorUtils.TOOLBAR_SEP_DELETE_ACTION)); |
| vEditorToolBarManager.appendToGroup(ActionBarContributorUtils.TOOLBAR_SEP_DELETE_ACTION, deleteAction); |
| vNeedToUpdate = true; |
| } |
| |
| |
| // Finally update the toolbar if needed |
| if (vNeedToUpdate) { |
| vEditorToolBarManager.update(true); |
| |
| vEditorToolBarManager.getControl().pack(true); |
| } |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * By default, no menu is added. |
| */ |
| @Override |
| public void contributeToMenu(final IMenuManager pMenuManager) { |
| // Nothing to do |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * When the active editor changes, this remembers the change and registers |
| * this instance with it as a selection provider. |
| */ |
| @Override |
| public void setActiveEditor(final IEditorPart pPart) { |
| // Call the parent method |
| super.setActiveEditor(pPart); |
| |
| // Remember the active editor |
| mActiveEditorPart = pPart; |
| |
| // If any selection provider was already registered, remove it |
| if (mSelectionProvider != null) { |
| mSelectionProvider.removeSelectionChangedListener(this); |
| } |
| |
| // Then switch to the new selection provider if possible |
| if (mActiveEditorPart != null) { |
| // Get the selection provider from the new active editor |
| mSelectionProvider = mActiveEditorPart.getSite().getSelectionProvider(); |
| |
| // Register this instance to listen to the change on this selection provider |
| mSelectionProvider.addSelectionChangedListener(this); |
| |
| // Fake a selection changed event to update the menus |
| if (mSelectionProvider.getSelection() != null) { |
| selectionChanged(new SelectionChangedEvent(mSelectionProvider, mSelectionProvider.getSelection())); |
| } |
| |
| } else { |
| // Reset the selection provider |
| mSelectionProvider = null; |
| } |
| |
| // Try to contribute to the tool bar that the active editor may provide |
| contributeToEditorToolBar(); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * This implements {@link ISelectionChangedListener}, handling {@link SelectionChangedEvent}s |
| * by querying for the children that can be created under the selected object and updating the menus accordingly. |
| */ |
| @Override |
| public void selectionChanged(final SelectionChangedEvent pEvent) { |
| // Recreate the actions linked to the current selection in the contextual menus and in the editor toolbar |
| addCreateSelectChildActions(pEvent.getSelection()); |
| } |
| |
| /** |
| * Create the new child actions for the current selection, in the context menu |
| * and the editor toolbar. |
| * |
| * @param pSelection The current selection for which the actions must be created |
| */ |
| protected void addCreateSelectChildActions(final ISelection pSelection) { |
| // Force to update the action from the current selection, |
| // and recreate the actions in the menu |
| addCreateSelectChildActionsToMenu(pSelection, true); |
| |
| // The recreate the actions in the tool bar, but without updating the |
| // actions as the selection has not changed |
| addCreateSelectChildActionsToEditorToolbar(pSelection, false); |
| } |
| |
| /** |
| * Create the new child actions for the current selection in the editor context menu. |
| * The actions may be updated according to the given flag value. If no, the list of action |
| * is not updated according to the current selection, but the menu content is refresh even so. |
| * |
| * @param pSelection The current selection for which the actions must be created |
| * @param pUpdateActions If <code>true</code> the list of actions is updated according to the given selection |
| */ |
| protected void addCreateSelectChildActionsToMenu(final ISelection pSelection, final boolean pUpdateActions) { |
| // Remove any menu items created for the old selection |
| if (mCreateSelectChildMenuManager != null) { |
| mActionBarContributorUtils.depopulateManager( |
| mCreateSelectChildMenuManager, |
| mCreateSelectChildMenuActionsMap); |
| |
| mActionBarContributorUtils.depopulateManager( |
| mCreateSelectChildMenuManager, |
| mCreateSelectChildActionsColl); |
| } |
| |
| // Update the list of actions used to create child for the |
| // given selection only if needed |
| if (pUpdateActions) { |
| updateCreateSelectChildActionsCollection(pSelection); |
| } |
| |
| // Finally populate and redraw the menus |
| if (mCreateSelectChildMenuManager != null) { |
| mActionBarContributorUtils.populateManager( |
| mCreateSelectChildMenuManager, |
| mCreateSelectChildMenuActionsMap, |
| null); |
| |
| mActionBarContributorUtils.populateManager( |
| mCreateSelectChildMenuManager, |
| mCreateSelectChildActionsColl, |
| null); |
| |
| mCreateSelectChildMenuManager.update(true); |
| } |
| } |
| |
| /** |
| * Create the new child actions for the current selection in the editor toolbar. |
| * The actions may be updated according to the given flag value. If no, the list of action |
| * is not updated according to the current selection, but the toolbar content is refresh even so. |
| * |
| * @param pSelection The current selection for which the actions must be created |
| * @param pUpdateActions If <code>true</code> the list of actions is updated according to the given selection |
| */ |
| protected void addCreateSelectChildActionsToEditorToolbar( |
| final ISelection pSelection, |
| final boolean pUpdateActions) { |
| |
| // Check if the editor provide a custom toolbar manager |
| if (mActiveEditorPart instanceof IToolBarManagerProvider) { |
| // Use a flag to known if the tool bar content have been modified |
| boolean vNeedToUpdate = false; |
| |
| // Get the tool bar manager from the active editor |
| ToolBarManager vEditorToolBarManager = ((IToolBarManagerProvider) mActiveEditorPart).getToolBarManager(); |
| |
| // Depopulate the tool bar with the potential existing create child actions |
| for (IContributionItem vContributionItem : vEditorToolBarManager.getItems()) { |
| // The actions to remove are identified with their id prefix, thus check it |
| if (StringUtils.startsWith( |
| vContributionItem.getId(), |
| ActionBarContributorUtils.CREATECHILD_ACTION_ID_PREFIX)) { |
| |
| // Remove the action |
| vEditorToolBarManager.remove(vContributionItem); |
| vNeedToUpdate = true; |
| } |
| } |
| |
| // Update the list of actions used to create child for the |
| // given selection only if needed |
| if (pUpdateActions) { |
| updateCreateSelectChildActionsCollection(pSelection); |
| } |
| |
| // Then populate the tool bar with the new actions |
| for (IAction vAction : mCreateSelectChildActionsColl) { |
| // Check if the action is not already in the tool bar |
| if (vEditorToolBarManager.find(vAction.getId()) == null) { |
| // Insert the action |
| vEditorToolBarManager.appendToGroup( |
| ActionBarContributorUtils.TOOLBAR_SEP_SELECTION_ACTIONS, |
| vAction); |
| |
| // Remember that the toolbar must be updated |
| vNeedToUpdate = true; |
| } |
| } |
| |
| // Finally, update the toolbar if needed |
| if (vNeedToUpdate) { |
| vEditorToolBarManager.update(true); |
| } |
| } |
| } |
| |
| /** |
| * Generate the list of create child actions corresponding to the selection given in parameter, |
| * and update this instance property {@link #mCreateSelectChildActionsColl} with it. |
| * |
| * The map of menus linked to the created action {@link #mCreateSelectChildMenuActionsMap}, is |
| * also updated. |
| * |
| * @param pSelection The current selection in the active editor |
| */ |
| protected void updateCreateSelectChildActionsCollection(final ISelection pSelection) { |
| |
| Collection<?> vNewChildDescrCollection = null; |
| |
| // Ensure that the selection contains only one element |
| if (pSelection instanceof IStructuredSelection && ((IStructuredSelection) pSelection).size() == 1) { |
| // Get the selected object |
| Object vSelectedObject = ((IStructuredSelection) pSelection).getFirstElement(); |
| |
| // Get the editing domain from the active editor, and then |
| // query the new selection to find the appropriate new child descriptors |
| EditingDomain vEditingDomain = null; |
| if (mActiveEditorPart instanceof IEditingDomainProvider) { |
| vEditingDomain = ((IEditingDomainProvider) mActiveEditorPart).getEditingDomain(); |
| |
| // Find the new child actions corresponding to the selected objects |
| // and the editing domain used in the active editor |
| vNewChildDescrCollection = vEditingDomain.getNewChildDescriptors(vSelectedObject, null); |
| } |
| } |
| |
| // Generate the actions corresponding to the current selection |
| mCreateSelectChildActionsColl = mActionBarContributorUtils.generateCreateChildActionsCollection( |
| mActiveEditorPart, |
| vNewChildDescrCollection, |
| pSelection); |
| |
| // Then update the map menus with the created actions |
| mCreateSelectChildMenuActionsMap = |
| mActionBarContributorUtils.extractSubmenuActions(mCreateSelectChildActionsColl); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * This populates the pop-up menu before it appears with the child creation actions. |
| */ |
| @Override |
| public void menuAboutToShow(final IMenuManager pMenuManager) { |
| // Call the parent method |
| super.menuAboutToShow(pMenuManager); |
| |
| // Create the create child submenu |
| MenuManager vCreateChildSubmenuManager = new MenuManager(ActionBarContributorUtils.CREATECHILD_MENU_LABEL); |
| |
| // Populate the submenu and insert it in the parent menu manager |
| mActionBarContributorUtils.populateManager( |
| vCreateChildSubmenuManager, |
| mCreateSelectChildMenuActionsMap, |
| null); |
| |
| mActionBarContributorUtils.populateManager( |
| vCreateChildSubmenuManager, |
| mCreateSelectChildActionsColl, |
| null); |
| |
| pMenuManager.insertBefore(ActionBarContributorUtils.EDIT_SEPARATOR_ID, vCreateChildSubmenuManager); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| protected void addGlobalActions(final IMenuManager pMenuManager) { |
| |
| // Insert the show properties action after a custom separator for the ui actions |
| pMenuManager.insertAfter( |
| ActionBarContributorUtils.ADDITIONS_END_SEPARATOR_ID, |
| new Separator(ActionBarContributorUtils.UI_ACTIONS_SEPARATOR_ID)); |
| pMenuManager.insertAfter( |
| ActionBarContributorUtils.UI_ACTIONS_SEPARATOR_ID, |
| mShowPropertiesViewAction); |
| |
| // Insert the refresh action, and update its state, after the the ui actions separator |
| mRefreshViewerAction.setEnabled(mRefreshViewerAction.isEnabled()); |
| pMenuManager.insertAfter(ActionBarContributorUtils.UI_ACTIONS_SEPARATOR_ID, mRefreshViewerAction); |
| |
| // Call the parent method to add the others global actions (Validate, etc.) |
| super.addGlobalActions(pMenuManager); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * This implementation ensures that a delete action will clean up all references to deleted objects. |
| */ |
| @Override |
| protected boolean removeAllReferencesOnDelete() { |
| return true; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * Overridden to ensure that the delete action id is set. |
| */ |
| @Override |
| protected DeleteAction createDeleteAction() { |
| // Create the custom action |
| DeleteAction vDeleteAction = new DeleteAction(removeAllReferencesOnDelete()); |
| |
| // Update the action to set its id |
| vDeleteAction.setId(ActionFactory.DELETE.getId()); |
| |
| return vDeleteAction; |
| } |
| |
| /** |
| * Create the expand all action to apply on the active editor, |
| * if this one is a viewer provider. |
| * |
| * @return The expand all action created |
| */ |
| protected IAction createExpandAllAction() { |
| // Get the action image |
| final ImageDescriptor vImageDescriptor = |
| CommonUIActivator.getPlugin().getImageRegistry().getDescriptor( |
| Implementation.ICON_EXPAND_ALL_KEY); |
| |
| // Create the action |
| final IAction vExpandAllAction = new Action( |
| ActionBarContributorUtils.EXPAND_ALL_ACTION_LABEL, |
| vImageDescriptor) { |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public void run() { |
| // Ensure that the active editor is a viewer provider |
| if (mActiveEditorPart instanceof IViewerProvider) { |
| // Get the viewer from the active editor |
| final Viewer vActiveViewer = ((IViewerProvider) mActiveEditorPart).getViewer(); |
| |
| // Check if the viewer is eligible for an expand action |
| if (vActiveViewer instanceof AbstractTreeViewer) { |
| // Prepare the expand action asynchronously, on the UI thread |
| mActiveEditorPart.getSite().getShell().getDisplay().asyncExec(new Runnable() { |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public void run() { |
| // Create the action handler on the viewer |
| final ExpandAllHandler vExpandAllHandler = |
| new ExpandAllHandler((AbstractTreeViewer) vActiveViewer); |
| |
| // And finally execute it |
| vExpandAllHandler.execute(null); |
| } |
| }); |
| } |
| } |
| } |
| }; |
| |
| // Set the unique id for this action |
| vExpandAllAction.setId(ActionBarContributorUtils.EXPAND_ALL_ACTION_ID); |
| |
| return vExpandAllAction; |
| } |
| |
| /** |
| * Create the collapse all action to apply on the active editor, |
| * if this one is a viewer provider. |
| * |
| * @return The collapse all action created |
| */ |
| protected IAction createCollapseAllAction() { |
| // Get the action image |
| final ImageDescriptor vImageDescriptor = |
| CommonUIActivator.getPlugin().getImageRegistry().getDescriptor( |
| Implementation.ICON_COLLAPSE_ALL_KEY); |
| |
| // Create the action |
| final IAction vCollapseAllAction = new Action( |
| ActionBarContributorUtils.COLLAPSE_ALL_ACTION_LABEL, |
| vImageDescriptor) { |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public void run() { |
| // Ensure that the active editor is a viewer provider |
| if (mActiveEditorPart instanceof IViewerProvider) { |
| // Get the viewer from the active editor |
| final Viewer vActiveViewer = ((IViewerProvider) mActiveEditorPart).getViewer(); |
| |
| // Check if the viewer is eligible for an expand action |
| if (vActiveViewer instanceof AbstractTreeViewer) { |
| // Prepare the expand action asynchronously, on the UI thread |
| mActiveEditorPart.getSite().getShell().getDisplay().asyncExec(new Runnable() { |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public void run() { |
| // Create the action handler on the viewer |
| final CollapseAllHandler vCollapseAllHandler = |
| new CollapseAllHandler((AbstractTreeViewer) vActiveViewer); |
| |
| // And finally execute it |
| vCollapseAllHandler.execute(null); |
| } |
| }); |
| } |
| } |
| } |
| }; |
| |
| // Set the unique id for this action |
| vCollapseAllAction.setId(ActionBarContributorUtils.COLLAPSE_ALL_ACTION_ID); |
| |
| return vCollapseAllAction; |
| } |
| |
| } |