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