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.CommonDBUtils;
47 import org.simantics.db.common.utils.NameUtils;
48 import org.simantics.db.exception.DatabaseException;
49 import org.simantics.db.layer0.util.Layer0Utils;
50 import org.simantics.db.layer0.variable.ValueAccessor;
51 import org.simantics.db.layer0.variable.Variable;
52 import org.simantics.db.layer0.variable.Variables;
53 import org.simantics.layer0.Layer0;
54 import org.simantics.modeling.ModelingResources;
55 import org.simantics.scl.compiler.types.TVar;
56 import org.simantics.scl.compiler.types.Type;
57 import org.simantics.scl.compiler.types.Types;
58 import org.simantics.scl.reflection.annotations.SCLValue;
59 import org.simantics.scl.runtime.function.Function1;
60 import org.simantics.selectionview.SelectionInput;
61 import org.simantics.selectionview.SelectionViewResources;
62 import org.simantics.selectionview.StandardSelectionInput;
63 import org.simantics.ui.colors.Colors;
64 import org.simantics.ui.fonts.Fonts;
65 import org.simantics.ui.selection.WorkbenchSelectionElement;
66 import org.simantics.ui.selection.WorkbenchSelectionUtils;
67 import org.simantics.utils.datastructures.collections.CollectionUtils;
68 import org.simantics.utils.strings.AlphanumComparator;
69 import org.simantics.utils.ui.AdaptionUtils;
70 import org.simantics.utils.ui.ErrorLogger;
71 import org.simantics.utils.ui.ISelectionUtils;
75 final private static Binding datatype_binging = Bindings.getBindingUnchecked(Datatype.class);
77 @SCLValue(type = "ReadGraph -> Resource -> Variable -> b")
78 public static Object colorModifier(ReadGraph graph, Resource resource, final Variable context) throws DatabaseException {
79 return new DialogModifier() {
82 public String getValue() {
87 public String isValid(String label) {
92 public void modify(final String label) {
93 Simantics.getSession().async(new WriteRequest() {
96 public void perform(WriteGraph graph) throws DatabaseException {
97 Variable displayValue = context.getParent(graph);
98 displayValue.setValue(graph, label, org.simantics.datatypes.literal.RGB.Integer.BINDING);
104 public String query(Object parentControl, Object controlItem, int columnIndex, NodeContext context, Consumer<String> applyCallback) {
105 Control ctrl = (Control) parentControl;
107 RGB initialValue = null;
108 final Variable v = AdaptionUtils.adaptToSingle(context, Variable.class);
111 org.simantics.datatypes.literal.RGB.Integer rgb = Simantics.getSession().syncRequest(new UniqueRead<org.simantics.datatypes.literal.RGB.Integer>() {
113 public org.simantics.datatypes.literal.RGB.Integer perform(ReadGraph graph) throws DatabaseException {
114 return v.getPossibleValue(graph, org.simantics.datatypes.literal.RGB.Integer.BINDING);
118 initialValue = Colors.rgb(rgb);
120 } catch (DatabaseException e) {
121 ErrorLogger.defaultLogError(e);
125 ColorDialog dialog = new ColorDialog(ctrl.getShell());
126 if (initialValue != null)
127 dialog.setRGB(initialValue);
128 RGB rgb = dialog.open();
130 applyCallback.accept("(" + rgb.red + "," + rgb.green + "," + rgb.blue + ")");
137 @SCLValue(type = "ReadGraph -> Resource -> Variable -> b")
138 public static Object fontModifier(ReadGraph graph, Resource resource, final Variable context) throws DatabaseException {
139 return new DialogModifier() {
142 public String getValue() {
147 public String isValid(String label) {
152 public void modify(final String label) {
153 Simantics.getSession().async(new WriteRequest() {
156 public void perform(WriteGraph graph) throws DatabaseException {
157 Variable displayValue = context.getParent(graph);
158 displayValue.setValue(graph, label, Font.BINDING);
164 public String query(Object parentControl, Object controlItem, int columnIndex, NodeContext context, Consumer<String> applyCallback) {
165 Control ctrl = (Control) parentControl;
167 FontData[] initialValue = null;
168 final Variable v = AdaptionUtils.adaptToSingle(context, Variable.class);
171 Font font = Simantics.getSession().syncRequest(new UniqueRead<Font>() {
173 public Font perform(ReadGraph graph) throws DatabaseException {
174 return v.getPossibleValue(graph, Font.BINDING);
178 initialValue = new FontData[] { Fonts.swtFontData(font) };
180 } catch (DatabaseException e) {
181 ErrorLogger.defaultLogError(e);
185 FontDialog dialog = new FontDialog(ctrl.getShell());
186 if (initialValue != null)
187 dialog.setFontList(initialValue);
188 FontData font = dialog.open();
190 applyCallback.accept("(\"" + font.getName() + "\"," + font.getHeight() + ",\"" + Fonts.fromSwtStyle(font.getStyle()) + "\")");
197 @SCLValue(type = "ReadGraph -> Resource -> a -> b")
198 public static Object getEnumerationValues(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
199 if(context instanceof Variable) {
200 Layer0 L0 = Layer0.getInstance(graph);
201 Variable parameter = ((Variable)context).browse(graph, "..");
202 Resource parameterResource = parameter.getRepresents(graph);
203 if(graph.sync(new IsEnumeratedValue(parameterResource))) {
204 Map<String, Resource> map = graph.sync(new InstanceEnumerationMap(parameterResource));
205 ArrayList<String> values = new ArrayList<>(map.keySet());
206 Collections.sort(values, AlphanumComparator.COMPARATOR);
208 } else if(graph.isInstanceOf(parameterResource, L0.Boolean)) {
209 return CollectionUtils.toList("true", "false");
215 @SCLValue(type = "ReadGraph -> Resource -> a -> b")
216 public static Object getPropertyChildName(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
217 if(context instanceof Variable) {
218 Variable variable = (Variable)context;
219 String label = variable.getParent(graph).getPossiblePropertyValue(graph, "HasLabel", Bindings.STRING);
222 return variable.getParent(graph).getName(graph);
224 throw new DatabaseException("Unknown context " + context);
227 @SCLValue(type = "WriteGraph -> Variable -> a -> b -> String")
228 public static String inputModifier(WriteGraph graph, Variable variable, Object value, Object _binding) throws DatabaseException {
230 // System.err.println("inputModifier " + variable.getURI(graph));
231 Layer0 L0 = Layer0.getInstance(graph);
233 Variable parent = variable.getParent(graph);
234 Resource property = variable.getPredicateResource(graph);
236 Resource container = parent.getRepresents(graph);
237 if(container == null) return null;
238 if(property == null) return null;
240 Statement object = graph.getPossibleStatement(container, property);
241 if(object == null) return null;
243 Resource objectResource = object.getObject();
244 if(graph.sync(new IsEnumeratedValue(objectResource))) {
246 Resource type = graph.getSingleObject(objectResource, L0.PartOf);
248 Map<String, Resource> enumMap = graph.syncRequest(new EnumerationMap(type));
249 Resource newLiteral = enumMap.get(value);
250 graph.deny(container, property, objectResource);
251 graph.claim(container, property, newLiteral);
257 Resource newType = Layer0Utils.getPossibleLiteralType(graph, variable);
258 if(newType == null) {
259 Type type = Layer0Utils.getSCLType(graph, variable);
260 // This means that type is a wildcard e.g. "a"
261 if(Types.canonical(type) instanceof TVar) {
262 newType = Layer0Utils.inferLiteralTypeFromString(graph, value.toString());
264 throw new DatabaseException("Failed to find type for property " + NameUtils.getSafeName(graph, property));
268 boolean correctType = graph.getPossibleType(objectResource, newType) != null;
269 boolean asserted = object.isAsserted(container);
270 if(asserted || !correctType) {
274 Statement dt = graph.getPossibleStatement(objectResource, L0.HasDataType);
275 Datatype custom = dt.isAsserted(objectResource) ? null : (Datatype)graph.getValue(dt.getObject(), datatype_binging);
277 objectResource = graph.newResource();
278 graph.claim(objectResource, L0.InstanceOf, null, newType);
279 graph.claim(container, property, objectResource);
281 // Only set HasValueType if the calculated new SCL type differs from the asserted value type
282 String newValueType = Layer0Utils.getSCLType(custom);
283 String currentValueType = graph.getPossibleRelatedValue(objectResource, L0.HasValueType, Bindings.STRING);
284 if (!newValueType.equals(currentValueType)) {
285 graph.addLiteral(objectResource, L0.HasValueType, L0.HasValueType_Inverse, L0.String, newValueType, Bindings.STRING);
287 graph.addLiteral(objectResource, L0.HasDataType, L0.HasDataType_Inverse, L0.DataType, custom, datatype_binging);
292 if(newType != null) {
294 if(!correctType && !asserted) // if not correct type and not asserted, remove the old value
295 graph.deny(container, property, objectResource);
297 objectResource = graph.newResource();
298 graph.claim(objectResource, L0.InstanceOf, newType);
299 graph.claim(container, property, objectResource);
307 Datatype datatype = variable.getDatatype(graph);
308 Binding binding = (Binding)_binding;
309 Layer0Utils.claimAdaptedValue(graph, objectResource, value, binding, datatype);
315 @SCLValue(type = "ReadGraph -> a -> Resource")
316 public static Resource singleResourceTransformation(ReadGraph graph, Object input) throws DatabaseException {
317 return WorkbenchSelectionUtils.getPossibleResource(graph, input);
321 @SCLValue(type = "ReadGraph -> a -> Variable")
322 public static Variable singleVariableTransformation(ReadGraph graph, Object input) throws DatabaseException {
323 Variable single = WorkbenchSelectionUtils.getPossibleVariable(graph, input);
324 if(single != null) return single;
325 return ISelectionUtils.filterSingleSelection(input, Variable.class);
328 @SCLValue(type = "ReadGraph -> a -> Variable")
329 public static Variable singleResourceToVariableTransformation(ReadGraph graph, Object input) throws DatabaseException {
330 Resource r = WorkbenchSelectionUtils.getPossibleResource(graph, input);
333 return Variables.getPossibleVariable(graph, r);
336 @SCLValue(type = "ReadGraph -> a -> SelectionInput")
337 public static SelectionInput standardSelectionInputTransformation(ReadGraph graph, Object input) throws DatabaseException {
338 WorkbenchSelectionElement wse = WorkbenchSelectionUtils.getPossibleSelectionElement(input);
341 return new StandardSelectionInput(wse);
344 @SCLValue(type = "ValueAccessor")
345 public static ValueAccessor displayUnitValueAccessor = new ValueAccessor() {
348 public Object getValue(ReadGraph graph, Variable context) throws DatabaseException {
349 return Variables.getPossibleUnit(graph, context.getParent(graph));
353 public Object getValue(ReadGraph graph, Variable context, Binding binding) throws DatabaseException {
355 Object value = Variables.getPossibleUnit(graph, context.getParent(graph));
356 if(value == null) return null;
357 Binding srcBinding = Bindings.OBJECT.getContentBinding(value);
358 return Bindings.adapt(value, srcBinding, binding);
359 } catch (AdaptException e) {
360 throw new DatabaseException(e);
361 } catch (BindingException e) {
362 throw new DatabaseException(e);
367 public void setValue(WriteGraph graph, Variable context, Object value) throws DatabaseException {
368 throw new UnsupportedOperationException();
372 public void setValue(WriteGraph graph, Variable context, Object value, Binding binding) throws DatabaseException {
373 throw new UnsupportedOperationException();
377 public Datatype getDatatype(ReadGraph graph, Variable context) throws DatabaseException {
378 return org.simantics.db.layer0.function.All.getDatatypeFromValue(graph, context);
383 @SCLValue(type = "ValueAccessor")
384 public static ValueAccessor displayPropertyValueAccessor = new ValueAccessor() {
387 public Object getValue(ReadGraph graph, Variable context) throws DatabaseException {
388 return getValue(graph, context, Bindings.STRING);
392 public Object getValue(ReadGraph graph, Variable context, Binding binding) throws DatabaseException {
393 Layer0 L0 = Layer0.getInstance(graph);
394 Variable property = context.getParent(graph);
395 Resource predicate = property.getPossiblePredicateResource(graph);
396 if(predicate == null) return property.getName(graph);
397 String value = graph.getPossibleRelatedValue2(predicate, L0.HasLabel, Bindings.STRING);
399 value = graph.getRelatedValue(predicate, L0.HasName, Bindings.STRING);
401 return Bindings.adapt(value, binding, Bindings.STRING);
402 } catch (AdaptException e) {
403 throw new DatabaseException(e);
408 public void setValue(WriteGraph graph, Variable context, Object value) throws DatabaseException {
409 throw new UnsupportedOperationException();
413 public void setValue(WriteGraph graph, Variable context, Object value, Binding binding) throws DatabaseException {
414 throw new UnsupportedOperationException();
418 public Datatype getDatatype(ReadGraph graph, Variable context)
419 throws DatabaseException {
420 return Datatypes.STRING;
425 @SCLValue(type = "ValueAccessor")
426 public static ValueAccessor displayValueValueAccessor = new ValueAccessor() {
429 public Object getValue(ReadGraph graph, Variable context) throws DatabaseException {
430 return getValue(graph, context, Bindings.STRING);
433 public boolean isPrimitive(Datatype dt) {
434 if(Datatypes.STRING.equals(dt)) return true;
438 private String possibleExpression(ReadGraph graph, Variable variable) throws DatabaseException {
440 Layer0 L0 = Layer0.getInstance(graph);
441 Resource object = variable.getPossibleRepresents(graph);
442 if(object != null && graph.isInstanceOf(object, L0.SCLValue)) {
443 String expression = graph.getPossibleRelatedValue(object, L0.SCLValue_expression);
444 if (expression != null)
445 return "=" + expression;
452 public Object getValue(ReadGraph graph, Variable context, Binding _binding) throws DatabaseException {
454 Variable property = context.getParent(graph);
456 String expression = possibleExpression(graph, property);
457 if(expression != null) return expression;
460 Resource formatter = property.getPossiblePropertyValue(graph, Variables.FORMATTER);
461 if(formatter != null) {
462 Formatter fmt = graph.adaptContextual(formatter, property, Variable.class, Formatter.class);
463 value = fmt.format(property.getValue(graph));
466 SelectionViewResources SEL = SelectionViewResources.getInstance(graph);
467 Function1<Object,String> formatterFunction = property.getPossiblePropertyValue(graph, SEL.formatter);
468 if(formatterFunction != null) {
469 value = formatterFunction.apply(property.getValue(graph));
473 Resource possibleValue = context.getParent(graph).getPossibleRepresents(graph);
474 if(possibleValue != null) {
475 if(graph.syncRequest(new IsEnumeratedValue(possibleValue))) {
476 return CommonDBUtils.getEnumerationValueName(graph, possibleValue);
482 Variant variant = property.getVariantValue(graph);
483 value = variant.getValue();
484 Binding binding = variant.getBinding();
485 if(binding != null) {
486 Datatype dt = binding.type();
488 if(!isPrimitive(dt)) {
490 value = DataValuePrinter.writeValueSingleLine(binding, value);
491 } catch (IOException e) {
493 } catch (BindingException e) {
503 return Bindings.adapt(value != null ? value.toString() : "null", _binding, Bindings.STRING);
504 } catch (AdaptException e) {
505 throw new DatabaseException(e);
510 public void setValue(WriteGraph graph, Variable context, Object value) throws DatabaseException {
512 Binding binding = Bindings.getBinding(value.getClass());
513 setValue(graph, context, value, binding);
514 } catch (BindingConstructionException e) {
515 throw new DatabaseException(e);
520 public void setValue(WriteGraph graph, Variable context, Object _value, Binding _binding) throws DatabaseException {
523 if(!(_value instanceof String)) throw new DatabaseException("setValue for HasDisplayValue only accepts String (got " + _value.getClass().getSimpleName() + ")");
525 String text = (String)_value;
526 if(text.startsWith("=")) {
527 Variable property = context.getParent(graph);
528 Layer0Utils.setExpression(graph, property, text, ModelingResources.getInstance(graph).SCLValue);
532 String parsedLabel = (String)_value;
533 Object value = parsedLabel;
535 boolean isEnumeration = false;
536 Resource possibleValue = context.getParent(graph).getPossibleRepresents(graph);
537 if(possibleValue != null) {
538 isEnumeration = graph.syncRequest(new IsEnumeratedValue(possibleValue));
541 Datatype type = context.getParent(graph).getPossibleDatatype(graph);
542 if (type != null && !isEnumeration) {
544 Binding binding = Bindings.getBinding(type);
546 if (binding instanceof StringBinding) {
548 if (binding instanceof MutableStringBinding)
549 value = new MutableString(parsedLabel);
555 if (binding instanceof NumberBinding) {
556 parsedLabel = parsedLabel.replace(",", ".");
559 value = binding.parseValue(parsedLabel, new DataValueRepository());
562 //System.out.println("VariableWrite " + ObjectUtils.toString(value));
563 context.getParent(graph).setValue(graph, value, binding);
567 context.getParent(graph).setValue(graph, value);
572 // Add a comment to metadata.
573 CommentMetadata cm = graph.getMetadata(CommentMetadata.class);
574 graph.addMetadata(cm.add("Set value " + ObjectUtils.toString(value)));
576 } catch (DataTypeSyntaxError e) {
577 throw new DatabaseException(e);
578 } catch (BindingException e) {
579 throw new DatabaseException(e);
584 public Datatype getDatatype(ReadGraph graph, Variable context)
585 throws DatabaseException {
586 return Datatypes.STRING;