-/*******************************************************************************\r
- * Copyright (c) 2012 Association for Decentralized Information Management in\r
- * Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- * VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.annotation.ui;\r
-\r
-import java.util.HashMap;\r
-import java.util.Map;\r
-import java.util.UUID;\r
-import java.util.function.Consumer;\r
-\r
-import org.eclipse.jface.dialogs.IDialogSettings;\r
-import org.eclipse.jface.resource.ImageDescriptor;\r
-import org.eclipse.jface.window.Window;\r
-import org.eclipse.swt.widgets.Display;\r
-import org.eclipse.swt.widgets.Shell;\r
-import org.eclipse.ui.PlatformUI;\r
-import org.simantics.Simantics;\r
-import org.simantics.annotation.ontology.AnnotationResource;\r
-import org.simantics.annotation.ui.internal.SaveAnnotationDialog;\r
-import org.simantics.databoard.Bindings;\r
-import org.simantics.databoard.util.URIStringUtils;\r
-import org.simantics.db.ReadGraph;\r
-import org.simantics.db.Resource;\r
-import org.simantics.db.WriteGraph;\r
-import org.simantics.db.common.CommentMetadata;\r
-import org.simantics.db.common.request.PossibleIndexRoot;\r
-import org.simantics.db.common.request.ReadRequest;\r
-import org.simantics.db.common.request.WriteRequest;\r
-import org.simantics.db.common.utils.Logger;\r
-import org.simantics.db.common.utils.NameUtils;\r
-import org.simantics.db.exception.DatabaseException;\r
-import org.simantics.db.layer0.adapter.Instances;\r
-import org.simantics.db.layer0.request.PossibleModel;\r
-import org.simantics.db.layer0.request.VariableRead;\r
-import org.simantics.db.layer0.util.Layer0Utils;\r
-import org.simantics.db.layer0.variable.Variable;\r
-import org.simantics.db.layer0.variable.Variables;\r
-import org.simantics.layer0.Layer0;\r
-import org.simantics.selectionview.SelectionViewResources;\r
-import org.simantics.structural.stubs.StructuralResource2;\r
-import org.simantics.ui.workbench.dialogs.ResourceSelectionDialog3;\r
-import org.simantics.utils.datastructures.Pair;\r
-\r
-/**\r
- * @author Teemu Mätäsniemi\r
- * @author Antti Villberg\r
- * @author Tuukka Lehtonen\r
- */\r
-public class AnnotationUtils {\r
-\r
- /**\r
- * @param graph\r
- * @param parent\r
- * @return (r1, r2) pair where r1 is the created annotation property\r
- * relation and and r2 is the created annotation type\r
- * @throws DatabaseException\r
- */\r
- public static Pair<Resource, Resource> newAnnotationType(WriteGraph graph, final Resource parent) throws DatabaseException {\r
- graph.markUndoPoint();\r
- Layer0 L0 = Layer0.getInstance(graph);\r
- AnnotationResource ANNO = AnnotationResource.getInstance(graph);\r
- SelectionViewResources SEL = SelectionViewResources.getInstance(graph);\r
- StructuralResource2 STR = StructuralResource2.getInstance(graph);\r
-\r
- Resource indexRoot = graph.sync(new PossibleIndexRoot(parent));\r
-\r
- // Get supertype for annotation type\r
- Resource propertySubrelation = graph.getPossibleObject(indexRoot, ANNO.HasAnnotationPropertySubrelation);\r
- if (propertySubrelation == null)\r
- propertySubrelation = L0.HasProperty;\r
- Resource supertype = graph.getPossibleObject(indexRoot, ANNO.HasAnnotationTypeSupertype);\r
- if (supertype == null)\r
- supertype = ANNO.Annotation;\r
-\r
- Resource property = graph.newResource();\r
- String name = NameUtils.findFreshName(graph, "newAnnotationProperty", parent, L0.ConsistsOf);\r
- graph.addLiteral(property, L0.HasName, L0.NameOf, L0.String, name, Bindings.STRING);\r
- graph.claim(property, L0.SubrelationOf, propertySubrelation);\r
-\r
- Resource type = graph.newResource();\r
- graph.claim(type, L0.Inherits, null, supertype);\r
- graph.addLiteral(type, L0.HasName, L0.NameOf, L0.String, UUID.randomUUID().toString(), Bindings.STRING);\r
- graph.claim(type, STR.ComponentType_HasDefaultPropertyRelationType, SEL.GenericParameterType);\r
-\r
- graph.claim(property, L0.HasRange, type);\r
-\r
- graph.claim(type, L0.ConsistsOf, property);\r
- graph.claim(parent, L0.ConsistsOf, type);\r
- \r
- CommentMetadata cm = graph.getMetadata(CommentMetadata.class);\r
- graph.addMetadata(cm.add("Added new annotationType " + type + " with property relation " + property + " "));\r
-\r
- return Pair.make(property, type);\r
- }\r
-\r
- public static void newAnnotation(ReadGraph graph, Resource parent, Resource model) throws DatabaseException {\r
-\r
- Map<Resource, Pair<String, ImageDescriptor>> map = new HashMap<>();\r
- findAnnotationTypes(graph, model, map);\r
- findAnnotations(graph, model, map);\r
- queryUserSelectedAnnotationType(map, selected -> {\r
- Simantics.getSession().async(new WriteRequest() {\r
- @Override\r
- public void perform(WriteGraph g) throws DatabaseException {\r
- newAnnotation(g, parent, selected);\r
- }\r
- });\r
- });\r
-\r
- }\r
-\r
- private static boolean isEntryAnnotation(ReadGraph graph, Resource selected) throws DatabaseException {\r
- Layer0 L0 = Layer0.getInstance(graph);\r
- AnnotationResource ANNO = AnnotationResource.getInstance(graph);\r
- if(graph.isInstanceOf(selected, ANNO.Annotation)) {\r
- Resource type = graph.getSingleType(selected, ANNO.Annotation);\r
- return !graph.hasStatement(type, L0.HasRange_Inverse);\r
- } else if (graph.isInstanceOf(selected, ANNO.AnnotationType)) {\r
- return !graph.hasStatement(selected, L0.HasRange_Inverse);\r
- } else {\r
- throw new DatabaseException("Incompatible resource " + selected);\r
- }\r
- }\r
- \r
- public static void newAnnotation(ReadGraph graph, Variable position, Resource model) throws DatabaseException {\r
-\r
- Map<Resource, Pair<String, ImageDescriptor>> map = new HashMap<>();\r
- findAnnotationTypes(graph, model, map);\r
- findAnnotations(graph, model, map);\r
- queryUserSelectedAnnotationType(map, selected -> {\r
- Simantics.getSession().async(new WriteRequest() {\r
- @Override\r
- public void perform(WriteGraph g) throws DatabaseException {\r
- g.markUndoPoint();\r
- if(isEntryAnnotation(g, selected)) {\r
- newAnnotation(g, position.getRepresents(g), selected);\r
- Layer0Utils.addCommentMetadata(g, "Attached new annotation to " + g.getRelatedValue2(position.getRepresents(g), Layer0.getInstance(g).HasName, Bindings.STRING));\r
- } else {\r
- newAnnotation(g, position.getParent(g).getRepresents(g), selected);\r
- Layer0Utils.addCommentMetadata(g, "Attached new annotation to " + g.getRelatedValue2(position.getParent(g).getRepresents(g), Layer0.getInstance(g).HasName, Bindings.STRING));\r
- }\r
- }\r
- });\r
- });\r
-\r
- }\r
- \r
- /**\r
- * Creates a new annotation instance for the specified parent after the user\r
- * selects the annotation type from the list of all annotation types in the\r
- * specified model. The annotation types are resolved from the model\r
- * dependency index.\r
- * \r
- * @param parent\r
- * @param model\r
- * @throws DatabaseException\r
- */\r
- public static void newAnnotation(Resource parent, Resource model) throws DatabaseException {\r
- if (model == null)\r
- return;\r
- Simantics.getSession().syncRequest(new ReadRequest() {\r
- @Override\r
- public void run(ReadGraph graph) throws DatabaseException {\r
- newAnnotation(graph, parent, model);\r
- }\r
- });\r
- }\r
-\r
- public static void newAnnotation(Resource parent) throws DatabaseException {\r
- Simantics.getSession().syncRequest(new ReadRequest() {\r
- @Override\r
- public void run(ReadGraph graph) throws DatabaseException {\r
- Resource model = graph.sync(new PossibleModel(parent));\r
- if(model == null) return;\r
- newAnnotation(graph, parent, model);\r
- }\r
- });\r
- }\r
-\r
- public static void newAnnotation(Variable position) throws DatabaseException {\r
- Simantics.getSession().syncRequest(new ReadRequest() {\r
- @Override\r
- public void run(ReadGraph graph) throws DatabaseException {\r
- Resource model = Variables.getModel(graph, position);\r
- if(model == null) return;\r
- newAnnotation(graph, position, model);\r
- }\r
- });\r
- }\r
-\r
- public static void newAnnotationInstance(Resource parent, Resource model) throws DatabaseException {\r
- if (model == null)\r
- return;\r
- Simantics.getSession().syncRequest(new ReadRequest() {\r
- @Override\r
- public void run(ReadGraph graph) throws DatabaseException {\r
- Map<Resource, Pair<String, ImageDescriptor>> map = new HashMap<>();\r
- findAnnotationTypes(graph, model, map);\r
- queryUserSelectedAnnotationType(map, selected -> {\r
- Simantics.getSession().async(new WriteRequest() {\r
- @Override\r
- public void perform(WriteGraph g) throws DatabaseException {\r
- g.markUndoPoint();\r
- newAnnotationInstance(g, parent, selected);\r
- }\r
- });\r
- });\r
- }\r
- });\r
- }\r
-\r
- /**\r
- * @param graph\r
- * @param model\r
- * @return\r
- * @throws DatabaseException \r
- */\r
- protected static void findAnnotationTypes(ReadGraph graph, Resource model, Map<Resource, Pair<String, ImageDescriptor>> map) throws DatabaseException {\r
-\r
- Layer0 L0 = Layer0.getInstance(graph);\r
- AnnotationResource ANNO = AnnotationResource.getInstance(graph);\r
-\r
- Instances query = graph.adapt(ANNO.AnnotationType, Instances.class);\r
-\r
- String modelURI = graph.getURI(model);\r
- \r
- ImageDescriptor descriptor = graph.adapt(ANNO.Images_AnnotationType, ImageDescriptor.class);\r
-\r
- for(Resource _res : query.find(graph, model)) {\r
- // Don't allow instantiation of abstract annotation types.\r
- if (graph.hasStatement(_res, L0.Abstract))\r
- continue;\r
-\r
- // Don't allow instantiation of non-user-selectable annotation types\r
- Boolean userSelectable = graph.getPossibleRelatedValue2(_res, ANNO.AnnotationType_systemAnnotation, Bindings.BOOLEAN);\r
- if (Boolean.TRUE.equals(userSelectable))\r
- continue;\r
-\r
- Resource res = graph.getPossibleObject(_res, L0.HasRange_Inverse);\r
- if(res == null) {\r
- \r
- // Entry type\r
-\r
- String name = graph.getPossibleRelatedValue(_res, L0.HasName, Bindings.STRING);\r
- if (name == null)\r
- continue;\r
- String label = graph.getPossibleRelatedValue2(_res, L0.HasLabel, Bindings.STRING);\r
-\r
- if (label != null && !name.equals(label)) {\r
- name = label + " (" + name + ")";\r
- }\r
-\r
- Resource parent = graph.getPossibleObject(_res, L0.PartOf);\r
- if(parent == null) continue;\r
-\r
- String parentURI = graph.getURI(parent);\r
- if(parentURI.startsWith(modelURI)) {\r
- parentURI = parentURI.substring(modelURI.length());\r
- if(parentURI.startsWith("/")) parentURI = parentURI.substring(1);\r
- }\r
-\r
- name = name + " - " + URIStringUtils.unescape(parentURI);\r
-\r
- map.put(_res, Pair.make(name, descriptor));\r
- \r
- } else {\r
- \r
- // Property type\r
- \r
- String name = graph.getPossibleRelatedValue(res, L0.HasName, Bindings.STRING);\r
- if (name == null)\r
- continue;\r
- String label = graph.getPossibleRelatedValue2(res, L0.HasLabel, Bindings.STRING);\r
-\r
- if (label != null && !name.equals(label)) {\r
- name = label + " (" + name + ")";\r
- }\r
-\r
- Resource parent = graph.getPossibleObject(_res, L0.PartOf);\r
- if(parent == null) continue;\r
-\r
- String parentURI = graph.getURI(parent);\r
- if(parentURI.startsWith(modelURI)) {\r
- parentURI = parentURI.substring(modelURI.length());\r
- if(parentURI.startsWith("/")) parentURI = parentURI.substring(1);\r
- }\r
-\r
- name = name + " - " + URIStringUtils.unescape(parentURI);\r
-\r
- map.put(_res, Pair.make(name, descriptor));\r
- \r
- }\r
- \r
- }\r
-\r
- }\r
-\r
- protected static void findAnnotations(ReadGraph graph, Resource model, Map<Resource, Pair<String, ImageDescriptor>> map) throws DatabaseException {\r
-\r
- Layer0 L0 = Layer0.getInstance(graph);\r
- AnnotationResource ANNO = AnnotationResource.getInstance(graph);\r
-\r
- Instances query = graph.adapt(ANNO.Annotation, Instances.class);\r
- \r
- String modelURI = graph.getURI(model);\r
- \r
- ImageDescriptor descriptor = graph.adapt(ANNO.Images_Annotation, ImageDescriptor.class);\r
-\r
- for(Resource _res : query.find(graph, model)) {\r
- String name = graph.getPossibleRelatedValue(_res, L0.HasName, Bindings.STRING);\r
- if (name == null)\r
- continue;\r
- String label = graph.getPossibleRelatedValue2(_res, L0.HasLabel, Bindings.STRING);\r
- if (label != null && !name.equals(label)) {\r
- name = label + " (" + name + ")";\r
- }\r
-\r
- Resource parent = graph.getPossibleObject(_res, L0.PartOf);\r
- if(parent == null) continue;\r
-\r
- String parentURI = graph.getPossibleURI(parent);\r
- if(parentURI == null) continue;\r
- \r
- if(parentURI.startsWith(modelURI)) {\r
- parentURI = parentURI.substring(modelURI.length());\r
- if(parentURI.startsWith("/")) parentURI = parentURI.substring(1);\r
- }\r
-\r
- Resource type = graph.getPossibleType(_res, ANNO.Annotation);\r
- if(type != null) {\r
- // Don't list instances of non-user-selectable annotation types\r
- Boolean userSelectable = graph.getPossibleRelatedValue2(type, ANNO.AnnotationType_systemAnnotation, Bindings.BOOLEAN);\r
- if (Boolean.TRUE.equals(userSelectable))\r
- continue;\r
-\r
- Resource relation = graph.getPossibleObject(type, L0.HasRange_Inverse);\r
- if(relation != null) {\r
- String rName = graph.getPossibleRelatedValue(relation, L0.HasName, Bindings.STRING);\r
- if(rName != null) {\r
- name = name + " - " + rName;\r
- }\r
- }\r
- }\r
- \r
- name = name + " - " + URIStringUtils.unescape(parentURI);\r
- \r
- map.put(_res, Pair.make(name, descriptor));\r
- \r
- }\r
-\r
- }\r
-\r
- protected static boolean isAnnotation(Variable variable) {\r
- if (variable == null)\r
- return false;\r
- try {\r
- return Simantics.sync(new VariableRead<Boolean>(variable) {\r
-\r
- @Override\r
- public Boolean perform(ReadGraph graph) throws DatabaseException {\r
- AnnotationResource ANNO = AnnotationResource.getInstance(graph);\r
- Resource represents = variable.getPossibleRepresents(graph);\r
- if(represents == null) return false;\r
- return graph.isInstanceOf(represents, ANNO.Annotation);\r
- }\r
-\r
- });\r
- } catch (DatabaseException e) {\r
- return false;\r
- }\r
- }\r
- \r
- protected static Map<Resource, Pair<String, ImageDescriptor>> findLibraries(Variable variable) {\r
-\r
- try {\r
-\r
- return Simantics.sync(new VariableRead<Map<Resource, Pair<String, ImageDescriptor>>>(variable) {\r
-\r
- @Override\r
- public Map<Resource, Pair<String, ImageDescriptor>> perform(ReadGraph graph) throws DatabaseException {\r
-\r
- Map<Resource, Pair<String, ImageDescriptor>> result = new HashMap<>();\r
-\r
- Layer0 L0 = Layer0.getInstance(graph);\r
- AnnotationResource ANNO = AnnotationResource.getInstance(graph);\r
-\r
- Resource model = Variables.getModel(graph, variable);\r
- Instances query = graph.adapt(L0.Library, Instances.class);\r
-\r
- String modelURI = graph.getURI(model);\r
- int modelPos = modelURI.length();\r
-\r
- ImageDescriptor descriptor = graph.adapt(ANNO.Images_Annotation, ImageDescriptor.class);\r
-\r
- for(Resource lib : query.find(graph, model)) {\r
-\r
- String path = graph.getURI(lib);\r
- if(!path.startsWith(modelURI)) continue;\r
- String suffix = URIStringUtils.unescape(path.substring(modelPos));\r
- if(suffix.startsWith("/")) suffix = suffix.substring(1);\r
- result.put(lib, Pair.make(suffix, descriptor));\r
-\r
- }\r
-\r
- return result;\r
- \r
- }\r
- });\r
-\r
- } catch (DatabaseException e) {\r
- Logger.defaultLogError(e);\r
- }\r
- \r
- return null;\r
-\r
- }\r
-\r
- public static Resource newAnnotation(WriteGraph graph, Resource container, Resource valueOrProperty) throws DatabaseException {\r
- graph.markUndoPoint();\r
- Layer0 L0 = Layer0.getInstance(graph);\r
- AnnotationResource ANNO = AnnotationResource.getInstance(graph);\r
-\r
- if(graph.isInstanceOf(valueOrProperty, ANNO.Annotation)) {\r
-\r
- Resource type = graph.getPossibleType(valueOrProperty, ANNO.Annotation);\r
- if(type == null) return null;\r
- Resource property = graph.getPossibleObject(type, L0.HasRange_Inverse);\r
- if(property == null) {\r
- graph.claim(container, ANNO.Annotation_HasEntry, valueOrProperty);\r
- } else {\r
- graph.deny(container, property);\r
- graph.claim(container, property, valueOrProperty);\r
- }\r
- Layer0Utils.addCommentMetadata(graph, "Created new annotation value/property " + valueOrProperty + " to " + graph.getRelatedValue2(container, L0.HasName, Bindings.STRING));\r
- return valueOrProperty;\r
- \r
- } else if (graph.isInstanceOf(valueOrProperty, ANNO.AnnotationType)) {\r
- \r
- Resource predicate = graph.getPossibleObject(valueOrProperty, L0.HasRange_Inverse);\r
- if(predicate != null) {\r
- Resource value = graph.newResource();\r
- graph.claim(value, L0.InstanceOf, valueOrProperty);\r
- graph.deny(container, predicate);\r
- graph.claim(container, predicate, value);\r
- Layer0Utils.addCommentMetadata(graph, "Created new annotation type " + value + " to " + graph.getRelatedValue2(container, L0.HasName, Bindings.STRING));\r
- return value;\r
- } else {\r
- Resource value = graph.newResource();\r
- graph.claim(value, L0.InstanceOf, valueOrProperty);\r
- String name = NameUtils.findFreshEscapedName(graph, "Value", container, ANNO.Annotation_HasEntry);\r
- graph.addLiteral(value, L0.HasName, L0.NameOf, L0.String, name, Bindings.STRING);\r
- graph.claim(container, ANNO.Annotation_HasEntry, value);\r
- Layer0Utils.addCommentMetadata(graph, "Created new annotation entry " + value + " to " + graph.getRelatedValue2(container, L0.HasName, Bindings.STRING));\r
- return value;\r
- }\r
- \r
- } else {\r
- \r
- Resource valueType = graph.getSingleObject(valueOrProperty, L0.HasRange);\r
- Resource value = graph.newResource();\r
- graph.claim(value, L0.InstanceOf, valueType);\r
- graph.deny(container, valueOrProperty);\r
- graph.claim(container, valueOrProperty, value);\r
- return value;\r
- \r
- }\r
- \r
- }\r
-\r
- public static Resource newAnnotationInstance(WriteGraph graph, Resource container, Resource annotationProperty) throws DatabaseException {\r
- return newAnnotationInstance(graph, container, null, annotationProperty);\r
- }\r
-\r
- public static Resource newAnnotationInstance(WriteGraph graph, Resource container, String name, Resource annotationProperty) throws DatabaseException {\r
- return newAnnotationInstance(graph, container, name, annotationProperty, true);\r
- }\r
- \r
- public static Resource newAnnotationInstance(WriteGraph graph, Resource container, String name, Resource annotationProperty, boolean addCommentMetadata) throws DatabaseException {\r
- //graph.markUndoPoint();\r
- Layer0 L0 = Layer0.getInstance(graph);\r
- AnnotationResource ANNO = AnnotationResource.getInstance(graph);\r
-\r
- if(graph.isInstanceOf(annotationProperty, ANNO.AnnotationType)) {\r
-\r
- Resource predicate = graph.getPossibleObject(annotationProperty, L0.HasRange_Inverse);\r
-\r
- String proposition = predicate != null ? (String)graph.getRelatedValue(predicate, L0.HasName, Bindings.STRING) :\r
- (String)graph.getRelatedValue(annotationProperty, L0.HasName, Bindings.STRING);\r
- \r
- Resource value = graph.newResource();\r
- graph.claim(value, L0.InstanceOf, annotationProperty);\r
- if(name == null)\r
- name = NameUtils.findFreshName(graph, proposition + " value", container);\r
- graph.addLiteral(value, L0.HasName, L0.NameOf, L0.String, name, Bindings.STRING);\r
-\r
- graph.claim(container, L0.ConsistsOf, value);\r
- \r
- if (addCommentMetadata) {\r
- CommentMetadata cm = graph.getMetadata(CommentMetadata.class);\r
- graph.addMetadata(cm.add("Added new annotationValue named " + name + ", resource " + value));\r
- }\r
- \r
- return value;\r
- \r
- } else {\r
-\r
- String propertyName = graph.getRelatedValue(annotationProperty, L0.HasName, Bindings.STRING);\r
- \r
- Resource valueType = graph.getSingleObject(annotationProperty, L0.HasRange);\r
- Resource value = graph.newResource();\r
- graph.claim(value, L0.InstanceOf, valueType);\r
- if(name == null)\r
- name = NameUtils.findFreshName(graph, propertyName + " value", container);\r
- graph.addLiteral(value, L0.HasName, L0.NameOf, L0.String, name, Bindings.STRING);\r
-\r
- graph.claim(container, L0.ConsistsOf, value);\r
- \r
- if (addCommentMetadata) {\r
- CommentMetadata cm = graph.getMetadata(CommentMetadata.class);\r
- graph.addMetadata(cm.add("Added new annotationValue named " + name + ", resource " + value));\r
- }\r
-\r
- return value;\r
- \r
- }\r
- \r
- }\r
-\r
- /**\r
- * @param map\r
- * @param selectionCallback\r
- */\r
- public static void queryUserSelectedAnnotationType(\r
- Map<Resource, Pair<String, ImageDescriptor>> map,\r
- Consumer<Resource> selectionCallback)\r
- {\r
- Display.getDefault().asyncExec(() -> {\r
- Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();\r
- ResourceSelectionDialog3<Resource> dialog = new ResourceSelectionDialog3<Resource>(shell, map, "Select annotation type from list") {\r
- @Override\r
- protected IDialogSettings getBaseDialogSettings() {\r
- return Activator.getDefault().getDialogSettings();\r
- }\r
- };\r
- if (dialog.open() == Window.OK) {\r
- Object[] result = dialog.getResult();\r
- if (result != null && result.length == 1) {\r
- selectionCallback.accept((Resource) result[0]);\r
- }\r
- }\r
- });\r
- }\r
-\r
- public static void queryLibrary(\r
- Map<Resource, Pair<String, ImageDescriptor>> map,\r
- Consumer<Pair<Resource,String>> selectionCallback)\r
- {\r
- Display.getDefault().asyncExec(() -> {\r
- Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();\r
- SaveAnnotationDialog page = new SaveAnnotationDialog(shell, map, "Select library");\r
- if (page.open() == Window.OK) {\r
- Object[] result = page.getResult();\r
- if (result != null && result.length == 1) {\r
- selectionCallback.accept(Pair.make((Resource)result[0], page.getName()));\r
- }\r
- }\r
- });\r
- }\r
- \r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2012 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.annotation.ui;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+import java.util.function.Consumer;
+
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.PlatformUI;
+import org.simantics.Simantics;
+import org.simantics.annotation.ontology.AnnotationResource;
+import org.simantics.annotation.ui.internal.SaveAnnotationDialog;
+import org.simantics.databoard.Bindings;
+import org.simantics.databoard.util.URIStringUtils;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.WriteGraph;
+import org.simantics.db.common.CommentMetadata;
+import org.simantics.db.common.request.PossibleIndexRoot;
+import org.simantics.db.common.request.ReadRequest;
+import org.simantics.db.common.request.WriteRequest;
+import org.simantics.db.common.utils.Logger;
+import org.simantics.db.common.utils.NameUtils;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.layer0.adapter.Instances;
+import org.simantics.db.layer0.request.PossibleModel;
+import org.simantics.db.layer0.request.VariableRead;
+import org.simantics.db.layer0.util.Layer0Utils;
+import org.simantics.db.layer0.variable.Variable;
+import org.simantics.db.layer0.variable.Variables;
+import org.simantics.layer0.Layer0;
+import org.simantics.selectionview.SelectionViewResources;
+import org.simantics.structural.stubs.StructuralResource2;
+import org.simantics.ui.workbench.dialogs.ResourceSelectionDialog3;
+import org.simantics.utils.datastructures.Pair;
+
+/**
+ * @author Teemu Mätäsniemi
+ * @author Antti Villberg
+ * @author Tuukka Lehtonen
+ */
+public class AnnotationUtils {
+
+ /**
+ * @param graph
+ * @param parent
+ * @return (r1, r2) pair where r1 is the created annotation property
+ * relation and and r2 is the created annotation type
+ * @throws DatabaseException
+ */
+ public static Pair<Resource, Resource> newAnnotationType(WriteGraph graph, final Resource parent) throws DatabaseException {
+ graph.markUndoPoint();
+ Layer0 L0 = Layer0.getInstance(graph);
+ AnnotationResource ANNO = AnnotationResource.getInstance(graph);
+ SelectionViewResources SEL = SelectionViewResources.getInstance(graph);
+ StructuralResource2 STR = StructuralResource2.getInstance(graph);
+
+ Resource indexRoot = graph.sync(new PossibleIndexRoot(parent));
+
+ // Get supertype for annotation type
+ Resource propertySubrelation = graph.getPossibleObject(indexRoot, ANNO.HasAnnotationPropertySubrelation);
+ if (propertySubrelation == null)
+ propertySubrelation = L0.HasProperty;
+ Resource supertype = graph.getPossibleObject(indexRoot, ANNO.HasAnnotationTypeSupertype);
+ if (supertype == null)
+ supertype = ANNO.Annotation;
+
+ Resource property = graph.newResource();
+ String name = NameUtils.findFreshName(graph, "newAnnotationProperty", parent, L0.ConsistsOf);
+ graph.addLiteral(property, L0.HasName, L0.NameOf, L0.String, name, Bindings.STRING);
+ graph.claim(property, L0.SubrelationOf, propertySubrelation);
+
+ Resource type = graph.newResource();
+ graph.claim(type, L0.Inherits, null, supertype);
+ graph.addLiteral(type, L0.HasName, L0.NameOf, L0.String, UUID.randomUUID().toString(), Bindings.STRING);
+ graph.claim(type, STR.ComponentType_HasDefaultPropertyRelationType, SEL.GenericParameterType);
+
+ graph.claim(property, L0.HasRange, type);
+
+ graph.claim(type, L0.ConsistsOf, property);
+ graph.claim(parent, L0.ConsistsOf, type);
+
+ CommentMetadata cm = graph.getMetadata(CommentMetadata.class);
+ graph.addMetadata(cm.add("Added new annotationType " + type + " with property relation " + property + " "));
+
+ return Pair.make(property, type);
+ }
+
+ public static void newAnnotation(ReadGraph graph, Resource parent, Resource model) throws DatabaseException {
+
+ Map<Resource, Pair<String, ImageDescriptor>> map = new HashMap<>();
+ findAnnotationTypes(graph, model, map);
+ findAnnotations(graph, model, map);
+ queryUserSelectedAnnotationType(map, selected -> {
+ Simantics.getSession().async(new WriteRequest() {
+ @Override
+ public void perform(WriteGraph g) throws DatabaseException {
+ newAnnotation(g, parent, selected);
+ }
+ });
+ });
+
+ }
+
+ private static boolean isEntryAnnotation(ReadGraph graph, Resource selected) throws DatabaseException {
+ Layer0 L0 = Layer0.getInstance(graph);
+ AnnotationResource ANNO = AnnotationResource.getInstance(graph);
+ if(graph.isInstanceOf(selected, ANNO.Annotation)) {
+ Resource type = graph.getSingleType(selected, ANNO.Annotation);
+ return !graph.hasStatement(type, L0.HasRange_Inverse);
+ } else if (graph.isInstanceOf(selected, ANNO.AnnotationType)) {
+ return !graph.hasStatement(selected, L0.HasRange_Inverse);
+ } else {
+ throw new DatabaseException("Incompatible resource " + selected);
+ }
+ }
+
+ public static void newAnnotation(ReadGraph graph, Variable position, Resource model) throws DatabaseException {
+
+ Map<Resource, Pair<String, ImageDescriptor>> map = new HashMap<>();
+ findAnnotationTypes(graph, model, map);
+ findAnnotations(graph, model, map);
+ queryUserSelectedAnnotationType(map, selected -> {
+ Simantics.getSession().async(new WriteRequest() {
+ @Override
+ public void perform(WriteGraph g) throws DatabaseException {
+ g.markUndoPoint();
+ if(isEntryAnnotation(g, selected)) {
+ newAnnotation(g, position.getRepresents(g), selected);
+ Layer0Utils.addCommentMetadata(g, "Attached new annotation to " + g.getRelatedValue2(position.getRepresents(g), Layer0.getInstance(g).HasName, Bindings.STRING));
+ } else {
+ newAnnotation(g, position.getParent(g).getRepresents(g), selected);
+ Layer0Utils.addCommentMetadata(g, "Attached new annotation to " + g.getRelatedValue2(position.getParent(g).getRepresents(g), Layer0.getInstance(g).HasName, Bindings.STRING));
+ }
+ }
+ });
+ });
+
+ }
+
+ /**
+ * Creates a new annotation instance for the specified parent after the user
+ * selects the annotation type from the list of all annotation types in the
+ * specified model. The annotation types are resolved from the model
+ * dependency index.
+ *
+ * @param parent
+ * @param model
+ * @throws DatabaseException
+ */
+ public static void newAnnotation(Resource parent, Resource model) throws DatabaseException {
+ if (model == null)
+ return;
+ Simantics.getSession().syncRequest(new ReadRequest() {
+ @Override
+ public void run(ReadGraph graph) throws DatabaseException {
+ newAnnotation(graph, parent, model);
+ }
+ });
+ }
+
+ public static void newAnnotation(Resource parent) throws DatabaseException {
+ Simantics.getSession().syncRequest(new ReadRequest() {
+ @Override
+ public void run(ReadGraph graph) throws DatabaseException {
+ Resource model = graph.sync(new PossibleModel(parent));
+ if(model == null) return;
+ newAnnotation(graph, parent, model);
+ }
+ });
+ }
+
+ public static void newAnnotation(Variable position) throws DatabaseException {
+ Simantics.getSession().syncRequest(new ReadRequest() {
+ @Override
+ public void run(ReadGraph graph) throws DatabaseException {
+ Resource model = Variables.getModel(graph, position);
+ if(model == null) return;
+ newAnnotation(graph, position, model);
+ }
+ });
+ }
+
+ public static void newAnnotationInstance(Resource parent, Resource model) throws DatabaseException {
+ if (model == null)
+ return;
+ Simantics.getSession().syncRequest(new ReadRequest() {
+ @Override
+ public void run(ReadGraph graph) throws DatabaseException {
+ Map<Resource, Pair<String, ImageDescriptor>> map = new HashMap<>();
+ findAnnotationTypes(graph, model, map);
+ queryUserSelectedAnnotationType(map, selected -> {
+ Simantics.getSession().async(new WriteRequest() {
+ @Override
+ public void perform(WriteGraph g) throws DatabaseException {
+ g.markUndoPoint();
+ newAnnotationInstance(g, parent, selected);
+ }
+ });
+ });
+ }
+ });
+ }
+
+ /**
+ * @param graph
+ * @param model
+ * @return
+ * @throws DatabaseException
+ */
+ protected static void findAnnotationTypes(ReadGraph graph, Resource model, Map<Resource, Pair<String, ImageDescriptor>> map) throws DatabaseException {
+
+ Layer0 L0 = Layer0.getInstance(graph);
+ AnnotationResource ANNO = AnnotationResource.getInstance(graph);
+
+ Instances query = graph.adapt(ANNO.AnnotationType, Instances.class);
+
+ String modelURI = graph.getURI(model);
+
+ ImageDescriptor descriptor = graph.adapt(ANNO.Images_AnnotationType, ImageDescriptor.class);
+
+ for(Resource _res : query.find(graph, model)) {
+ // Don't allow instantiation of abstract annotation types.
+ if (graph.hasStatement(_res, L0.Abstract))
+ continue;
+
+ // Don't allow instantiation of non-user-selectable annotation types
+ Boolean userSelectable = graph.getPossibleRelatedValue2(_res, ANNO.AnnotationType_systemAnnotation, Bindings.BOOLEAN);
+ if (Boolean.TRUE.equals(userSelectable))
+ continue;
+
+ Resource res = graph.getPossibleObject(_res, L0.HasRange_Inverse);
+ if(res == null) {
+
+ // Entry type
+
+ String name = graph.getPossibleRelatedValue(_res, L0.HasName, Bindings.STRING);
+ if (name == null)
+ continue;
+ String label = graph.getPossibleRelatedValue2(_res, L0.HasLabel, Bindings.STRING);
+
+ if (label != null && !name.equals(label)) {
+ name = label + " (" + name + ")";
+ }
+
+ Resource parent = graph.getPossibleObject(_res, L0.PartOf);
+ if(parent == null) continue;
+
+ String parentURI = graph.getURI(parent);
+ if(parentURI.startsWith(modelURI)) {
+ parentURI = parentURI.substring(modelURI.length());
+ if(parentURI.startsWith("/")) parentURI = parentURI.substring(1);
+ }
+
+ name = name + " - " + URIStringUtils.unescape(parentURI);
+
+ map.put(_res, Pair.make(name, descriptor));
+
+ } else {
+
+ // Property type
+
+ String name = graph.getPossibleRelatedValue(res, L0.HasName, Bindings.STRING);
+ if (name == null)
+ continue;
+ String label = graph.getPossibleRelatedValue2(res, L0.HasLabel, Bindings.STRING);
+
+ if (label != null && !name.equals(label)) {
+ name = label + " (" + name + ")";
+ }
+
+ Resource parent = graph.getPossibleObject(_res, L0.PartOf);
+ if(parent == null) continue;
+
+ String parentURI = graph.getURI(parent);
+ if(parentURI.startsWith(modelURI)) {
+ parentURI = parentURI.substring(modelURI.length());
+ if(parentURI.startsWith("/")) parentURI = parentURI.substring(1);
+ }
+
+ name = name + " - " + URIStringUtils.unescape(parentURI);
+
+ map.put(_res, Pair.make(name, descriptor));
+
+ }
+
+ }
+
+ }
+
+ protected static void findAnnotations(ReadGraph graph, Resource model, Map<Resource, Pair<String, ImageDescriptor>> map) throws DatabaseException {
+
+ Layer0 L0 = Layer0.getInstance(graph);
+ AnnotationResource ANNO = AnnotationResource.getInstance(graph);
+
+ Instances query = graph.adapt(ANNO.Annotation, Instances.class);
+
+ String modelURI = graph.getURI(model);
+
+ ImageDescriptor descriptor = graph.adapt(ANNO.Images_Annotation, ImageDescriptor.class);
+
+ for(Resource _res : query.find(graph, model)) {
+ String name = graph.getPossibleRelatedValue(_res, L0.HasName, Bindings.STRING);
+ if (name == null)
+ continue;
+ String label = graph.getPossibleRelatedValue2(_res, L0.HasLabel, Bindings.STRING);
+ if (label != null && !name.equals(label)) {
+ name = label + " (" + name + ")";
+ }
+
+ Resource parent = graph.getPossibleObject(_res, L0.PartOf);
+ if(parent == null) continue;
+
+ String parentURI = graph.getPossibleURI(parent);
+ if(parentURI == null) continue;
+
+ if(parentURI.startsWith(modelURI)) {
+ parentURI = parentURI.substring(modelURI.length());
+ if(parentURI.startsWith("/")) parentURI = parentURI.substring(1);
+ }
+
+ Resource type = graph.getPossibleType(_res, ANNO.Annotation);
+ if(type != null) {
+ // Don't list instances of non-user-selectable annotation types
+ Boolean userSelectable = graph.getPossibleRelatedValue2(type, ANNO.AnnotationType_systemAnnotation, Bindings.BOOLEAN);
+ if (Boolean.TRUE.equals(userSelectable))
+ continue;
+
+ Resource relation = graph.getPossibleObject(type, L0.HasRange_Inverse);
+ if(relation != null) {
+ String rName = graph.getPossibleRelatedValue(relation, L0.HasName, Bindings.STRING);
+ if(rName != null) {
+ name = name + " - " + rName;
+ }
+ }
+ }
+
+ name = name + " - " + URIStringUtils.unescape(parentURI);
+
+ map.put(_res, Pair.make(name, descriptor));
+
+ }
+
+ }
+
+ protected static boolean isAnnotation(Variable variable) {
+ if (variable == null)
+ return false;
+ try {
+ return Simantics.sync(new VariableRead<Boolean>(variable) {
+
+ @Override
+ public Boolean perform(ReadGraph graph) throws DatabaseException {
+ AnnotationResource ANNO = AnnotationResource.getInstance(graph);
+ Resource represents = variable.getPossibleRepresents(graph);
+ if(represents == null) return false;
+ return graph.isInstanceOf(represents, ANNO.Annotation);
+ }
+
+ });
+ } catch (DatabaseException e) {
+ return false;
+ }
+ }
+
+ protected static Map<Resource, Pair<String, ImageDescriptor>> findLibraries(Variable variable) {
+
+ try {
+
+ return Simantics.sync(new VariableRead<Map<Resource, Pair<String, ImageDescriptor>>>(variable) {
+
+ @Override
+ public Map<Resource, Pair<String, ImageDescriptor>> perform(ReadGraph graph) throws DatabaseException {
+
+ Map<Resource, Pair<String, ImageDescriptor>> result = new HashMap<>();
+
+ Layer0 L0 = Layer0.getInstance(graph);
+ AnnotationResource ANNO = AnnotationResource.getInstance(graph);
+
+ Resource model = Variables.getModel(graph, variable);
+ Instances query = graph.adapt(L0.Library, Instances.class);
+
+ String modelURI = graph.getURI(model);
+ int modelPos = modelURI.length();
+
+ ImageDescriptor descriptor = graph.adapt(ANNO.Images_Annotation, ImageDescriptor.class);
+
+ for(Resource lib : query.find(graph, model)) {
+
+ String path = graph.getURI(lib);
+ if(!path.startsWith(modelURI)) continue;
+ String suffix = URIStringUtils.unescape(path.substring(modelPos));
+ if(suffix.startsWith("/")) suffix = suffix.substring(1);
+ result.put(lib, Pair.make(suffix, descriptor));
+
+ }
+
+ return result;
+
+ }
+ });
+
+ } catch (DatabaseException e) {
+ Logger.defaultLogError(e);
+ }
+
+ return null;
+
+ }
+
+ public static Resource newAnnotation(WriteGraph graph, Resource container, Resource valueOrProperty) throws DatabaseException {
+ graph.markUndoPoint();
+ Layer0 L0 = Layer0.getInstance(graph);
+ AnnotationResource ANNO = AnnotationResource.getInstance(graph);
+
+ if(graph.isInstanceOf(valueOrProperty, ANNO.Annotation)) {
+
+ Resource type = graph.getPossibleType(valueOrProperty, ANNO.Annotation);
+ if(type == null) return null;
+ Resource property = graph.getPossibleObject(type, L0.HasRange_Inverse);
+ if(property == null) {
+ graph.claim(container, ANNO.Annotation_HasEntry, valueOrProperty);
+ } else {
+ graph.deny(container, property);
+ graph.claim(container, property, valueOrProperty);
+ }
+ Layer0Utils.addCommentMetadata(graph, "Created new annotation value/property " + valueOrProperty + " to " + graph.getRelatedValue2(container, L0.HasName, Bindings.STRING));
+ return valueOrProperty;
+
+ } else if (graph.isInstanceOf(valueOrProperty, ANNO.AnnotationType)) {
+
+ Resource predicate = graph.getPossibleObject(valueOrProperty, L0.HasRange_Inverse);
+ if(predicate != null) {
+ Resource value = graph.newResource();
+ graph.claim(value, L0.InstanceOf, valueOrProperty);
+ graph.deny(container, predicate);
+ graph.claim(container, predicate, value);
+ Layer0Utils.addCommentMetadata(graph, "Created new annotation type " + value + " to " + graph.getRelatedValue2(container, L0.HasName, Bindings.STRING));
+ return value;
+ } else {
+ Resource value = graph.newResource();
+ graph.claim(value, L0.InstanceOf, valueOrProperty);
+ String name = NameUtils.findFreshEscapedName(graph, "Value", container, ANNO.Annotation_HasEntry);
+ graph.addLiteral(value, L0.HasName, L0.NameOf, L0.String, name, Bindings.STRING);
+ graph.claim(container, ANNO.Annotation_HasEntry, value);
+ Layer0Utils.addCommentMetadata(graph, "Created new annotation entry " + value + " to " + graph.getRelatedValue2(container, L0.HasName, Bindings.STRING));
+ return value;
+ }
+
+ } else {
+
+ Resource valueType = graph.getSingleObject(valueOrProperty, L0.HasRange);
+ Resource value = graph.newResource();
+ graph.claim(value, L0.InstanceOf, valueType);
+ graph.deny(container, valueOrProperty);
+ graph.claim(container, valueOrProperty, value);
+ return value;
+
+ }
+
+ }
+
+ public static Resource newAnnotationInstance(WriteGraph graph, Resource container, Resource annotationProperty) throws DatabaseException {
+ return newAnnotationInstance(graph, container, null, annotationProperty);
+ }
+
+ public static Resource newAnnotationInstance(WriteGraph graph, Resource container, String name, Resource annotationProperty) throws DatabaseException {
+ return newAnnotationInstance(graph, container, name, annotationProperty, true);
+ }
+
+ public static Resource newAnnotationInstance(WriteGraph graph, Resource container, String name, Resource annotationProperty, boolean addCommentMetadata) throws DatabaseException {
+ //graph.markUndoPoint();
+ Layer0 L0 = Layer0.getInstance(graph);
+ AnnotationResource ANNO = AnnotationResource.getInstance(graph);
+
+ if(graph.isInstanceOf(annotationProperty, ANNO.AnnotationType)) {
+
+ Resource predicate = graph.getPossibleObject(annotationProperty, L0.HasRange_Inverse);
+
+ String proposition = predicate != null ? (String)graph.getRelatedValue(predicate, L0.HasName, Bindings.STRING) :
+ (String)graph.getRelatedValue(annotationProperty, L0.HasName, Bindings.STRING);
+
+ Resource value = graph.newResource();
+ graph.claim(value, L0.InstanceOf, annotationProperty);
+ if(name == null)
+ name = NameUtils.findFreshName(graph, proposition + " value", container);
+ graph.addLiteral(value, L0.HasName, L0.NameOf, L0.String, name, Bindings.STRING);
+
+ graph.claim(container, L0.ConsistsOf, value);
+
+ if (addCommentMetadata) {
+ CommentMetadata cm = graph.getMetadata(CommentMetadata.class);
+ graph.addMetadata(cm.add("Added new annotationValue named " + name + ", resource " + value));
+ }
+
+ return value;
+
+ } else {
+
+ String propertyName = graph.getRelatedValue(annotationProperty, L0.HasName, Bindings.STRING);
+
+ Resource valueType = graph.getSingleObject(annotationProperty, L0.HasRange);
+ Resource value = graph.newResource();
+ graph.claim(value, L0.InstanceOf, valueType);
+ if(name == null)
+ name = NameUtils.findFreshName(graph, propertyName + " value", container);
+ graph.addLiteral(value, L0.HasName, L0.NameOf, L0.String, name, Bindings.STRING);
+
+ graph.claim(container, L0.ConsistsOf, value);
+
+ if (addCommentMetadata) {
+ CommentMetadata cm = graph.getMetadata(CommentMetadata.class);
+ graph.addMetadata(cm.add("Added new annotationValue named " + name + ", resource " + value));
+ }
+
+ return value;
+
+ }
+
+ }
+
+ /**
+ * @param map
+ * @param selectionCallback
+ */
+ public static void queryUserSelectedAnnotationType(
+ Map<Resource, Pair<String, ImageDescriptor>> map,
+ Consumer<Resource> selectionCallback)
+ {
+ Display.getDefault().asyncExec(() -> {
+ Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
+ ResourceSelectionDialog3<Resource> dialog = new ResourceSelectionDialog3<Resource>(shell, map, "Select annotation type from list") {
+ @Override
+ protected IDialogSettings getBaseDialogSettings() {
+ return Activator.getDefault().getDialogSettings();
+ }
+ };
+ if (dialog.open() == Window.OK) {
+ Object[] result = dialog.getResult();
+ if (result != null && result.length == 1) {
+ selectionCallback.accept((Resource) result[0]);
+ }
+ }
+ });
+ }
+
+ public static void queryLibrary(
+ Map<Resource, Pair<String, ImageDescriptor>> map,
+ Consumer<Pair<Resource,String>> selectionCallback)
+ {
+ Display.getDefault().asyncExec(() -> {
+ Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
+ SaveAnnotationDialog page = new SaveAnnotationDialog(shell, map, "Select library");
+ if (page.open() == Window.OK) {
+ Object[] result = page.getResult();
+ if (result != null && result.length == 1) {
+ selectionCallback.accept(Pair.make((Resource)result[0], page.getName()));
+ }
+ }
+ });
+ }
+
+}