]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.selectionview/src/org/simantics/selectionview/function/All.java
Default property editing restores assertions
[simantics/platform.git] / bundles / org.simantics.selectionview / src / org / simantics / selectionview / function / All.java
1 package org.simantics.selectionview.function;
2
3 import java.io.IOException;
4 import java.util.ArrayList;
5 import java.util.Map;
6 import java.util.function.Consumer;
7
8 import org.eclipse.swt.graphics.FontData;
9 import org.eclipse.swt.graphics.RGB;
10 import org.eclipse.swt.widgets.ColorDialog;
11 import org.eclipse.swt.widgets.Control;
12 import org.eclipse.swt.widgets.FontDialog;
13 import org.simantics.Simantics;
14 import org.simantics.browsing.ui.NodeContext;
15 import org.simantics.browsing.ui.content.Labeler.DialogModifier;
16 import org.simantics.common.format.Formatter;
17 import org.simantics.databoard.Bindings;
18 import org.simantics.databoard.Datatypes;
19 import org.simantics.databoard.adapter.AdaptException;
20 import org.simantics.databoard.binding.Binding;
21 import org.simantics.databoard.binding.NumberBinding;
22 import org.simantics.databoard.binding.StringBinding;
23 import org.simantics.databoard.binding.error.BindingConstructionException;
24 import org.simantics.databoard.binding.error.BindingException;
25 import org.simantics.databoard.binding.mutable.MutableStringBinding;
26 import org.simantics.databoard.binding.mutable.Variant;
27 import org.simantics.databoard.parser.DataValuePrinter;
28 import org.simantics.databoard.parser.repository.DataTypeSyntaxError;
29 import org.simantics.databoard.parser.repository.DataValueRepository;
30 import org.simantics.databoard.primitives.MutableString;
31 import org.simantics.databoard.type.Datatype;
32 import org.simantics.databoard.util.ObjectUtils;
33 import org.simantics.datatypes.literal.Font;
34 import org.simantics.db.ReadGraph;
35 import org.simantics.db.Resource;
36 import org.simantics.db.Statement;
37 import org.simantics.db.WriteGraph;
38 import org.simantics.db.common.CommentMetadata;
39 import org.simantics.db.common.request.EnumerationMap;
40 import org.simantics.db.common.request.InstanceEnumerationMap;
41 import org.simantics.db.common.request.IsEnumeratedValue;
42 import org.simantics.db.common.request.UniqueRead;
43 import org.simantics.db.common.request.WriteRequest;
44 import org.simantics.db.common.utils.NameUtils;
45 import org.simantics.db.exception.DatabaseException;
46 import org.simantics.db.layer0.util.Layer0Utils;
47 import org.simantics.db.layer0.variable.ValueAccessor;
48 import org.simantics.db.layer0.variable.Variable;
49 import org.simantics.db.layer0.variable.Variables;
50 import org.simantics.layer0.Layer0;
51 import org.simantics.modeling.ModelingResources;
52 import org.simantics.scl.compiler.types.TVar;
53 import org.simantics.scl.compiler.types.Type;
54 import org.simantics.scl.compiler.types.Types;
55 import org.simantics.scl.reflection.annotations.SCLValue;
56 import org.simantics.selectionview.SelectionInput;
57 import org.simantics.selectionview.StandardSelectionInput;
58 import org.simantics.ui.colors.Colors;
59 import org.simantics.ui.fonts.Fonts;
60 import org.simantics.ui.selection.WorkbenchSelectionElement;
61 import org.simantics.ui.selection.WorkbenchSelectionUtils;
62 import org.simantics.utils.datastructures.collections.CollectionUtils;
63 import org.simantics.utils.ui.AdaptionUtils;
64 import org.simantics.utils.ui.ErrorLogger;
65 import org.simantics.utils.ui.ISelectionUtils;
66
67 public class All {
68
69         final private static Binding datatype_binging = Bindings.getBindingUnchecked(Datatype.class);
70
71         @SCLValue(type = "ReadGraph -> Resource -> Variable -> b")
72         public static Object colorModifier(ReadGraph graph, Resource resource, final Variable context) throws DatabaseException {
73                 return new DialogModifier() {
74
75                         @Override
76                         public String getValue() {
77                                 return null;
78                         }
79
80                         @Override
81                         public String isValid(String label) {
82                                 return null;
83                         }
84
85                         @Override
86                         public void modify(final String label) {
87                                 Simantics.getSession().async(new WriteRequest() {
88
89                                         @Override
90                                         public void perform(WriteGraph graph) throws DatabaseException {
91                                                 Variable displayValue = context.getParent(graph);
92                                                 displayValue.setValue(graph, label, org.simantics.datatypes.literal.RGB.Integer.BINDING);
93                                         }
94
95                                 });
96                         }
97
98                         public String query(Object parentControl, Object controlItem, int columnIndex, NodeContext context, Consumer<String> applyCallback) {
99                                 Control ctrl = (Control) parentControl;
100
101                                 RGB initialValue = null;
102                                 final Variable v = AdaptionUtils.adaptToSingle(context, Variable.class);
103                                 if (v != null) {
104                                         try {
105                                                 org.simantics.datatypes.literal.RGB.Integer rgb = Simantics.getSession().syncRequest(new UniqueRead<org.simantics.datatypes.literal.RGB.Integer>() {
106                                                         @Override
107                                                         public org.simantics.datatypes.literal.RGB.Integer perform(ReadGraph graph) throws DatabaseException {
108                                                                 return v.getPossibleValue(graph, org.simantics.datatypes.literal.RGB.Integer.BINDING);
109                                                         }
110                                                 });
111                                                 if (rgb != null) {
112                                                         initialValue = Colors.rgb(rgb);
113                                                 }
114                                         } catch (DatabaseException e) {
115                                                 ErrorLogger.defaultLogError(e);
116                                         }
117                                 }
118
119                                 ColorDialog dialog = new ColorDialog(ctrl.getShell());
120                                 if (initialValue != null)
121                                         dialog.setRGB(initialValue);
122                                 RGB rgb = dialog.open();
123                                 if (rgb != null)
124                                         applyCallback.accept("(" + rgb.red + "," + rgb.green + "," + rgb.blue + ")");
125                                 return null;
126                         }
127
128                 };
129         }
130
131         @SCLValue(type = "ReadGraph -> Resource -> Variable -> b")
132         public static Object fontModifier(ReadGraph graph, Resource resource, final Variable context) throws DatabaseException {
133                 return new DialogModifier() {
134
135                         @Override
136                         public String getValue() {
137                                 return null;
138                         }
139
140                         @Override
141                         public String isValid(String label) {
142                                 return null;
143                         }
144
145                         @Override
146                         public void modify(final String label) {
147                                 Simantics.getSession().async(new WriteRequest() {
148
149                                         @Override
150                                         public void perform(WriteGraph graph) throws DatabaseException {
151                                                 Variable displayValue = context.getParent(graph);
152                                                 displayValue.setValue(graph, label, Font.BINDING);
153                                         }
154
155                                 });
156                         }
157
158                         public String query(Object parentControl, Object controlItem, int columnIndex, NodeContext context, Consumer<String> applyCallback) {
159                                 Control ctrl = (Control) parentControl;
160
161                                 FontData[] initialValue = null;
162                                 final Variable v = AdaptionUtils.adaptToSingle(context, Variable.class);
163                                 if (v != null) {
164                                         try {
165                                                 Font font = Simantics.getSession().syncRequest(new UniqueRead<Font>() {
166                                                         @Override
167                                                         public Font perform(ReadGraph graph) throws DatabaseException {
168                                                                 return v.getPossibleValue(graph, Font.BINDING);
169                                                         }
170                                                 });
171                                                 if (font != null) {
172                                                         initialValue = new FontData[] { Fonts.swtFontData(font) };
173                                                 }
174                                         } catch (DatabaseException e) {
175                                                 ErrorLogger.defaultLogError(e);
176                                         }
177                                 }
178
179                                 FontDialog dialog = new FontDialog(ctrl.getShell());
180                                 if (initialValue != null)
181                                         dialog.setFontList(initialValue);
182                                 FontData font = dialog.open();
183                                 if (font != null)
184                                         applyCallback.accept("(\"" + font.getName() + "\"," + font.getHeight() + ",\"" + Fonts.fromSwtStyle(font.getStyle()) + "\")");
185                                 return null;
186                         }
187
188                 };
189         }
190
191         @SCLValue(type = "ReadGraph -> Resource -> a -> b")
192         public static Object getEnumerationValues(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
193                 if(context instanceof Variable) {
194                         Layer0 L0 = Layer0.getInstance(graph);
195                         Variable parameter = ((Variable)context).browse(graph, "..");
196                         Resource parameterResource = parameter.getRepresents(graph);
197                         if(graph.sync(new IsEnumeratedValue(parameterResource))) {
198                                 Map<String, Resource> map = graph.sync(new InstanceEnumerationMap(parameterResource));
199                                 return new ArrayList<String>(map.keySet());
200                         } else if(graph.isInstanceOf(parameterResource, L0.Boolean)) {
201                                 return CollectionUtils.toList("true", "false");
202                         }
203                 }
204                 return null;
205         }
206
207         @SCLValue(type = "ReadGraph -> Resource -> a -> b")
208         public static Object getPropertyChildName(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
209                 if(context instanceof Variable) {
210                         Variable variable = (Variable)context;
211                         return variable.getParent(graph).getName(graph);
212                 }
213                 throw new DatabaseException("Unknown context " + context);
214         }
215         
216         @SCLValue(type = "WriteGraph -> Variable -> a -> b -> String")
217         public static String inputModifier(WriteGraph graph, Variable variable, Object value, Object _binding) throws DatabaseException {
218
219                 //      System.err.println("inputModifier " + variable.getURI(graph));
220                 Layer0 L0 = Layer0.getInstance(graph);
221
222                 Variable parent = variable.getParent(graph);
223                 Resource property = variable.getPredicateResource(graph);
224
225                 Resource container = parent.getRepresents(graph);
226                 if(container == null) return null;
227                 if(property == null) return null;
228
229                 Statement object = graph.getPossibleStatement(container, property);
230                 if(object == null) return null;
231
232                 Resource objectResource = object.getObject();
233                 if(graph.sync(new IsEnumeratedValue(objectResource))) {
234
235                         Resource type = graph.getSingleObject(objectResource, L0.PartOf);
236
237                         Map<String, Resource> enumMap = graph.syncRequest(new EnumerationMap(type));
238                         Resource newLiteral = enumMap.get(value);
239                         graph.deny(container, property, objectResource);
240                         graph.claim(container, property, newLiteral);
241
242                         return null;
243
244                 }
245
246                 Resource newType = Layer0Utils.getPossibleLiteralType(graph, variable);
247                 if(newType == null) {
248                         Type type = Layer0Utils.getSCLType(graph, variable);
249                         // This means that type is a wildcard e.g. "a"
250                         if(Types.canonical(type) instanceof TVar) {
251                                 newType = Layer0Utils.inferLiteralTypeFromString(graph, value.toString());
252                         } else {
253                                 throw new DatabaseException("Failed to find type for property " + NameUtils.getSafeName(graph, property));
254                         }
255                 }
256
257                 boolean correctType = graph.getPossibleType(objectResource, newType) != null;
258                 boolean asserted = object.isAsserted(container);
259                 if(asserted || !correctType) {
260
261                         if(correctType) {
262
263                                 Statement dt = graph.getPossibleStatement(objectResource, L0.HasDataType);
264                                 Datatype custom = dt.isAsserted(objectResource) ? null : (Datatype)graph.getValue(dt.getObject(), datatype_binging);
265
266                                 objectResource = graph.newResource();
267                                 graph.claim(objectResource, L0.InstanceOf, null, newType);
268                                 graph.claim(container, property, objectResource);
269                                 if(custom != null) {
270                                         // Only set HasValueType if the calculated new SCL type differs from the asserted value type
271                                         String newValueType = Layer0Utils.getSCLType(custom);
272                                         String currentValueType = graph.getPossibleRelatedValue(objectResource, L0.HasValueType, Bindings.STRING);
273                                         if (!newValueType.equals(currentValueType)) {
274                                                 graph.addLiteral(objectResource, L0.HasValueType, L0.HasValueType_Inverse, L0.String, newValueType, Bindings.STRING);
275                                         }
276                                         graph.addLiteral(objectResource, L0.HasDataType, L0.HasDataType_Inverse, L0.DataType, custom, datatype_binging);
277                                 }
278
279                         } else {
280
281                                 if(newType != null) {
282
283                                         if(!correctType && !asserted) // if not correct type and not asserted, remove the old value
284                                                 graph.deny(container, property, objectResource);
285
286                                         objectResource = graph.newResource();
287                                         graph.claim(objectResource, L0.InstanceOf, newType);
288                                         graph.claim(container, property, objectResource);
289
290                                 }
291
292                         }
293
294                 }
295
296                 if(!asserted) {
297                         Resource assertedObject = Layer0Utils.getPossibleAssertedObject(graph, container, property);
298                         if(assertedObject != null) {
299                                 if(graph.isInstanceOf(assertedObject, newType)) {
300                                         Object assertedValue = graph.getValue(assertedObject, (Binding)_binding);
301                                         if(assertedValue.equals(value)) {
302                                                 graph.deny(container, property);
303                                                 return null;
304                                         }
305                                 }
306                         }
307                 }
308                 
309                 Datatype datatype = variable.getDatatype(graph);
310                 Binding binding = (Binding)_binding;
311                 Layer0Utils.claimAdaptedValue(graph, objectResource, value, binding, datatype);
312
313                 return null;
314
315         }
316
317         @SCLValue(type = "ReadGraph -> a -> Resource")
318         public static Resource singleResourceTransformation(ReadGraph graph, Object input) throws DatabaseException {
319                 return WorkbenchSelectionUtils.getPossibleResource(graph, input);
320         }
321
322
323         @SCLValue(type = "ReadGraph -> a -> Variable")
324         public static Variable singleVariableTransformation(ReadGraph graph, Object input) throws DatabaseException {
325                 Variable single = WorkbenchSelectionUtils.getPossibleVariable(graph, input);
326                 if(single != null) return single;
327                 return ISelectionUtils.filterSingleSelection(input, Variable.class);
328         }
329
330         @SCLValue(type = "ReadGraph -> a -> Variable")
331         public static Variable singleResourceToVariableTransformation(ReadGraph graph, Object input) throws DatabaseException {
332                 Resource r = WorkbenchSelectionUtils.getPossibleResource(graph, input);
333                 if (r == null)
334                         return null;
335                 return Variables.getPossibleVariable(graph, r);
336         }
337
338         @SCLValue(type = "ReadGraph -> a -> SelectionInput")
339         public static SelectionInput standardSelectionInputTransformation(ReadGraph graph, Object input) throws DatabaseException {
340                 WorkbenchSelectionElement wse = WorkbenchSelectionUtils.getPossibleSelectionElement(input);
341                 if (wse == null)
342                         return null;
343                 return new StandardSelectionInput(wse);
344         }
345
346         @SCLValue(type = "ValueAccessor")
347         public static ValueAccessor displayUnitValueAccessor = new ValueAccessor() {
348
349                 @Override
350                 public Object getValue(ReadGraph graph, Variable context) throws DatabaseException {
351                         return Variables.getPossibleUnit(graph, context.getParent(graph));
352                 }
353
354                 @Override
355                 public Object getValue(ReadGraph graph, Variable context, Binding binding) throws DatabaseException {
356                         try {
357                                 Object value = Variables.getPossibleUnit(graph, context.getParent(graph));
358                                 if(value == null) return null;
359                                 Binding srcBinding = Bindings.OBJECT.getContentBinding(value);
360                                 return Bindings.adapt(value, srcBinding, binding);
361                         } catch (AdaptException e) {
362                                 throw new DatabaseException(e);
363                         } catch (BindingException e) {
364                                 throw new DatabaseException(e);
365                         }
366                 }
367
368                 @Override
369                 public void setValue(WriteGraph graph, Variable context, Object value) throws DatabaseException {
370                         throw new UnsupportedOperationException();
371                 }
372
373                 @Override
374                 public void setValue(WriteGraph graph, Variable context, Object value, Binding binding) throws DatabaseException {
375                         throw new UnsupportedOperationException();
376                 }
377
378                 @Override
379                 public Datatype getDatatype(ReadGraph graph, Variable context) throws DatabaseException {
380                         return org.simantics.db.layer0.function.All.getDatatypeFromValue(graph, context);
381                 }
382
383         };
384
385         @SCLValue(type = "ValueAccessor")
386         public static ValueAccessor displayPropertyValueAccessor = new ValueAccessor() {
387
388                 @Override
389                 public Object getValue(ReadGraph graph, Variable context) throws DatabaseException {
390                         return getValue(graph, context, Bindings.STRING);
391                 }
392
393                 @Override
394                 public Object getValue(ReadGraph graph, Variable context, Binding binding) throws DatabaseException {
395                         Layer0 L0 = Layer0.getInstance(graph);
396                         Variable property = context.getParent(graph);
397                         Resource predicate = property.getPossiblePredicateResource(graph);
398                         if(predicate == null) return property.getName(graph);
399                         String value = graph.getPossibleRelatedValue2(predicate, L0.HasLabel, Bindings.STRING);
400                         if(value == null)
401                             value = graph.getRelatedValue(predicate, L0.HasName, Bindings.STRING);
402                         try {
403                                 return Bindings.adapt(value, binding, Bindings.STRING);
404                         } catch (AdaptException e) {
405                                 throw new DatabaseException(e);
406                         }
407                 }
408
409                 @Override
410                 public void setValue(WriteGraph graph, Variable context, Object value) throws DatabaseException {
411                         throw new UnsupportedOperationException();
412                 }
413
414                 @Override
415                 public void setValue(WriteGraph graph, Variable context, Object value, Binding binding) throws DatabaseException {
416                         throw new UnsupportedOperationException();
417                 }
418
419                 @Override
420                 public Datatype getDatatype(ReadGraph graph, Variable context)
421                                 throws DatabaseException {
422                         return Datatypes.STRING;
423                 }
424
425         };      
426
427         @SCLValue(type = "ValueAccessor")
428         public static ValueAccessor displayValueValueAccessor = new ValueAccessor() {
429
430                 @Override
431                 public Object getValue(ReadGraph graph, Variable context) throws DatabaseException {
432                         return getValue(graph, context, Bindings.STRING);
433                 }
434
435                 public boolean isPrimitive(Datatype dt) {
436                         if(Datatypes.STRING.equals(dt)) return true;
437                         else return false;
438                 }
439
440                 private String possibleExpression(ReadGraph graph, Variable variable) throws DatabaseException {
441
442                         Layer0 L0 = Layer0.getInstance(graph);
443                         Resource object = variable.getPossibleRepresents(graph);
444                         if(object != null && graph.isInstanceOf(object, L0.SCLValue)) {
445                                 String expression = graph.getPossibleRelatedValue(object, L0.SCLValue_expression);
446                                 if (expression != null)
447                                         return "=" + expression;
448                         }
449                         return null;
450
451                 }
452
453                 @Override
454                 public Object getValue(ReadGraph graph, Variable context, Binding _binding) throws DatabaseException {
455
456                         Variable property = context.getParent(graph);
457
458                         String expression = possibleExpression(graph, property);
459                         if(expression != null) return expression;
460
461                         Object value = null;
462                         Resource formatter = property.getPossiblePropertyValue(graph, Variables.FORMATTER);
463                         if(formatter != null) {
464                                 
465                                 Formatter fmt = graph.adaptContextual(formatter, property, Variable.class, Formatter.class);
466                                 value = fmt.format(property.getValue(graph));
467                                 
468                         } else {
469
470                                 Variant variant = property.getVariantValue(graph);
471                                 value = variant.getValue();
472                                 
473                                 Binding binding = variant.getBinding();
474                                 if(binding != null) {
475                                         Datatype dt = binding.type();   
476                                         if(dt != null) {
477                                                 if(!isPrimitive(dt)) {
478                                                         try {
479                                                                 value = DataValuePrinter.writeValueSingleLine(binding, value);
480                                                         } catch (IOException e) {
481                                                                 e.printStackTrace();
482                                                         } catch (BindingException e) {
483                                                                 e.printStackTrace();
484                                                         }
485                                                 }
486                                         }
487                                 }
488
489                         }
490
491                         try {
492                                 return Bindings.adapt(value != null ? value.toString() : "null", _binding, Bindings.STRING);
493                         } catch (AdaptException e) {
494                                 throw new DatabaseException(e);
495                         }
496                 }
497
498                 @Override
499                 public void setValue(WriteGraph graph, Variable context, Object value) throws DatabaseException {
500                         try {
501                                 Binding binding = Bindings.getBinding(value.getClass());
502                                 setValue(graph, context, value, binding);
503                         } catch (BindingConstructionException e) {
504                                 throw new DatabaseException(e);
505                         }
506                 }
507
508                 @Override
509                 public void setValue(WriteGraph graph, Variable context, Object _value, Binding _binding) throws DatabaseException {
510                         try {
511
512                                 if(!(_value instanceof String)) throw new DatabaseException("setValue for HasDisplayValue only accepts String (got " + _value.getClass().getSimpleName() + ")");
513
514                                 String text = (String)_value;
515                                 if(text.startsWith("=")) {
516                                         Variable property = context.getParent(graph);
517                                         Layer0Utils.setExpression(graph, property, text, ModelingResources.getInstance(graph).SCLValue);
518                                         return;
519                                 }
520
521                                 String parsedLabel = (String)_value;
522                                 Object value = parsedLabel;
523
524                                 Datatype type = context.getParent(graph).getPossibleDatatype(graph);
525                                 if (type != null) {
526
527                                         Binding binding = Bindings.getBinding(type);
528
529                                         if (binding instanceof StringBinding) {
530
531                                                 if (binding instanceof MutableStringBinding)
532                                                         value = new MutableString(parsedLabel);
533                                                 else
534                                                         value = parsedLabel;
535
536                                         } else {
537
538                                                 if (binding instanceof NumberBinding) {
539                                                         parsedLabel = parsedLabel.replace(",", ".");
540                                                 }
541
542                                                 value = binding.parseValue(parsedLabel, new DataValueRepository());
543                                         }
544
545                                         //System.out.println("VariableWrite " + ObjectUtils.toString(value));
546                                         context.getParent(graph).setValue(graph, value, binding);
547
548                                 } else {
549
550                                         context.getParent(graph).setValue(graph, value);
551
552                                 }
553
554
555                                 // Add a comment to metadata.
556                                 CommentMetadata cm = graph.getMetadata(CommentMetadata.class);
557                                 graph.addMetadata(cm.add("Set value " + ObjectUtils.toString(value)));
558
559                         } catch (DataTypeSyntaxError e) {
560                                 throw new DatabaseException(e);
561                         } catch (BindingException e) {
562                                 throw new DatabaseException(e);
563                         }
564                 }
565
566                 @Override
567                 public Datatype getDatatype(ReadGraph graph, Variable context)
568                                 throws DatabaseException {
569                         return Datatypes.STRING;
570                 }
571
572         };              
573 }