9a3e8732679d284b4a30abfdbcfc274da9a708e7
[simantics/platform.git] / bundles / org.simantics.spreadsheet.graph / src / org / simantics / spreadsheet / graph / GraphUI.java
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
3  * in Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.spreadsheet.graph;\r
13 \r
14 import java.util.ArrayList;\r
15 import java.util.Collection;\r
16 import java.util.Collections;\r
17 import java.util.List;\r
18 import java.util.Map;\r
19 import java.util.function.Consumer;\r
20 \r
21 import org.eclipse.e4.core.contexts.IEclipseContext;\r
22 import org.eclipse.e4.ui.di.UISynchronize;\r
23 import org.eclipse.jface.dialogs.Dialog;\r
24 import org.eclipse.ui.PlatformUI;\r
25 import org.simantics.Simantics;\r
26 import org.simantics.databoard.Bindings;\r
27 import org.simantics.databoard.binding.Binding;\r
28 import org.simantics.databoard.binding.mutable.MutableVariant;\r
29 import org.simantics.databoard.binding.mutable.Variant;\r
30 import org.simantics.db.AsyncReadGraph;\r
31 import org.simantics.db.ReadGraph;\r
32 import org.simantics.db.RequestProcessor;\r
33 import org.simantics.db.Resource;\r
34 import org.simantics.db.WriteGraph;\r
35 import org.simantics.db.common.procedure.adapter.AsyncListenerSupport;\r
36 import org.simantics.db.common.procedure.adapter.ListenerSupport;\r
37 import org.simantics.db.common.procedure.adapter.SyncListenerSupport;\r
38 import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener;\r
39 import org.simantics.db.common.procedure.single.SingleSetSyncListenerDelegate;\r
40 import org.simantics.db.common.request.ReadRequest;\r
41 import org.simantics.db.common.request.ResourceRead;\r
42 import org.simantics.db.common.request.UnaryRead;\r
43 import org.simantics.db.common.request.UniqueRead;\r
44 import org.simantics.db.common.request.WriteRequest;\r
45 import org.simantics.db.common.request.WriteResultRequest;\r
46 import org.simantics.db.common.session.SessionEventListenerAdapter;\r
47 import org.simantics.db.exception.DatabaseException;\r
48 import org.simantics.db.layer0.StandardRealm;\r
49 import org.simantics.db.layer0.request.PossibleURIVariable;\r
50 import org.simantics.db.layer0.request.VariableName;\r
51 import org.simantics.db.layer0.request.VariableRead;\r
52 import org.simantics.db.layer0.variable.ProxyVariables;\r
53 import org.simantics.db.layer0.variable.Variable;\r
54 import org.simantics.db.layer0.variable.Variables;\r
55 import org.simantics.db.procedure.SyncListener;\r
56 import org.simantics.db.request.Write;\r
57 import org.simantics.db.service.SessionEventSupport;\r
58 import org.simantics.layer0.Layer0;\r
59 import org.simantics.spreadsheet.Adaptable;\r
60 import org.simantics.spreadsheet.CellEditor;\r
61 import org.simantics.spreadsheet.ClientModel;\r
62 import org.simantics.spreadsheet.ClientModel.OperationMode;\r
63 import org.simantics.spreadsheet.SheetCommands;\r
64 import org.simantics.spreadsheet.common.logging.Logger;\r
65 import org.simantics.spreadsheet.event.model.RemoveCellHandler;\r
66 import org.simantics.spreadsheet.resource.SpreadsheetResource;\r
67 import org.simantics.ui.selection.WorkbenchSelectionUtils;\r
68 import org.simantics.utils.datastructures.Pair;\r
69 import org.simantics.utils.strings.AlphanumComparator;\r
70 import org.simantics.utils.threads.logger.ITask;\r
71 import org.simantics.utils.threads.logger.ThreadLogger;\r
72 \r
73 import gnu.trove.map.hash.THashMap;\r
74 import gnu.trove.map.hash.TObjectIntHashMap;\r
75 \r
76 class FilteredVariableProperties extends UnaryRead<Variable, Collection<Pair<String,Variable>>> {\r
77 \r
78         final static String CLASSIFICATION = SpreadsheetResource.URIs.Attribute;\r
79         \r
80     public FilteredVariableProperties(Variable variable) {\r
81         super(variable);\r
82     }\r
83 \r
84     @Override\r
85     public Collection<Pair<String,Variable>> perform(ReadGraph graph) throws DatabaseException {\r
86         ArrayList<Pair<String,Variable>> result = new ArrayList<Pair<String,Variable>>();\r
87         for(Variable var : parameter.getProperties(graph, CLASSIFICATION)) {\r
88                 String name = var.getName(graph);\r
89                 String uri = var.getURI(graph);\r
90                 result.add(Pair.make(name, var));\r
91                 Variable expression = var.getPossibleProperty(graph, "expression");\r
92                 if(expression != null)\r
93                     result.add(Pair.make(name + "#expression", expression));\r
94                 Variable editable = var.getPossibleProperty(graph, "editable");\r
95             if(editable != null)\r
96                 result.add(Pair.make(name + "#editable", editable));\r
97         }\r
98         return result;\r
99     }\r
100 \r
101 }\r
102 \r
103 public class GraphUI implements Adaptable, ListenerSupport, AsyncListenerSupport, SyncListenerSupport {\r
104 \r
105         final public static boolean DEBUG = false;\r
106         \r
107     final private RequestProcessor processor;\r
108     \r
109     private CellEditor<Write> cellEditor;\r
110     \r
111     private Variable run;\r
112     private ClientModel client;\r
113 \r
114     private Map<String, PropertyListener> listenerCache = new THashMap<>();\r
115 \r
116     public GraphUI(RequestProcessor processor) {\r
117         this.processor = processor;\r
118     }\r
119     \r
120     public void addCell(ReadGraph graph, Pair<String, Variable> child, final ClientModel client) throws DatabaseException {\r
121 \r
122                 if(DEBUG) System.out.println("GraphUI adds cell  " + child.second.getURI(graph));\r
123 \r
124         final String childName = child.second.getName(graph);\r
125         Boolean immutable = child.second.getPossiblePropertyValue(graph, "immutable", Bindings.BOOLEAN);\r
126         if(immutable != null && immutable) {\r
127                 Collection<Variable> properties = child.second.getProperties(graph, FilteredVariableProperties.CLASSIFICATION);\r
128                 addProperties(graph, properties, client, childName);\r
129         } else {\r
130             PropertyListener listener = listenerCache.get(child.first); \r
131             if (listener == null) {\r
132                     listener = propertyListener(client, childName);\r
133                     listenerCache.put(child.first, listener);\r
134             }\r
135                 graph.asyncRequest(new FilteredVariableProperties(child.second), listener);\r
136         }\r
137 \r
138     }\r
139 \r
140     public void removeCell(ReadGraph graph, Pair<String, Variable> child, final ClientModel client) throws DatabaseException {\r
141 \r
142                 if(DEBUG) System.out.println("GraphUI removed cell " + child.first);\r
143                 \r
144                 client.clear(child.first);\r
145                 PropertyListener listener = listenerCache.remove(child.first);\r
146                 if (listener != null)\r
147                     listener.dispose();\r
148 \r
149     }\r
150 \r
151     public void loadCells(ReadGraph graph, Variable container, boolean immutable, final ClientModel client) throws DatabaseException {\r
152         \r
153                 if(DEBUG) System.out.println("GraphUI loads cells from " + container.getURI(graph));\r
154                 \r
155                 if(immutable) {\r
156                         for(Pair<String, Variable> cell : graph.syncRequest(new Cells(container), TransientCacheAsyncListener.<Collection<Pair<String, Variable>>>instance())) { \r
157                                 addCell(graph, cell, client);\r
158                         }\r
159                 } else {\r
160                 graph.syncRequest(new Cells(container), new SingleSetSyncListenerDelegate<Pair<String, Variable>>(GraphUI.this) {\r
161         \r
162                     @Override\r
163                     public void add(ReadGraph graph, final Pair<String, Variable> child) throws DatabaseException {\r
164                         addCell(graph, child, client);\r
165                     }\r
166         \r
167                     @Override\r
168                     public void remove(ReadGraph graph, final Pair<String, Variable> child) throws DatabaseException {\r
169                         removeCell(graph, child, client);\r
170                     }\r
171                 });\r
172                 }\r
173         \r
174     }\r
175     \r
176     private SessionEventListenerAdapter listener;\r
177     \r
178     private String currentSource;\r
179 \r
180     private boolean disposed;\r
181     \r
182     public Resource load(final Variable variable, final ClientModel client) throws DatabaseException {\r
183         \r
184 //        for (PropertyListener listener : listenerCache.values())\r
185 //            listener.dispose();\r
186 //        \r
187 //        listenerCache.clear();\r
188         \r
189         \r
190         \r
191         assert(variable != null);\r
192         \r
193         this.run = variable;\r
194         this.client = client;\r
195         \r
196         SessionEventSupport support = processor.getService(SessionEventSupport.class);\r
197         \r
198         for (PropertyListener listener : listenerCache.values()) {\r
199             listener.dispose();\r
200         }\r
201         listenerCache.clear();\r
202         \r
203         if(listener != null)\r
204                 support.removeListener(listener);\r
205         \r
206         listener = new SessionEventListenerAdapter() {\r
207                 \r
208                 @Override\r
209                 public void writeTransactionFinished() {\r
210                         client.flush();\r
211                 }\r
212                 \r
213         }; \r
214         \r
215         support.addListener(listener);\r
216 \r
217         this.cellEditor = processor.sync(new VariableRead<CellEditor>(variable) {\r
218 \r
219                         @Override\r
220                         public CellEditor perform(ReadGraph graph) throws DatabaseException {\r
221                                 SpreadsheetResource SHEET = SpreadsheetResource.getInstance(graph);\r
222                                 return variable.getPropertyValue(graph, SHEET.cellEditor);\r
223                         }\r
224                 \r
225         });\r
226         \r
227                 final ITask task = ThreadLogger.getInstance().begin("GraphUI.init");\r
228 \r
229                 client.clearAll();\r
230 \r
231                 Map<String,Variable> sources = processor.syncRequest(new Sources(variable));\r
232 \r
233                 List<String> sheetList = processor.syncRequest(new Sheets(variable));\r
234                 String currentSheet = processor.syncRequest(new VariableName(variable));\r
235                 \r
236                 Map<String, Resource> stateList = processor.syncRequest(new SpreadsheetStates(variable));\r
237 \r
238                 if(currentSource == null) currentSource = "Sheet";\r
239                 \r
240                 ArrayList<String> sourceList = new ArrayList<String>(sources.keySet());\r
241                 \r
242                 Collections.sort(sourceList, AlphanumComparator.CASE_INSENSITIVE_COMPARATOR);\r
243                 if(!sourceList.contains(currentSource)) sourceList.add(currentSource);\r
244                 \r
245                 client.setProperty(ClientModel.SOURCES, ClientModel.SOURCES_AVAILABLE, sourceList.toArray(new String[sourceList.size()]));\r
246                 client.setProperty(ClientModel.SOURCES, ClientModel.SOURCES_CURRENT, currentSource);\r
247 \r
248                 client.setProperty(ClientModel.SHEETS, ClientModel.SHEETS_AVAILABLE, sheetList.toArray(new String[sheetList.size()]));\r
249                 client.setProperty(ClientModel.SHEETS, ClientModel.SHEETS_CURRENT, currentSheet);\r
250                 \r
251                 client.setProperty(ClientModel.STATES, ClientModel.STATES_AVAILABLE, stateList.keySet().toArray(new String[stateList.size()]));\r
252                 \r
253                 client.setProperty(ClientModel.CONTEXT, ClientModel.CONTEXT_CURRENT, variable);\r
254                 \r
255                 client.setProperty(ClientModel.MODE, ClientModel.MODE_CURRENT, OperationMode.OPERATION);\r
256                 \r
257                 String currentState = processor.syncRequest(new UniqueRead<String>() {\r
258 \r
259             @Override\r
260             public String perform(ReadGraph graph) throws DatabaseException {\r
261                 Resource book = variable.getParent(graph).getRepresents(graph);\r
262                 Resource ic = graph.getPossibleObject(book, SpreadsheetResource.getInstance(graph).Book_HasDefaultInitialCondition);\r
263                 if (ic == null)\r
264                         return "";\r
265                 return graph.getRelatedValue2(ic, Layer0.getInstance(graph).HasName, Bindings.STRING);\r
266             }\r
267         });\r
268                 \r
269                 client.setProperty(ClientModel.STATES, ClientModel.STATES_CURRENT, currentState);\r
270 \r
271         processor.syncRequest(new ReadRequest() {\r
272 \r
273             @Override\r
274             public void run(ReadGraph graph) throws DatabaseException {\r
275 \r
276                 loadCells(graph, variable, false, client);\r
277 \r
278                 graph.syncRequest(new Ranges(variable), new SingleSetSyncListenerDelegate<Variable>(GraphUI.this) {\r
279 \r
280                     @Override\r
281                     public void add(ReadGraph graph, final Variable range) throws DatabaseException {\r
282 \r
283                                 if(DEBUG) System.out.println("GraphUI adds range  " + range.getURI(graph));\r
284 \r
285                         Boolean immutable = range.getPossiblePropertyValue(graph, "immutable", Bindings.BOOLEAN);\r
286                         loadCells(graph, range, immutable != null && immutable, client);\r
287 \r
288                     }\r
289 \r
290                     @Override\r
291                     public void remove(ReadGraph graph, final Variable range) throws DatabaseException {\r
292 \r
293                     }\r
294                     \r
295                 });\r
296                 \r
297                 \r
298                 graph.syncRequest(new SheetLines(variable), new SingleSetSyncListenerDelegate<Variable>(GraphUI.this) {\r
299 \r
300                     @Override\r
301                     public void add(ReadGraph graph, final Variable range) throws DatabaseException {\r
302 \r
303                                 if(DEBUG) System.out.println("GraphUI adds line  " + range.getURI(graph));\r
304 \r
305                         Boolean immutable = range.getPossiblePropertyValue(graph, "immutable", Bindings.BOOLEAN);\r
306                         loadCells(graph, range, immutable != null && immutable, client);\r
307 \r
308                     }\r
309 \r
310                     @Override\r
311                     public void remove(ReadGraph graph, final Variable range) throws DatabaseException {\r
312 \r
313                     }\r
314                 });\r
315 \r
316             }\r
317 \r
318 //            @Override\r
319 //            public void remove(ReadGraph graph, Variable child) throws DatabaseException {\r
320 //\r
321 //              String location = locations.get(cellResource);\r
322 //              assert(location != null);\r
323 //\r
324 //              client.setProperty(location, "Label", null);\r
325 //              client.setProperty(location, "Expression", null);\r
326 //\r
327 //            }\r
328 \r
329         });\r
330         \r
331 \r
332                 task.finish();\r
333                 client.flush();\r
334                 \r
335                 return null;\r
336 \r
337     }\r
338     \r
339     private static class PropertyListener extends SingleSetSyncListenerDelegate<Pair<String,Variable>> {\r
340 \r
341         private ClientModel client;\r
342         private String childName;\r
343         private boolean listenerDisposed;\r
344 \r
345         public PropertyListener(AsyncListenerSupport support, ClientModel client, String childName) {\r
346             super(support);\r
347             this.client = client;\r
348             this.childName = childName;\r
349         }\r
350         \r
351         @Override\r
352         public void add(ReadGraph graph, final Pair<String,Variable> property) throws DatabaseException {\r
353 \r
354             if(DEBUG)\r
355                 System.out.println("GraphUI adds property  " + property.second.getURI(graph));\r
356 \r
357             graph.asyncRequest(new CellValue(property.second), new SyncListener<Object>() {\r
358 \r
359                 @Override\r
360                 public void execute(ReadGraph graph, final Object value) throws DatabaseException {\r
361 \r
362                     String propertyName = property.first;\r
363 \r
364                     if(DEBUG)\r
365                         System.out.println("GraphUI detected content change(1) at  " + childName + " - " + propertyName + " -> " + value);\r
366                     client.setProperty(childName, propertyName, value);\r
367                     \r
368                 }\r
369 \r
370                 @Override\r
371                 public void exception(ReadGraph graph, Throwable throwable) throws DatabaseException {\r
372                     \r
373                     Logger.defaultLogError(throwable);\r
374                     \r
375                     String propertyName = property.first;\r
376                     if("content".equals(propertyName)) {\r
377                         if(throwable == null) throwable = new Exception();\r
378                         String message = throwable.getMessage();\r
379                         if(message == null) message = throwable.toString();\r
380                         client.setProperty(childName, propertyName, Variant.ofInstance(message));\r
381                     } else {\r
382                         client.setProperty(childName, propertyName, null);\r
383                     }\r
384                     \r
385                 }\r
386 \r
387                 @Override\r
388                 public boolean isDisposed() {\r
389                     return listenerDisposed;\r
390                 }\r
391 \r
392             });\r
393         }\r
394 \r
395         public void dispose() {\r
396             listenerDisposed = true;\r
397         }\r
398         \r
399         @Override\r
400         public String toString() {\r
401             return super.toString() + ":" + childName;\r
402         }\r
403         \r
404     }\r
405     \r
406     private PropertyListener propertyListener(final ClientModel client, final String childName) {\r
407         return new PropertyListener(this, client, childName);\r
408     }\r
409     \r
410     private void addProperties(ReadGraph graph, final Collection<Variable> properties, final ClientModel client, final String childName) throws DatabaseException {\r
411 \r
412         for(Variable property : properties) {\r
413                 \r
414                 if(DEBUG) System.out.println("GraphUI adds immutable property  " + property.getURI(graph));\r
415 \r
416                 final String propertyName = property.getName(graph);\r
417                 \r
418                 Object value = property.getValue(graph);\r
419 \r
420                 if(DEBUG) System.out.println("GraphUI detected change at  " + childName + " - " + propertyName + " -> " + value);\r
421                 client.setProperty(childName, propertyName, value);\r
422                 \r
423                 String expression = property.getPossiblePropertyValue(graph, "expression", Bindings.STRING);\r
424                 if(expression != null) {\r
425                         if(DEBUG) System.out.println("GraphUI detected change at  " + childName + " - " + (propertyName + "#expression") + " -> " + value);\r
426                         client.setProperty(childName, propertyName + "#expression", expression);\r
427                 }\r
428                 \r
429             Boolean editable = property.getPossiblePropertyValue(graph, "editable", Bindings.STRING);\r
430             if(editable != null) {\r
431                 if(DEBUG) System.out.println("GraphUI detected change at  " + childName + " - " + (propertyName + "#editable") + " -> " + value);\r
432                 client.setProperty(childName, propertyName + "#editable", editable);\r
433             }\r
434         \r
435         }\r
436 \r
437     }\r
438     \r
439     @SuppressWarnings("unchecked")\r
440     @Override\r
441     public <T> T getAdapter(Class<T> clazz) {\r
442 \r
443         if(Variable.class == clazz) {\r
444 \r
445                 return (T)run;\r
446                 \r
447         } else if(RemoveCellHandler.class == clazz) {\r
448                 \r
449             return (T) new RemoveCellHandler() {\r
450 \r
451                                 @Override\r
452                                 public void handle(final String location) {\r
453                                         \r
454                                 processor.asyncRequest(new ReadRequest() {\r
455 \r
456                                     @Override\r
457                                     public void run(ReadGraph graph) throws DatabaseException {\r
458                                         \r
459                                                         Variable cellVariable = run.getPossibleChild(graph, location);\r
460                                                         if(cellVariable != null) {\r
461                                                                 final Resource config = cellVariable.getPossiblePropertyValue(graph, "Represents");\r
462                                                                 if(config != null) {\r
463                                                                         \r
464                                                                         graph.asyncRequest(new WriteRequest() {\r
465 \r
466                                                                                 @Override\r
467                                                                                 public void perform(WriteGraph graph) throws DatabaseException {\r
468                                                                                         \r
469                                                                                         Layer0 l0 = Layer0.getInstance(graph);\r
470 //                                                                                      SpreadsheetResource sr = SpreadsheetResource.getInstance(graph);\r
471                                                                                         graph.deny(config, l0.PartOf);\r
472 //                                                                                      graph.deny(config, sr.RowOf);\r
473 //                                                                                      graph.deny(config, sr.ColumnOf);\r
474                                                                                         \r
475                                                                                 }\r
476                                                                                 \r
477                                                                         });\r
478                                                                         \r
479                                                                 }\r
480                                                         }\r
481                                                         \r
482                                     }\r
483                                     \r
484                                 });\r
485                                         \r
486                                 }\r
487                 \r
488             };\r
489 \r
490         } else if(CellEditor.class == clazz) {\r
491         \r
492                 return (T)new CellEditor<Write>() {\r
493 \r
494                                 @Override\r
495                                 public <T> void edit(Transaction<Write> transaction, String location, String property, T value, Binding binding, Consumer<?> callback) {\r
496                                         \r
497                                     if (ClientModel.ITERATION_ENABLED.equals(location)) {\r
498                                         Simantics.getSession().asyncRequest(new ReadRequest() {\r
499                                                         @Override\r
500                                                         public void run(ReadGraph graph) throws DatabaseException {\r
501                                                                 getBook(graph).setIterationEnabled((boolean)value);\r
502                                                         }\r
503                                                 });\r
504                                         return;\r
505                                     }\r
506                                     \r
507                                     if (ClientModel.MODE.equals(location)) {\r
508                                         if (ClientModel.MODE_CURRENT.equals(property)) {\r
509                                             client.setProperty(location, property, value);\r
510                                             client.flush();\r
511                                             return;\r
512                                         }\r
513                                     }\r
514                                     \r
515                                     if (ClientModel.CONTEXT.equals(location)) {\r
516                                         if(ClientModel.CONTEXT_CURRENT.equals(property)) {\r
517                             if(value instanceof String) {\r
518                                 try {\r
519                                     Variable newContext = processor.syncRequest(new UnaryRead<String, Variable>((String)value) {\r
520 \r
521                                         @Override\r
522                                         public Variable perform(ReadGraph graph) throws DatabaseException {\r
523                                       \r
524                                             String sheetName = run.getName(graph);\r
525                                             \r
526                                             Variable book = Variables.getContext(graph, run);\r
527                                             Resource bookResource = book.getRepresents(graph);\r
528                                             \r
529                                             Variable input = Variables.getVariable(graph, parameter);\r
530                                             Variable proxy = ProxyVariables.makeProxyVariable(graph, Variables.getVariable(graph, bookResource), input);\r
531                                             \r
532                                             return proxy.getChild(graph, sheetName);\r
533                                             \r
534 //                                            return variable.getParent(graph).getChild(graph, parameter);\r
535                                         }\r
536 \r
537                                     });\r
538                                     \r
539                                     load(newContext, client);\r
540                                     return;\r
541                                 } catch (DatabaseException e) {\r
542                                     Logger.defaultLogError(e);\r
543                                 }\r
544                             }\r
545                                         }\r
546                                     }\r
547                                     \r
548                                         if(ClientModel.SHEETS.equals(location)) {\r
549                                                 if(ClientModel.SHEETS_CURRENT.equals(property)) {\r
550                                                         \r
551                                                         if(value instanceof String) {\r
552 \r
553                                                                 try {\r
554 \r
555                                                                         Variable newInput = processor.syncRequest(new UnaryRead<String, Variable>((String)value) {\r
556 \r
557                                                                                 @Override\r
558                                                                                 public Variable perform(ReadGraph graph) throws DatabaseException {\r
559                                                                                         return run.getParent(graph).getChild(graph, parameter);\r
560                                                                                 }\r
561 \r
562                                                                         });\r
563 \r
564                                                                         load(newInput, client);\r
565                                                                         return;\r
566                                                                 } catch (DatabaseException e) {\r
567                                                                         Logger.defaultLogError(e);\r
568                                                                 }\r
569                                                         }\r
570                                                 }\r
571                                         }\r
572                                         \r
573                    if(ClientModel.STATES.equals(location)) {\r
574                         if(ClientModel.STATES_CURRENT.equals(property)) {\r
575                             if(value instanceof String) {\r
576                                 final String parameter = (String) value;\r
577                                 try {\r
578                                     \r
579                                     String uri = processor.syncRequest(new WriteResultRequest<String>() {\r
580                 \r
581                                         @Override\r
582                                         public String perform(WriteGraph graph) throws DatabaseException {\r
583                                             \r
584                                             Map<String, Resource> states = graph.syncRequest(new SpreadsheetStates(run));\r
585                                             \r
586                                             Resource state = null;\r
587                                             for (Map.Entry<String, Resource> entry : states.entrySet()) {\r
588                                                 if (entry.getKey().equals(parameter)) {\r
589                                                     state = entry.getValue();\r
590                                                     break;\r
591                                                 }\r
592                                             }\r
593                                             if (state != null) {\r
594                                                 Variable context = Variables.getContext(graph, run);\r
595                                                 Resource bookResource = context.getRepresents(graph);\r
596                                                 SpreadsheetGraphUtils.setDefaultInitialConditionForBook(graph, bookResource, state);\r
597                                                 \r
598                                                 String contextURI = context.getURI(graph);\r
599                                                 \r
600                                                 String sessionName = context.getParent(graph).getURI(graph);\r
601                                                 SpreadsheetSessionManager.getInstance().removeRealm(sessionName);\r
602                                                 SpreadsheetSessionManager.getInstance().getOrCreateRealm(graph, sessionName);\r
603                                             }\r
604                                             \r
605                                             return run.getURI(graph);\r
606                                         }\r
607                                     });\r
608                                     Variable newInput = processor.syncRequest(new PossibleURIVariable(uri));\r
609                                     load(newInput, client);\r
610 //                                    fullSynchronize();\r
611                                     return;\r
612                                 } catch (DatabaseException e) {\r
613                                     Logger.defaultLogError(e);\r
614                                 }\r
615                             }\r
616                         }\r
617                     }\r
618 \r
619                                         if(ClientModel.SOURCES.equals(location)) {\r
620                                                 if(ClientModel.SOURCES_CURRENT.equals(property)) {\r
621                                                         try {\r
622                                                                 Resource res = WorkbenchSelectionUtils.getPossibleResource(value);\r
623                                                                 if(res != null) {\r
624                                                                         \r
625                                                                         Variable newInput = processor.syncRequest(new ResourceRead<Variable>(res) {\r
626 \r
627                                                                                 @Override\r
628                                                                                 public Variable perform(ReadGraph graph) throws DatabaseException {\r
629                                                                                         Variable base = ProxyVariables.proxyVariableBase(graph, run);\r
630                                                                                         Variable in = Variables.getVariable(graph, resource);\r
631                                                                                         currentSource = in.getURI(graph);\r
632                                                                                         return ProxyVariables.makeProxyVariable(graph, base, in);\r
633                                                                                 }\r
634                                                 \r
635                                                                         });\r
636                                                                         \r
637                                                                         load(newInput, client);\r
638                                                                         \r
639                                                                         return;\r
640 \r
641                                                                 } else if(value instanceof String) {\r
642                                                                         \r
643                                                                         Variable newInput = processor.syncRequest(new UnaryRead<String, Variable>((String)value) {\r
644 \r
645                                                                                 @Override\r
646                                                                                 public Variable perform(ReadGraph graph) throws DatabaseException {\r
647                                                                                         \r
648                                                                                         Variable base = ProxyVariables.proxyVariableBase(graph, run);\r
649                                                                                         Map<String,Variable> sources = graph.syncRequest(new Sources(base));\r
650 \r
651                                                                                         Variable found = sources.get(parameter);\r
652                                                                                         if(found == null) return null;\r
653                                                                                         \r
654                                                                                         currentSource = parameter;\r
655 \r
656                                                                                         return ProxyVariables.makeProxyVariable(graph, base, found);\r
657                                                                                         \r
658                                                                                 }\r
659                                                 \r
660                                                                         });\r
661                                                                         \r
662                                                                         load(newInput, client);\r
663                                                                         return;\r
664                                                                 }\r
665                                                                 \r
666                                                         } catch (DatabaseException e) {\r
667                                                                 Logger.defaultLogError(e);\r
668                                                         }\r
669                                                 }\r
670                                                 return;\r
671                                         }\r
672                                         boolean needsCommit = false;\r
673                                         if (transaction == null) {\r
674                                             OperationMode mode = client.getPropertyAt(ClientModel.MODE, ClientModel.MODE_CURRENT);\r
675                                             transaction = startTransaction(mode);\r
676 //                                          if (mode.equals(OperationMode.OPERATION))\r
677                                         transaction.setContext(run);\r
678                                             needsCommit = true;\r
679                                         }\r
680                                         final Transaction<Write> finalTransaction = transaction;\r
681                                         cellEditor.edit(transaction, location, property, value, binding, new Consumer<Object>() {\r
682                         \r
683                         @Override\r
684                         public void accept(Object param) {\r
685                             if (finalTransaction.needSynchronization() != null)\r
686                                 synchronize(finalTransaction.needSynchronization());\r
687                         }\r
688                                         });\r
689                                         if (needsCommit)\r
690                                             transaction.commit();\r
691                                 }\r
692 \r
693                                 @Override\r
694                                 public void edit(Transaction<Write> transaction, String location, Variant variant, Consumer<?> callback) {\r
695                                     boolean needsCommit = false;\r
696                                     if (transaction == null) {\r
697                                         OperationMode mode = client.getPropertyAt(ClientModel.MODE, ClientModel.MODE_CURRENT);\r
698                                         transaction = startTransaction(mode);\r
699 //                                      if (mode.equals(OperationMode.OPERATION))\r
700                                     transaction.setContext(run);\r
701                                         needsCommit = true;\r
702                                     }\r
703                                     final Transaction<Write> finalTransaction = transaction;\r
704                                         cellEditor.edit(transaction, location, variant, new Consumer<Object>() {\r
705                         \r
706                         @Override\r
707                         public void accept(Object param) {\r
708                             if (finalTransaction.needSynchronization() != null)\r
709                                 synchronize(finalTransaction.needSynchronization());\r
710                         }\r
711                     });\r
712                                         if (needsCommit)\r
713                                             transaction.commit();\r
714                                 }\r
715 \r
716                                 @Override\r
717                                 public void copy(final Transaction<Write> transaction, String location, MutableVariant variant, Consumer<?> callback) {\r
718                                         cellEditor.edit(transaction, location, variant, new Consumer<Object>() {\r
719                         \r
720                         @Override\r
721                         public void accept(Object param) {\r
722                             if (transaction.needSynchronization() != null)\r
723                                 synchronize(transaction.needSynchronization());\r
724                         }\r
725                                         });\r
726                                 }\r
727 \r
728                                 @Override\r
729                                 public Transaction<Write> startTransaction(OperationMode mode) {\r
730                                         return cellEditor.startTransaction(mode);\r
731                                 }\r
732                                 \r
733                 };\r
734                 \r
735         } else if (SheetCommands.class == clazz ) {\r
736             \r
737             return (T) new SheetCommands() {\r
738                 \r
739                 @Override\r
740                 public void saveState() {\r
741                     \r
742                     Simantics.getSession().asyncRequest(new ReadRequest() {\r
743                         \r
744                         @Override\r
745                         public void run(ReadGraph graph) throws DatabaseException {\r
746                             IEclipseContext context = PlatformUI.getWorkbench().getService(IEclipseContext.class);\r
747                             \r
748                             Resource uiContextResource = run.getRepresents(graph);\r
749                             Resource bookResource = Variables.getContext(graph, run).getRepresents(graph);\r
750                             Layer0 L0 = Layer0.getInstance(graph);\r
751                             String uiContextName = graph.getRelatedValue2(uiContextResource, L0.HasName, Bindings.STRING);\r
752                             String bookName = graph.getRelatedValue2(bookResource, L0.HasName, Bindings.STRING);\r
753                             \r
754                             UISynchronize synchronizer = context.get(UISynchronize.class);\r
755                             synchronizer.asyncExec(() -> {\r
756                                 Pair<String, Resource>[] pairs = new Pair[] {Pair.make(uiContextName, uiContextResource), Pair.make(bookName, bookResource) };\r
757                                 SaveSpreadsheetStateDialog dialog = new SaveSpreadsheetStateDialog(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor().getSite(), "Save Spreadsheet state", pairs);\r
758                                 if (dialog.open() == Dialog.OK) {\r
759                                     Object[] result = dialog.getSelection();\r
760                                     if (result != null) {\r
761                                         Pair<Resource, String> p = (Pair<Resource, String>) result[0];\r
762                                         Simantics.getSession().asyncRequest(new WriteRequest() {\r
763                                             \r
764                                             @Override\r
765                                             public void perform(WriteGraph graph) throws DatabaseException {\r
766                                                 \r
767                                                 Variable parent = run.getParent(graph);\r
768                                                 Variable base = ProxyVariables.proxyVariableBase(graph, parent);\r
769                                                 SpreadsheetGraphUtils.saveInitialCondition(graph, parent, p.first, p.second);\r
770                                             }\r
771                                         });\r
772                                     }\r
773                                 } else {\r
774                                     return;\r
775                                 }\r
776                             });\r
777                         }\r
778                     });\r
779                 }\r
780             };\r
781         }\r
782 \r
783         return null;\r
784 \r
785     }\r
786 \r
787     @Override\r
788     public void exception(Throwable t) {\r
789         t.printStackTrace();\r
790     }\r
791 \r
792     @Override\r
793     public boolean isDisposed() {\r
794         return disposed;\r
795     }\r
796 \r
797     @Override\r
798     public void exception(AsyncReadGraph graph, Throwable t) {\r
799         Logger.defaultLogError("Failed to read properties.", t);\r
800     }\r
801 \r
802     @Override\r
803     public void exception(ReadGraph graph, Throwable t) {\r
804         Logger.defaultLogError("Failed to read properties.", t);\r
805     }\r
806 \r
807     public void dispose() {\r
808         for (PropertyListener listener : listenerCache.values())\r
809             listener.dispose();\r
810         \r
811         listenerCache.clear();\r
812         SessionEventSupport support = processor.getService(SessionEventSupport.class);\r
813         support.removeListener(listener);\r
814         disposed = true;\r
815     }\r
816     \r
817     private void synchronize(List<Object> list) {\r
818         Simantics.getSession().asyncRequest(new FullSynchronizeBook(run, list));\r
819     }\r
820     \r
821     public static class FullSynchronizeBook extends ReadRequest {\r
822 \r
823         private final Variable run;\r
824         private final List<Object> location;\r
825         \r
826         public FullSynchronizeBook(Variable run, List<Object> cellLocation) {\r
827             this.run = run;\r
828             this.location = cellLocation;\r
829         }\r
830         \r
831         @Override\r
832         public void run(ReadGraph graph) throws DatabaseException {\r
833             String uri = run.getURI(graph);\r
834             String parentUri = run.getParent(graph).getURI(graph);\r
835             System.err.println("Full sync for book " + parentUri);\r
836             \r
837             Resource sheetResource = run.getRepresents(graph);\r
838             Variable sheetVariable = Variables.getVariable(graph, sheetResource);\r
839             \r
840             TObjectIntHashMap<Variable> changes = null;\r
841             if (location != null) {\r
842                 changes = new TObjectIntHashMap<>(location.size());\r
843                 for (Object loc : location) {\r
844                     Variable var = (Variable) loc;\r
845                     changes.put(var, 1);\r
846                 };\r
847             }\r
848             SpreadsheetGraphUtils.partialSynchronization(graph, run.getParent(graph), changes);\r
849         }\r
850         \r
851     }\r
852     \r
853     private SpreadsheetBook getBook(ReadGraph graph) throws DatabaseException {\r
854         String sessionName = run.getParent(graph).getParent(graph).getURI(graph);\r
855         StandardRealm<SheetNode, SpreadsheetBook> realm = SpreadsheetSessionManager.getInstance().getOrCreateRealm(graph, sessionName);\r
856         SpreadsheetBook book = realm.getEngine();\r
857         return book;\r
858     }\r
859     \r
860 }\r