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