From: Tuukka Lehtonen Date: Thu, 19 Jan 2017 23:06:09 +0000 (+0200) Subject: Issues-view menu improvements & Variable-based issue context resolution X-Git-Tag: v1.27.0~12 X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=commitdiff_plain;h=8ec310714002ecf514ee520448bb4c7595241455 Issues-view menu improvements & Variable-based issue context resolution This adds a new [Resource] valued property for Issue instances that is by default defined to just read the old Issue.HasContexts L0.List property. The property allows for more specific domains to override the issue context resource calculations. To support this calculation a noteworthy change needed to be made to org.simantics.db.layer0.function.All.getStandardChildDomainPropertyVariable. It now performs a new final fallback step that resembles how the standard procedural variables work. If the parent variable has a solver variable node defined, it will use NodeManager.getClassifications as an attempt to read the type Resource of the variable. If this is successful, the asserted properties of the type are searched to find a property matching name of the the requested property. To support this a new request was added: UnescapedAssertedPropertyMapOfResource. This request is also used to optimize the implementation of All.standardGetValue[12]. These changes also add a Help action for Issues view context menu that looks for the "contextHelpId" String property from the Variable describing the issue. refs #6948 Change-Id: I9655ea3647851fa04fb2420686cb13dd0c6719b6 --- diff --git a/bundles/org.simantics.db.layer0/META-INF/MANIFEST.MF b/bundles/org.simantics.db.layer0/META-INF/MANIFEST.MF index d6a2b6365..7bf579b69 100644 --- a/bundles/org.simantics.db.layer0/META-INF/MANIFEST.MF +++ b/bundles/org.simantics.db.layer0/META-INF/MANIFEST.MF @@ -32,7 +32,8 @@ Require-Bundle: gnu.trove3;bundle-version="3.0.3", org.simantics.issues.ontology;bundle-version="1.2.0", org.simantics.simulator.variable;bundle-version="1.0.0", org.simantics.scl.osgi;bundle-version="1.0.4", - org.simantics.scl.compiler;bundle-version="0.4.0" + org.simantics.scl.compiler;bundle-version="0.4.0", + org.slf4j.api Export-Package: org.simantics.db.layer0, org.simantics.db.layer0.adapter, org.simantics.db.layer0.adapter.impl, diff --git a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/function/All.java b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/function/All.java index 1c9331069..6a1441652 100644 --- a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/function/All.java +++ b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/function/All.java @@ -27,10 +27,10 @@ import org.simantics.db.Statement; import org.simantics.db.WriteGraph; import org.simantics.db.common.issue.StandardIssue; import org.simantics.db.common.primitiverequest.PossibleRelatedValueImplied2; +import org.simantics.db.common.primitiverequest.PossibleResource; import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener; import org.simantics.db.common.procedure.adapter.TransientCacheListener; import org.simantics.db.common.request.IsEnumeratedValue; -import org.simantics.db.common.request.ObjectsWithType; import org.simantics.db.common.uri.UnescapedChildMapOfResource; import org.simantics.db.common.utils.CommonDBUtils; import org.simantics.db.common.utils.Functions; @@ -47,6 +47,7 @@ import org.simantics.db.layer0.exception.VariableException; import org.simantics.db.layer0.request.PossibleURI; import org.simantics.db.layer0.request.PropertyInfo; import org.simantics.db.layer0.request.PropertyInfoRequest; +import org.simantics.db.layer0.request.UnescapedAssertedPropertyMapOfResource; import org.simantics.db.layer0.request.UnescapedPropertyMapOfResource; import org.simantics.db.layer0.scl.CompileResourceValueRequest; import org.simantics.db.layer0.scl.CompileValueRequest; @@ -56,6 +57,7 @@ import org.simantics.db.layer0.variable.AbstractVariable; import org.simantics.db.layer0.variable.ChildVariableMapRequest; import org.simantics.db.layer0.variable.ExternalSetValue; import org.simantics.db.layer0.variable.PropertyVariableMapRequest; +import org.simantics.db.layer0.variable.StandardAssertedGraphPropertyVariable; import org.simantics.db.layer0.variable.StandardComposedProperty; import org.simantics.db.layer0.variable.StandardGraphChildVariable; import org.simantics.db.layer0.variable.StandardGraphPropertyVariable; @@ -118,10 +120,20 @@ public class All { if (variable.isAsserted()) { if (variable.parentResource != null) { - Layer0 L0 = Layer0.getInstance(graph); - for(Resource assertion : graph.syncRequest(new ObjectsWithType(variable.parentResource, L0.Asserts, L0.Assertion))) { - if(variable.property.predicate.equals(graph.getSingleObject(assertion, L0.HasPredicate))) { - return graph.getRelatedValue2(assertion, L0.HasObject, variable); + Map> assertions = graph.syncRequest( + new UnescapedAssertedPropertyMapOfResource(variable.parentResource), + TransientCacheAsyncListener.instance()); + + // NOTE: This optimization assumes the property + // variable's representation is the asserted object. + Resource object = variable.getPossibleRepresents(graph); + if (object != null) { + return graph.getValue2(object, variable); + } else { + for (Pair assertion : assertions.values()) { + if (assertion.first.predicate.equals(variable.property.predicate)) { + return graph.getValue2(assertion.second, variable); + } } } } @@ -156,13 +168,12 @@ public class All { try { - Layer0 L0 = Layer0.getInstance(graph); - if(variable.property.hasEnumerationRange) { Resource object = variable.getRepresents(graph); if(graph.sync(new IsEnumeratedValue(object))) { + Layer0 L0 = Layer0.getInstance(graph); if(graph.isInstanceOf(object, L0.Literal)) { - return graph.getValue(object); + return graph.getValue(object, binding); } else { return graph.getRelatedValue2(variable.getRepresents(graph), L0.HasLabel, binding); } @@ -171,11 +182,22 @@ public class All { if (variable.isAsserted()) { if (variable.parentResource != null) { - for(Resource assertion : graph.syncRequest(new ObjectsWithType(variable.parentResource, L0.Asserts, L0.Assertion))) { - if(variable.property.predicate.equals(graph.getSingleObject(assertion, L0.HasPredicate))) { - return graph.getRelatedValue2(assertion, L0.HasObject, context); - } - } + Map> assertions = graph.syncRequest( + new UnescapedAssertedPropertyMapOfResource(variable.parentResource), + TransientCacheAsyncListener.instance()); + + // NOTE: This optimization assumes the property + // variable's representation is the asserted object. + Resource object = variable.getPossibleRepresents(graph); + if (object != null) { + return graph.getValue2(object, variable, binding); + } else { + for (Pair assertion : assertions.values()) { + if (assertion.first.predicate.equals(variable.property.predicate)) { + return graph.getValue2(assertion.second, variable, binding); + } + } + } } } @@ -450,6 +472,33 @@ public class All { // Fallback: try to ask property resource uri from NodeManager return createStandardGraphPropertyVariable(graph, variable, propertyNode); } + // Final fallback: check types corresponding to + // node classification(s) and look for asserted + // properties from the URIs specified. + if (variable.node != null) { + try { + @SuppressWarnings("unchecked") + Set classifications = variable.node.support.manager.getClassifications(variable.node.node); + if (!classifications.isEmpty()) { + for (String uri : classifications) { + Resource type = graph.syncRequest( + new PossibleResource(uri), + TransientCacheAsyncListener.instance()); + if (type == null) + continue; + Map> pm = graph.syncRequest( + new UnescapedAssertedPropertyMapOfResource(type), + TransientCacheAsyncListener.instance()); + Pair pi = pm.get(name); + if (pi != null) { + return new StandardAssertedGraphPropertyVariable(graph, context, null, type, pi.first.predicate, pi.second); + } + } + } + } catch(NodeManagerException e) { + throw new DatabaseException(e); + } + } return null; } diff --git a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/request/UnescapedAssertedPropertyMapOfResource.java b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/request/UnescapedAssertedPropertyMapOfResource.java new file mode 100644 index 000000000..63413635c --- /dev/null +++ b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/request/UnescapedAssertedPropertyMapOfResource.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2017 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: + * Semantum Oy - initial API and implementation + *******************************************************************************/ +package org.simantics.db.layer0.request; + + import gnu.trove.map.hash.THashMap; + +import java.util.Collection; +import java.util.Map; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.Statement; +import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener; +import org.simantics.db.common.request.ResourceRead; +import org.simantics.db.exception.DatabaseException; +import org.simantics.layer0.Layer0; +import org.simantics.utils.datastructures.Pair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Tuukka Lehtonen + * @since 1.27.0 + */ +public class UnescapedAssertedPropertyMapOfResource extends ResourceRead>> { + + private static final Logger LOGGER = LoggerFactory.getLogger(UnescapedAssertedPropertyMapOfResource.class); + + public UnescapedAssertedPropertyMapOfResource(Resource resource) { + super(resource); + } + + @Override + public Map> perform(ReadGraph graph) throws DatabaseException { + Layer0 L0 = Layer0.getInstance(graph); + Collection assertions = graph.getAssertedStatements(resource, L0.HasProperty); + THashMap> result = new THashMap<>(assertions.size()); + for (Statement stm : assertions) { + PropertyInfo info = graph.syncRequest(new PropertyInfoRequest(stm.getPredicate()), TransientCacheAsyncListener.instance()); + if (info != null && info.isHasProperty) { + String name = info.name; + // Use putIfAbsent because we want to prefer the results that are first, + // i.e. the ones deeper in the type inheritance chain. + if (result.putIfAbsent(name, Pair.make(info, stm.getObject())) != null) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug(this + ": The database resource $" + resource.getResourceId() + + " asserts the multiple properties with the same name " + name + " (resource=$" + + info.predicate.getResourceId() + ")."); + } + } + } + } + return result; + } + +} diff --git a/bundles/org.simantics.issues.common/src/org/simantics/issues/common/All.java b/bundles/org.simantics.issues.common/src/org/simantics/issues/common/All.java index 6ff625c0b..9173101ee 100644 --- a/bundles/org.simantics.issues.common/src/org/simantics/issues/common/All.java +++ b/bundles/org.simantics.issues.common/src/org/simantics/issues/common/All.java @@ -76,5 +76,10 @@ public class All { return IssueUtils.pathString(uri, modelURI.length()+1); } } - + + @SCLValue(type = "ReadGraph -> Resource -> Variable -> [Resource]") + public static List standardIssueContexts(ReadGraph graph, Resource converter, Variable property) throws DatabaseException { + return IssueUtils.getContextsForProperty(graph, property); + } + } diff --git a/bundles/org.simantics.issues.ontology/graph.tg b/bundles/org.simantics.issues.ontology/graph.tg index d0ad31bf4..7ed3dc924 100644 Binary files a/bundles/org.simantics.issues.ontology/graph.tg and b/bundles/org.simantics.issues.ontology/graph.tg differ diff --git a/bundles/org.simantics.issues.ontology/graph/Issue.pgraph b/bundles/org.simantics.issues.ontology/graph/Issue.pgraph index 3d428ed59..47a8160b5 100644 --- a/bundles/org.simantics.issues.ontology/graph/Issue.pgraph +++ b/bundles/org.simantics.issues.ontology/graph/Issue.pgraph @@ -33,6 +33,7 @@ ISSUE.Issue -- ISSUE.Issue.HasSeverity --> ISSUE.Severity -- ISSUE.Issue.HasContexts --> L0.List -- ISSUE.Issue.contexts ==> "[Resource]" -- ISSUE.Issue.severity ==> "String" -- ISSUE.Issue.resource ==> "String" -- ISSUE.Issue.path ==> "String" : L0.Ontology L0.HasResourceClass "org.simantics.issues.ui.ontology.IssueUIResource" //-------------------------------------------------------------------------- -// Functions +// Libraries UI.Functions : L0.Library @@ -43,6 +43,7 @@ ACTIONS.SeverityActionCategory : VP.ActionCategory ACTIONS.SetSeverityAction -- ACTIONS.SetSeverityAction.HasSeverity --> ISSUE.Severity - + + diff --git a/bundles/org.simantics.issues.ui/plugin.xml b/bundles/org.simantics.issues.ui/plugin.xml index e67d2e12b..584bd41ae 100644 --- a/bundles/org.simantics.issues.ui/plugin.xml +++ b/bundles/org.simantics.issues.ui/plugin.xml @@ -19,15 +19,6 @@ id="org.simantics.issues.category" name="Issues"> - T getAdapter(Class adapter) { + if (GraphExplorer.class == adapter) + return (T) tryGetExplorer(container); + if (BrowseContext.class == adapter) + return (T) tryGetBrowseContext(container); + return super.getAdapter(adapter); + } + + private BrowseContext tryGetBrowseContext(Control control) { + return SWTUtils.tryGetObject(control, c -> { + return c instanceof IAdaptable + ? (BrowseContext) ((IAdaptable) c).getAdapter(BrowseContext.class) + : null; + }); + } + + private GraphExplorer tryGetExplorer(Control control) { + return SWTUtils.tryGetObject(control, c -> { + return c.isDisposed() ? null + : (GraphExplorer) c.getData(GraphExplorer.KEY_GRAPH_EXPLORER); + }); + } + } diff --git a/bundles/org.simantics.issues.ui/src/org/simantics/issues/ui/handler/Help.java b/bundles/org.simantics.issues.ui/src/org/simantics/issues/ui/handler/Help.java new file mode 100644 index 000000000..ebdb5a4b2 --- /dev/null +++ b/bundles/org.simantics.issues.ui/src/org/simantics/issues/ui/handler/Help.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2017 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: + * Semantum Oy - initial API and implementation + *******************************************************************************/ +package org.simantics.issues.ui.handler; + +import org.eclipse.ui.PlatformUI; +import org.simantics.Simantics; +import org.simantics.databoard.Bindings; +import org.simantics.databoard.binding.Binding; +import org.simantics.db.ReadGraph; +import org.simantics.db.common.request.TernaryRead; +import org.simantics.db.common.utils.Logger; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.adapter.ActionFactory; +import org.simantics.db.layer0.variable.Variable; + +/** + * @author Tuukka Lehtonen + * @since 1.27.0 + */ +public class Help implements ActionFactory { + + @Override + public Runnable create(Object target) { + if (target instanceof Variable) { + return () -> { + try { + String id = Simantics.sync(new PossibleVariablePropertyValue((Variable) target, "contextualHelpId", Bindings.STRING)); + if (id == null) { + PlatformUI.getWorkbench().getHelpSystem().displayDynamicHelp(); + return; + } + PlatformUI.getWorkbench().getHelpSystem().displayHelp(id); + } catch (DatabaseException e) { + Logger.defaultLogError(e); + } + }; + } + + return null; + } + + static class PossibleVariablePropertyValue extends TernaryRead { + + public PossibleVariablePropertyValue(Variable variable, String property, Binding binding) { + super(variable, property, binding); + } + + @Override + public T perform(ReadGraph graph) throws DatabaseException { + return parameter.getPossiblePropertyValue(graph, parameter2, parameter3); + } + + } + +} diff --git a/bundles/org.simantics.issues.ui/src/org/simantics/issues/ui/handler/MenuActions.java b/bundles/org.simantics.issues.ui/src/org/simantics/issues/ui/handler/MenuActions.java index 032359731..b607eb7e1 100644 --- a/bundles/org.simantics.issues.ui/src/org/simantics/issues/ui/handler/MenuActions.java +++ b/bundles/org.simantics.issues.ui/src/org/simantics/issues/ui/handler/MenuActions.java @@ -39,7 +39,6 @@ import org.simantics.issues.common.IssueUtils; import org.simantics.issues.ontology.IssueResource; import org.simantics.issues.ui.internal.Activator; import org.simantics.ui.contribution.DynamicMenuContribution; -import org.simantics.utils.datastructures.Callback; import org.simantics.utils.ui.ErrorLogger; import org.simantics.utils.ui.ISelectionUtils; @@ -181,12 +180,9 @@ public class MenuActions extends DynamicMenuContribution { graph.deny(issue, ISSUE.Issue_HasSeverity); } } - }, new Callback() { - @Override - public void run(DatabaseException e) { - if (e != null) - ErrorLogger.defaultLogError(e); - } + }, e -> { + if (e != null) + ErrorLogger.defaultLogError(e); }); } diff --git a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/diagramEditor/OpenDiagramFromIssue.java b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/diagramEditor/OpenDiagramFromIssue.java index 8595d7374..6af1ff84b 100644 --- a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/diagramEditor/OpenDiagramFromIssue.java +++ b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/diagramEditor/OpenDiagramFromIssue.java @@ -27,10 +27,8 @@ import org.simantics.issues.ontology.IssueResource; import org.simantics.layer0.Layer0; import org.simantics.modeling.ModelingResources; import org.simantics.modeling.ui.Activator; -import org.simantics.structural.stubs.StructuralResource2; import org.simantics.ui.SimanticsUI; import org.simantics.ui.workbench.editor.AbstractResourceEditorAdapter; -import org.simantics.utils.datastructures.Pair; /** * @author Tuukka Lehtonen