X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.browsing.ui.model%2Fsrc%2Forg%2Fsimantics%2Fbrowsing%2Fui%2Fmodel%2Fbrowsecontexts%2FBrowseContext.java;h=8e5bf73c7ee88f565f9c3cfab585cd798400b37c;hp=8d5a427c2502bf573e22a87fd682f3eccd69ec34;hb=0ae2b770234dfc3cbb18bd38f324125cf0faca07;hpb=24e2b34260f219f0d1644ca7a138894980e25b14 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 index 8d5a427c2..8e5bf73c7 100644 --- 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 @@ -1,523 +1,523 @@ -/******************************************************************************* - * 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.Event; -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.tooltips.TooltipContribution; -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(); - OrderedNodeTypeMultiMap tooltipContributions = 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.tooltipContributions - ); - } - } - //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 = null; - if(resolveABC) { - abc = graph.syncRequest(new ResolveActionBrowseContext(context)); - if(abc == null) abc = (ActionBrowseContext)context.getConstant(BuiltinKeys.ACTION_BROWSE_CONTEXT); - } - 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; - } - - public TooltipContribution shouldCreateToolTip(ReadGraph graph, Event event, NodeContext context) throws DatabaseException { - NodeType nodeType = getNodeType(graph, context); - if(nodeType != null) - for(TooltipContribution contribution : tooltipContributions.get(graph, nodeType)) { - if (contribution.shouldCreateToolTip(graph, context)) - return contribution; - } - return null; - } - - public Object getTooltip(TooltipContribution contribution, Object event, Object parent, NodeContext context) throws DatabaseException { - Object tooltip = contribution.getTooltip(event, parent, context); - if (tooltip != null) - return tooltip; - 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); - } - -} +/******************************************************************************* + * 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.Event; +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.tooltips.TooltipContribution; +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(); + OrderedNodeTypeMultiMap tooltipContributions = 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.tooltipContributions + ); + } + } + //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 = null; + if(resolveABC) { + abc = graph.syncRequest(new ResolveActionBrowseContext(context)); + if(abc == null) abc = (ActionBrowseContext)context.getConstant(BuiltinKeys.ACTION_BROWSE_CONTEXT); + } + 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; + } + + public TooltipContribution shouldCreateToolTip(ReadGraph graph, Event event, NodeContext context) throws DatabaseException { + NodeType nodeType = getNodeType(graph, context); + if(nodeType != null) + for(TooltipContribution contribution : tooltipContributions.get(graph, nodeType)) { + if (contribution.shouldCreateToolTip(graph, context)) + return contribution; + } + return null; + } + + public Object getTooltip(TooltipContribution contribution, Object event, Object parent, NodeContext context) throws DatabaseException { + Object tooltip = contribution.getTooltip(event, parent, context); + if (tooltip != null) + return tooltip; + 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); + } + +}