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