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