/******************************************************************************* * Copyright (c) 2011, 2016 Association for Decentralized Information Management * in Industry THTH ry. * 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: * VTT Technical Research Centre of Finland - initial API and implementation * Semantum Oy - refactoring *******************************************************************************/ package org.simantics.modeling.ui.actions; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExecutableExtension; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.ActionContributionItem; import org.eclipse.jface.action.IContributionItem; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.osgi.util.NLS; import org.simantics.browsing.ui.NodeContext; import org.simantics.browsing.ui.common.NodeContextBuilder; import org.simantics.browsing.ui.model.InvalidContribution; import org.simantics.browsing.ui.model.actions.ActionBrowseContext; import org.simantics.browsing.ui.model.actions.IActionCategory; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.exception.DatabaseException; import org.simantics.issues.common.IssueUtils; import org.simantics.modeling.ui.Activator; import org.simantics.project.ontology.ProjectResource; import org.simantics.ui.contribution.DynamicMenuContribution; import org.simantics.ui.selection.WorkbenchSelectionUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ModeledActions extends DynamicMenuContribution implements IExecutableExtension { private static final Logger LOGGER = LoggerFactory.getLogger(IssueUtils.class); public static final Set defaultBrowseContexts = Collections.singleton(ProjectResource.URIs.ProjectActionContext); protected Set browseContexts = defaultBrowseContexts; public static final Comparator ACTION_COMPARATOR = new Comparator() { @Override public int compare(Action o1, Action o2) { String t1 = o1.getText(); String t2 = o2.getText(); if(t1 == null) { if(t2 == null) return 0; else return -1; } else { if(t2 == null) return 1; else return t1.compareTo(t2); } } }; @Override public void setInitializationData(IConfigurationElement config, String propertyName, Object data) throws CoreException { if(data instanceof String) { String str = (String)data; String[] parms = str.split(";"); //$NON-NLS-1$ for(String parm : parms) { String[] keyValue = parm.split("="); //$NON-NLS-1$ if(keyValue.length == 2) { String key = keyValue[0].trim(); if("context".equals(key)) { //$NON-NLS-1$ browseContexts = Collections.singleton(keyValue[1]); } } } } } protected Collection getBrowseContexts() { return browseContexts; } protected Collection getBrowseContextResources(ReadGraph graph) throws DatabaseException { Collection names = getBrowseContexts(); ArrayList result = new ArrayList<>(names.size()); for(String name : names) result.add(graph.getResource(name)); return result; } protected List getContexts(Object[] selection) { if (selection.length == 0) return Collections.emptyList(); ArrayList result = new ArrayList<>(selection.length); for (Object o : selection) { if ((o instanceof IAdaptable)) { NodeContext nodeContext = ((IAdaptable) o).getAdapter(NodeContext.class); if (nodeContext != null) { result.add(nodeContext); continue; } } try { Resource res = WorkbenchSelectionUtils.getPossibleResource(o); if(res != null) { result.add(NodeContextBuilder.buildWithInput(res)); } } catch (DatabaseException e) { LOGGER.error("Failed to get node contexts for selection.", e); //$NON-NLS-1$ } } return result; } protected List getContexts(ReadGraph graph, Object[] selection) throws DatabaseException { return getContexts(selection); } protected static IContributionItem[] toContributionItems(Map> map) { if (map.isEmpty()) return NONE; IActionCategory[] categories = map.keySet().toArray(new IActionCategory[map.size()]); Arrays.sort(categories, IActionCategory.ACTION_CATEGORY_COMPARATOR); ArrayList items = new ArrayList(); boolean first = true; for (IActionCategory category : categories) { List actions = map.get(category); Collections.sort(actions, ACTION_COMPARATOR); if (category != null && category.isSubmenu()) { MenuManager manager = new MenuManager(category.getLabel()); for (Action action : actions) manager.add(new ActionContributionItem(action)); items.add(manager); } else { if (first) first = false; else items.add(new Separator(category == null ? "" : category.getLabel())); //$NON-NLS-1$ for (Action action : actions) items.add(new ActionContributionItem(action)); } } return items.toArray(new IContributionItem[items.size()]); } @Override protected Object[] getSelectedObjects() { Object[] sel = super.getSelectedObjects(); List contexts = getContexts(sel); return contexts.toArray(NodeContext.NONE); } @Override protected IContributionItem[] getContributionItems(ReadGraph graph, Object[] selection) throws DatabaseException { List contexts = Arrays.asList((NodeContext[]) selection); if (contexts.isEmpty()) return NONE; try { NodeContext nodeContext = contexts.get(0); ActionBrowseContext defaultContext = ActionBrowseContext.create(graph, getBrowseContextResources(graph)); ActionBrowseContext browseContext = ActionBrowseContext.get(graph, nodeContext, defaultContext); Map> result = browseContext.getActions(graph, nodeContext, contexts); Map> current = result; for (int i = 1; i < contexts.size(); i++) { browseContext = ActionBrowseContext.get(graph, nodeContext, defaultContext); Map> m = browseContext.getActions(graph, contexts.get(i), contexts); result = new HashMap<>(); for (Map.Entry> entry : m.entrySet()) { List exist = current.get(entry.getKey()); if (exist == null) continue; ArrayList l = new ArrayList(); for (Action e : exist) { String id = e.getId(); boolean found = false; for (Action a : entry.getValue()) { if (id.equals(a.getId())) { found = true; break; } } if (found) l.add(e); } if (!l.isEmpty()) result.put(entry.getKey(), l); } current = result; } return toContributionItems(result); } catch (InvalidContribution e) { Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, NLS.bind(Messages.ModeledActions_ActivatorInvalidContributionsEncounteredIn, getClass().getSimpleName()), e)); } return NONE; } }