/******************************************************************************* * Copyright (c) 2010, 2011 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 *******************************************************************************/ package org.simantics.browsing.ui.model.actions; import gnu.trove.map.hash.THashMap; import gnu.trove.set.hash.THashSet; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.jface.action.Action; import org.simantics.browsing.ui.BuiltinKeys; import org.simantics.browsing.ui.NodeContext; import org.simantics.browsing.ui.model.InvalidContribution; import org.simantics.browsing.ui.model.browsecontexts.BrowseContexts; import org.simantics.browsing.ui.model.browsecontexts.ResolveActionBrowseContext; import org.simantics.browsing.ui.model.nodetypes.EntityNodeType; import org.simantics.browsing.ui.model.nodetypes.NodeType; import org.simantics.browsing.ui.model.nodetypes.NodeTypeMultiMap; import org.simantics.browsing.ui.model.nodetypes.SpecialNodeType; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.exception.DatabaseException; import org.simantics.viewpoint.ontology.ViewpointResource; /** * ActionBrowseContext holds all contributions related to given set of action browse contexts. * * @author Hannu Niemistö */ public class ActionBrowseContext { NodeTypeMultiMap actionContributions = new NodeTypeMultiMap(); // TODO: remove these two temporary mechanisms THashSet removableNodeTypes = new THashSet(); THashSet renameableNodeTypes = new THashSet(); NodeTypeMultiMap removalContributions = new NodeTypeMultiMap(); NodeTypeMultiMap renamingContributions = new NodeTypeMultiMap(); private final String[] uris; private ActionBrowseContext(String[] uris) { if (uris == null) throw new NullPointerException("null URIs"); this.uris = uris; } public String[] getURIs() { return uris; } public static ActionBrowseContext get(ReadGraph graph,NodeContext context,ActionBrowseContext defaultContext) throws DatabaseException { ActionBrowseContext mbc = graph.syncRequest(new ResolveActionBrowseContext(context)); if(mbc != null) return mbc; ActionBrowseContext parentContext = (ActionBrowseContext)context.getConstant(BuiltinKeys.ACTION_BROWSE_CONTEXT); if(parentContext != null) return parentContext; return defaultContext; } public static ActionBrowseContext create(ReadGraph g, Collection browseContextResources) throws DatabaseException, InvalidContribution { ViewpointResource vr = ViewpointResource.getInstance(g); ActionBrowseContext browseContext = new ActionBrowseContext( BrowseContexts.toSortedURIs(g, browseContextResources) ); for(Resource browseContextResource : findSubcontexts(g, browseContextResources)) { for(Resource actionContributionResource : g.getObjects(browseContextResource, vr.BrowseContext_HasActionContribution)) { try { ActionContribution.load(g, actionContributionResource, browseContext.actionContributions ); } catch(DatabaseException e) { e.printStackTrace(); } } for(Resource canRemove : g.getObjects(browseContextResource, vr.BrowseContext_SupportsRemovalOf)) browseContext.removableNodeTypes.add(canRemove); for(Resource canRemove : g.getObjects(browseContextResource, vr.BrowseContext_SupportsRenamingOf)) browseContext.renameableNodeTypes.add(canRemove); for (Resource testContribution : g.getObjects(browseContextResource, vr.BrowseContext_HasTestContribution)) { try { Set types = g.getTypes(testContribution); if (types.contains(vr.RemovalTestContribution)) TestContribution.load(g, testContribution, browseContext.removalContributions); if (types.contains(vr.RenamingTestContribution)) TestContribution.load(g, testContribution, browseContext.renamingContributions); } catch (DatabaseException e) { e.printStackTrace(); } } } return browseContext; } private static Collection findSubcontexts(ReadGraph g, Collection browseContexts) throws DatabaseException { ViewpointResource vr = ViewpointResource.getInstance(g); HashSet result = new HashSet(browseContexts); ArrayList stack = new ArrayList(browseContexts); while(!stack.isEmpty()) { Resource cur = stack.remove(stack.size()-1); for(Resource sc : g.getObjects(cur, vr.BrowseContext_Includes)) if(result.add(sc)) stack.add(sc); } return result; } private static NodeType getNodeType(ReadGraph graph, NodeContext parent) throws DatabaseException { NodeType nodeType = parent.getConstant(NodeType.TYPE); if(nodeType == null) { // TODO remove this code when root of model browser is fixed Object input = parent.getConstant(BuiltinKeys.INPUT); if(input instanceof Resource) nodeType = EntityNodeType.getNodeTypeFor(graph, (Resource)input); } return nodeType; } public Map> getActions(ReadGraph graph, NodeContext parent, Collection all) throws DatabaseException { NodeType nodeType = getNodeType(graph, parent); if(nodeType == null) return Collections.emptyMap(); THashMap> map = new THashMap>(); for(ActionContribution contribution : actionContributions.get(graph, nodeType)) { CategorizedAction action = contribution.getAction(graph, parent, all); if(action != null) { List actions = map.get(action.category); if(actions == null) { actions = new ArrayList(); map.put(action.category, actions); } actions.add(action.action); } } return map; } @Override public int hashCode() { return Arrays.hashCode(uris); } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; ActionBrowseContext other = (ActionBrowseContext) obj; return Arrays.equals(uris, other.uris); } @Override public String toString() { return getClass().getSimpleName() + Arrays.toString(uris); } /* * This is an attempt to improve removal logic with SpecialNodeTypes. However it * should not be considered as a final solution. */ public boolean canRemove(ReadGraph graph, NodeContext parent) throws DatabaseException { return testContributions(graph, parent, removalContributions, removableNodeTypes); } /* * This is an attempt to improve renaming logic with SpecialNodeTypes. However it * should not be considered as a final solution. */ public boolean canRename(ReadGraph graph, NodeContext parent) throws DatabaseException { return testContributions(graph, parent, renamingContributions, renameableNodeTypes); } private boolean testContributions( ReadGraph graph, NodeContext parent, NodeTypeMultiMap contributions, Set allowedSpecialTypes) throws DatabaseException { NodeType nodeType = getNodeType(graph, parent); if (nodeType == null) // Return true for now if node type is not available // to prevent older and more custom solutions such as // property view tables from breaking up. return true; // TODO: this is a previous temporary solution that should probably be removed if (nodeType instanceof SpecialNodeType && allowedSpecialTypes.contains(((SpecialNodeType) nodeType).resource)) return true; for (TestContribution contribution : contributions.get(graph, nodeType)) { if (!contribution.test(graph, parent)) return false; } return true; } }