blob: 4551acd18687a76bd881746689898174eff7b227 [file] [log] [blame]
/**
* <copyright>
*
* Copyright (c) 2008-2010 See4sys and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
*
* Contributors:
* See4sys - Initial API and implementation
*
* </copyright>
*/
package org.eclipse.sphinx.emf.ui.actions.providers;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.StringTokenizer;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.jface.action.ActionContributionItem;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IContributionItem;
import org.eclipse.jface.action.IContributionManager;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.SubContributionItem;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.osgi.util.NLS;
import org.eclipse.sphinx.emf.edit.TransientItemProvider;
import org.eclipse.sphinx.emf.messages.EMFMessages;
import org.eclipse.sphinx.emf.ui.internal.Activator;
import org.eclipse.sphinx.emf.util.WorkspaceEditingDomainUtil;
import org.eclipse.sphinx.platform.ui.util.SelectionUtil;
import org.eclipse.sphinx.platform.util.PlatformLogUtil;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.navigator.CommonActionProvider;
import org.eclipse.ui.navigator.CommonNavigator;
import org.eclipse.ui.navigator.ICommonActionExtensionSite;
import org.eclipse.ui.navigator.ICommonViewerSite;
import org.eclipse.ui.navigator.ICommonViewerWorkbenchSite;
import org.eclipse.ui.views.properties.PropertySheet;
/**
* Basic implementation of {@linkplain CommonActionProvider action provider} that provides default implementations for
* initialization and for filling (and emptying) the menu managed by this action provider.
* <p>
* Initialization is ensured by the method {@linkplain #init(ICommonActionExtensionSite)} that is not supposed to
* overridden by client implementations (override {@linkplain #doInit()} instead).
* <p>
* Filling and emptying contextual menu (maintained by {@linkplain IContributionManager manager}) with
* {@linkplain IAction action}s are respectively supported by
* {@linkplain #populateManager(IContributionManager, Collection, String)} and
* {@linkplain #depopulateManager(IContributionManager, Collection)}.
*/
public class BasicActionProvider extends CommonActionProvider {
protected IWorkbenchPart workbenchPart;
protected Viewer viewer;
protected String viewerId;
protected ISelectionProvider selectionProvider;
/*
* Clients should avoid overriding this method; providing an implementation of doInit() is preferable.
* @see org.eclipse.ui.navigator.CommonActionProvider#init(org.eclipse.ui.navigator.ICommonActionExtensionSite)
*/
@Override
public final void init(ICommonActionExtensionSite site) {
super.init(site);
// Assume that action provider is only used in workbench parts but not in dialogs
ICommonViewerSite viewSite = site.getViewSite();
if (viewSite instanceof ICommonViewerWorkbenchSite) {
ICommonViewerWorkbenchSite workbenchSite = (ICommonViewerWorkbenchSite) viewSite;
// Retrieve underlying viewer and selection provider
workbenchPart = workbenchSite.getPart();
if (workbenchPart instanceof CommonNavigator) {
CommonNavigator navigator = (CommonNavigator) workbenchPart;
viewer = navigator.getCommonViewer();
selectionProvider = navigator.getCommonViewer();
} else {
selectionProvider = workbenchSite.getSelectionProvider();
}
// Retrieve underlying viewer id
viewerId = workbenchSite.getId();
doInit();
}
}
/*
* @see org.eclipse.ui.actions.ActionGroup#fillContextMenu(org.eclipse.jface.action.IMenuManager)
*/
@Override
public void fillContextMenu(IMenuManager contextMenuManager) {
// Retrieve sub menu
IMenuManager subMenuManager = addSubMenu(contextMenuManager);
// Fill sub menu
fillSubMenu(subMenuManager != null ? subMenuManager : contextMenuManager);
}
/**
* Method to override in order to provide a custom initialization of this {@linkplain BasicActionProvider action
* provider}.
*/
protected void doInit() {
// Do nothing by default
}
/**
* Returns true when the property sheet is the current active page.
*
* @return as specified above.
*/
protected boolean isActivePropertySheet() {
IWorkbenchPart activePart = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActivePart();
return activePart instanceof PropertySheet;
}
/**
* Returns the {@link IMenuManager sub menu} into which the {@linkplain org.eclipse.jface.action.IAction action}s
* provided by this {@link BasicActionProvider action provider} implementation are to be placed. Creates a new
* {@link IMenuManager sub menu} and appends it to specified {@link IMenuManager context menu} if no such is present
* yet. Returns <code>null</code> if the {@linkplain org.eclipse.jface.action.IAction action}s should go directly
* into the {@link IMenuManager context menu}. The default implementation returns <code>null</code>. Subclasses may
* override or extend this method.
*
* @param contextMenuManager
* The {@link IMenuManager context menu} for which the {@link IMenuManager sub menu} is to be retrieved
* or created.
* @return The {@link IMenuManager sub menu} into which the {@linkplain org.eclipse.jface.action.IAction action}s
* provided by this {@link BasicActionProvider action provider} implementation are to be placed or
* <code>null</code> if they should go directly into the {@link IMenuManager context menu}.
* @see #fillSubMenu(IMenuManager)
*/
protected IMenuManager addSubMenu(IMenuManager contextMenuManager) {
return null;
}
/**
* Adds the applicable {@linkplain org.eclipse.jface.action.IAction action}s to the {@link IMenuManager sub menu} of
* the {@link IMenuManager context menu} resulting from previous invocation of {@link #addSubMenu(IMenuManager)}.
* The default implementation does nothing. Subclasses may override or extend this method.
*
* @param subMenu
* The {@link IMenuManager sub menu} to which applicable {@linkplain org.eclipse.jface.action.IAction
* action}s are to be added.
* @see #addSubMenu(IMenuManager)
*/
protected void fillSubMenu(IMenuManager subMenuManager) {
// Do nothing by default
}
/**
* A convenience method to get the editing domain from an {@link ISelection}. This method will return null in
* different cases :
* <ul>
* <li>selection isn't instance of {@link IStructuredSelection}.
* <li>selection is empty.
* <li>selection contains unresolved model element(s).
* <li>selection contains model elements which belong to more than one editing domain (In case of multi-selection).
* </ul>
* <p>
*
* @since 0.7.0
* @param selection
* @return the editing domain from the selected model objects or null in either empty selection or when the selected
* model objects belong to more than one editing domain.
*/
protected TransactionalEditingDomain getEditingDomainFromSelection(ISelection selection) {
if (selection instanceof IStructuredSelection) {
IStructuredSelection structuredSelection = (IStructuredSelection) selection;
if (!structuredSelection.isEmpty()) {
TransactionalEditingDomain previousEditingDomain = null;
TransactionalEditingDomain currentEditingDomain = null;
for (Object seletedObject : structuredSelection.toList()) {
if (seletedObject instanceof EObject && ((EObject) seletedObject).eIsProxy()) {
PlatformLogUtil.logAsWarning(Activator.getPlugin(),
new RuntimeException(NLS.bind(EMFMessages.warning_selectionContainsUnresolvedModelElement, seletedObject)));
}
currentEditingDomain = WorkspaceEditingDomainUtil.getEditingDomain(seletedObject);
if (currentEditingDomain == null) {
return null;
} else if (previousEditingDomain == null) {
previousEditingDomain = currentEditingDomain;
} else if (!previousEditingDomain.equals(currentEditingDomain)) {
return null;
}
}
return currentEditingDomain;
}
}
return null;
}
/**
* Populates the specified {@link IContributionManager manager} with
* {@linkplain org.eclipse.jface.action.ActionContributionItem contribution item}s based on the
* {@linkplain org.eclipse.jface.action.IAction action}s contained in the <code>actions</code> collection, by
* inserting them before the specified contribution item <code>contributionId</code>.<br>
* If <code>contributionId</code> is <code>null</code>, they are simply added.
*
* @param manager
* The {@linkplain IContributionManager contribution manager} to which specified {@linkplain IAction
* action}s must be populated.
* @param actions
* The {@linkplain IAction action}s to insert in the menu described by the given
* {@link IContributionManager manager}.
* @param contributionId
* The identifier of the contribution before which actions must be inserted.
*/
protected void populateManager(IContributionManager manager, Collection<? extends IAction> actions, String contributionId) {
if (actions != null) {
for (IAction action : actions) {
if (contributionId != null) {
manager.insertBefore(contributionId, action);
} else {
manager.add(action);
}
}
}
}
/**
* This populates the specified <code>manager</code> with {@link org.eclipse.jface.action.MenuManager}s containing
* {@link org.eclipse.jface.action.ActionContributionItem}s based on the {@link org.eclipse.jface.action.IAction}s
* contained in the <code>submenuActions</code> collection, by inserting them before the specified contribution item
* <code>contributionId</code>. If <code>contributionId</code> is <code>null</code>, they are simply added.
*
* @param manager
* The {@linkplain IContributionManager contribution manager} to which specified {@linkplain IAction
* action}s must be populated.
* @param submenuActions
* The {@linkplain IAction submenu actions}s to insert in the menu described by the given
* {@link IContributionManager manager}.
* @param contributionId
* The identifier of the contribution before which actions must be inserted.
* @since 0.7.0
*/
protected void populateManager(IContributionManager manager, Map<String, Collection<IAction>> submenuActions, String contributionId) {
if (submenuActions != null) {
for (Map.Entry<String, Collection<IAction>> entry : submenuActions.entrySet()) {
MenuManager submenuManager = new MenuManager(entry.getKey());
if (contributionId != null) {
manager.insertBefore(contributionId, submenuManager);
} else {
manager.add(submenuManager);
}
populateManager(submenuManager, entry.getValue(), null);
}
}
}
/**
* Removes from the specified {@link IContributionManager manager} all
* {@linkplain org.eclipse.jface.action.ActionContributionItem contribution item}s based on the
* {@linkplain org.eclipse.jface.action.IAction action}s contained in the <code>actions</code> collection.
*
* @param manager
* The {@linkplain IContributionManager contribution manager} from which specified {@linkplain IAction
* action}s must be removed.
* @param actions
* The {@linkplain IAction action}s to remove from the menu described by the given
* {@link IContributionManager manager}.
*/
protected void depopulateManager(IContributionManager manager, Collection<? extends IAction> actions) {
if (actions != null) {
IContributionItem[] items = manager.getItems();
for (IContributionItem contributionItem : items) {
while (contributionItem instanceof SubContributionItem) {
contributionItem = ((SubContributionItem) contributionItem).getInnerItem();
}
// Delete the ActionContributionItems with matching action
if (contributionItem instanceof ActionContributionItem) {
IAction action = ((ActionContributionItem) contributionItem).getAction();
if (actions.contains(action)) {
manager.remove(contributionItem);
}
}
}
}
}
/**
* This removes from the specified <code>manager</code> all {@link org.eclipse.jface.action.MenuManager}s and their
* {@link org.eclipse.jface.action.ActionContributionItem}s based on the {@link org.eclipse.jface.action.IAction}s
* contained in the <code>submenuActions</code> map.
*
* @param manager
* The {@linkplain IContributionManager contribution manager} from which specified {@linkplain IAction
* action}s must be removed.
* @param submenuActions
* The {@linkplain IAction submenu actions}s to remove from the menu described by the given
* {@link IContributionManager manager}.
* @since 0.7.0
*/
protected void depopulateManager(IContributionManager manager, Map<String, Collection<IAction>> submenuActions) {
if (submenuActions != null) {
IContributionItem[] items = manager.getItems();
for (IContributionItem contributionItem : items) {
if (contributionItem instanceof MenuManager) {
MenuManager submenuManager = (MenuManager) contributionItem;
if (submenuActions.containsKey(submenuManager.getMenuText())) {
depopulateManager(submenuManager, submenuActions.get(contributionItem));
manager.remove(contributionItem);
}
}
}
}
}
/**
* This extracts those actions in the <code>submenuActions</code> collection whose text is qualified and returns a
* map of these actions, keyed by submenu text (see GenModel option "Editor > Creation Sub-menus" for details).
*
* @since 0.7.0
*/
protected Map<String, Collection<IAction>> extractSubmenuActions(Collection<IAction> createActions, ISelection selection) {
Map<String, Collection<IAction>> createSubmenuActions = new LinkedHashMap<String, Collection<IAction>>();
if (createActions != null) {
for (Iterator<IAction> actions = createActions.iterator(); actions.hasNext();) {
IAction action = actions.next();
if (action.getText() != null) {
StringTokenizer st = new StringTokenizer(action.getText(), "|"); //$NON-NLS-1$
if (st.countTokens() == 2) {
String text = st.nextToken().trim();
IStructuredSelection structuredSelection = SelectionUtil.getStructuredSelection(selection);
if (isTransient(structuredSelection.getFirstElement())) {
// Suppress submenus if we are on an intermediate category node
action.setText(st.nextToken().trim());
} else {
// Decompose qualified action label in to submenu item and simple action text
Collection<IAction> submenuActions = createSubmenuActions.get(text);
if (submenuActions == null) {
createSubmenuActions.put(text, submenuActions = new ArrayList<IAction>());
}
action.setText(st.nextToken().trim());
submenuActions.add(action);
actions.remove();
}
}
}
}
}
return createSubmenuActions;
}
/**
* Returns true if the given object is a transient item provider i.e. an intermediary node, false else.
*
* @param object
* an object.
* @return true if the given object is a transient item provider i.e. an intermediary node, false else.
*/
protected boolean isTransient(Object object) {
if (object instanceof TransientItemProvider) {
return true;
}
return false;
}
}