/******************************************************************************* * Copyright (c) 2009 Obeo. * 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: * Obeo - initial API and implementation * Emilien Perico - use extension point to define dynamically registered actions *******************************************************************************/ package org.eclipse.papyrus.views.modelexplorer.actionprovider; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.Platform; import org.eclipse.emf.transaction.TransactionalEditingDomain; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.ActionContributionItem; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.papyrus.infra.core.utils.EditorUtils; import org.eclipse.papyrus.views.modelexplorer.factory.IActionHandlerFactory; import org.eclipse.ui.IActionBars; import org.eclipse.ui.navigator.CommonNavigator; import org.eclipse.ui.navigator.ICommonActionExtensionSite; import org.osgi.framework.Bundle; /** * Provider used to create actions applicable on semantic elements * * @author <a href="mailto:jerome.benois@obeo.fr">Jerome Benois</a> * @author Emilien Perico - see extension point * org.eclipse.papyrus.navigator.actionHandler to add specific action */ public class EditingDomainActionProvider extends AbstractSubmenuActionProvider { public static final String ACTION_HANDLER_EXTENSION_POINT_ID = "org.eclipse.papyrus.views.modelexplorer.actionHandler"; protected CommonNavigator activeViewPart; protected Map<IActionHandlerFactory, ActionProperties> actionsFactoriesMap; /** * {@inheritDoc} */ @Override public void init(ICommonActionExtensionSite site) { super.init(site); this.activeViewPart = getCommonNavigator(); this.actionsFactoriesMap = new HashMap<IActionHandlerFactory, ActionProperties>(); TransactionalEditingDomain editingDomain = EditorUtils.getTransactionalEditingDomain(); IConfigurationElement[] registry = Platform.getExtensionRegistry().getConfigurationElementsFor(ACTION_HANDLER_EXTENSION_POINT_ID); for(IConfigurationElement elt : registry) { try { final String actionId = elt.getAttribute("actionId"); final String afterAction = elt.getAttribute("afterAction"); boolean needSeparator = Boolean.valueOf(elt.getAttribute("needSeparator")); ActionProperties properties = new ActionProperties(actionId, afterAction, needSeparator); IActionHandlerFactory factory = (IActionHandlerFactory)createExtension(elt, elt.getAttribute("actionHandler")); // create registered actions factory.createActions(editingDomain); actionsFactoriesMap.put(factory, properties); } catch (Exception exception) { exception.printStackTrace(); } } } /** * {@inheritDoc} */ @Override public void fillActionBars(IActionBars actionBars) { super.fillActionBars(actionBars); for(IActionHandlerFactory factory : actionsFactoriesMap.keySet()) { factory.fillActionBars(actionBars); } } /** * Load an instance of a class * * @param element * the extension point * @param classAttribute * the name of the class to load * @return the loaded Class * @throws Exception * if the class is not loaded */ @SuppressWarnings("rawtypes") private static Object createExtension(final IConfigurationElement element, final String classAttribute) throws Exception { try { Bundle extensionBundle = Platform.getBundle(element.getDeclaringExtension().getNamespaceIdentifier()); Class clazz = extensionBundle.loadClass(classAttribute); Object obj = clazz.newInstance(); return obj; // return element.createExecutableExtension(classAttribute); } catch (Exception e) { throw new Exception("unable to create Extension " + e); } } /** * {@inheritDoc} */ @Override public void fillContextMenu(IMenuManager menu) { update(); // sort factories from "afterAction" property List<IActionHandlerFactory> sortedFactories = sortFactories(actionsFactoriesMap); // Add the edit menu actions for(IActionHandlerFactory factory : sortedFactories) { ActionProperties actionProperties = actionsFactoriesMap.get(factory); if(actionProperties != null && actionProperties.isNeedSeparator()) { menu.add(new Separator()); } for(Action action : factory.getActions()) { menu.add(new ActionContributionItem(action)); } } activate(); } /** * Update actions */ public void update() { ISelection selection = getCommonNavigator().getCommonViewer().getSelection(); IStructuredSelection structuredSelection = StructuredSelection.EMPTY; if(selection instanceof IStructuredSelection) { structuredSelection = (IStructuredSelection)selection; } for(IActionHandlerFactory factory : actionsFactoriesMap.keySet()) { factory.update(structuredSelection); } } /** * Activate actions */ public void activate() { for(IActionHandlerFactory factory : actionsFactoriesMap.keySet()) { factory.activate(activeViewPart); } update(); } /** * Deactivate actions */ // @unused public void deactivate() { for(IActionHandlerFactory factory : actionsFactoriesMap.keySet()) { factory.deactivate(activeViewPart); } } /** * {@inheritDoc} */ @Override public void updateActionBars() { super.updateActionBars(); activate(); update(); } /** * Sort factories. * * @param actionsFactoriesMap * the actions factories map * * @return the sorted list of factories */ private List<IActionHandlerFactory> sortFactories(final Map<IActionHandlerFactory, ActionProperties> actionsFactoriesMap) { List<IActionHandlerFactory> factories = new ArrayList<IActionHandlerFactory>(actionsFactoriesMap.keySet()); Collections.sort(factories, new Comparator<IActionHandlerFactory>() { public int compare(IActionHandlerFactory factory1, IActionHandlerFactory factory2) { ActionProperties properties1 = getDefaultForNull(actionsFactoriesMap.get(factory1)); ActionProperties properties2 = getDefaultForNull(actionsFactoriesMap.get(factory2)); String after1 = properties1.getAfterAction(); String after2 = properties2.getAfterAction(); if(properties1.getActionId().equals(properties2.getActionId())) { return 0; } else if(properties1.getActionId().equals(after2)) { return -1; } else if(properties2.getActionId().equals(after1)) { return 1; } else if(after1 == null) { return -1; } else if(after2 == null) { return 1; } return 0; } private ActionProperties getDefaultForNull(ActionProperties actionProperties) { if(actionProperties == null) { actionProperties = new ActionProperties("", "", false); } return actionProperties; } }); return factories; } /** * The Class ActionProperties to store properties for a registered action * from extension point org.eclipse.papyrus.navigator.actionHandler */ private class ActionProperties { private final String actionId; private final String afterAction; private final boolean needSeparator; /** * @param actionId * @param afterAction * @param needSeparator */ // @unused public ActionProperties(String actionId, String afterAction, boolean needSeparator) { super(); this.actionId = actionId; this.afterAction = afterAction; this.needSeparator = needSeparator; } /** * @return the actionId */ public String getActionId() { return actionId; } /** * @return the afterAction */ public String getAfterAction() { return afterAction; } /** * @return the needSeparator */ public boolean isNeedSeparator() { return needSeparator; } } }