package org.simantics.selectionview.function; import java.io.IOException; import java.util.ArrayList; import java.util.Map; import java.util.function.Consumer; import org.eclipse.swt.graphics.FontData; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.widgets.ColorDialog; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.FontDialog; import org.simantics.Simantics; import org.simantics.browsing.ui.NodeContext; import org.simantics.browsing.ui.content.Labeler.DialogModifier; import org.simantics.common.format.Formatter; import org.simantics.databoard.Bindings; import org.simantics.databoard.Datatypes; import org.simantics.databoard.adapter.AdaptException; import org.simantics.databoard.binding.Binding; import org.simantics.databoard.binding.NumberBinding; import org.simantics.databoard.binding.StringBinding; import org.simantics.databoard.binding.error.BindingConstructionException; import org.simantics.databoard.binding.error.BindingException; import org.simantics.databoard.binding.mutable.MutableStringBinding; import org.simantics.databoard.binding.mutable.Variant; import org.simantics.databoard.parser.DataValuePrinter; import org.simantics.databoard.parser.repository.DataTypeSyntaxError; import org.simantics.databoard.parser.repository.DataValueRepository; import org.simantics.databoard.primitives.MutableString; import org.simantics.databoard.type.Datatype; import org.simantics.databoard.util.ObjectUtils; import org.simantics.datatypes.literal.Font; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.Statement; import org.simantics.db.WriteGraph; import org.simantics.db.common.CommentMetadata; import org.simantics.db.common.request.EnumerationMap; import org.simantics.db.common.request.InstanceEnumerationMap; import org.simantics.db.common.request.IsEnumeratedValue; import org.simantics.db.common.request.UniqueRead; import org.simantics.db.common.request.WriteRequest; import org.simantics.db.common.utils.NameUtils; import org.simantics.db.exception.DatabaseException; import org.simantics.db.layer0.util.Layer0Utils; import org.simantics.db.layer0.variable.ValueAccessor; import org.simantics.db.layer0.variable.Variable; import org.simantics.db.layer0.variable.Variables; import org.simantics.layer0.Layer0; import org.simantics.modeling.ModelingResources; import org.simantics.scl.compiler.types.TVar; import org.simantics.scl.compiler.types.Type; import org.simantics.scl.compiler.types.Types; import org.simantics.scl.reflection.annotations.SCLValue; import org.simantics.scl.runtime.function.Function1; import org.simantics.selectionview.SelectionInput; import org.simantics.selectionview.SelectionViewResources; import org.simantics.selectionview.StandardSelectionInput; import org.simantics.ui.colors.Colors; import org.simantics.ui.fonts.Fonts; import org.simantics.ui.selection.WorkbenchSelectionElement; import org.simantics.ui.selection.WorkbenchSelectionUtils; import org.simantics.utils.datastructures.collections.CollectionUtils; import org.simantics.utils.ui.AdaptionUtils; import org.simantics.utils.ui.ErrorLogger; import org.simantics.utils.ui.ISelectionUtils; public class All { final private static Binding datatype_binging = Bindings.getBindingUnchecked(Datatype.class); @SCLValue(type = "ReadGraph -> Resource -> Variable -> b") public static Object colorModifier(ReadGraph graph, Resource resource, final Variable context) throws DatabaseException { return new DialogModifier() { @Override public String getValue() { return null; } @Override public String isValid(String label) { return null; } @Override public void modify(final String label) { Simantics.getSession().async(new WriteRequest() { @Override public void perform(WriteGraph graph) throws DatabaseException { Variable displayValue = context.getParent(graph); displayValue.setValue(graph, label, org.simantics.datatypes.literal.RGB.Integer.BINDING); } }); } public String query(Object parentControl, Object controlItem, int columnIndex, NodeContext context, Consumer applyCallback) { Control ctrl = (Control) parentControl; RGB initialValue = null; final Variable v = AdaptionUtils.adaptToSingle(context, Variable.class); if (v != null) { try { org.simantics.datatypes.literal.RGB.Integer rgb = Simantics.getSession().syncRequest(new UniqueRead() { @Override public org.simantics.datatypes.literal.RGB.Integer perform(ReadGraph graph) throws DatabaseException { return v.getPossibleValue(graph, org.simantics.datatypes.literal.RGB.Integer.BINDING); } }); if (rgb != null) { initialValue = Colors.rgb(rgb); } } catch (DatabaseException e) { ErrorLogger.defaultLogError(e); } } ColorDialog dialog = new ColorDialog(ctrl.getShell()); if (initialValue != null) dialog.setRGB(initialValue); RGB rgb = dialog.open(); if (rgb != null) applyCallback.accept("(" + rgb.red + "," + rgb.green + "," + rgb.blue + ")"); return null; } }; } @SCLValue(type = "ReadGraph -> Resource -> Variable -> b") public static Object fontModifier(ReadGraph graph, Resource resource, final Variable context) throws DatabaseException { return new DialogModifier() { @Override public String getValue() { return null; } @Override public String isValid(String label) { return null; } @Override public void modify(final String label) { Simantics.getSession().async(new WriteRequest() { @Override public void perform(WriteGraph graph) throws DatabaseException { Variable displayValue = context.getParent(graph); displayValue.setValue(graph, label, Font.BINDING); } }); } public String query(Object parentControl, Object controlItem, int columnIndex, NodeContext context, Consumer applyCallback) { Control ctrl = (Control) parentControl; FontData[] initialValue = null; final Variable v = AdaptionUtils.adaptToSingle(context, Variable.class); if (v != null) { try { Font font = Simantics.getSession().syncRequest(new UniqueRead() { @Override public Font perform(ReadGraph graph) throws DatabaseException { return v.getPossibleValue(graph, Font.BINDING); } }); if (font != null) { initialValue = new FontData[] { Fonts.swtFontData(font) }; } } catch (DatabaseException e) { ErrorLogger.defaultLogError(e); } } FontDialog dialog = new FontDialog(ctrl.getShell()); if (initialValue != null) dialog.setFontList(initialValue); FontData font = dialog.open(); if (font != null) applyCallback.accept("(\"" + font.getName() + "\"," + font.getHeight() + ",\"" + Fonts.fromSwtStyle(font.getStyle()) + "\")"); return null; } }; } @SCLValue(type = "ReadGraph -> Resource -> a -> b") public static Object getEnumerationValues(ReadGraph graph, Resource resource, Object context) throws DatabaseException { if(context instanceof Variable) { Layer0 L0 = Layer0.getInstance(graph); Variable parameter = ((Variable)context).browse(graph, ".."); Resource parameterResource = parameter.getRepresents(graph); if(graph.sync(new IsEnumeratedValue(parameterResource))) { Map map = graph.sync(new InstanceEnumerationMap(parameterResource)); return new ArrayList(map.keySet()); } else if(graph.isInstanceOf(parameterResource, L0.Boolean)) { return CollectionUtils.toList("true", "false"); } } return null; } @SCLValue(type = "ReadGraph -> Resource -> a -> b") public static Object getPropertyChildName(ReadGraph graph, Resource resource, Object context) throws DatabaseException { if(context instanceof Variable) { Variable variable = (Variable)context; String label = variable.getParent(graph).getPossiblePropertyValue(graph, "HasLabel", Bindings.STRING); if(label != null) return label; return variable.getParent(graph).getName(graph); } throw new DatabaseException("Unknown context " + context); } @SCLValue(type = "WriteGraph -> Variable -> a -> b -> String") public static String inputModifier(WriteGraph graph, Variable variable, Object value, Object _binding) throws DatabaseException { // System.err.println("inputModifier " + variable.getURI(graph)); Layer0 L0 = Layer0.getInstance(graph); Variable parent = variable.getParent(graph); Resource property = variable.getPredicateResource(graph); Resource container = parent.getRepresents(graph); if(container == null) return null; if(property == null) return null; Statement object = graph.getPossibleStatement(container, property); if(object == null) return null; Resource objectResource = object.getObject(); if(graph.sync(new IsEnumeratedValue(objectResource))) { Resource type = graph.getSingleObject(objectResource, L0.PartOf); Map enumMap = graph.syncRequest(new EnumerationMap(type)); Resource newLiteral = enumMap.get(value); graph.deny(container, property, objectResource); graph.claim(container, property, newLiteral); return null; } Resource newType = Layer0Utils.getPossibleLiteralType(graph, variable); if(newType == null) { Type type = Layer0Utils.getSCLType(graph, variable); // This means that type is a wildcard e.g. "a" if(Types.canonical(type) instanceof TVar) { newType = Layer0Utils.inferLiteralTypeFromString(graph, value.toString()); } else { throw new DatabaseException("Failed to find type for property " + NameUtils.getSafeName(graph, property)); } } boolean correctType = graph.getPossibleType(objectResource, newType) != null; boolean asserted = object.isAsserted(container); if(asserted || !correctType) { if(correctType) { Statement dt = graph.getPossibleStatement(objectResource, L0.HasDataType); Datatype custom = dt.isAsserted(objectResource) ? null : (Datatype)graph.getValue(dt.getObject(), datatype_binging); objectResource = graph.newResource(); graph.claim(objectResource, L0.InstanceOf, null, newType); graph.claim(container, property, objectResource); if(custom != null) { // Only set HasValueType if the calculated new SCL type differs from the asserted value type String newValueType = Layer0Utils.getSCLType(custom); String currentValueType = graph.getPossibleRelatedValue(objectResource, L0.HasValueType, Bindings.STRING); if (!newValueType.equals(currentValueType)) { graph.addLiteral(objectResource, L0.HasValueType, L0.HasValueType_Inverse, L0.String, newValueType, Bindings.STRING); } graph.addLiteral(objectResource, L0.HasDataType, L0.HasDataType_Inverse, L0.DataType, custom, datatype_binging); } } else { if(newType != null) { if(!correctType && !asserted) // if not correct type and not asserted, remove the old value graph.deny(container, property, objectResource); objectResource = graph.newResource(); graph.claim(objectResource, L0.InstanceOf, newType); graph.claim(container, property, objectResource); } } } Datatype datatype = variable.getDatatype(graph); Binding binding = (Binding)_binding; Layer0Utils.claimAdaptedValue(graph, objectResource, value, binding, datatype); return null; } @SCLValue(type = "ReadGraph -> a -> Resource") public static Resource singleResourceTransformation(ReadGraph graph, Object input) throws DatabaseException { return WorkbenchSelectionUtils.getPossibleResource(graph, input); } @SCLValue(type = "ReadGraph -> a -> Variable") public static Variable singleVariableTransformation(ReadGraph graph, Object input) throws DatabaseException { Variable single = WorkbenchSelectionUtils.getPossibleVariable(graph, input); if(single != null) return single; return ISelectionUtils.filterSingleSelection(input, Variable.class); } @SCLValue(type = "ReadGraph -> a -> Variable") public static Variable singleResourceToVariableTransformation(ReadGraph graph, Object input) throws DatabaseException { Resource r = WorkbenchSelectionUtils.getPossibleResource(graph, input); if (r == null) return null; return Variables.getPossibleVariable(graph, r); } @SCLValue(type = "ReadGraph -> a -> SelectionInput") public static SelectionInput standardSelectionInputTransformation(ReadGraph graph, Object input) throws DatabaseException { WorkbenchSelectionElement wse = WorkbenchSelectionUtils.getPossibleSelectionElement(input); if (wse == null) return null; return new StandardSelectionInput(wse); } @SCLValue(type = "ValueAccessor") public static ValueAccessor displayUnitValueAccessor = new ValueAccessor() { @Override public Object getValue(ReadGraph graph, Variable context) throws DatabaseException { return Variables.getPossibleUnit(graph, context.getParent(graph)); } @Override public Object getValue(ReadGraph graph, Variable context, Binding binding) throws DatabaseException { try { Object value = Variables.getPossibleUnit(graph, context.getParent(graph)); if(value == null) return null; Binding srcBinding = Bindings.OBJECT.getContentBinding(value); return Bindings.adapt(value, srcBinding, binding); } catch (AdaptException e) { throw new DatabaseException(e); } catch (BindingException e) { throw new DatabaseException(e); } } @Override public void setValue(WriteGraph graph, Variable context, Object value) throws DatabaseException { throw new UnsupportedOperationException(); } @Override public void setValue(WriteGraph graph, Variable context, Object value, Binding binding) throws DatabaseException { throw new UnsupportedOperationException(); } @Override public Datatype getDatatype(ReadGraph graph, Variable context) throws DatabaseException { return org.simantics.db.layer0.function.All.getDatatypeFromValue(graph, context); } }; @SCLValue(type = "ValueAccessor") public static ValueAccessor displayPropertyValueAccessor = new ValueAccessor() { @Override public Object getValue(ReadGraph graph, Variable context) throws DatabaseException { return getValue(graph, context, Bindings.STRING); } @Override public Object getValue(ReadGraph graph, Variable context, Binding binding) throws DatabaseException { Layer0 L0 = Layer0.getInstance(graph); Variable property = context.getParent(graph); Resource predicate = property.getPossiblePredicateResource(graph); if(predicate == null) return property.getName(graph); String value = graph.getPossibleRelatedValue2(predicate, L0.HasLabel, Bindings.STRING); if(value == null) value = graph.getRelatedValue(predicate, L0.HasName, Bindings.STRING); try { return Bindings.adapt(value, binding, Bindings.STRING); } catch (AdaptException e) { throw new DatabaseException(e); } } @Override public void setValue(WriteGraph graph, Variable context, Object value) throws DatabaseException { throw new UnsupportedOperationException(); } @Override public void setValue(WriteGraph graph, Variable context, Object value, Binding binding) throws DatabaseException { throw new UnsupportedOperationException(); } @Override public Datatype getDatatype(ReadGraph graph, Variable context) throws DatabaseException { return Datatypes.STRING; } }; @SCLValue(type = "ValueAccessor") public static ValueAccessor displayValueValueAccessor = new ValueAccessor() { @Override public Object getValue(ReadGraph graph, Variable context) throws DatabaseException { return getValue(graph, context, Bindings.STRING); } public boolean isPrimitive(Datatype dt) { if(Datatypes.STRING.equals(dt)) return true; else return false; } private String possibleExpression(ReadGraph graph, Variable variable) throws DatabaseException { Layer0 L0 = Layer0.getInstance(graph); Resource object = variable.getPossibleRepresents(graph); if(object != null && graph.isInstanceOf(object, L0.SCLValue)) { String expression = graph.getPossibleRelatedValue(object, L0.SCLValue_expression); if (expression != null) return "=" + expression; } return null; } @Override public Object getValue(ReadGraph graph, Variable context, Binding _binding) throws DatabaseException { Variable property = context.getParent(graph); String expression = possibleExpression(graph, property); if(expression != null) return expression; Object value = null; Resource formatter = property.getPossiblePropertyValue(graph, Variables.FORMATTER); if(formatter != null) { Formatter fmt = graph.adaptContextual(formatter, property, Variable.class, Formatter.class); value = fmt.format(property.getValue(graph)); } if(value == null) { SelectionViewResources SEL = SelectionViewResources.getInstance(graph); Function1 formatterFunction = property.getPossiblePropertyValue(graph, SEL.formatter); if(formatterFunction != null) { value = formatterFunction.apply(property.getValue(graph)); } } if(value == null) { Variant variant = property.getVariantValue(graph); value = variant.getValue(); Binding binding = variant.getBinding(); if(binding != null) { Datatype dt = binding.type(); if(dt != null) { if(!isPrimitive(dt)) { try { value = DataValuePrinter.writeValueSingleLine(binding, value); } catch (IOException e) { e.printStackTrace(); } catch (BindingException e) { e.printStackTrace(); } } } } } try { return Bindings.adapt(value != null ? value.toString() : "null", _binding, Bindings.STRING); } catch (AdaptException e) { throw new DatabaseException(e); } } @Override public void setValue(WriteGraph graph, Variable context, Object value) throws DatabaseException { try { Binding binding = Bindings.getBinding(value.getClass()); setValue(graph, context, value, binding); } catch (BindingConstructionException e) { throw new DatabaseException(e); } } @Override public void setValue(WriteGraph graph, Variable context, Object _value, Binding _binding) throws DatabaseException { try { if(!(_value instanceof String)) throw new DatabaseException("setValue for HasDisplayValue only accepts String (got " + _value.getClass().getSimpleName() + ")"); String text = (String)_value; if(text.startsWith("=")) { Variable property = context.getParent(graph); Layer0Utils.setExpression(graph, property, text, ModelingResources.getInstance(graph).SCLValue); return; } String parsedLabel = (String)_value; Object value = parsedLabel; Datatype type = context.getParent(graph).getPossibleDatatype(graph); if (type != null) { Binding binding = Bindings.getBinding(type); if (binding instanceof StringBinding) { if (binding instanceof MutableStringBinding) value = new MutableString(parsedLabel); else value = parsedLabel; } else { if (binding instanceof NumberBinding) { parsedLabel = parsedLabel.replace(",", "."); } value = binding.parseValue(parsedLabel, new DataValueRepository()); } //System.out.println("VariableWrite " + ObjectUtils.toString(value)); context.getParent(graph).setValue(graph, value, binding); } else { context.getParent(graph).setValue(graph, value); } // Add a comment to metadata. CommentMetadata cm = graph.getMetadata(CommentMetadata.class); graph.addMetadata(cm.add("Set value " + ObjectUtils.toString(value))); } catch (DataTypeSyntaxError e) { throw new DatabaseException(e); } catch (BindingException e) { throw new DatabaseException(e); } } @Override public Datatype getDatatype(ReadGraph graph, Variable context) throws DatabaseException { return Datatypes.STRING; } }; }