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