]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.spreadsheet.graph/src/org/simantics/spreadsheet/graph/GraphUI.java
Added some enforcement of immutability to structural user component UI's.
[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                                         \r
499                                     }\r
500                                     \r
501                                     if (ClientModel.MODE.equals(location)) {\r
502                                         if (ClientModel.MODE_CURRENT.equals(property)) {\r
503                                             client.setProperty(location, property, value);\r
504                                             client.flush();\r
505                                             return;\r
506                                         }\r
507                                     }\r
508                                     \r
509                                     if (ClientModel.CONTEXT.equals(location)) {\r
510                                         if(ClientModel.CONTEXT_CURRENT.equals(property)) {\r
511                             if(value instanceof String) {\r
512                                 try {\r
513                                     Variable newContext = processor.syncRequest(new UnaryRead<String, Variable>((String)value) {\r
514 \r
515                                         @Override\r
516                                         public Variable perform(ReadGraph graph) throws DatabaseException {\r
517                                       \r
518                                             String sheetName = run.getName(graph);\r
519                                             \r
520                                             Variable book = Variables.getContext(graph, run);\r
521                                             Resource bookResource = book.getRepresents(graph);\r
522                                             \r
523                                             Variable input = Variables.getVariable(graph, parameter);\r
524                                             Variable proxy = ProxyVariables.makeProxyVariable(graph, Variables.getVariable(graph, bookResource), input);\r
525                                             \r
526                                             return proxy.getChild(graph, sheetName);\r
527                                             \r
528 //                                            return variable.getParent(graph).getChild(graph, parameter);\r
529                                         }\r
530 \r
531                                     });\r
532                                     \r
533                                     load(newContext, client);\r
534                                     return;\r
535                                 } catch (DatabaseException e) {\r
536                                     Logger.defaultLogError(e);\r
537                                 }\r
538                             }\r
539                                         }\r
540                                     }\r
541                                     \r
542                                         if(ClientModel.SHEETS.equals(location)) {\r
543                                                 if(ClientModel.SHEETS_CURRENT.equals(property)) {\r
544                                                         \r
545                                                         if(value instanceof String) {\r
546 \r
547                                                                 try {\r
548 \r
549                                                                         Variable newInput = processor.syncRequest(new UnaryRead<String, Variable>((String)value) {\r
550 \r
551                                                                                 @Override\r
552                                                                                 public Variable perform(ReadGraph graph) throws DatabaseException {\r
553                                                                                         return run.getParent(graph).getChild(graph, parameter);\r
554                                                                                 }\r
555 \r
556                                                                         });\r
557 \r
558                                                                         load(newInput, client);\r
559                                                                         return;\r
560                                                                 } catch (DatabaseException e) {\r
561                                                                         Logger.defaultLogError(e);\r
562                                                                 }\r
563                                                         }\r
564                                                 }\r
565                                         }\r
566                                         \r
567                    if(ClientModel.STATES.equals(location)) {\r
568                         if(ClientModel.STATES_CURRENT.equals(property)) {\r
569                             if(value instanceof String) {\r
570                                 final String parameter = (String) value;\r
571                                 try {\r
572                                     \r
573                                     String uri = processor.syncRequest(new WriteResultRequest<String>() {\r
574                 \r
575                                         @Override\r
576                                         public String perform(WriteGraph graph) throws DatabaseException {\r
577                                             \r
578                                             Map<String, Resource> states = graph.syncRequest(new SpreadsheetStates(run));\r
579                                             \r
580                                             Resource state = null;\r
581                                             for (Map.Entry<String, Resource> entry : states.entrySet()) {\r
582                                                 if (entry.getKey().equals(parameter)) {\r
583                                                     state = entry.getValue();\r
584                                                     break;\r
585                                                 }\r
586                                             }\r
587                                             if (state != null) {\r
588                                                 Variable context = Variables.getContext(graph, run);\r
589                                                 Resource bookResource = context.getRepresents(graph);\r
590                                                 SpreadsheetGraphUtils.setDefaultInitialConditionForBook(graph, bookResource, state);\r
591                                                 \r
592                                                 String contextURI = context.getURI(graph);\r
593                                                 \r
594                                                 String sessionName = context.getParent(graph).getURI(graph);\r
595                                                 SpreadsheetSessionManager.getInstance().removeRealm(sessionName);\r
596                                                 SpreadsheetSessionManager.getInstance().getOrCreateRealm(graph, sessionName);\r
597                                             }\r
598                                             \r
599                                             return run.getURI(graph);\r
600                                         }\r
601                                     });\r
602                                     Variable newInput = processor.syncRequest(new PossibleURIVariable(uri));\r
603                                     load(newInput, client);\r
604 //                                    fullSynchronize();\r
605                                     return;\r
606                                 } catch (DatabaseException e) {\r
607                                     Logger.defaultLogError(e);\r
608                                 }\r
609                             }\r
610                         }\r
611                     }\r
612 \r
613                                         if(ClientModel.SOURCES.equals(location)) {\r
614                                                 if(ClientModel.SOURCES_CURRENT.equals(property)) {\r
615                                                         try {\r
616                                                                 Resource res = WorkbenchSelectionUtils.getPossibleResource(value);\r
617                                                                 if(res != null) {\r
618                                                                         \r
619                                                                         Variable newInput = processor.syncRequest(new ResourceRead<Variable>(res) {\r
620 \r
621                                                                                 @Override\r
622                                                                                 public Variable perform(ReadGraph graph) throws DatabaseException {\r
623                                                                                         Variable base = ProxyVariables.proxyVariableBase(graph, run);\r
624                                                                                         Variable in = Variables.getVariable(graph, resource);\r
625                                                                                         currentSource = in.getURI(graph);\r
626                                                                                         return ProxyVariables.makeProxyVariable(graph, base, in);\r
627                                                                                 }\r
628                                                 \r
629                                                                         });\r
630                                                                         \r
631                                                                         load(newInput, client);\r
632                                                                         \r
633                                                                         return;\r
634 \r
635                                                                 } else if(value instanceof String) {\r
636                                                                         \r
637                                                                         Variable newInput = processor.syncRequest(new UnaryRead<String, Variable>((String)value) {\r
638 \r
639                                                                                 @Override\r
640                                                                                 public Variable perform(ReadGraph graph) throws DatabaseException {\r
641                                                                                         \r
642                                                                                         Variable base = ProxyVariables.proxyVariableBase(graph, run);\r
643                                                                                         Map<String,Variable> sources = graph.syncRequest(new Sources(base));\r
644 \r
645                                                                                         Variable found = sources.get(parameter);\r
646                                                                                         if(found == null) return null;\r
647                                                                                         \r
648                                                                                         currentSource = parameter;\r
649 \r
650                                                                                         return ProxyVariables.makeProxyVariable(graph, base, found);\r
651                                                                                         \r
652                                                                                 }\r
653                                                 \r
654                                                                         });\r
655                                                                         \r
656                                                                         load(newInput, client);\r
657                                                                         return;\r
658                                                                 }\r
659                                                                 \r
660                                                         } catch (DatabaseException e) {\r
661                                                                 Logger.defaultLogError(e);\r
662                                                         }\r
663                                                 }\r
664                                                 return;\r
665                                         }\r
666                                         boolean needsCommit = false;\r
667                                         if (transaction == null) {\r
668                                             OperationMode mode = client.getPropertyAt(ClientModel.MODE, ClientModel.MODE_CURRENT);\r
669                                             transaction = startTransaction(mode);\r
670 //                                          if (mode.equals(OperationMode.OPERATION))\r
671                                         transaction.setContext(run);\r
672                                             needsCommit = true;\r
673                                         }\r
674                                         final Transaction<Write> finalTransaction = transaction;\r
675                                         cellEditor.edit(transaction, location, property, value, binding, new Consumer<Object>() {\r
676                         \r
677                         @Override\r
678                         public void accept(Object param) {\r
679                             if (finalTransaction.needSynchronization() != null)\r
680                                 synchronize(finalTransaction.needSynchronization());\r
681                         }\r
682                                         });\r
683                                         if (needsCommit)\r
684                                             transaction.commit();\r
685                                 }\r
686 \r
687                                 @Override\r
688                                 public void edit(Transaction<Write> transaction, String location, Variant variant, Consumer<?> callback) {\r
689                                     boolean needsCommit = false;\r
690                                     if (transaction == null) {\r
691                                         OperationMode mode = client.getPropertyAt(ClientModel.MODE, ClientModel.MODE_CURRENT);\r
692                                         transaction = startTransaction(mode);\r
693 //                                      if (mode.equals(OperationMode.OPERATION))\r
694                                     transaction.setContext(run);\r
695                                         needsCommit = true;\r
696                                     }\r
697                                     final Transaction<Write> finalTransaction = transaction;\r
698                                         cellEditor.edit(transaction, location, variant, new Consumer<Object>() {\r
699                         \r
700                         @Override\r
701                         public void accept(Object param) {\r
702                             if (finalTransaction.needSynchronization() != null)\r
703                                 synchronize(finalTransaction.needSynchronization());\r
704                         }\r
705                     });\r
706                                         if (needsCommit)\r
707                                             transaction.commit();\r
708                                 }\r
709 \r
710                                 @Override\r
711                                 public void copy(final Transaction<Write> transaction, String location, MutableVariant variant, Consumer<?> callback) {\r
712                                         cellEditor.edit(transaction, location, variant, new Consumer<Object>() {\r
713                         \r
714                         @Override\r
715                         public void accept(Object param) {\r
716                             if (transaction.needSynchronization() != null)\r
717                                 synchronize(transaction.needSynchronization());\r
718                         }\r
719                                         });\r
720                                 }\r
721 \r
722                                 @Override\r
723                                 public Transaction<Write> startTransaction(OperationMode mode) {\r
724                                         return cellEditor.startTransaction(mode);\r
725                                 }\r
726                                 \r
727                 };\r
728                 \r
729         } else if (SheetCommands.class == clazz ) {\r
730             \r
731             return (T) new SheetCommands() {\r
732                 \r
733                 @Override\r
734                 public void saveState() {\r
735                     \r
736                     Simantics.getSession().asyncRequest(new ReadRequest() {\r
737                         \r
738                         @Override\r
739                         public void run(ReadGraph graph) throws DatabaseException {\r
740                             IEclipseContext context = PlatformUI.getWorkbench().getService(IEclipseContext.class);\r
741                             \r
742                             Resource uiContextResource = run.getRepresents(graph);\r
743                             Resource bookResource = Variables.getContext(graph, run).getRepresents(graph);\r
744                             Layer0 L0 = Layer0.getInstance(graph);\r
745                             String uiContextName = graph.getRelatedValue2(uiContextResource, L0.HasName, Bindings.STRING);\r
746                             String bookName = graph.getRelatedValue2(bookResource, L0.HasName, Bindings.STRING);\r
747                             \r
748                             UISynchronize synchronizer = context.get(UISynchronize.class);\r
749                             synchronizer.asyncExec(() -> {\r
750                                 Pair<String, Resource>[] pairs = new Pair[] {Pair.make(uiContextName, uiContextResource), Pair.make(bookName, bookResource) };\r
751                                 SaveSpreadsheetStateDialog dialog = new SaveSpreadsheetStateDialog(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor().getSite(), "Save Spreadsheet state", pairs);\r
752                                 if (dialog.open() == Dialog.OK) {\r
753                                     Object[] result = dialog.getSelection();\r
754                                     if (result != null) {\r
755                                         Pair<Resource, String> p = (Pair<Resource, String>) result[0];\r
756                                         Simantics.getSession().asyncRequest(new WriteRequest() {\r
757                                             \r
758                                             @Override\r
759                                             public void perform(WriteGraph graph) throws DatabaseException {\r
760                                                 \r
761                                                 Variable parent = run.getParent(graph);\r
762                                                 Variable base = ProxyVariables.proxyVariableBase(graph, parent);\r
763                                                 SpreadsheetGraphUtils.saveInitialCondition(graph, parent, p.first, p.second);\r
764                                             }\r
765                                         });\r
766                                     }\r
767                                 } else {\r
768                                     return;\r
769                                 }\r
770                             });\r
771                         }\r
772                     });\r
773                 }\r
774             };\r
775         }\r
776 \r
777         return null;\r
778 \r
779     }\r
780 \r
781     @Override\r
782     public void exception(Throwable t) {\r
783         t.printStackTrace();\r
784     }\r
785 \r
786     @Override\r
787     public boolean isDisposed() {\r
788         return disposed;\r
789     }\r
790 \r
791     @Override\r
792     public void exception(AsyncReadGraph graph, Throwable t) {\r
793         Logger.defaultLogError("Failed to read properties.", t);\r
794     }\r
795 \r
796     @Override\r
797     public void exception(ReadGraph graph, Throwable t) {\r
798         Logger.defaultLogError("Failed to read properties.", t);\r
799     }\r
800 \r
801     public void dispose() {\r
802         for (PropertyListener listener : listenerCache.values())\r
803             listener.dispose();\r
804         \r
805         listenerCache.clear();\r
806         SessionEventSupport support = processor.getService(SessionEventSupport.class);\r
807         support.removeListener(listener);\r
808         disposed = true;\r
809     }\r
810     \r
811     private void synchronize(List<Object> list) {\r
812         Simantics.getSession().asyncRequest(new FullSynchronizeBook(run, list));\r
813     }\r
814     \r
815     public static class FullSynchronizeBook extends ReadRequest {\r
816 \r
817         private final Variable run;\r
818         private final List<Object> location;\r
819         \r
820         public FullSynchronizeBook(Variable run, List<Object> cellLocation) {\r
821             this.run = run;\r
822             this.location = cellLocation;\r
823         }\r
824         \r
825         @Override\r
826         public void run(ReadGraph graph) throws DatabaseException {\r
827             String uri = run.getURI(graph);\r
828             String parentUri = run.getParent(graph).getURI(graph);\r
829             System.err.println("Full sync for book " + parentUri);\r
830             \r
831             Resource sheetResource = run.getRepresents(graph);\r
832             Variable sheetVariable = Variables.getVariable(graph, sheetResource);\r
833             \r
834             TObjectIntHashMap<Variable> changes = null;\r
835             if (location != null) {\r
836                 changes = new TObjectIntHashMap<>(location.size());\r
837                 for (Object loc : location) {\r
838                     Variable var = (Variable) loc;\r
839                     changes.put(var, 1);\r
840                 };\r
841             }\r
842             SpreadsheetGraphUtils.partialSynchronization(graph, run.getParent(graph), changes);\r
843         }\r
844         \r
845     }\r
846     \r
847     private SpreadsheetBook getBook(ReadGraph graph) throws DatabaseException {\r
848         String sessionName = run.getParent(graph).getParent(graph).getURI(graph);\r
849         StandardRealm<SheetNode, SpreadsheetBook> realm = SpreadsheetSessionManager.getInstance().getOrCreateRealm(graph, sessionName);\r
850         SpreadsheetBook book = realm.getEngine();\r
851         return book;\r
852     }\r
853     \r
854 }\r