]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.spreadsheet.graph/src/org/simantics/spreadsheet/graph/function/All.java
865a60ebe8c89e0d56eeb95024be98ceda1512e9
[simantics/platform.git] / bundles / org.simantics.spreadsheet.graph / src / org / simantics / spreadsheet / graph / function / All.java
1 package org.simantics.spreadsheet.graph.function;
2
3 import java.io.StringReader;
4 import java.util.ArrayList;
5 import java.util.Collection;
6 import java.util.Collections;
7 import java.util.HashMap;
8 import java.util.HashSet;
9 import java.util.List;
10 import java.util.Map;
11 import java.util.Set;
12 import java.util.function.Consumer;
13
14 import org.simantics.databoard.Bindings;
15 import org.simantics.databoard.Databoard;
16 import org.simantics.databoard.adapter.AdaptException;
17 import org.simantics.databoard.binding.Binding;
18 import org.simantics.databoard.binding.mutable.MutableVariant;
19 import org.simantics.databoard.binding.mutable.Variant;
20 import org.simantics.databoard.type.Datatype;
21 import org.simantics.datatypes.literal.Font;
22 import org.simantics.datatypes.literal.RGB;
23 import org.simantics.datatypes.utils.BTreeContentBean;
24 import org.simantics.db.ReadGraph;
25 import org.simantics.db.Resource;
26 import org.simantics.db.WriteGraph;
27 import org.simantics.db.common.request.ObjectsWithType;
28 import org.simantics.db.common.request.WriteRequest;
29 import org.simantics.db.common.utils.Logger;
30 import org.simantics.db.common.utils.NameUtils;
31 import org.simantics.db.exception.DatabaseException;
32 import org.simantics.db.layer0.exception.MissingVariableException;
33 import org.simantics.db.layer0.function.StandardChildDomainChildren;
34 import org.simantics.db.layer0.request.PossibleActiveRun;
35 import org.simantics.db.layer0.util.Layer0Utils;
36 import org.simantics.db.layer0.variable.ConstantChildVariable;
37 import org.simantics.db.layer0.variable.ConstantPropertyVariableBuilder;
38 import org.simantics.db.layer0.variable.ProxyChildVariable;
39 import org.simantics.db.layer0.variable.ProxyVariables;
40 import org.simantics.db.layer0.variable.StandardGraphPropertyVariable;
41 import org.simantics.db.layer0.variable.ValueAccessor;
42 import org.simantics.db.layer0.variable.Variable;
43 import org.simantics.db.layer0.variable.VariableMap;
44 import org.simantics.db.layer0.variable.VariableMapImpl;
45 import org.simantics.db.layer0.variable.Variables;
46 import org.simantics.db.request.Write;
47 import org.simantics.document.server.io.IColor;
48 import org.simantics.document.server.io.IFont;
49 import org.simantics.document.server.io.ITableCell;
50 import org.simantics.layer0.Layer0;
51 import org.simantics.scl.reflection.annotations.SCLValue;
52 import org.simantics.simulator.toolkit.StandardRealm;
53 import org.simantics.simulator.variable.exceptions.NodeManagerException;
54 import org.simantics.spreadsheet.CellEditor;
55 import org.simantics.spreadsheet.ClientModel;
56 import org.simantics.spreadsheet.Range;
57 import org.simantics.spreadsheet.Spreadsheets;
58 import org.simantics.spreadsheet.graph.SpreadsheetGraphUtils;
59 import org.simantics.spreadsheet.graph.SpreadsheetNodeManager;
60 import org.simantics.spreadsheet.graph.SpreadsheetSessionManager;
61 import org.simantics.spreadsheet.graph.celleditor.GraphCellEditorAdapter;
62 import org.simantics.spreadsheet.resource.SpreadsheetResource;
63 import org.simantics.spreadsheet.solver.SheetNode;
64 import org.simantics.spreadsheet.solver.SpreadsheetBook;
65 import org.simantics.spreadsheet.solver.SpreadsheetCell;
66 import org.simantics.spreadsheet.solver.SpreadsheetCellContent;
67 import org.simantics.spreadsheet.solver.SpreadsheetFormula;
68 import org.simantics.spreadsheet.solver.SpreadsheetSCLConstant;
69 import org.simantics.spreadsheet.solver.SpreadsheetStyle;
70 import org.simantics.spreadsheet.solver.SpreadsheetStyle.SpreadsheetStyleBuilder;
71 import org.simantics.spreadsheet.solver.formula.parser.ParseException;
72 import org.simantics.spreadsheet.solver.formula.parser.SheetFormulaParser;
73 import org.simantics.spreadsheet.solver.formula.parser.ast.AstValue;
74 import org.simantics.spreadsheet.synchronization.ExcelFormula;
75 import org.simantics.spreadsheet.synchronization.LineContentBean;
76 import org.simantics.spreadsheet.synchronization.LineContentBeanCell;
77 import org.simantics.spreadsheet.util.SpreadsheetUtils;
78
79 import gnu.trove.map.TMap;
80 import gnu.trove.map.hash.THashMap;
81 import it.unimi.dsi.fastutil.objects.ObjectArrayList;
82
83 public class All {
84
85     @SCLValue(type = "ReadGraph -> Resource -> a -> String")
86     public static String cellLabel(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
87         if(context instanceof Resource) {
88             return NameUtils.getSafeLabel(graph, ((Resource)context));  
89         } else if (context instanceof Variable) {
90             Variable parent = ((Variable)context).getParent(graph);
91             Variable content =  parent.getPossibleProperty(graph, ClientModel.CONTENT);
92             if(content != null) {
93                 Databoard db = graph.getService(Databoard.class);
94                 Variant variant = content.getValue(graph, db.VARIANT);
95                 return variant.getValue().toString();
96             } else {
97                 return parent.getName(graph);
98             }
99         } else {
100             throw new DatabaseException("Unknown context " + context);
101         }
102     }
103
104     private static Set<String> CLASSIFICATIONS = new HashSet<String>();
105     private static ConstantPropertyVariableBuilder immutableBuilder = new ConstantPropertyVariableBuilder("immutable", true, Bindings.BOOLEAN); 
106
107     static {
108         CLASSIFICATIONS.add(SpreadsheetResource.URIs.Attribute);
109     }
110
111     @SCLValue(type = "ValueAccessor")
112     public static ValueAccessor contentValueAccessor = new ValueAccessor() {
113
114         @Override
115         public void setValue(WriteGraph graph, Variable context, Object value, Binding binding) throws DatabaseException {
116             if(value instanceof String) {
117
118                 // Expressions are given as string
119                 String text = (String)value;
120                 SpreadsheetResource SHEET = SpreadsheetResource.getInstance(graph);
121                 if (text.startsWith("==")) {
122
123                     if(ProxyVariables.isProxy(graph, context))
124                         // SCL expressions are not supported in solver
125                         return;
126
127                     if(!Layer0Utils.setOrClearExpression(graph, context, text.substring(1), SHEET.SCLValue)) {
128                         org.simantics.db.layer0.function.All.standardSetValue3(graph, context, Variant.ofInstance(value), Bindings.VARIANT);
129                         //StandardValueAccessor.setValue(graph, context, Variant.ofInstance(value), Bindings.VARIANT);
130                         //org.simantics.db.layer0.function.All.standardValueAccessor.setValue(graph, context, Variant.ofInstance(value), Bindings.VARIANT);
131                     }
132                     return;
133                 } else {
134
135                     Variable cell = context.getParent(graph);
136
137                     String formula = text.substring(1);
138
139                     if (ProxyVariables.isProxy(graph, context)) {
140                         try {
141                             SheetFormulaParser p = new SheetFormulaParser(new StringReader(formula));
142                             AstValue v = p.relation();
143                             SpreadsheetFormula sformula = new SpreadsheetFormula(v, formula);
144                             setValueToEngine(graph, cell, context, sformula, SpreadsheetFormula.BINDING);
145                         } catch (ParseException e) {
146                             e.printStackTrace();
147                         }
148                         return;
149
150                     }
151
152                     Variant v = new Variant(ExcelFormula.BINDING, new ExcelFormula(formula));
153                     Layer0Utils.claimLiteral(graph, cell.getRepresents(graph), SHEET.Cell_content, SHEET.Cell_content_Inverse, Layer0.getInstance(graph).Variant, v, Bindings.VARIANT);
154
155                 }
156             } else {
157
158                 if(ProxyVariables.isProxy(graph, context)) {
159
160                     Variable cell = context.getParent(graph);
161                     setValueToEngine(graph, cell, context, value, binding);
162                     return;
163                 }
164
165                 // Values are given as Variant
166                 String expression = context.getPossiblePropertyValue(graph, "expression");
167                 if(expression != null) {
168                     Object current_ = context.getPossibleValue(graph);
169                     if(current_ instanceof Variable) {
170                         Variable current = (Variable)current_;
171                         Variant variant = (Variant)value;
172                         Datatype dt = current.getDatatype(graph);
173                         if (dt == null) {
174                             throw new DatabaseException();
175                         }
176                         Binding variableBinding = Bindings.getBinding(dt);
177                         try {
178                             Object adapted = variant.getValue(variableBinding);
179                             current.setValue(graph, adapted, variableBinding);
180                         } catch (AdaptException e) {
181                             Logger.defaultLogError(e);
182                         }
183                         return;
184                     }
185                     SpreadsheetResource SHEET = SpreadsheetResource.getInstance(graph);
186                     Layer0Utils.clearExpression(graph, context, SHEET.SCLValue);
187                 }
188                 org.simantics.db.layer0.function.All.standardSetValue3(graph, context, value, binding);
189                 //org.simantics.db.layer0.function.All.standardValueAccessor.setValue(graph, context, value, binding);
190             }
191         }
192
193         private void setValueToEngine(WriteGraph graph, Variable cell, Variable context, Object value, Binding binding) throws DatabaseException {
194             Variable sheet = cell.getParent(graph);
195
196             SpreadsheetResource SHEET = SpreadsheetResource.getInstance(graph);
197
198             while(!sheet.getType(graph).equals(SHEET.Spreadsheet)) {
199                 sheet = sheet.getParent(graph);
200             }
201
202             Range r = Spreadsheets.decodeCellAbsolute(cell.getName(graph));
203
204             Variable root = ProxyVariables.proxyVariableRoot(graph, context);
205
206             String sessionName = root.getParent(graph).getURI(graph);
207             StandardRealm<SheetNode, SpreadsheetBook> realm = SpreadsheetSessionManager.getInstance().getOrCreateRealm(graph, sessionName);
208             SpreadsheetBook book = realm.getEngine();
209             SpreadsheetCell sc = book.get(sheet.getName(graph), r.startRow, r.startColumn);
210             sc.setContent(value);
211             realm.asyncExec(new Runnable() {
212
213                 @Override
214                 public void run() {
215                     try {
216                         SpreadsheetCellContent content = (SpreadsheetCellContent)sc.getProperties().get("content");
217                         realm.getNodeManager().setValue(content, value, binding);
218                     } catch (NodeManagerException e) {
219                         Logger.defaultLogError(e);
220                     }
221                 }
222             });
223         }
224
225         @Override
226         public void setValue(WriteGraph graph, Variable context, Object value) throws DatabaseException {
227             if(value instanceof String) setValue(graph, context, value, Bindings.STRING);
228             else if(value instanceof Variant) setValue(graph, context, value, Bindings.VARIANT);
229             else throw new DatabaseException("Unsupported value type " + value);
230         }
231
232         @Override
233         public Object getValue(ReadGraph graph, Variable context, Binding binding) throws DatabaseException {
234             return org.simantics.db.layer0.function.All.standardGetValue2(graph, context, binding);
235             //return org.simantics.db.layer0.function.All.standardValueAccessor.getValue(graph, context, binding);
236         }
237
238         @Override
239         public Object getValue(ReadGraph graph, Variable context) throws DatabaseException {
240             return org.simantics.db.layer0.function.All.standardGetValue1(graph, ((StandardGraphPropertyVariable)context));
241 //                      return org.simantics.db.layer0.function.All.standardValueAccessor.getValue(graph, context);
242         }
243
244         @Override
245         public Datatype getDatatype(ReadGraph graph, Variable context) throws DatabaseException {
246             return org.simantics.db.layer0.function.All.standardGetDatatype(graph, context);
247 //                      return org.simantics.db.layer0.function.All.standardValueAccessor.getDatatype(graph, context);
248         }
249
250     };
251
252     @SCLValue(type = "ValueAccessor")
253     public static ValueAccessor contentDisplayValueAccessor = new ValueAccessor() {
254
255         @Override
256         public void setValue(WriteGraph graph, Variable context, Object value, Binding binding) throws DatabaseException {
257             if (!Bindings.STRING.equals(binding)) throw new IllegalArgumentException();
258             if (!(value instanceof String)) throw new IllegalArgumentException();
259
260             if (((String)value).startsWith("=")) {
261                 context.getParent(graph).setValue(graph, value, Bindings.STRING);
262             } else {
263                 context.getParent(graph).setValue(graph, new Variant(Bindings.STRING, value), Bindings.VARIANT);
264             }
265         }
266
267         @Override
268         public void setValue(WriteGraph graph, Variable context, Object value) throws DatabaseException {
269             if (!(value instanceof String)) throw new IllegalArgumentException();
270
271             if (((String)value).startsWith("=")) {
272                 context.getParent(graph).setValue(graph, value, Bindings.STRING);
273             } else {
274                 context.getParent(graph).setValue(graph, new Variant(Bindings.STRING, value), Bindings.VARIANT);
275             }
276         }
277
278         @Override
279         public Object getValue(ReadGraph graph, Variable context, Binding binding) throws DatabaseException {
280             return context.getParent(graph).getValue(graph, binding);
281         }
282
283         @Override
284         public Object getValue(ReadGraph graph, Variable context) throws DatabaseException {
285             return context.getParent(graph).getValue(graph);
286         }
287
288         @Override
289         public Datatype getDatatype(ReadGraph graph, Variable context) throws DatabaseException {
290             return context.getParent(graph).getDatatype(graph);
291         }
292
293     };
294
295     @SCLValue(type = "VariableMap")
296     public static VariableMap stringArrayChildren = new VariableMapImpl() {
297
298         @Override
299         public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
300
301             TMap<String, Variable> map = new THashMap<String, Variable>();
302             getVariables(graph, context, map);
303             return map.get(name);                                       
304
305         }
306
307         @Override
308         public Map<String, Variable> getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
309
310             Resource resource = context.getRepresents(graph);
311
312             SpreadsheetResource sr = SpreadsheetResource.getInstance(graph);
313
314             String location = graph.getPossibleRelatedValue(resource, sr.Range_location, Bindings.STRING);
315             if(location == null) return map;
316             Integer width = graph.getPossibleRelatedValue(resource, sr.Range_widthBound, Bindings.INTEGER);
317             if(width == null) return map;
318             String[] array = graph.getPossibleRelatedValue(resource, sr.StringArrayRange_array, Bindings.STRING_ARRAY);
319             if(array == null) return map;
320
321             int rows = array.length / width;
322
323             if(map == null) map = new HashMap<String,Variable>();
324
325             for(int offset=0,i=0;i<rows;i++) {
326                 for(int j=0;j<width;j++) {
327
328                     String value = array[offset++];
329                     String valueLocation = Spreadsheets.offset(location, i, j);
330
331                     ConstantPropertyVariableBuilder labelBuilder = new ConstantPropertyVariableBuilder(ClientModel.LABEL, value, Bindings.STRING, Collections.<ConstantPropertyVariableBuilder>emptyList(), CLASSIFICATIONS);
332                     ConstantPropertyVariableBuilder typeBuilder = new ConstantPropertyVariableBuilder(Variables.TYPE, sr.Cell, null, Collections.<ConstantPropertyVariableBuilder>emptyList(), Collections.<String>emptySet());
333
334                     map.put(valueLocation, new ConstantChildVariable(context, valueLocation, labelBuilder, typeBuilder, immutableBuilder));
335
336                 }
337             }
338
339             return map;
340
341         }
342
343     };
344
345     @SCLValue(type = "VariableMap")
346     public static VariableMap queryRangeChildren = new VariableMapImpl() {
347
348         @Override
349         public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
350
351             TMap<String, Variable> map = new THashMap<String, Variable>();
352             getVariables(graph, context, map);
353             return map.get(name);                                       
354
355         }
356
357         @Override
358         public Map<String, Variable> getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
359
360             SpreadsheetResource sr = SpreadsheetResource.getInstance(graph);
361
362             String location = "A1";
363
364             try {
365
366                 Object object = context.getPropertyValue(graph, sr.ExpressionRange_cells);
367
368                 List<?> data = (List<?>)object;
369
370                 if(map == null) map = new HashMap<String,Variable>();
371
372                 for(Object o : data) {
373                     if(o instanceof ITableCell) {
374
375                         ITableCell cell = (ITableCell)o;
376
377                         String valueLocation = Spreadsheets.offset(location, cell.getRow(), cell.getColumn());
378
379                         ArrayList<ConstantPropertyVariableBuilder> builders = new ArrayList<ConstantPropertyVariableBuilder>();
380
381                         builders.add(new ConstantPropertyVariableBuilder(ClientModel.CONTENT, Variant.ofInstance(cell.getText()), Bindings.VARIANT, Collections.<ConstantPropertyVariableBuilder>emptyList(), CLASSIFICATIONS));
382                         builders.add(new ConstantPropertyVariableBuilder(Variables.TYPE, sr.Cell, null, Collections.<ConstantPropertyVariableBuilder>emptyList(), Collections.<String>emptySet()));
383
384                         IFont font = cell.getFont();
385                         if(font != null) {
386                             builders.add(new ConstantPropertyVariableBuilder(ClientModel.FONT, new Font(font.getFamily(), font.getHeight(), font.getStyle()), Font.BINDING, Collections.<ConstantPropertyVariableBuilder>emptyList(), CLASSIFICATIONS));
387                         }
388
389                         int align = cell.getAlign();
390                         builders.add(new ConstantPropertyVariableBuilder(ClientModel.ALIGN, align, Bindings.INTEGER, Collections.<ConstantPropertyVariableBuilder>emptyList(), CLASSIFICATIONS));
391
392                         IColor foreground = cell.getFGColor();
393                         if(foreground != null) {
394                             builders.add(new ConstantPropertyVariableBuilder(ClientModel.FOREGROUND, new RGB.Integer(foreground.red(), foreground.green(), foreground.blue()), RGB.Integer.BINDING, Collections.<ConstantPropertyVariableBuilder>emptyList(), CLASSIFICATIONS));
395                         }
396
397                         IColor background = cell.getBGColor();
398                         if(background != null) {
399                             builders.add(new ConstantPropertyVariableBuilder(ClientModel.BACKGROUND, new RGB.Integer(background.red(), background.green(), background.blue()), RGB.Integer.BINDING, Collections.<ConstantPropertyVariableBuilder>emptyList(), CLASSIFICATIONS));
400                         }
401
402                         map.put(valueLocation, new ConstantChildVariable(context, valueLocation, builders));
403
404                     }
405                 }
406
407             } catch (DatabaseException e) {
408                 throw (DatabaseException)e;
409             } catch (Throwable t) {
410                 throw new DatabaseException(t);
411             } finally {
412             }
413
414             return map;
415
416         }
417
418     };
419
420     @SCLValue(type = "VariableMap")
421     public static VariableMap spreadsheetLinesChildren = new StandardChildDomainChildren() {
422
423         @Override
424         public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
425
426             if(ProxyVariables.isProxy(graph, context))
427                 return StandardChildDomainChildren.getStandardChildDomainChildVariable(graph, context, null, name);
428
429             return super.getVariable(graph, context, name);
430
431         }
432
433         @Override
434         public Map<String, Variable> getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
435
436             if(ProxyVariables.isProxy(graph, context))
437                 return StandardChildDomainChildren.getStandardChildDomainChildVariables(graph, context, Collections.emptyMap(), map);
438
439             return super.getVariables(graph, context, map);
440
441         }
442
443     };
444
445     @SCLValue(type = "VariableMap")
446     public static VariableMap doubleArrayChildren = new VariableMapImpl() {
447
448         @Override
449         public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
450
451             TMap<String, Variable> map = new THashMap<String, Variable>();
452             getVariables(graph, context, map);
453             return map.get(name);                                       
454
455         }
456
457         @Override
458         public Map<String, Variable> getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
459
460             Resource resource = context.getRepresents(graph);
461
462             SpreadsheetResource sr = SpreadsheetResource.getInstance(graph);
463
464             String location = graph.getPossibleRelatedValue(resource, sr.Range_location, Bindings.STRING);
465             if(location == null) return map;
466             Integer width = graph.getPossibleRelatedValue(resource, sr.Range_widthBound, Bindings.INTEGER);
467             if(width == null) return map;
468             double[] array = graph.getPossibleRelatedValue(resource, sr.DoubleArrayRange_array, Bindings.DOUBLE_ARRAY);
469             if(array == null) return map;
470
471             if(map == null) map = new HashMap<String,Variable>();
472
473             int rows = array.length / width;
474
475             for(int offset=0,i=0;i<rows;i++) {
476                 for(int j=0;j<width;j++) {
477
478                     double value = array[offset++];
479                     String valueLocation = Spreadsheets.offset(location, i, j);
480
481                     ConstantPropertyVariableBuilder labelBuilder = new ConstantPropertyVariableBuilder(ClientModel.LABEL, String.valueOf(value), Bindings.STRING, Collections.<ConstantPropertyVariableBuilder>emptyList(), CLASSIFICATIONS);
482                     ConstantPropertyVariableBuilder typeBuilder = new ConstantPropertyVariableBuilder(Variables.TYPE, sr.Cell, null, Collections.<ConstantPropertyVariableBuilder>emptyList(), Collections.<String>emptySet());
483
484                     map.put(valueLocation, new ConstantChildVariable(context, valueLocation, labelBuilder, typeBuilder, immutableBuilder));
485
486                 }
487             }
488
489             return map;
490
491         }
492
493     };
494
495     static class SpreadsheetProxyChildVariable extends ProxyChildVariable {
496
497         public SpreadsheetProxyChildVariable(Variable base, Variable parent, Variable other, String name) {
498             super(base, parent, other, name);
499         }
500
501         @Override
502         public Variable create(Variable base, Variable parent, Variable other, String name) {
503             return new SpreadsheetProxyChildVariable(base, parent, other, name);
504         }
505
506         public Variable getPossibleChild(ReadGraph graph, String name) throws DatabaseException {
507
508             if(CONTEXT_END.equals(name)) {
509                 if(other instanceof ProxyChildVariable) {
510                     // The context is also a proxy - let it do the job
511                     return super.getPossibleChild(graph, name);
512                 } else {
513                     return org.simantics.db.layer0.function.All.buildChildVariable(graph, this, base.getRepresents(graph), null);
514                 }
515             }
516
517             return super.getPossibleChild(graph, name);
518
519         }
520
521         public Collection<Variable> getChildren(ReadGraph graph) throws DatabaseException {
522
523             Collection<Variable> result = super.getChildren(graph);
524             if(!(base instanceof ProxyChildVariable)) {
525                 Variable root = org.simantics.db.layer0.function.All.buildChildVariable(graph, this, base.getRepresents(graph), null);
526                 result.add(root);
527             }
528             return result;
529
530         }       
531
532     }
533
534     @SCLValue(type = "VariableMap")
535     public static VariableMap spreadsheetChildren = new VariableMapImpl() {
536
537         @Override
538         public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
539
540             if(ProxyChildVariable.CONTEXT_BEGIN.equals(name)) return getProxy(graph, context);
541             return org.simantics.db.layer0.function.All.standardChildDomainChildren.getVariable(graph, context, name);
542
543         }
544
545         private Variable getProxy(ReadGraph graph, Variable context) throws DatabaseException {
546             Variable root = Variables.getRootVariable(graph);
547             return new SpreadsheetProxyChildVariable(context, context, root, ProxyChildVariable.CONTEXT_BEGIN);
548         }
549
550
551         @Override
552         public Map<String, Variable> getVariables(ReadGraph graph, Variable context, Map<String, Variable> map)
553                 throws DatabaseException {
554
555             map = org.simantics.db.layer0.function.All.standardChildDomainChildren.getVariables(graph, context, map);
556
557             if(map == null) map = new HashMap<String,Variable>();
558             map.put(ProxyChildVariable.CONTEXT_BEGIN, getProxy(graph, context));
559             return map;
560         }
561
562     };
563
564
565     @SCLValue(type = "ReadGraph -> Resource -> Variable -> CellEditor")
566     public static CellEditor<Write> defaultSheetCellEditor(ReadGraph graph, Resource resource, final Variable context_) throws DatabaseException {
567
568         final Variable sheet = context_.getParent(graph);
569
570         return new GraphCellEditorAdapter(null) {
571
572             @Override
573             public <T> void edit(final Transaction<Write> transaction, final String location, final String property, final T value, final Binding binding, Consumer<?> callback) {
574
575                 SpreadsheetUtils.schedule(transaction, new WriteRequest() {
576
577                     @Override
578                     public void perform(WriteGraph graph) throws DatabaseException {
579                         CellEditor<Write> editor = getPossibleCellEditor(graph, location, value == null ? null : new Variant(binding, value));
580                         if (editor == null)
581                             return;
582                         editor.edit(transaction, location, property, value, binding, callback);
583                     }
584                 });
585
586             }
587
588             @Override
589             public void edit(final Transaction<Write> transaction, final String location, final Variant value, Consumer<?> callback) {
590                 SpreadsheetUtils.schedule(transaction, new WriteRequest() {
591
592                     @Override
593                     public void perform(WriteGraph graph) throws DatabaseException {
594                         CellEditor<Write> editor = getPossibleCellEditor(graph, location, value);
595                         if (editor == null)
596                             return;
597                         editor.edit(transaction, location, value, callback);
598                     }
599                 });
600
601             }
602
603             private CellEditor<Write> getPossibleCellEditor(WriteGraph graph, String location, Variant value) throws DatabaseException {
604                 SpreadsheetResource SHEET = SpreadsheetResource.getInstance(graph);
605                 Range range = Spreadsheets.decodePossibleCellAbsolute(location);
606                 if(range == null) return null; //No editor found
607
608                 List<Variable> cells = SpreadsheetGraphUtils.possibleConfigurationCellVariables(graph, sheet, range);
609                 if (cells.isEmpty()) {
610                     if (value == null) {
611                         return null;
612                     } else {
613                         cells = SpreadsheetGraphUtils.getOrCreateConfigurationCellVariables(graph, sheet, range);
614                     }
615                 }
616                 if (cells.size() != 1)
617                     throw new DatabaseException("Can edit only one cell at a time!");
618
619                 return cells.iterator().next().getPropertyValue(graph, SHEET.cellEditor);
620             }
621
622             @Override
623             public void copy(final Transaction<Write> transaction, final String location, final MutableVariant variant, Consumer<?> callback) {
624
625                 SpreadsheetUtils.schedule(transaction, new WriteRequest() {
626
627                     @Override
628                     public void perform(WriteGraph graph) throws DatabaseException {
629
630                         SpreadsheetResource SHEET = SpreadsheetResource.getInstance(graph);
631                         Variable variable = sheet.getPossibleChild(graph, location);
632                         if(variable != null) {
633                             CellEditor<Write> editor = variable.getPossiblePropertyValue(graph, SHEET.cellEditor);
634                             if(editor != null) {
635                                 editor.copy(transaction, location, variant, null);
636                             }
637                         }
638                     }
639
640                 });
641
642             }
643
644         };
645
646     }
647
648     @SCLValue(type = "ReadGraph -> Resource -> Variable -> CellEditor")
649     public static CellEditor<Write> variableCellEditor(ReadGraph graph, Resource resource, final Variable context_) throws DatabaseException {
650
651         final Variable cell = context_.getParent(graph);
652
653         return new GraphCellEditorAdapter(cell) {
654
655             @Override
656             public <T> void edit(WriteGraph graph, Transaction<Write> transaction, String location, String property, T value, Binding binding) throws DatabaseException {
657                 cell.setPropertyValue(graph, property, value, binding);
658             }
659         };
660     }
661
662     private static int encodeLineOrNode(ReadGraph graph, Resource r) throws DatabaseException {
663         if(r == null) return 0;
664         Layer0 L0 = Layer0.getInstance(graph);
665         String name = graph.getRelatedValue(r, L0.HasName, Bindings.STRING);
666         if(name.charAt(0) == 'R') {
667             return -Integer.parseInt(name.substring(3));
668         } else {
669             return Integer.parseInt(name);
670         }
671     }
672
673     @SCLValue(type = "ReadGraph -> Resource -> Variable -> a")
674     public static int[] lineNodeKeys(ReadGraph graph, Resource resource, final Variable context_) throws DatabaseException {
675
676         Resource node = context_.getParent(graph).getRepresents(graph);
677         BTreeContentBean bean = BTreeContentBean.readPossible(graph, node);
678         if(bean == null) return new int[0];
679         // There are n keys and n+1 resources
680         int[] result = new int[2*bean.n+1];
681         for(int i=0;i<bean.n;i++) {
682             result[2*i] = encodeLineOrNode(graph, bean.getChild(i));
683             result[2*i+1] = (int)bean.getKey(i).getValue();
684         }
685         result[2*bean.n] = encodeLineOrNode(graph, bean.getChild(bean.n));
686         return result;
687
688     }
689
690     @SCLValue(type = "ReadGraph -> Resource -> Variable -> LineContentBean")
691     public static LineContentBean defaultLineCells(ReadGraph graph, Resource resource, final Variable context_) throws DatabaseException {
692
693         String contextUri = context_.getURI(graph);
694
695         Variable line = context_.getParent(graph);
696
697         Collection<Variable> children = line.getChildren(graph);
698         ObjectArrayList<LineContentBeanCell> result = new ObjectArrayList<>();
699         SpreadsheetResource SR = SpreadsheetResource.getInstance(graph);
700         for (Variable child : children) {
701             Resource repr = child.getRepresents(graph);
702
703             Resource style = graph.getPossibleObject(repr, SR.Cell_HasStyle);
704             Integer styleId = null;
705             if (style != null)
706                 styleId = graph.getPossibleRelatedValue(style, SR.Style_id, Bindings.INTEGER);
707             if (styleId == null) {
708                 System.err.println("Style " + style + " has no ID or either cell "+ repr + " has no style attached to it !!");
709                 styleId = SpreadsheetStyle.empty().getStyleId();
710             }
711
712             LineContentBeanCell cell = new LineContentBeanCell(styleId);
713
714             Variant variant = child.getPossiblePropertyValue(graph, SR.Cell_content);
715
716             if(variant != null) {
717
718                 Variable var = child.getPossibleProperty(graph, SR.Cell_content);
719                 String expression = var.getPossiblePropertyValue(graph, "expression");
720                 if (expression != null) {
721                     cell.setContent(new Variant(SpreadsheetSCLConstant.BINDING, new SpreadsheetSCLConstant(expression, variant.getValue())));
722                 } else {
723                     cell.setContent(variant);
724                 }
725                 Range r = Spreadsheets.decodeCellAbsolute(child.getName(graph));
726 //                result.add(cell);
727                 while(result.size() < r.startColumn + 1)
728                     result.add(new LineContentBeanCell());
729                 result.set(r.startColumn, cell);
730
731             }
732
733         }
734         LineContentBean bean = new LineContentBean();
735         bean.cells = result.toArray(new LineContentBeanCell[result.size()]);
736         return bean;
737
738     }
739
740     @SCLValue(type = "ReadGraph -> Resource -> Variable -> CellEditor")
741     public static CellEditor<Write> textCellEditor(ReadGraph graph, Resource resource, final Variable context_) throws DatabaseException {
742
743         Variable cells = context_.getParent(graph);
744
745         return new GraphCellEditorAdapter(cells) {
746
747             public <T> void edit(WriteGraph graph, Transaction<Write> transaction, String location, String property, T value, Binding binding) throws DatabaseException {
748
749                 SpreadsheetResource SHEET = SpreadsheetResource.getInstance(graph);
750                 if(ClientModel.CONTENT.equals(property)) {
751                     cell.setPropertyValue(graph, SHEET.Cell_content, value, Bindings.VARIANT);
752                     Variable runCell = null;
753                     Object transactionContext = transaction.getContext();
754                     if (transactionContext != null && transactionContext instanceof Variable) {
755                         Variable varContext = (Variable) transactionContext;
756                         Variable context = Variables.getContext(graph, varContext);
757                         try {
758                             runCell = Variables.switchRealization(graph, cell, context.getRepresents(graph), context);
759                         } catch (MissingVariableException e) {
760                             // Creating new cell, need synchronizing
761                             transaction.needSynchronization(cell.getParent(graph));
762                         }
763                     }
764                     if (runCell != null)
765                         runCell.setPropertyValue(graph, SHEET.Cell_content, value, Bindings.VARIANT);
766                 } else if(ClientModel.CONTENT_EXPRESSION.equals(property)) {
767                     cell.setPropertyValue(graph, SHEET.Cell_content, value, Bindings.STRING);
768                     Variable runCell = null;
769                     Object transactionContext = transaction.getContext();
770                     if (transactionContext != null && transactionContext instanceof Variable) {
771                         Variable varContext = (Variable) transactionContext;
772                         Variable context = Variables.getContext(graph, varContext);
773                         try {
774                             runCell = Variables.switchRealization(graph, cell, context.getRepresents(graph), context);
775                         } catch (MissingVariableException e) {
776                             //Creating new cell, need synchronizing
777                             transaction.needSynchronization(cell.getParent(graph));
778                         }
779                     }
780                     if (runCell != null)
781                         runCell.setPropertyValue(graph, SHEET.Cell_content, value, Bindings.STRING);
782                     // SCL expressions always require synchronization
783                     if(value.toString().startsWith("=="))
784                         transaction.needSynchronization(cell.getParent(graph));
785                 } else if(ClientModel.BORDER.equals(property)) {
786                     Resource textCell = cell.getRepresents(graph);
787                     Resource styleContainer = graph.getSingleObject(textCell, SHEET.Cell_HasStyle);
788                     SpreadsheetStyleBuilder builder = computeStyleBuilder(SHEET, graph, styleContainer);
789                     builder.border((Integer)value);
790                     finishStyleUpdate(graph, SHEET, styleContainer, textCell, builder, transaction);
791                 } else if(ClientModel.ALIGN.equals(property)) {
792                     Resource textCell = cell.getRepresents(graph);
793                     Resource styleContainer = graph.getSingleObject(textCell, SHEET.Cell_HasStyle);
794                     SpreadsheetStyleBuilder builder = computeStyleBuilder(SHEET, graph, styleContainer);
795                     builder.align((Integer)value);
796                     finishStyleUpdate(graph, SHEET, styleContainer, textCell, builder, transaction);
797                 } else if(ClientModel.LOCKED.equals(property)) {
798                     cell.setPropertyValue(graph, SHEET.Cell_locked, value, Bindings.BOOLEAN);   
799                 } else if(ClientModel.ROW_SPAN.equals(property)) {
800                     cell.setPropertyValue(graph, SHEET.Cell_rowSpan, value, Bindings.INTEGER);
801                 } else if(ClientModel.COLUMN_SPAN.equals(property)) {
802                     cell.setPropertyValue(graph, SHEET.Cell_columnSpan, value, Bindings.INTEGER);
803                 } else if(ClientModel.FONT.equals(property)) {
804                     Resource textCell = cell.getRepresents(graph);
805                     Resource styleContainer = graph.getSingleObject(textCell, SHEET.Cell_HasStyle);
806                     SpreadsheetStyleBuilder builder = computeStyleBuilder(SHEET, graph, styleContainer);
807                     builder.font((Font)value);
808                     finishStyleUpdate(graph, SHEET, styleContainer, textCell, builder, transaction);
809                 } else if(ClientModel.FOREGROUND.equals(property)) {
810                     Resource textCell = cell.getRepresents(graph);
811                     Resource styleContainer = graph.getSingleObject(textCell, SHEET.Cell_HasStyle);
812                     SpreadsheetStyleBuilder builder = computeStyleBuilder(SHEET, graph, styleContainer);
813                     builder.foreground((RGB.Integer)value);
814                     finishStyleUpdate(graph, SHEET, styleContainer, textCell, builder, transaction);
815                 } else if(ClientModel.BACKGROUND.equals(property)) {
816                     Resource textCell = cell.getRepresents(graph);
817                     Resource styleContainer = graph.getSingleObject(textCell, SHEET.Cell_HasStyle);
818                     SpreadsheetStyleBuilder builder = computeStyleBuilder(SHEET, graph, styleContainer);
819                     builder.background((RGB.Integer)value);
820                     finishStyleUpdate(graph, SHEET, styleContainer, textCell, builder, transaction);
821                 }
822             }
823
824             private void finishStyleUpdate(WriteGraph graph, SpreadsheetResource SHEET, Resource styleContainer, Resource textCell, SpreadsheetStyleBuilder builder, Transaction<?> transaction) throws DatabaseException {
825
826                 Variable bookVariable = Variables.getContext(graph, cell);
827                 Resource book = bookVariable.getRepresents(graph);
828                 Resource createdStyle = null;
829
830                 SpreadsheetStyle style = builder.build();
831                 int styleId = style.getStyleId();
832
833                 Collection<Resource> existingStyles = graph.syncRequest(new ObjectsWithType(book, Layer0.getInstance(graph).ConsistsOf, SHEET.Style));
834                 for (Resource eStyle : existingStyles) {
835                     int eStyleId = graph.getRelatedValue2(eStyle, SHEET.Style_id, Bindings.INTEGER);
836                     if (eStyleId == styleId) {
837                         createdStyle = eStyle;
838                         break;
839                     }
840                 }
841                 if (createdStyle == null) {
842                     style = builder.name("Style_" + existingStyles.size()).build();
843                     createdStyle = SpreadsheetGraphUtils.createStyle(graph, book, style);
844                 }
845
846                 graph.deny(textCell, SHEET.Cell_HasStyle);
847                 Collection<Resource> cellsOfStyle = graph.getObjects(styleContainer, SHEET.Cell_StyleOf);
848                 if (cellsOfStyle.isEmpty()) {
849                     graph.deny(styleContainer);
850                 }
851                 graph.claim(textCell, SHEET.Cell_HasStyle, createdStyle);
852
853             }
854
855             private SpreadsheetStyleBuilder computeStyleBuilder(SpreadsheetResource SHEET, WriteGraph graph, Resource styleContainer) throws DatabaseException {
856                 RGB.Integer foreground = graph.getPossibleRelatedValue2(styleContainer, SHEET.Cell_foreground, RGB.Integer.BINDING);
857                 RGB.Integer background = graph.getPossibleRelatedValue2(styleContainer, SHEET.Cell_background, RGB.Integer.BINDING);
858                 Font font = graph.getPossibleRelatedValue2(styleContainer, SHEET.Cell_font, Font.BINDING);
859                 Integer align = graph.getPossibleRelatedValue2(styleContainer, SHEET.Cell_align, Bindings.INTEGER);
860                 Integer border = graph.getPossibleRelatedValue2(styleContainer, SHEET.Cell_border, Bindings.INTEGER);
861
862                 return SpreadsheetStyle.newInstace().foreground(foreground).background(background).font(font).align(align).border(border);
863             }
864
865             @Override
866             public <T> void edit(WriteGraph graph, Transaction<Write> transaction, String location, Variant value) throws DatabaseException {
867                 SpreadsheetResource SHEET = SpreadsheetResource.getInstance(graph);
868
869                 // Handle possible deletes
870                 if (value == null)
871                     value = Variant.ofInstance("");
872
873                 if (!transaction.isOperationMode()) {
874                     cell.setPropertyValue(graph, SHEET.Cell_content, value, Bindings.VARIANT);
875 //                    return;
876                 }
877                 Variable runCell = null;
878                 Object transactionContext = transaction.getContext();
879                 if (transactionContext != null && transactionContext instanceof Variable) {
880                     Variable varContext = (Variable) transactionContext;
881                     Variable context = Variables.getContext(graph, varContext);
882                     try {
883                         runCell = Variables.switchRealization(graph, cell, context.getRepresents(graph), context);
884                     } catch (MissingVariableException e) {
885                         // Creating cell for the first time so no runCell available at this time, needs synchronization
886                         transaction.needSynchronization(cell.getParent(graph));
887                     }
888
889                 }
890
891                 if (runCell != null) {
892                     System.out.println("All.edit " + runCell.getURI(graph));
893                     runCell.setPropertyValue(graph, SHEET.Cell_content, value, Bindings.VARIANT);
894                 }
895             }
896
897             @Override
898             public <T> void copy(WriteGraph graph, Transaction<Write> transaction, String location, MutableVariant variant) throws DatabaseException {
899                 SpreadsheetResource SHEET = SpreadsheetResource.getInstance(graph);
900
901                 Variable runCell = null;
902                 Object transactionContext = transaction.getContext();
903                 if (transactionContext != null && transactionContext instanceof Variable) {
904                     Variable varContext = (Variable) transactionContext;
905                     Variable context = Variables.getContext(graph, varContext);
906                     runCell = Variables.switchRealization(graph, cell, context.getRepresents(graph), context);
907                 }
908
909                 Object object = cell.getPropertyValue(graph, SHEET.Cell_content);
910                 Variant content = null;
911                 if (object instanceof Variant) {
912                     content = (Variant)object;
913                 } else if (object instanceof Double) {
914                     content = Variant.ofInstance((Double)object);
915                 } else if (object instanceof Float) {
916                     content = Variant.ofInstance((Float)object);
917                 } else if (object instanceof Integer) {
918                     content = Variant.ofInstance((Integer)object);
919                 } else if (object instanceof Long) {
920                     content = Variant.ofInstance((Long)object);
921                 } else if (object instanceof String) {
922                     content = Variant.ofInstance((String)object);
923                 } else if (object instanceof Variable) {
924                     content = Variant.ofInstance((Variable)object);
925                 } else {
926                     throw new DatabaseException("");
927                 }
928                 variant.setValue(content);
929             }
930
931         };
932
933     }
934
935     @SCLValue(type = "ReadGraph -> Resource -> Variable -> Variable")
936     public static Variable spreadsheetInput(ReadGraph graph, Resource converter, Variable sheet) throws DatabaseException {
937         return ProxyVariables.inputVariable(graph, sheet);
938     }
939
940     @SCLValue(type = "ReadGraph -> Resource -> Variable -> Variable")
941     public static Variable spreadsheetSession(ReadGraph graph, Resource converter, Variable sheet) throws DatabaseException {
942         return ProxyVariables.proxySessionVariable(graph, sheet);
943     }
944
945     @SCLValue(type = "ReadGraph -> Resource -> Variable -> Variable")
946     public static Variable spreadsheetRunInput(ReadGraph graph, Resource converter, Variable property) throws DatabaseException {
947         Resource model = Variables.getModel(graph, property);
948         Variable activeRun = graph.syncRequest(new PossibleActiveRun(model));
949         if(activeRun != null) return activeRun;
950         return Variables.getConfigurationContext(graph, model);
951     }
952
953     @SCLValue(type = "ReadGraph -> Resource -> Variable -> a")
954     public static Object sclValue(ReadGraph graph, Resource converter, Variable context) throws DatabaseException {
955         return CompileSCLValueRequest.compileAndEvaluate(graph, context);
956     }
957
958 }