]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.annotation.ui/src/org/simantics/annotation/ui/AnnotationUtils.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.annotation.ui / src / org / simantics / annotation / ui / AnnotationUtils.java
1 /*******************************************************************************
2  * Copyright (c) 2012 Association for Decentralized Information Management in
3  * Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.annotation.ui;
13
14 import java.util.HashMap;
15 import java.util.Map;
16 import java.util.UUID;
17 import java.util.function.Consumer;
18
19 import org.eclipse.jface.dialogs.IDialogSettings;
20 import org.eclipse.jface.resource.ImageDescriptor;
21 import org.eclipse.jface.window.Window;
22 import org.eclipse.swt.widgets.Display;
23 import org.eclipse.swt.widgets.Shell;
24 import org.eclipse.ui.PlatformUI;
25 import org.simantics.Simantics;
26 import org.simantics.annotation.ontology.AnnotationResource;
27 import org.simantics.annotation.ui.internal.SaveAnnotationDialog;
28 import org.simantics.databoard.Bindings;
29 import org.simantics.databoard.util.URIStringUtils;
30 import org.simantics.db.ReadGraph;
31 import org.simantics.db.Resource;
32 import org.simantics.db.WriteGraph;
33 import org.simantics.db.common.CommentMetadata;
34 import org.simantics.db.common.request.PossibleIndexRoot;
35 import org.simantics.db.common.request.ReadRequest;
36 import org.simantics.db.common.request.WriteRequest;
37 import org.simantics.db.common.utils.Logger;
38 import org.simantics.db.common.utils.NameUtils;
39 import org.simantics.db.exception.DatabaseException;
40 import org.simantics.db.layer0.adapter.Instances;
41 import org.simantics.db.layer0.request.PossibleModel;
42 import org.simantics.db.layer0.request.VariableRead;
43 import org.simantics.db.layer0.util.Layer0Utils;
44 import org.simantics.db.layer0.variable.Variable;
45 import org.simantics.db.layer0.variable.Variables;
46 import org.simantics.layer0.Layer0;
47 import org.simantics.selectionview.SelectionViewResources;
48 import org.simantics.structural.stubs.StructuralResource2;
49 import org.simantics.ui.workbench.dialogs.ResourceSelectionDialog3;
50 import org.simantics.utils.datastructures.Pair;
51
52 /**
53  * @author Teemu Mätäsniemi
54  * @author Antti Villberg
55  * @author Tuukka Lehtonen
56  */
57 public class AnnotationUtils {
58
59         /**
60          * @param graph
61          * @param parent
62          * @return (r1, r2) pair where r1 is the created annotation property
63          *         relation and and r2 is the created annotation type
64          * @throws DatabaseException
65          */
66         public static Pair<Resource, Resource> newAnnotationType(WriteGraph graph, final Resource parent) throws DatabaseException {
67             graph.markUndoPoint();
68                 Layer0 L0 = Layer0.getInstance(graph);
69                 AnnotationResource ANNO = AnnotationResource.getInstance(graph);
70                 SelectionViewResources SEL = SelectionViewResources.getInstance(graph);
71                 StructuralResource2 STR = StructuralResource2.getInstance(graph);
72
73                 Resource indexRoot = graph.sync(new PossibleIndexRoot(parent));
74
75                 // Get supertype for annotation type
76                 Resource propertySubrelation = graph.getPossibleObject(indexRoot, ANNO.HasAnnotationPropertySubrelation);
77                 if (propertySubrelation == null)
78                         propertySubrelation = L0.HasProperty;
79                 Resource supertype = graph.getPossibleObject(indexRoot, ANNO.HasAnnotationTypeSupertype);
80                 if (supertype == null)
81                         supertype = ANNO.Annotation;
82
83                 Resource property = graph.newResource();
84                 String name = NameUtils.findFreshName(graph, "newAnnotationProperty", parent, L0.ConsistsOf);
85                 graph.addLiteral(property, L0.HasName, L0.NameOf, L0.String, name, Bindings.STRING);
86                 graph.claim(property, L0.SubrelationOf, propertySubrelation);
87
88                 Resource type = graph.newResource();
89                 graph.claim(type, L0.Inherits, null, supertype);
90                 graph.addLiteral(type, L0.HasName, L0.NameOf, L0.String, UUID.randomUUID().toString(), Bindings.STRING);
91                 graph.claim(type, STR.ComponentType_HasDefaultPropertyRelationType, SEL.GenericParameterType);
92
93                 graph.claim(property, L0.HasRange, type);
94
95                 graph.claim(type, L0.ConsistsOf, property);
96                 graph.claim(parent, L0.ConsistsOf, type);
97                 
98                 CommentMetadata cm = graph.getMetadata(CommentMetadata.class);
99         graph.addMetadata(cm.add("Added new annotationType " + type + " with property relation " + property + " "));
100
101                 return Pair.make(property, type);
102         }
103
104         public static void newAnnotation(ReadGraph graph, Resource parent, Resource model) throws DatabaseException {
105
106         Map<Resource, Pair<String, ImageDescriptor>> map = new HashMap<>();
107         findAnnotationTypes(graph, model, map);
108         findAnnotations(graph, model, map);
109         queryUserSelectedAnnotationType(map, selected -> {
110             Simantics.getSession().async(new WriteRequest() {
111                 @Override
112                 public void perform(WriteGraph g) throws DatabaseException {
113                     newAnnotation(g, parent, selected);
114                 }
115             });
116         });
117
118         }
119
120         private static boolean isEntryAnnotation(ReadGraph graph, Resource selected) throws DatabaseException {
121                 Layer0 L0 = Layer0.getInstance(graph);
122         AnnotationResource ANNO = AnnotationResource.getInstance(graph);
123         if(graph.isInstanceOf(selected, ANNO.Annotation)) {
124                 Resource type = graph.getSingleType(selected, ANNO.Annotation);
125                 return !graph.hasStatement(type, L0.HasRange_Inverse);
126         } else if (graph.isInstanceOf(selected, ANNO.AnnotationType)) {
127                 return !graph.hasStatement(selected, L0.HasRange_Inverse);
128         } else {
129                 throw new DatabaseException("Incompatible resource " + selected);
130         }
131         }
132         
133         public static void newAnnotation(ReadGraph graph, Variable position, Resource model) throws DatabaseException {
134
135         Map<Resource, Pair<String, ImageDescriptor>> map = new HashMap<>();
136         findAnnotationTypes(graph, model, map);
137         findAnnotations(graph, model, map);
138         queryUserSelectedAnnotationType(map, selected -> {
139             Simantics.getSession().async(new WriteRequest() {
140                 @Override
141                 public void perform(WriteGraph g) throws DatabaseException {
142                     g.markUndoPoint();
143                     if(isEntryAnnotation(g, selected)) {
144                         newAnnotation(g, position.getRepresents(g), selected);
145                         Layer0Utils.addCommentMetadata(g, "Attached new annotation to " + g.getRelatedValue2(position.getRepresents(g), Layer0.getInstance(g).HasName, Bindings.STRING));
146                     } else {
147                         newAnnotation(g, position.getParent(g).getRepresents(g), selected);
148                         Layer0Utils.addCommentMetadata(g, "Attached new annotation to " + g.getRelatedValue2(position.getParent(g).getRepresents(g), Layer0.getInstance(g).HasName, Bindings.STRING));
149                     }
150                 }
151             });
152         });
153
154         }
155         
156         /**
157          * Creates a new annotation instance for the specified parent after the user
158          * selects the annotation type from the list of all annotation types in the
159          * specified model. The annotation types are resolved from the model
160          * dependency index.
161          * 
162          * @param parent
163          * @param model
164          * @throws DatabaseException
165          */
166         public static void newAnnotation(Resource parent, Resource model) throws DatabaseException {
167                 if (model == null)
168                         return;
169                 Simantics.getSession().syncRequest(new ReadRequest() {
170                         @Override
171                         public void run(ReadGraph graph) throws DatabaseException {
172                             newAnnotation(graph, parent, model);
173                         }
174                 });
175         }
176
177         public static void newAnnotation(Resource parent) throws DatabaseException {
178         Simantics.getSession().syncRequest(new ReadRequest() {
179             @Override
180             public void run(ReadGraph graph) throws DatabaseException {
181                 Resource model = graph.sync(new PossibleModel(parent));
182                 if(model == null) return;
183                 newAnnotation(graph, parent, model);
184             }
185         });
186         }
187
188         public static void newAnnotation(Variable position) throws DatabaseException {
189         Simantics.getSession().syncRequest(new ReadRequest() {
190             @Override
191             public void run(ReadGraph graph) throws DatabaseException {
192                 Resource model = Variables.getModel(graph, position);
193                 if(model == null) return;
194                 newAnnotation(graph, position, model);
195             }
196         });
197         }
198
199         public static void newAnnotationInstance(Resource parent, Resource model) throws DatabaseException {
200         if (model == null)
201             return;
202         Simantics.getSession().syncRequest(new ReadRequest() {
203             @Override
204             public void run(ReadGraph graph) throws DatabaseException {
205                 Map<Resource, Pair<String, ImageDescriptor>> map = new HashMap<>();
206                 findAnnotationTypes(graph, model, map);
207                 queryUserSelectedAnnotationType(map, selected -> {
208                     Simantics.getSession().async(new WriteRequest() {
209                         @Override
210                         public void perform(WriteGraph g) throws DatabaseException {
211                             g.markUndoPoint();
212                             newAnnotationInstance(g, parent, selected);
213                         }
214                     });
215                 });
216             }
217         });
218     }
219
220         /**
221          * @param graph
222          * @param model
223          * @return
224          * @throws DatabaseException 
225          */
226         protected static void findAnnotationTypes(ReadGraph graph, Resource model, Map<Resource, Pair<String, ImageDescriptor>> map) throws DatabaseException {
227
228                 Layer0 L0 = Layer0.getInstance(graph);
229                 AnnotationResource ANNO = AnnotationResource.getInstance(graph);
230
231                 Instances query = graph.adapt(ANNO.AnnotationType, Instances.class);
232
233                 String modelURI = graph.getURI(model);
234                 
235         ImageDescriptor descriptor = graph.adapt(ANNO.Images_AnnotationType, ImageDescriptor.class);
236
237                 for(Resource _res : query.find(graph, model)) {
238                         // Don't allow instantiation of abstract annotation types.
239                         if (graph.hasStatement(_res, L0.Abstract))
240                                 continue;
241
242                         // Don't allow instantiation of non-user-selectable annotation types
243                         Boolean userSelectable = graph.getPossibleRelatedValue2(_res, ANNO.AnnotationType_systemAnnotation, Bindings.BOOLEAN);
244                         if (Boolean.TRUE.equals(userSelectable))
245                                 continue;
246
247                         Resource res = graph.getPossibleObject(_res, L0.HasRange_Inverse);
248                         if(res == null) {
249                                 
250                                 // Entry type
251
252                                 String name = graph.getPossibleRelatedValue(_res, L0.HasName, Bindings.STRING);
253                                 if (name == null)
254                                         continue;
255                                 String label = graph.getPossibleRelatedValue2(_res, L0.HasLabel, Bindings.STRING);
256
257                                 if (label != null && !name.equals(label)) {
258                                         name = label + " (" + name + ")";
259                                 }
260
261                                 Resource parent = graph.getPossibleObject(_res, L0.PartOf);
262                                 if(parent == null) continue;
263
264                                 String parentURI = graph.getURI(parent);
265                                 if(parentURI.startsWith(modelURI)) {
266                                         parentURI = parentURI.substring(modelURI.length());
267                                         if(parentURI.startsWith("/")) parentURI = parentURI.substring(1);
268                                 }
269
270                                 name = name + " - " + URIStringUtils.unescape(parentURI);
271
272                                 map.put(_res, Pair.make(name, descriptor));
273                                 
274                         } else {
275                                 
276                                 // Property type
277                         
278                                 String name = graph.getPossibleRelatedValue(res, L0.HasName, Bindings.STRING);
279                                 if (name == null)
280                                         continue;
281                                 String label = graph.getPossibleRelatedValue2(res, L0.HasLabel, Bindings.STRING);
282
283                                 if (label != null && !name.equals(label)) {
284                                         name = label + " (" + name + ")";
285                                 }
286
287                                 Resource parent = graph.getPossibleObject(_res, L0.PartOf);
288                                 if(parent == null) continue;
289
290                                 String parentURI = graph.getURI(parent);
291                                 if(parentURI.startsWith(modelURI)) {
292                                         parentURI = parentURI.substring(modelURI.length());
293                                         if(parentURI.startsWith("/")) parentURI = parentURI.substring(1);
294                                 }
295
296                                 name = name + " - " + URIStringUtils.unescape(parentURI);
297
298                                 map.put(_res, Pair.make(name, descriptor));
299                         
300                         }
301                         
302                 }
303
304         }
305
306     protected static void findAnnotations(ReadGraph graph, Resource model, Map<Resource, Pair<String, ImageDescriptor>> map) throws DatabaseException {
307
308         Layer0 L0 = Layer0.getInstance(graph);
309         AnnotationResource ANNO = AnnotationResource.getInstance(graph);
310
311         Instances query = graph.adapt(ANNO.Annotation, Instances.class);
312         
313         String modelURI = graph.getURI(model);
314         
315         ImageDescriptor descriptor = graph.adapt(ANNO.Images_Annotation, ImageDescriptor.class);
316
317         for(Resource _res : query.find(graph, model)) {
318             String name = graph.getPossibleRelatedValue(_res, L0.HasName, Bindings.STRING);
319             if (name == null)
320                 continue;
321             String label = graph.getPossibleRelatedValue2(_res, L0.HasLabel, Bindings.STRING);
322             if (label != null && !name.equals(label)) {
323                 name = label + " (" + name + ")";
324             }
325
326             Resource parent = graph.getPossibleObject(_res, L0.PartOf);
327             if(parent == null) continue;
328
329             String parentURI = graph.getPossibleURI(parent);
330             if(parentURI == null) continue;
331              
332             if(parentURI.startsWith(modelURI)) {
333                 parentURI = parentURI.substring(modelURI.length());
334                 if(parentURI.startsWith("/")) parentURI = parentURI.substring(1);
335             }
336
337             Resource type = graph.getPossibleType(_res, ANNO.Annotation);
338             if(type != null) {
339                 // Don't list instances of non-user-selectable annotation types
340                 Boolean userSelectable = graph.getPossibleRelatedValue2(type, ANNO.AnnotationType_systemAnnotation, Bindings.BOOLEAN);
341                 if (Boolean.TRUE.equals(userSelectable))
342                     continue;
343
344                 Resource relation = graph.getPossibleObject(type, L0.HasRange_Inverse);
345                 if(relation != null) {
346                     String rName = graph.getPossibleRelatedValue(relation, L0.HasName, Bindings.STRING);
347                     if(rName != null) {
348                         name = name + " - " + rName;
349                     }
350                 }
351             }
352             
353             name = name + " - " + URIStringUtils.unescape(parentURI);
354             
355             map.put(_res, Pair.make(name, descriptor));
356             
357         }
358
359     }
360
361     protected static boolean isAnnotation(Variable variable) {
362         if (variable == null)
363                 return false;
364         try {
365                 return Simantics.sync(new VariableRead<Boolean>(variable) {
366
367                         @Override
368                         public Boolean perform(ReadGraph graph) throws DatabaseException {
369                                 AnnotationResource ANNO = AnnotationResource.getInstance(graph);
370                                 Resource represents = variable.getPossibleRepresents(graph);
371                                 if(represents == null) return false;
372                                 return graph.isInstanceOf(represents, ANNO.Annotation);
373                         }
374
375                 });
376         } catch (DatabaseException e) {
377                 return false;
378         }
379     }
380     
381     protected static Map<Resource, Pair<String, ImageDescriptor>> findLibraries(Variable variable) {
382
383         try {
384
385                 return Simantics.sync(new VariableRead<Map<Resource, Pair<String, ImageDescriptor>>>(variable) {
386
387                         @Override
388                         public Map<Resource, Pair<String, ImageDescriptor>> perform(ReadGraph graph) throws DatabaseException {
389
390                                 Map<Resource, Pair<String, ImageDescriptor>> result = new HashMap<>();
391
392                                 Layer0 L0 = Layer0.getInstance(graph);
393                                 AnnotationResource ANNO = AnnotationResource.getInstance(graph);
394
395                                 Resource model = Variables.getModel(graph, variable);
396                                 Instances query = graph.adapt(L0.Library, Instances.class);
397
398                                 String modelURI = graph.getURI(model);
399                                 int modelPos = modelURI.length();
400
401                                 ImageDescriptor descriptor = graph.adapt(ANNO.Images_Annotation, ImageDescriptor.class);
402
403                                 for(Resource lib : query.find(graph, model)) {
404
405                                         String path = graph.getURI(lib);
406                                         if(!path.startsWith(modelURI)) continue;
407                                         String suffix = URIStringUtils.unescape(path.substring(modelPos));
408                                         if(suffix.startsWith("/")) suffix = suffix.substring(1);
409                                         result.put(lib, Pair.make(suffix, descriptor));
410
411                                 }
412
413                                 return result;
414                                 
415                         }
416                 });
417
418         } catch (DatabaseException e) {
419                 Logger.defaultLogError(e);
420         }
421         
422         return null;
423
424     }
425
426     public static Resource newAnnotation(WriteGraph graph, Resource container, Resource valueOrProperty) throws DatabaseException {
427             graph.markUndoPoint();
428                 Layer0 L0 = Layer0.getInstance(graph);
429                 AnnotationResource ANNO = AnnotationResource.getInstance(graph);
430
431                 if(graph.isInstanceOf(valueOrProperty, ANNO.Annotation)) {
432
433                     Resource type = graph.getPossibleType(valueOrProperty, ANNO.Annotation);
434                     if(type == null) return null;
435                     Resource property = graph.getPossibleObject(type, L0.HasRange_Inverse);
436             if(property == null) {
437                 graph.claim(container, ANNO.Annotation_HasEntry, valueOrProperty);
438             } else {
439                 graph.deny(container, property);
440                 graph.claim(container, property, valueOrProperty);
441             }
442             Layer0Utils.addCommentMetadata(graph, "Created new annotation value/property " + valueOrProperty + " to " + graph.getRelatedValue2(container, L0.HasName, Bindings.STRING));
443                 return valueOrProperty;
444             
445                 } else if (graph.isInstanceOf(valueOrProperty, ANNO.AnnotationType)) {
446                     
447                         Resource predicate = graph.getPossibleObject(valueOrProperty, L0.HasRange_Inverse);
448                         if(predicate != null) {
449                             Resource value = graph.newResource();
450                             graph.claim(value, L0.InstanceOf, valueOrProperty);
451                             graph.deny(container, predicate);
452                             graph.claim(container, predicate, value);
453                             Layer0Utils.addCommentMetadata(graph, "Created new annotation type " + value + " to " + graph.getRelatedValue2(container, L0.HasName, Bindings.STRING));
454                             return value;
455                         } else {
456                             Resource value = graph.newResource();
457                             graph.claim(value, L0.InstanceOf, valueOrProperty);
458                             String name = NameUtils.findFreshEscapedName(graph, "Value", container, ANNO.Annotation_HasEntry);
459                             graph.addLiteral(value, L0.HasName, L0.NameOf, L0.String, name, Bindings.STRING);
460                             graph.claim(container, ANNO.Annotation_HasEntry, value);
461                             Layer0Utils.addCommentMetadata(graph, "Created new annotation entry " + value + " to " + graph.getRelatedValue2(container, L0.HasName, Bindings.STRING));
462                             return value;
463                         }
464                         
465                 } else {
466                 
467                     Resource valueType = graph.getSingleObject(valueOrProperty, L0.HasRange);
468                     Resource value = graph.newResource();
469                     graph.claim(value, L0.InstanceOf, valueType);
470                     graph.deny(container, valueOrProperty);
471                     graph.claim(container, valueOrProperty, value);
472                     return value;
473                 
474                 }
475                 
476         }
477
478     public static Resource newAnnotationInstance(WriteGraph graph, Resource container, Resource annotationProperty) throws DatabaseException {
479         return newAnnotationInstance(graph, container, null, annotationProperty);
480     }
481
482     public static Resource newAnnotationInstance(WriteGraph graph, Resource container, String name, Resource annotationProperty) throws DatabaseException {
483         return newAnnotationInstance(graph, container, name, annotationProperty, true);
484     }
485     
486     public static Resource newAnnotationInstance(WriteGraph graph, Resource container, String name, Resource annotationProperty, boolean addCommentMetadata) throws DatabaseException {
487         //graph.markUndoPoint();
488         Layer0 L0 = Layer0.getInstance(graph);
489         AnnotationResource ANNO = AnnotationResource.getInstance(graph);
490
491         if(graph.isInstanceOf(annotationProperty, ANNO.AnnotationType)) {
492
493                 Resource predicate = graph.getPossibleObject(annotationProperty, L0.HasRange_Inverse);
494
495                 String proposition = predicate != null ?  (String)graph.getRelatedValue(predicate, L0.HasName, Bindings.STRING) :
496                         (String)graph.getRelatedValue(annotationProperty, L0.HasName, Bindings.STRING);
497                 
498                 Resource value = graph.newResource();
499                 graph.claim(value, L0.InstanceOf, annotationProperty);
500                 if(name == null)
501                         name = NameUtils.findFreshName(graph, proposition + " value", container);
502                 graph.addLiteral(value, L0.HasName, L0.NameOf, L0.String, name, Bindings.STRING);
503
504                 graph.claim(container, L0.ConsistsOf, value);
505                 
506                 if (addCommentMetadata) {
507                         CommentMetadata cm = graph.getMetadata(CommentMetadata.class);
508                         graph.addMetadata(cm.add("Added new annotationValue named " + name + ", resource " + value));
509                 }
510                 
511                 return value;
512                 
513         } else {
514
515             String propertyName = graph.getRelatedValue(annotationProperty, L0.HasName, Bindings.STRING);
516             
517             Resource valueType = graph.getSingleObject(annotationProperty, L0.HasRange);
518             Resource value = graph.newResource();
519             graph.claim(value, L0.InstanceOf, valueType);
520                 if(name == null)
521                         name = NameUtils.findFreshName(graph, propertyName + " value", container);
522             graph.addLiteral(value, L0.HasName, L0.NameOf, L0.String, name, Bindings.STRING);
523
524             graph.claim(container, L0.ConsistsOf, value);
525             
526             if (addCommentMetadata) {
527                 CommentMetadata cm = graph.getMetadata(CommentMetadata.class);
528                 graph.addMetadata(cm.add("Added new annotationValue named " + name + ", resource " + value));
529             }
530
531             return value;
532                 
533         }
534         
535     }
536
537         /**
538          * @param map
539          * @param selectionCallback
540          */
541         public static void queryUserSelectedAnnotationType(
542                         Map<Resource, Pair<String, ImageDescriptor>> map,
543                         Consumer<Resource> selectionCallback)
544         {
545                 Display.getDefault().asyncExec(() -> {
546                         Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
547                         ResourceSelectionDialog3<Resource> dialog = new ResourceSelectionDialog3<Resource>(shell, map, "Select annotation type from list") {
548                                 @Override
549                                 protected IDialogSettings getBaseDialogSettings() {
550                                         return Activator.getDefault().getDialogSettings();
551                                 }
552                         };
553                         if (dialog.open() == Window.OK) {
554                                 Object[] result = dialog.getResult();
555                                 if (result != null && result.length == 1) {
556                                         selectionCallback.accept((Resource) result[0]);
557                                 }
558                         }
559                 });
560         }
561
562         public static void queryLibrary(
563                         Map<Resource, Pair<String, ImageDescriptor>> map,
564                         Consumer<Pair<Resource,String>> selectionCallback)
565         {
566                 Display.getDefault().asyncExec(() -> {
567                         Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
568                         SaveAnnotationDialog page = new SaveAnnotationDialog(shell, map, "Select library");
569                         if (page.open() == Window.OK) {
570                                 Object[] result = page.getResult();
571                                 if (result != null && result.length == 1) {
572                                         selectionCallback.accept(Pair.make((Resource)result[0], page.getName()));
573                                 }
574                         }
575                 });
576         }
577         
578 }