]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.annotation.ui/src/org/simantics/annotation/ui/SCL.java
Merge commit 'd186091'
[simantics/platform.git] / bundles / org.simantics.annotation.ui / src / org / simantics / annotation / ui / SCL.java
1 /*******************************************************************************\r
2  * Copyright (c) 2013 Association for Decentralized Information Management in\r
3  * Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     Semantum Oy - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.annotation.ui;\r
13 \r
14 import java.util.ArrayList;\r
15 import java.util.Collection;\r
16 import java.util.Collections;\r
17 import java.util.Comparator;\r
18 import java.util.List;\r
19 import java.util.Map;\r
20 import java.util.Set;\r
21 \r
22 import org.eclipse.core.runtime.IStatus;\r
23 import org.eclipse.core.runtime.Status;\r
24 import org.eclipse.jface.resource.ImageDescriptor;\r
25 import org.eclipse.jface.viewers.ISelection;\r
26 import org.simantics.Simantics;\r
27 import org.simantics.annotation.ontology.AnnotationResource;\r
28 import org.simantics.databoard.Bindings;\r
29 import org.simantics.databoard.util.URIStringUtils;\r
30 import org.simantics.db.ReadGraph;\r
31 import org.simantics.db.Resource;\r
32 import org.simantics.db.Session;\r
33 import org.simantics.db.VirtualGraph;\r
34 import org.simantics.db.WriteGraph;\r
35 import org.simantics.db.common.request.UnaryRead;\r
36 import org.simantics.db.common.request.WriteRequest;\r
37 import org.simantics.db.exception.DatabaseException;\r
38 import org.simantics.db.layer0.util.Layer0Utils;\r
39 import org.simantics.db.layer0.util.RemoverUtil;\r
40 import org.simantics.db.layer0.variable.Variable;\r
41 import org.simantics.db.layer0.variable.VariableBuilder;\r
42 import org.simantics.db.layer0.variable.VariableMap;\r
43 import org.simantics.db.layer0.variable.VariableMapImpl;\r
44 import org.simantics.db.layer0.variable.Variables;\r
45 import org.simantics.db.service.VirtualGraphSupport;\r
46 import org.simantics.diagram.stubs.DiagramResource;\r
47 import org.simantics.layer0.Layer0;\r
48 import org.simantics.modeling.ModelingResources;\r
49 import org.simantics.modeling.ModelingUtils;\r
50 import org.simantics.scenegraph.loader.ScenegraphLoaderUtils;\r
51 import org.simantics.scenegraph.utils.NodeUtil;\r
52 import org.simantics.scl.reflection.annotations.SCLValue;\r
53 import org.simantics.scl.runtime.function.FunctionImpl1;\r
54 import org.simantics.scl.runtime.tuple.Tuple;\r
55 import org.simantics.scl.runtime.tuple.Tuple2;\r
56 import org.simantics.scl.runtime.tuple.Tuple3;\r
57 import org.simantics.utils.datastructures.Pair;\r
58 import org.simantics.utils.strings.AlphanumComparator;\r
59 import org.simantics.utils.ui.ISelectionUtils;\r
60 import org.simantics.views.swt.client.base.ISWTViewNode;\r
61 import org.simantics.views.swt.client.impl.SWTExplorer;\r
62 import org.slf4j.Logger;\r
63 import org.slf4j.LoggerFactory;\r
64 \r
65 import gnu.trove.map.hash.THashMap;\r
66 import gnu.trove.set.hash.THashSet;\r
67 \r
68 /**\r
69  * @author Antti Villberg\r
70  * @author Tuukka Lehtonen\r
71  */\r
72 public class SCL {\r
73     \r
74     private static final Logger LOGGER = LoggerFactory.getLogger(SCL.class);\r
75 \r
76     final public static String EMPTY = "";\r
77     final public static String MAPPED = "Mapped";\r
78     final public static String SELECTED = "Selected";\r
79 \r
80     final public static String NO_ANNOTATIONS = "No annotations";\r
81 \r
82     @SCLValue(type = "ReadGraph -> Resource -> Variable -> [(String, Resource)]")\r
83     public static List<Tuple> availableSources(ReadGraph graph, Resource resource, Variable context) throws DatabaseException {\r
84         \r
85         Variable selection = ScenegraphLoaderUtils.getPossibleVariableSelection(graph, context);\r
86         if (selection == null)\r
87             return Collections.emptyList();\r
88         List<Tuple3> sources = availableSourcesImpl(graph, selection);\r
89         if (sources.isEmpty())\r
90             return Collections.emptyList();\r
91         List<Tuple> result = new ArrayList<Tuple>(sources.size());\r
92         for(Tuple3 anno : sources) {\r
93             result.add(new Tuple2(anno.get(0),""));\r
94         }\r
95         return result;\r
96         \r
97     }\r
98 \r
99     /**\r
100      * Gathers available annotation sources and always returns them in the same\r
101      * order.\r
102      * \r
103      * @param graph\r
104      * @param selection\r
105      * @return\r
106      * @throws DatabaseException\r
107      */\r
108     private static List<Tuple3> availableSourcesImpl(ReadGraph graph, Variable selection) throws DatabaseException {\r
109         List<Variable> vars = gatherSourceVariables(graph, selection);\r
110         if (vars.isEmpty())\r
111             return Collections.emptyList();\r
112         int size = vars.size();\r
113         ArrayList<Tuple3> result = new ArrayList<Tuple3>(size);\r
114         result.add(new Tuple3(sourceLabel(graph, vars.get(0)), SELECTED, vars.get(0)));\r
115         for (int i = 1; i < size; ++i) {\r
116             Variable v = vars.get(i);\r
117             result.add(new Tuple3(sourceLabel(graph, v), MAPPED, v));\r
118         }\r
119         return result;\r
120     }\r
121 \r
122     /**\r
123      * Gathers variables starting from source in a particular order each time.\r
124      * First configuration components and second diagram elements.\r
125      * \r
126      * @param graph\r
127      * @param source\r
128      * @return\r
129      * @throws DatabaseException\r
130      */\r
131     private static List<Variable> gatherSourceVariables(ReadGraph graph, Variable source) throws DatabaseException {\r
132         Resource represents = source.getPossibleRepresents(graph);\r
133         if (represents == null)\r
134             return Collections.singletonList(source);\r
135 \r
136         ModelingResources MOD = ModelingResources.getInstance(graph);\r
137         ArrayList<Variable> result = new ArrayList<Variable>(4);\r
138         for (Resource r : ModelingUtils.getElementCorrespondendences(graph, represents))\r
139             addPossibleVariable(graph, r, result);\r
140         for(Resource r : graph.getObjects(represents, MOD.DiagramToComposite))\r
141             addPossibleVariable(graph, r, result);\r
142         result.add(source);\r
143         for(Resource r : graph.getObjects(represents, MOD.ComponentToElement))\r
144             addPossibleVariable(graph, r, result);\r
145         for(Resource r : graph.getObjects(represents, MOD.CompositeToDiagram))\r
146             addPossibleVariable(graph, r, result);\r
147         return result;\r
148     }\r
149 \r
150     private static void addPossibleVariable(ReadGraph graph, Resource r, List<Variable> result) throws DatabaseException {\r
151         Variable v = Variables.getPossibleVariable(graph, r);\r
152         if (v != null)\r
153             result.add(v);\r
154     }\r
155 \r
156     private static String sourceLabel(ReadGraph graph, Variable variable) throws DatabaseException {\r
157         Resource represents = variable.getPossibleRepresents(graph);\r
158         if(represents != null) {\r
159             DiagramResource DIA = DiagramResource.getInstance(graph);\r
160             if(graph.isInstanceOf(represents, DIA.Diagram)) return "Diagram";\r
161             else if(graph.isInstanceOf(represents, DIA.Flag)) return "Flag Element";\r
162             else if(graph.isInstanceOf(represents, DIA.RouteGraphConnection)) return "Connection Element";\r
163             else if(graph.isInstanceOf(represents, DIA.Monitor)) return "Monitor Element";\r
164             else if(graph.isInstanceOf(represents, DIA.Element)) return "Diagram Element";\r
165             else return variable.getName(graph);\r
166         } else {\r
167             return variable.getURI(graph);\r
168         }\r
169     }\r
170 \r
171     @SuppressWarnings("unchecked")\r
172     private static <T> T selectedSource(ReadGraph graph, Variable selection) throws DatabaseException {\r
173 \r
174         String name = selectedSourceName(graph, selection);\r
175         for(Tuple tuple : availableSourcesImpl(graph, selection)) {\r
176             if(tuple.get(1).equals(name)) return (T)tuple.get(2);\r
177         }\r
178         \r
179         return null;\r
180         \r
181     }\r
182     \r
183     @SCLValue(type = "ReadGraph -> Resource -> Variable -> String")\r
184     public static String selectedSource(ReadGraph graph, Resource resource, final Variable context) throws DatabaseException {\r
185 \r
186         Variable selection = ScenegraphLoaderUtils.getVariableSelection(graph, context);\r
187         String name = selectedSourceName(graph, selection);\r
188         for(Tuple tuple : availableSourcesImpl(graph, selection)) {\r
189             if(tuple.get(1).equals(name)) return (String)tuple.get(0);\r
190         }\r
191         \r
192         return EMPTY;\r
193 \r
194     }\r
195 \r
196     @SCLValue(type = "ReadGraph -> Resource -> Variable -> a")\r
197     public static Object selectedSourceModifier(ReadGraph graph, Resource resource, final Variable context) throws DatabaseException {\r
198 \r
199         return new FunctionImpl1<Object, Object>() {\r
200 \r
201             @Override\r
202             public Object apply(Object sourceKey) {\r
203                 try {\r
204                     Session s = Simantics.getSession();\r
205                     VirtualGraph vg = s.getService(VirtualGraphSupport.class).getWorkspacePersistent("preferences");\r
206                     s.syncRequest(new SetDefaultAnnotationSourceRequest(vg, context, sourceKey));\r
207                 } catch (DatabaseException e) {\r
208                     Activator.getDefault().getLog().log(\r
209                             new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Failed to update default annotation source, see exception for details.", e));\r
210                 }\r
211                 return null;\r
212             }\r
213 \r
214         };\r
215 \r
216     }\r
217 \r
218     private static class SetDefaultAnnotationSourceRequest extends WriteRequest {\r
219 \r
220         private Variable context;\r
221         private Object sourceKey;\r
222 \r
223         public SetDefaultAnnotationSourceRequest(VirtualGraph vg, Variable context, Object sourceKey) {\r
224             super(vg);\r
225             this.context = context;\r
226             this.sourceKey = sourceKey;\r
227         }\r
228 \r
229         @Override\r
230         public void perform(WriteGraph graph) throws DatabaseException {\r
231             AnnotationResource ANNO = AnnotationResource.getInstance(graph);\r
232             Variable selection = ScenegraphLoaderUtils.getVariableSelection(graph, context);\r
233             Resource model = Variables.getPossibleIndexRoot(graph, selection);\r
234 \r
235             List<Tuple3> annos = availableSourcesImpl(graph, selection);\r
236             for(Tuple3 anno : annos) {\r
237                 if(anno.get(0).equals(sourceKey)) {\r
238                     graph.claimLiteral(model, ANNO.DefaultAnnotationSource, (String)anno.get(1), Bindings.STRING);\r
239                     break;\r
240                 }\r
241             }\r
242         }\r
243 \r
244     }\r
245 \r
246     private static final Comparator<? super Tuple3> AVAILABLE_ANNOTATION_SORTER = new Comparator<Tuple3>() {\r
247         @Override\r
248         public int compare(Tuple3 o1, Tuple3 o2) {\r
249             String s1 = (String) o1.c2;\r
250             String s2 = (String) o2.c2;\r
251             return AlphanumComparator.CASE_INSENSITIVE_COMPARATOR.compare(s1, s2);\r
252         }\r
253     };\r
254 \r
255     /**\r
256      * @param graph\r
257      * @param selection\r
258      * @return list of (Variable annotation, Resource annotation, String name) tuples\r
259      * @throws DatabaseException\r
260      */\r
261     private static Collection<Tuple3> availableAnnotationsImpl(ReadGraph graph, Variable selection) throws DatabaseException {\r
262 \r
263         Layer0 L0 = Layer0.getInstance(graph);\r
264         AnnotationResource ANNO = AnnotationResource.getInstance(graph);\r
265 \r
266         selection = selectedSource(graph, selection);\r
267         \r
268         ArrayList<Tuple3> result = new ArrayList<Tuple3>();\r
269         for (Variable child : selection.getChildren(graph)) {\r
270             Resource represents = child.getPossibleRepresents(graph);\r
271             if (represents != null && graph.isInstanceOf(represents, ANNO.Annotation)) {\r
272                 String name = graph.getPossibleRelatedValue(represents, L0.HasName);\r
273                 if (name != null)\r
274                     result.add(new Tuple3(child, represents, name));\r
275             }\r
276         }\r
277         for (Variable property : selection.getProperties(graph)) {\r
278             Resource propertyResource = property.getPossibleRepresents(graph);\r
279             if (propertyResource != null && graph.isInstanceOf(propertyResource, ANNO.Annotation)) {\r
280                 String propertyName = property.getName(graph);\r
281                 result.add(new Tuple3(property, propertyResource, propertyName));\r
282             }\r
283         }\r
284 \r
285         // Sort returned annotations by annotation property name to keep the results stable.\r
286         Collections.sort(result, AVAILABLE_ANNOTATION_SORTER);\r
287 \r
288         return result;\r
289 \r
290     }\r
291 \r
292     private static Pair<Resource, String> defaultAnnotationTypeAndName(ReadGraph graph, Variable selection) throws DatabaseException {\r
293         AnnotationResource ANNO = AnnotationResource.getInstance(graph);\r
294         Resource model = Variables.getPossibleIndexRoot(graph, selection);\r
295         Resource type = graph.getPossibleObject(model, ANNO.HasDefaultAnnotationType);\r
296         String name = graph.getPossibleRelatedValue(model, ANNO.HasDefaultAnnotationName, Bindings.STRING);\r
297         return Pair.make(type, name);\r
298     }\r
299 \r
300     private static String selectedAnnotationName(ReadGraph graph, Variable selection) throws DatabaseException {\r
301         Pair<Resource, String> typeAndName = defaultAnnotationTypeAndName(graph, selection);\r
302         Collection<Tuple3> available = availableAnnotationsImpl(graph, selection);\r
303         if (!available.isEmpty()) {\r
304             if (available.size() == 1 || typeAndName.first == null)\r
305                 return (String) available.iterator().next().c2;\r
306             String firstTypeMatch = null;\r
307             for (Tuple3 anno : available) {\r
308                 if (graph.isInstanceOf((Resource) anno.c1, typeAndName.first)) {\r
309                     if (firstTypeMatch == null)\r
310                         firstTypeMatch = (String) anno.c2;\r
311                     if (typeAndName.second != null && typeAndName.second.equals(anno.c2)) {\r
312                         // Ok, it just doesn't match better than this.\r
313                         return (String) anno.c2;\r
314                     }\r
315                 }\r
316             }\r
317             if (firstTypeMatch != null)\r
318                 return firstTypeMatch;\r
319             // Nothing => return the first one from list\r
320             return (String)available.iterator().next().c2;\r
321         }\r
322         return NO_ANNOTATIONS;\r
323     }\r
324 \r
325     private static String selectedSourceName(ReadGraph graph, Variable selection) throws DatabaseException {\r
326     \r
327         AnnotationResource ANNO = AnnotationResource.getInstance(graph);\r
328         Resource model = Variables.getPossibleIndexRoot(graph, selection);\r
329         if (model == null)\r
330             return EMPTY;\r
331         String name = graph.getPossibleRelatedValue(model, ANNO.DefaultAnnotationSource, Bindings.STRING);\r
332         if(name != null) {\r
333             for(Tuple tuple : availableSourcesImpl(graph, selection)) {\r
334                 if(tuple.get(1).equals(name)) return name;\r
335             }\r
336         }\r
337 \r
338         Set<String> available = new THashSet<String>();\r
339         for(Tuple tuple : availableSourcesImpl(graph, selection)) available.add((String)tuple.get(1));\r
340         if(available.isEmpty()) return EMPTY;\r
341         \r
342         if(available.contains(MAPPED)) return MAPPED;\r
343         else return available.iterator().next();\r
344     \r
345     }\r
346 \r
347     @SCLValue(type = "ReadGraph -> Resource -> Variable -> a")\r
348     public static Object explorerInput(ReadGraph graph, Resource resource, final Variable context) throws DatabaseException {\r
349 \r
350         Variable selection = ScenegraphLoaderUtils.getVariableSelection(graph, context);\r
351         String selected = selectedAnnotationName(graph, selection);\r
352         for(Tuple3 anno : availableAnnotationsImpl(graph, selection)) {\r
353             if(selected.equals(anno.c2)) {\r
354                 return anno.c0;\r
355             }\r
356         }\r
357         return null;\r
358 \r
359     }\r
360 \r
361     @SCLValue(type = "ReadGraph -> Resource -> Variable -> String")\r
362     public static String descriptionText(ReadGraph graph, Resource resource, final Variable context) throws DatabaseException {\r
363 \r
364         String result = "";\r
365         Variable sel = getSelectedAnnotationVariable(graph, context);\r
366         if(sel != null) {\r
367 \r
368                 Layer0 L0 = Layer0.getInstance(graph);\r
369             Resource literal = sel.getPossibleRepresents(graph);\r
370             if(literal != null) {\r
371                 Resource container = graph.getPossibleObject(literal, L0.PartOf);\r
372                 if(container != null) {\r
373                         Resource model = Variables.getPossibleIndexRoot(graph, sel);\r
374                         String modelURI = graph.getURI(model);\r
375                         String path = graph.getURI(literal);\r
376                         if(path.startsWith(modelURI)) path = path.substring(modelURI.length()+1);\r
377                     result += URIStringUtils.unescape(path); \r
378                 } else {\r
379                         result += "The annotation is not attached to a library";\r
380                 }\r
381             }\r
382             \r
383         }\r
384         \r
385         return result;\r
386 \r
387     }\r
388 \r
389     @SCLValue(type = "ReadGraph -> Resource -> Variable -> a")\r
390     public static Object explorerInput2(ReadGraph graph, Resource resource, final Variable context) throws DatabaseException {\r
391 \r
392         return ScenegraphLoaderUtils.getVariableSelection(graph, context);\r
393 \r
394     }\r
395 \r
396     @SCLValue(type = "ReadGraph -> Resource -> Variable -> [(String, Resource)]")\r
397     public static List<Tuple> availableAnnotations(ReadGraph graph, Resource resource, Variable context) throws DatabaseException {\r
398         Variable selection = ScenegraphLoaderUtils.getVariableSelection(graph, context);\r
399         ArrayList<Tuple> result = new ArrayList<Tuple>();\r
400         for(Tuple3 anno : availableAnnotationsImpl(graph, selection)) {\r
401             result.add(new Tuple2(anno.c2, anno.c1));\r
402         }\r
403         if(result.isEmpty()) result.add(new Tuple2(NO_ANNOTATIONS, ""));\r
404         return result;\r
405     }\r
406 \r
407     @SCLValue(type = "ReadGraph -> Resource -> Variable -> String")\r
408     public static String selectedAnnotation(ReadGraph graph, Resource resource, final Variable context) throws DatabaseException {\r
409 \r
410         final Variable selection = ScenegraphLoaderUtils.getVariableSelection(graph, context);\r
411         return selectedAnnotationName(graph, selection);\r
412 \r
413     }\r
414     \r
415     @SCLValue(type = "ReadGraph -> Resource -> Variable -> a")\r
416     public static Object selectedAnnotationModifier(ReadGraph graph, Resource resource, final Variable context) throws DatabaseException {\r
417 \r
418         return new FunctionImpl1<Object, Object>() {\r
419 \r
420             @Override\r
421             public Object apply(final Object _key) {\r
422 \r
423                 Session s = Simantics.getSession();\r
424                 VirtualGraph vg = s.getService(VirtualGraphSupport.class).getWorkspacePersistent("preferences");\r
425                 s.async(new WriteRequest(vg) {\r
426 \r
427                     @Override\r
428                     public void perform(WriteGraph graph) throws DatabaseException {\r
429                         AnnotationResource ANNO = AnnotationResource.getInstance(graph);\r
430                         String key = (String)_key;\r
431                         Variable selection = ScenegraphLoaderUtils.getVariableSelection(graph, context);\r
432                         for(Tuple3 anno : availableAnnotationsImpl(graph, selection)) {\r
433                             if(key.equals(anno.c2)) {\r
434                                 Resource type = graph.getPossibleType((Resource) anno.c1, ANNO.Annotation);\r
435                                 Resource model = Variables.getPossibleIndexRoot(graph, selection);\r
436                                 graph.deny(model, ANNO.HasDefaultAnnotationType);\r
437                                 graph.claim(model, ANNO.HasDefaultAnnotationType, type);\r
438                                 graph.denyValue(model, ANNO.HasDefaultAnnotationName);\r
439                                 graph.claimLiteral(model, ANNO.HasDefaultAnnotationName, key, Bindings.STRING);\r
440                                 break;\r
441                             }\r
442                         }\r
443                     }\r
444 \r
445                 });\r
446 \r
447                 return null;\r
448 \r
449             }\r
450 \r
451         };\r
452 \r
453     }\r
454     \r
455     private static Resource getSelectionResource(Variable context) throws DatabaseException {\r
456         return Simantics.getSession().syncRequest(new UnaryRead<Variable,Resource>(context) {\r
457 \r
458             @Override\r
459             public Resource perform(ReadGraph graph) throws DatabaseException {\r
460                 Variable selection = ScenegraphLoaderUtils.getVariableSelection(graph, parameter);\r
461                 Variable source = selectedSource(graph, selection);\r
462                 return source.getPossibleRepresents(graph);\r
463             }\r
464             \r
465         });\r
466     }\r
467 \r
468     static class AddModifier extends FunctionImpl1<Object, Object> {\r
469         \r
470         private final Variable context;\r
471         \r
472         public AddModifier(Variable context) {\r
473                 this.context = context;\r
474         }\r
475         \r
476         private void doAdd(final Variable variable) throws DatabaseException {\r
477                 \r
478                 if(variable != null) {\r
479                         // We have a selected annotation\r
480                 AnnotationUtils.newAnnotation(variable);\r
481                 } else {\r
482                         // No annotation selected\r
483                 Resource parent = getSelectionResource(context);\r
484                 if(parent != null)\r
485                     AnnotationUtils.newAnnotation(parent);\r
486                 }\r
487 \r
488         }\r
489 \r
490                 @Override\r
491                 public Object apply(Object p0) {\r
492                         \r
493                         ISWTViewNode node = (ISWTViewNode)p0;\r
494                         SWTExplorer properties = (SWTExplorer)NodeUtil.browsePossible(node, "./Properties");\r
495                         if(properties == null) return null;\r
496                         try {\r
497                                 doAdd((Variable)properties.input);\r
498                         } catch (DatabaseException e) {\r
499                             LOGGER.error("newAnnotationModifier failed", e);\r
500                         }\r
501                         return null;\r
502                         \r
503                 }\r
504         \r
505     }\r
506     \r
507     @SCLValue(type = "ReadGraph -> Resource -> Variable -> a")\r
508     public static Object newAnnotationModifier(ReadGraph graph, Resource resource, final Variable context) throws DatabaseException {\r
509         return new AddModifier(context);\r
510     }\r
511 \r
512     private static Variable getSelectedAnnotationVariable(ReadGraph graph, Variable context) throws DatabaseException {\r
513         Variable selection = ScenegraphLoaderUtils.getVariableSelection(graph, context);\r
514                 String selected = selectedAnnotationName(graph, selection);\r
515         for(Tuple3 anno : availableAnnotationsImpl(graph, selection)) {\r
516                 if(anno.c2.equals(selected)) {\r
517                         return (Variable)anno.c0;\r
518                 }\r
519         }\r
520         return null;\r
521     }\r
522     \r
523     @SCLValue(type = "ReadGraph -> Resource -> Variable -> a")\r
524     public static Object removeAnnotationModifier(ReadGraph graph, Resource resource, final Variable context) throws DatabaseException {\r
525 \r
526         return new RemoveModifier();\r
527         \r
528     }\r
529 \r
530     public static class SaveModifier extends FunctionImpl1<Object, Object> {\r
531         \r
532         private boolean doSave(final Variable variable) {\r
533                 \r
534                 if(!AnnotationUtils.isAnnotation(variable)) return false;\r
535                 \r
536                         final Map<Resource, Pair<String, ImageDescriptor>> map = AnnotationUtils.findLibraries(variable);\r
537                         if(map == null) return false;\r
538 \r
539                 AnnotationUtils.queryLibrary(map, selected -> {\r
540                     Simantics.getSession().async(new WriteRequest() {\r
541                         @Override\r
542                         public void perform(WriteGraph graph) throws DatabaseException {\r
543                             Resource represents = variable.getPossibleRepresents(graph);\r
544                             if(represents != null && !selected.second.isEmpty()) {\r
545                                 saveAnnotation(graph, represents, selected.first, selected.second);     \r
546                             }\r
547                         }\r
548                     });\r
549                 });\r
550 \r
551                 return true;\r
552         }\r
553         \r
554         public static Resource saveAnnotation(WriteGraph graph, Resource annotation, Resource library, String name) throws DatabaseException {\r
555                 \r
556                 Layer0 L0 = Layer0.getInstance(graph);\r
557                 if(graph.hasStatement(annotation, L0.PartOf)) {\r
558                         graph.deny(annotation, L0.PartOf);\r
559                 }\r
560                 graph.claim(library, L0.ConsistsOf, L0.PartOf, annotation);\r
561                 graph.claimLiteral(annotation, L0.HasName, name, Bindings.STRING);\r
562                         \r
563                 return annotation;\r
564         }\r
565         \r
566 \r
567                 @Override\r
568                 public Object apply(Object p0) {\r
569                         \r
570                         ISWTViewNode node = (ISWTViewNode)p0;\r
571                         SWTExplorer properties = (SWTExplorer)NodeUtil.browsePossible(node, "./Properties");\r
572                         if(properties == null) return null;\r
573                         ISelection selection = properties.lastSelection;\r
574                         if(selection == null || selection.isEmpty()) {\r
575                                 doSave((Variable)properties.input);\r
576                                 return null;\r
577                         }\r
578                         \r
579                         Collection<Variable> vars = ISelectionUtils.filterSetSelection(selection, Variable.class);\r
580                         if(vars.size() != 1) return null;\r
581 \r
582                 Variable selected = vars.iterator().next();\r
583                 if(!doSave(selected))\r
584                         doSave((Variable)properties.input);\r
585                         \r
586                         return null;\r
587                         \r
588                 }\r
589         \r
590     }\r
591     \r
592     static class RemoveModifier extends FunctionImpl1<Object, Object> {\r
593 \r
594         private boolean doRemove(final Variable variable) {\r
595 \r
596                 if(!AnnotationUtils.isAnnotation(variable))\r
597                         return false;\r
598 \r
599                 Simantics.getSession().async(new WriteRequest() {\r
600                         @Override\r
601                         public void perform(WriteGraph graph) throws DatabaseException {\r
602                                 graph.markUndoPoint();\r
603                                 Resource represents = variable.getPossibleRepresents(graph);\r
604                                 if(represents != null) {\r
605                                         Layer0 L0 = Layer0.getInstance(graph);\r
606                         AnnotationResource ANNO = AnnotationResource.getInstance(graph);\r
607                                         if(graph.isInstanceOf(represents, ANNO.Annotation)) {\r
608                                                 Resource subject = variable.getParent(graph).getRepresents(graph);\r
609                                                 Resource predicate = variable.getPossiblePredicateResource(graph);\r
610                                                 if(predicate != null) {\r
611                                                         // This is a property annotation (no entry) - unlink\r
612                                                 graph.deny(subject, predicate);\r
613                                                 Layer0Utils.addCommentMetadata(graph, "Unlinked a property annotation " + graph.getRelatedValue2(predicate, L0.HasName, Bindings.STRING) + " " + predicate.toString() + " from " + graph.getRelatedValue2(subject, L0.HasName, Bindings.STRING) + " " + subject.toString());\r
614                                                 } else {\r
615                                                         // This should be an entry annotation - remove from container\r
616                                                         graph.deny(subject, ANNO.Annotation_HasEntry, represents);\r
617                                                         Layer0Utils.addCommentMetadata(graph, "Removed an entry annotation " + graph.getRelatedValue2(subject, L0.HasName, Bindings.STRING) + " " + subject.toString() + " from its container " + graph.getRelatedValue2(represents, L0.HasName, Bindings.STRING));\r
618                                                 }\r
619                                                 // If the annotation is not in any library remove it\r
620                                                 if(!graph.hasStatement(represents, L0.PartOf))\r
621                                                         RemoverUtil.remove(graph, represents);\r
622                                         }\r
623                                 }\r
624 \r
625                         }\r
626                         \r
627                 });\r
628 \r
629                 return true;\r
630         }\r
631 \r
632         @Override\r
633         public Object apply(Object p0) {\r
634 \r
635                 ISWTViewNode node = (ISWTViewNode)p0;\r
636                 SWTExplorer properties = (SWTExplorer)NodeUtil.browsePossible(node, "./Properties");\r
637                 if(properties == null) return null;\r
638                 ISelection selection = properties.lastSelection;\r
639                 if(selection == null || selection.isEmpty()) {\r
640                         doRemove((Variable)properties.input);\r
641                         return null;\r
642                 }\r
643 \r
644                 Collection<Variable> vars = ISelectionUtils.filterSetSelection(selection, Variable.class);\r
645                 if(vars.size() != 1) return null;\r
646 \r
647                 Variable selected = vars.iterator().next();\r
648                 if(!doRemove(selected))\r
649                         doRemove((Variable)properties.input);\r
650 \r
651                 return null;\r
652 \r
653         }\r
654 \r
655     }\r
656     \r
657     @SCLValue(type = "ReadGraph -> Resource -> Variable -> a")\r
658     public static Object saveAnnotationModifier(ReadGraph graph, Resource resource, final Variable context) throws DatabaseException {\r
659 \r
660         return new SaveModifier();\r
661 \r
662     }\r
663 \r
664     @SCLValue(type = "VariableMap")\r
665         public static VariableMap domainChildren = new VariableMapImpl() {\r
666 \r
667         private Map<String,Resource> children(ReadGraph graph, Resource resource) throws DatabaseException {\r
668                 AnnotationResource ANNO = AnnotationResource.getInstance(graph);\r
669                 Layer0 L0 = Layer0.getInstance(graph);\r
670                 Collection<Resource> objects = graph.getObjects(resource, ANNO.Annotation_HasEntry); \r
671                 THashMap<String, Resource> result = new THashMap<String, Resource>(objects.size());\r
672                 for(Resource r : objects) {\r
673                         String name = graph.getPossibleRelatedValue(r, L0.HasName, Bindings.STRING);\r
674                         if(name != null) {\r
675                                 if (result.put(name, r) != null)\r
676                                     LOGGER.error("The database contains siblings with the same name " + name + " (resource=$" + resource.getResourceId() +").");\r
677                         }\r
678                 }\r
679                 return result;\r
680         }\r
681         \r
682                 @Override\r
683                 public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {\r
684                 Map<String, Resource> children = children(graph,context.getRepresents(graph));\r
685                 Resource child = children.get(name);\r
686                 if(child == null) return null;\r
687                         VariableBuilder variableBuilder = graph.adapt(child, VariableBuilder.class);\r
688                         return variableBuilder.buildChild(graph, context, null, child);\r
689                 }\r
690 \r
691                 @Override\r
692                 public Map<String, Variable> getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {\r
693                         Map<String,Resource> childMap = children(graph,context.getRepresents(graph));\r
694                         if(childMap.isEmpty()) return map;\r
695                         if(map == null) map = new THashMap<String,Variable>();\r
696                 for(Map.Entry<String, Resource> entry : childMap.entrySet()) {\r
697                     String name = entry.getKey();\r
698                     Resource child = entry.getValue();\r
699                         VariableBuilder variableBuilder = graph.adapt(child, VariableBuilder.class);\r
700                         Variable var = variableBuilder.buildChild(graph, context, null, child);\r
701                     if(var != null) {\r
702                         map.put(name, var);\r
703                     } else {\r
704                         System.err.println("No adapter for " + child + " in " + context.getURI(graph));\r
705                     }\r
706                 }\r
707                 return map;\r
708                 }\r
709                 \r
710         };\r
711 \r
712 }\r