X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.browsing.ui.model%2Fsrc%2Forg%2Fsimantics%2Fbrowsing%2Fui%2Fmodel%2Fbrowsecontexts%2FBrowseContext.java;fp=bundles%2Forg.simantics.browsing.ui.model%2Fsrc%2Forg%2Fsimantics%2Fbrowsing%2Fui%2Fmodel%2Fbrowsecontexts%2FBrowseContext.java;h=50281f20dc4e1287ea502145175029c7b31666ec;hb=969bd23cab98a79ca9101af33334000879fb60c5;hp=0000000000000000000000000000000000000000;hpb=866dba5cd5a3929bbeae85991796acb212338a08;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.browsing.ui.model/src/org/simantics/browsing/ui/model/browsecontexts/BrowseContext.java b/bundles/org.simantics.browsing.ui.model/src/org/simantics/browsing/ui/model/browsecontexts/BrowseContext.java new file mode 100644 index 000000000..50281f20d --- /dev/null +++ b/bundles/org.simantics.browsing.ui.model/src/org/simantics/browsing/ui/model/browsecontexts/BrowseContext.java @@ -0,0 +1,498 @@ +/******************************************************************************* + * 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.browsecontexts; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.simantics.browsing.ui.BuiltinKeys; +import org.simantics.browsing.ui.CheckedState; +import org.simantics.browsing.ui.NodeContext; +import org.simantics.browsing.ui.common.ColumnKeys; +import org.simantics.browsing.ui.common.NodeContextBuilder; +import org.simantics.browsing.ui.content.CompositeImageDecorator; +import org.simantics.browsing.ui.content.CompositeLabelDecorator; +import org.simantics.browsing.ui.content.ImageDecorator; +import org.simantics.browsing.ui.content.LabelDecorator; +import org.simantics.browsing.ui.content.Labeler.Modifier; +import org.simantics.browsing.ui.model.InvalidContribution; +import org.simantics.browsing.ui.model.actions.ActionBrowseContext; +import org.simantics.browsing.ui.model.check.CheckedStateContribution; +import org.simantics.browsing.ui.model.children.ChildContribution; +import org.simantics.browsing.ui.model.imagedecorators.ImageDecorationContribution; +import org.simantics.browsing.ui.model.images.ImageContribution; +import org.simantics.browsing.ui.model.labeldecorators.LabelDecorationContribution; +import org.simantics.browsing.ui.model.labels.LabelContribution; +import org.simantics.browsing.ui.model.modifiers.ModifierContribution; +import org.simantics.browsing.ui.model.modifiers.NoModifierRule; +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.OrderedNodeTypeMultiMap; +import org.simantics.browsing.ui.model.nodetypes.SpecialNodeType; +import org.simantics.browsing.ui.model.sorters.AlphanumericSorter; +import org.simantics.browsing.ui.model.sorters.Sorter; +import org.simantics.browsing.ui.model.sorters.SorterContribution; +import org.simantics.browsing.ui.model.visuals.FlatNodeContribution; +import org.simantics.browsing.ui.model.visuals.VisualsContribution; +import org.simantics.db.ReadGraph; +import org.simantics.db.RequestProcessor; +import org.simantics.db.Resource; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.exception.ResourceNotFoundException; +import org.simantics.db.layer0.variable.Variable; +import org.simantics.db.request.Read; +import org.simantics.graphviz.Graph; +import org.simantics.graphviz.Node; +import org.simantics.graphviz.ui.GraphvizComponent; +import org.simantics.scl.reflection.OntologyVersions; +import org.simantics.viewpoint.ontology.ViewpointResource; + +/** + * BrowseContext holds all contributions related to given set of browse contexts. + * + * @author Hannu Niemistö + */ +public class BrowseContext { + + public static final boolean DEBUG = false; + + NodeTypeMultiMap childContributions = new NodeTypeMultiMap(); + NodeTypeMultiMap parentContributions = new NodeTypeMultiMap(); + OrderedNodeTypeMultiMap labelContributions = new OrderedNodeTypeMultiMap(); + OrderedNodeTypeMultiMap imageContributions = new OrderedNodeTypeMultiMap(); + OrderedNodeTypeMultiMap checkedStateContributions = new OrderedNodeTypeMultiMap(); + OrderedNodeTypeMultiMap labelDecorationContributions = new OrderedNodeTypeMultiMap(); + OrderedNodeTypeMultiMap imageDecorationContributions = new OrderedNodeTypeMultiMap(); + OrderedNodeTypeMultiMap modifierContributions = new OrderedNodeTypeMultiMap(); + OrderedNodeTypeMultiMap sorterContributions = new OrderedNodeTypeMultiMap(); + OrderedNodeTypeMultiMap flatNodeContributions = new OrderedNodeTypeMultiMap(); + + private final String[] uris; + + private BrowseContext(String[] uris) { + if (uris == null) + throw new NullPointerException("null URIs"); + this.uris = uris; + } + + public String[] getURIs() { + return uris; + } + + public static BrowseContext get(ReadGraph graph,NodeContext context,BrowseContext defaultContext, boolean useNodeBrowseContexts) throws DatabaseException { + if(!useNodeBrowseContexts) return defaultContext; + BrowseContext mbc = graph.syncRequest(new ResolveBrowseContext(context)); + if(mbc != null) return mbc; + BrowseContext parentContext = (BrowseContext)context.getConstant(BuiltinKeys.BROWSE_CONTEXT); + if(parentContext != null) return parentContext; + return defaultContext; + } + + /** + * Creates a new BrowseContext for the given Collection of {@link Resource}s. + * + * @param g + * @param browseContextResources + * @return new BrowseContext + * @throws DatabaseException + * @throws InvalidContribution + */ + public static BrowseContext create(ReadGraph g, Collection browseContextResources) throws DatabaseException, InvalidContribution { + ViewpointResource vr = ViewpointResource.getInstance(g); + BrowseContext browseContext = new BrowseContext( BrowseContexts.toSortedURIs(g, browseContextResources) ); + for(Resource browseContextResource : findSubcontexts(g, browseContextResources)) { + + for(Resource childContributionResource : + g.getObjects(browseContextResource, vr.BrowseContext_HasChildContribution)) { + ChildContribution contribution = ChildContribution.create(g, childContributionResource); + browseContext.childContributions.put(contribution.getParentNodeType(), contribution); + browseContext.parentContributions.put(contribution.getChildNodeType(), contribution); + } + + for(Resource visualsContributionResource : + g.getObjects(browseContextResource, vr.BrowseContext_HasVisualsContribution)) { + VisualsContribution.load(g, visualsContributionResource, + browseContext.labelContributions, + browseContext.imageContributions, + browseContext.checkedStateContributions, + browseContext.labelDecorationContributions, + browseContext.imageDecorationContributions, + browseContext.modifierContributions, + browseContext.sorterContributions, + browseContext.flatNodeContributions + ); + } + } + //browseContext.visualize(); + return browseContext; + } + + public static Set getBrowseContextClosure(RequestProcessor processor, final Set browseContexts) throws DatabaseException { + return processor.syncRequest(new Read>() { + @Override + public Set perform(ReadGraph graph) throws DatabaseException { + Collection browseContextResources = new ArrayList(browseContexts.size()); + for (String browseContext : browseContexts) { + try { + browseContextResources.add(graph.getResource(browseContext)); + } catch (ResourceNotFoundException e) { + // Expected result, if no modelled contributions exist. + //System.err.println("Didn't find " + browseContext + " while loading model browser."); + } + } + Collection allBrowseContextResources = BrowseContext.findSubcontexts(graph, browseContextResources); + Set result = new HashSet(); + for (Resource r : allBrowseContextResources) + result.add(graph.getURI(r)); + return result; + } + }); + } + + public 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; + } + + /** + * Finds the possible children of the given {@link NodeContext} parameter. + * + * @param graph + * @param parent + * @return Collection of children or an empty collection in case node has no children + * @throws DatabaseException + */ + public Collection getChildren(ReadGraph graph, NodeContext parent) throws DatabaseException { + if(isFlattened(graph, parent)) + return Collections.emptyList(); + else + return getChildrenImpl(graph, parent); + } + + private Collection getChildrenImpl(ReadGraph graph, NodeContext parent) throws DatabaseException { + NodeType nodeType = getNodeType(graph, parent); + if(nodeType == null) + return Collections.emptyList(); + ArrayList result = new ArrayList(); + Collection contributions = childContributions.get(graph, nodeType); + if(contributions.size() > 1) { + Map contribs = new HashMap<>(); + for(ChildContribution contribution : contributions) { + String identifier = contribution.getIdentifier(); + ChildContribution current = contribs.get(identifier); + if(current != null && current.getPriority() > contribution.getPriority()) continue; + contribs.put(identifier, contribution); + } + contributions = contribs.values(); + } + for(ChildContribution contribution : contributions) { + Collection children = contribution.getChildren(graph, parent); + result.addAll(children); + if(DEBUG) { + System.err.println("contribution: " + contribution.getIdentifier()); + for(NodeContext ctx : children) + System.err.println("-" + ctx); + } + } + + // Sorting the result + if(!result.isEmpty()) { + for(SorterContribution contribution : sorterContributions.get(graph, nodeType)) { + Sorter sorter = contribution.getSorter(graph, parent); + if(sorter != null) { + sorter.sort(graph, this, result); + return result; + } + } + AlphanumericSorter.INSTANCE.sort(graph, this, result); + } + + result = flatten(graph, result); + //result = augment(graph, result); + + return result; + } + + private ArrayList flatten(ReadGraph graph, ArrayList result) throws DatabaseException { + ArrayList flattened = new ArrayList(); + for(NodeContext node : result) + if(isFlattened(graph, node)) { + flattened.add(node); + flattened.addAll(getChildrenImpl(graph, node)); + } + else + flattened.add(node); + return flattened; + } + + public static ArrayList augment(ReadGraph graph, BrowseContext bc, Collection contexts, boolean resolveABC) throws DatabaseException { + ArrayList result = new ArrayList(); + for(NodeContext context : contexts) { + ActionBrowseContext abc = resolveABC ? graph.syncRequest(new ResolveActionBrowseContext(context)) : null; + result.add(NodeContextBuilder.buildWithData(NodeType.KEY_SEQUENCE_EXT, + new Object[] { + context.getConstant(BuiltinKeys.INPUT), + context.getConstant(NodeType.TYPE), + context.getConstant(BuiltinKeys.UI_CONTEXT), + bc, abc})); + } + return result; + } + + private boolean isFlattened(ReadGraph graph, NodeContext node) throws DatabaseException { + NodeType nodeType = getNodeType(graph, node); + return nodeType != null && !flatNodeContributions.get(graph, nodeType).isEmpty(); + } + + /** + * Finds the possible parents of the given {@link NodeContext} parameter. + * + * @param graph + * @param child + * @return Collection of parents or an empty Collection in case node has no parents. + * @throws DatabaseException + */ + public Collection getParents(ReadGraph graph, NodeContext child) throws DatabaseException { + NodeType nodeType = getNodeType(graph, child); + if(nodeType == null) + return Collections.emptyList(); + ArrayList result = new ArrayList(); + for(ChildContribution contribution : parentContributions.get(graph, nodeType)) { + result.addAll(contribution.getParents(graph, child)); + } + return result; + } + + public boolean hasChildren(ReadGraph graph, NodeContext parent) throws DatabaseException { + NodeType nodeType = getNodeType(graph, parent); + if(nodeType == null) + return false; + for(ChildContribution contribution : childContributions.get(graph, nodeType)) + if(contribution.hasChildren(graph, parent)) + return true; + return false; + } + + 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); + } else if (input instanceof Variable) { + String uri = OntologyVersions.getInstance().currentVersion("http://www.simantics.org/Modeling-0.0/ModelingBrowseContext/Variable"); + return new SpecialNodeType(graph.getResource(uri), Variable.class); + } + } + return nodeType; + } + + /** + * Finds labels for the given {@link NodeContext} parameter. + * + * @param graph + * @param parent + * @return Map containing all the labels assigned by key indicating the column e.g. "single" + * @throws DatabaseException + */ + public Map getLabel(ReadGraph graph, NodeContext parent) throws DatabaseException { + NodeType nodeType = getNodeType(graph, parent); + if(nodeType == null) + return Collections.singletonMap(ColumnKeys.SINGLE, "ERROR (no node type)"); + List contributions = labelContributions.get(graph, nodeType); + for(LabelContribution contribution : contributions) { + Map label = contribution.getLabel(graph, parent); + if(label != null) + return label; + } + return Collections.singletonMap(ColumnKeys.SINGLE, "(no label rule)"); + } + + /** + * Finds {@link ImageDescriptor}s for the given {@link NodeContext} parameter. + * + * @param graph + * @param parent + * @return Map containing all the {@ImageDescriptor}s or empty + * @throws DatabaseException + */ + public Map getImage(ReadGraph graph, NodeContext parent) throws DatabaseException { + NodeType nodeType = getNodeType(graph, parent); + if(nodeType == null) + return Collections.emptyMap(); + for(ImageContribution contribution : imageContributions.get(graph, nodeType)) { + Map image = contribution.getImage(graph, parent); + if(image != null) + return image; + } + return Collections.emptyMap(); + } + + /** + * Finds if the given {@link NodeContext} is checked or not. + * + * @param graph + * @param parent + * @return + * @throws DatabaseException + */ + public CheckedState getCheckedState(ReadGraph graph, NodeContext parent) throws DatabaseException { + NodeType nodeType = getNodeType(graph, parent); + if(nodeType == null) + return CheckedState.NOT_CHECKED; + for(CheckedStateContribution contribution : checkedStateContributions.get(graph, nodeType)) { + CheckedState state = contribution.getCheckedState(graph, parent); + if(state != null) + return state; + } + return CheckedState.NOT_CHECKED; + } + + /** + * Finds {@link LabelDecorator} for the given {@link NodeContext} parameter. + * + * @param graph + * @param context + * @return + * @throws DatabaseException + */ + public LabelDecorator getLabelDecorator(ReadGraph graph, NodeContext context) throws DatabaseException { + NodeType nodeType = getNodeType(graph, context); + if(nodeType == null) + return CompositeLabelDecorator.ID; + ArrayList decorators = new ArrayList(); + for(LabelDecorationContribution contribution : labelDecorationContributions.get(graph, nodeType)) { + LabelDecorator decorator = contribution.getLabelDecorator(graph, context); + if(decorator != null) + decorators.add(decorator); + } + return CompositeLabelDecorator.create(decorators); + } + + /** + * Finds {@link ImageDecorator} for the given {@link NodeContext} parameter. + * + * @param graph + * @param context + * @return + * @throws DatabaseException + */ + public ImageDecorator getImageDecorator(ReadGraph graph, NodeContext context) throws DatabaseException { + NodeType nodeType = getNodeType(graph, context); + if(nodeType == null) + return CompositeImageDecorator.ID; + ArrayList decorators = new ArrayList(); + for(ImageDecorationContribution contribution : imageDecorationContributions.get(graph, nodeType)) { + ImageDecorator decorator = contribution.getImageDecorator(graph, context); + if(decorator != null) + decorators.add(decorator); + } + return CompositeImageDecorator.create(decorators); + } + + /** + * Finds {@link Modifier} for the given {@link NodeContext} parameter. + * + * @param graph + * @param context + * @param columnKey + * @return + * @throws DatabaseException + */ + public Modifier getModifier(ReadGraph graph, NodeContext context, + String columnKey) throws DatabaseException { + NodeType nodeType = getNodeType(graph, context); + if(nodeType != null) + for(ModifierContribution contribution : modifierContributions.get(graph, nodeType)) { + Modifier modifier = contribution.getModifier(graph, context, columnKey); + if(modifier == NoModifierRule.NO_MODIFIER) + return null; + if(modifier != null) + return modifier; + } + return null; + } + + private Graph toGraph() { + Graph graph = new Graph(); + new Node(graph, "Foo"); + return graph; + } + + @SuppressWarnings("unused") + private void visualize() { + final Graph graph = toGraph(); + + // Show it + new Thread() { + public void run() { + final Display display = new Display(); + final Shell shell = new Shell(display); + + GraphvizComponent comp = new GraphvizComponent(shell, 0); + comp.setGraph(graph); + + comp.setBounds(0, 0, 800, 600); + shell.pack(); + shell.open (); + while (!shell.isDisposed()) { + if (!display.readAndDispatch()) display.sleep(); + } + display.dispose(); + } + }.start(); + } + + @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; + BrowseContext other = (BrowseContext) obj; + return Arrays.equals(uris, other.uris); + } + + @Override + public String toString() { + return getClass().getSimpleName() + Arrays.toString(uris); + } + +}