1 package org.simantics.selectionview.function;
3 import java.io.IOException;
4 import java.util.ArrayList;
5 import java.util.Collections;
7 import java.util.function.Consumer;
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;
74 final private static Binding datatype_binging = Bindings.getBindingUnchecked(Datatype.class);
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() {
81 public String getValue() {
86 public String isValid(String label) {
91 public void modify(final String label) {
92 Simantics.getSession().async(new WriteRequest() {
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);
103 public String query(Object parentControl, Object controlItem, int columnIndex, NodeContext context, Consumer<String> applyCallback) {
104 Control ctrl = (Control) parentControl;
106 RGB initialValue = null;
107 final Variable v = AdaptionUtils.adaptToSingle(context, Variable.class);
110 org.simantics.datatypes.literal.RGB.Integer rgb = Simantics.getSession().syncRequest(new UniqueRead<org.simantics.datatypes.literal.RGB.Integer>() {
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);
117 initialValue = Colors.rgb(rgb);
119 } catch (DatabaseException e) {
120 ErrorLogger.defaultLogError(e);
124 ColorDialog dialog = new ColorDialog(ctrl.getShell());
125 if (initialValue != null)
126 dialog.setRGB(initialValue);
127 RGB rgb = dialog.open();
129 applyCallback.accept("(" + rgb.red + "," + rgb.green + "," + rgb.blue + ")");
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() {
141 public String getValue() {
146 public String isValid(String label) {
151 public void modify(final String label) {
152 Simantics.getSession().async(new WriteRequest() {
155 public void perform(WriteGraph graph) throws DatabaseException {
156 Variable displayValue = context.getParent(graph);
157 displayValue.setValue(graph, label, Font.BINDING);
163 public String query(Object parentControl, Object controlItem, int columnIndex, NodeContext context, Consumer<String> applyCallback) {
164 Control ctrl = (Control) parentControl;
166 FontData[] initialValue = null;
167 final Variable v = AdaptionUtils.adaptToSingle(context, Variable.class);
170 Font font = Simantics.getSession().syncRequest(new UniqueRead<Font>() {
172 public Font perform(ReadGraph graph) throws DatabaseException {
173 return v.getPossibleValue(graph, Font.BINDING);
177 initialValue = new FontData[] { Fonts.swtFontData(font) };
179 } catch (DatabaseException e) {
180 ErrorLogger.defaultLogError(e);
184 FontDialog dialog = new FontDialog(ctrl.getShell());
185 if (initialValue != null)
186 dialog.setFontList(initialValue);
187 FontData font = dialog.open();
189 applyCallback.accept("(\"" + font.getName() + "\"," + font.getHeight() + ",\"" + Fonts.fromSwtStyle(font.getStyle()) + "\")");
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);
207 } else if(graph.isInstanceOf(parameterResource, L0.Boolean)) {
208 return CollectionUtils.toList("true", "false");
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);
221 return variable.getParent(graph).getName(graph);
223 throw new DatabaseException("Unknown context " + context);
226 @SCLValue(type = "WriteGraph -> Variable -> a -> b -> String")
227 public static String inputModifier(WriteGraph graph, Variable variable, Object value, Object _binding) throws DatabaseException {
229 // System.err.println("inputModifier " + variable.getURI(graph));
230 Layer0 L0 = Layer0.getInstance(graph);
232 Variable parent = variable.getParent(graph);
233 Resource property = variable.getPredicateResource(graph);
235 Resource container = parent.getRepresents(graph);
236 if(container == null) return null;
237 if(property == null) return null;
239 Statement object = graph.getPossibleStatement(container, property);
240 if(object == null) return null;
242 Resource objectResource = object.getObject();
243 if(graph.sync(new IsEnumeratedValue(objectResource))) {
245 Resource type = graph.getSingleObject(objectResource, L0.PartOf);
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);
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());
263 throw new DatabaseException("Failed to find type for property " + NameUtils.getSafeName(graph, property));
267 boolean correctType = graph.getPossibleType(objectResource, newType) != null;
268 boolean asserted = object.isAsserted(container);
269 if(asserted || !correctType) {
273 Statement dt = graph.getPossibleStatement(objectResource, L0.HasDataType);
274 Datatype custom = dt.isAsserted(objectResource) ? null : (Datatype)graph.getValue(dt.getObject(), datatype_binging);
276 objectResource = graph.newResource();
277 graph.claim(objectResource, L0.InstanceOf, null, newType);
278 graph.claim(container, property, objectResource);
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);
286 graph.addLiteral(objectResource, L0.HasDataType, L0.HasDataType_Inverse, L0.DataType, custom, datatype_binging);
291 if(newType != null) {
293 if(!correctType && !asserted) // if not correct type and not asserted, remove the old value
294 graph.deny(container, property, objectResource);
296 objectResource = graph.newResource();
297 graph.claim(objectResource, L0.InstanceOf, newType);
298 graph.claim(container, property, objectResource);
306 Datatype datatype = variable.getDatatype(graph);
307 Binding binding = (Binding)_binding;
308 Layer0Utils.claimAdaptedValue(graph, objectResource, value, binding, datatype);
314 @SCLValue(type = "ReadGraph -> a -> Resource")
315 public static Resource singleResourceTransformation(ReadGraph graph, Object input) throws DatabaseException {
316 return WorkbenchSelectionUtils.getPossibleResource(graph, input);
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);
327 @SCLValue(type = "ReadGraph -> a -> Variable")
328 public static Variable singleResourceToVariableTransformation(ReadGraph graph, Object input) throws DatabaseException {
329 Resource r = WorkbenchSelectionUtils.getPossibleResource(graph, input);
332 return Variables.getPossibleVariable(graph, r);
335 @SCLValue(type = "ReadGraph -> a -> SelectionInput")
336 public static SelectionInput standardSelectionInputTransformation(ReadGraph graph, Object input) throws DatabaseException {
337 WorkbenchSelectionElement wse = WorkbenchSelectionUtils.getPossibleSelectionElement(input);
340 return new StandardSelectionInput(wse);
343 @SCLValue(type = "ValueAccessor")
344 public static ValueAccessor displayUnitValueAccessor = new ValueAccessor() {
347 public Object getValue(ReadGraph graph, Variable context) throws DatabaseException {
348 return Variables.getPossibleUnit(graph, context.getParent(graph));
352 public Object getValue(ReadGraph graph, Variable context, Binding binding) throws DatabaseException {
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);
366 public void setValue(WriteGraph graph, Variable context, Object value) throws DatabaseException {
367 throw new UnsupportedOperationException();
371 public void setValue(WriteGraph graph, Variable context, Object value, Binding binding) throws DatabaseException {
372 throw new UnsupportedOperationException();
376 public Datatype getDatatype(ReadGraph graph, Variable context) throws DatabaseException {
377 return org.simantics.db.layer0.function.All.getDatatypeFromValue(graph, context);
382 @SCLValue(type = "ValueAccessor")
383 public static ValueAccessor displayPropertyValueAccessor = new ValueAccessor() {
386 public Object getValue(ReadGraph graph, Variable context) throws DatabaseException {
387 return getValue(graph, context, Bindings.STRING);
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);
398 value = graph.getRelatedValue(predicate, L0.HasName, Bindings.STRING);
400 return Bindings.adapt(value, binding, Bindings.STRING);
401 } catch (AdaptException e) {
402 throw new DatabaseException(e);
407 public void setValue(WriteGraph graph, Variable context, Object value) throws DatabaseException {
408 throw new UnsupportedOperationException();
412 public void setValue(WriteGraph graph, Variable context, Object value, Binding binding) throws DatabaseException {
413 throw new UnsupportedOperationException();
417 public Datatype getDatatype(ReadGraph graph, Variable context)
418 throws DatabaseException {
419 return Datatypes.STRING;
424 @SCLValue(type = "ValueAccessor")
425 public static ValueAccessor displayValueValueAccessor = new ValueAccessor() {
428 public Object getValue(ReadGraph graph, Variable context) throws DatabaseException {
429 return getValue(graph, context, Bindings.STRING);
432 public boolean isPrimitive(Datatype dt) {
433 if(Datatypes.STRING.equals(dt)) return true;
437 private String possibleExpression(ReadGraph graph, Variable variable) throws DatabaseException {
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;
451 public Object getValue(ReadGraph graph, Variable context, Binding _binding) throws DatabaseException {
453 Variable property = context.getParent(graph);
455 String expression = possibleExpression(graph, property);
456 if(expression != null) return expression;
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));
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));
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);
481 Variant variant = property.getVariantValue(graph);
482 value = variant.getValue();
483 Binding binding = variant.getBinding();
484 if(binding != null) {
485 Datatype dt = binding.type();
487 if(!isPrimitive(dt)) {
489 value = DataValuePrinter.writeValueSingleLine(binding, value);
490 } catch (IOException e) {
492 } catch (BindingException e) {
502 return Bindings.adapt(value != null ? value.toString() : "null", _binding, Bindings.STRING);
503 } catch (AdaptException e) {
504 throw new DatabaseException(e);
509 public void setValue(WriteGraph graph, Variable context, Object value) throws DatabaseException {
511 Binding binding = Bindings.getBinding(value.getClass());
512 setValue(graph, context, value, binding);
513 } catch (BindingConstructionException e) {
514 throw new DatabaseException(e);
519 public void setValue(WriteGraph graph, Variable context, Object _value, Binding _binding) throws DatabaseException {
522 if(!(_value instanceof String)) throw new DatabaseException("setValue for HasDisplayValue only accepts String (got " + _value.getClass().getSimpleName() + ")");
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);
531 String parsedLabel = (String)_value;
532 Object value = parsedLabel;
534 boolean isEnumeration = false;
535 Resource possibleValue = context.getParent(graph).getPossibleRepresents(graph);
536 if(possibleValue != null) {
537 isEnumeration = graph.syncRequest(new IsEnumeratedValue(possibleValue));
540 Datatype type = context.getParent(graph).getPossibleDatatype(graph);
541 if (type != null && !isEnumeration) {
543 Binding binding = Bindings.getBinding(type);
545 if (binding instanceof StringBinding) {
547 if (binding instanceof MutableStringBinding)
548 value = new MutableString(parsedLabel);
554 if (binding instanceof NumberBinding) {
555 parsedLabel = parsedLabel.replace(",", ".");
558 value = binding.parseValue(parsedLabel, new DataValueRepository());
561 //System.out.println("VariableWrite " + ObjectUtils.toString(value));
562 context.getParent(graph).setValue(graph, value, binding);
566 context.getParent(graph).setValue(graph, value);
571 // Add a comment to metadata.
572 CommentMetadata cm = graph.getMetadata(CommentMetadata.class);
573 graph.addMetadata(cm.add("Set value " + ObjectUtils.toString(value)));
575 } catch (DataTypeSyntaxError e) {
576 throw new DatabaseException(e);
577 } catch (BindingException e) {
578 throw new DatabaseException(e);
583 public Datatype getDatatype(ReadGraph graph, Variable context)
584 throws DatabaseException {
585 return Datatypes.STRING;