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