]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.spreadsheet.graph/src/org/simantics/spreadsheet/graph/GraphUI.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.spreadsheet.graph / src / org / simantics / spreadsheet / graph / GraphUI.java
diff --git a/bundles/org.simantics.spreadsheet.graph/src/org/simantics/spreadsheet/graph/GraphUI.java b/bundles/org.simantics.spreadsheet.graph/src/org/simantics/spreadsheet/graph/GraphUI.java
new file mode 100644 (file)
index 0000000..80e9656
--- /dev/null
@@ -0,0 +1,854 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.spreadsheet.graph;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.Collections;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.function.Consumer;\r
+\r
+import org.eclipse.e4.core.contexts.IEclipseContext;\r
+import org.eclipse.e4.ui.di.UISynchronize;\r
+import org.eclipse.jface.dialogs.Dialog;\r
+import org.eclipse.ui.PlatformUI;\r
+import org.simantics.Simantics;\r
+import org.simantics.databoard.Bindings;\r
+import org.simantics.databoard.binding.Binding;\r
+import org.simantics.databoard.binding.mutable.MutableVariant;\r
+import org.simantics.databoard.binding.mutable.Variant;\r
+import org.simantics.db.AsyncReadGraph;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.RequestProcessor;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.common.procedure.adapter.AsyncListenerSupport;\r
+import org.simantics.db.common.procedure.adapter.ListenerSupport;\r
+import org.simantics.db.common.procedure.adapter.SyncListenerSupport;\r
+import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener;\r
+import org.simantics.db.common.procedure.single.SingleSetSyncListenerDelegate;\r
+import org.simantics.db.common.request.ReadRequest;\r
+import org.simantics.db.common.request.ResourceRead;\r
+import org.simantics.db.common.request.UnaryRead;\r
+import org.simantics.db.common.request.UniqueRead;\r
+import org.simantics.db.common.request.WriteRequest;\r
+import org.simantics.db.common.request.WriteResultRequest;\r
+import org.simantics.db.common.session.SessionEventListenerAdapter;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.layer0.StandardRealm;\r
+import org.simantics.db.layer0.request.PossibleURIVariable;\r
+import org.simantics.db.layer0.request.VariableName;\r
+import org.simantics.db.layer0.request.VariableRead;\r
+import org.simantics.db.layer0.variable.ProxyVariables;\r
+import org.simantics.db.layer0.variable.Variable;\r
+import org.simantics.db.layer0.variable.Variables;\r
+import org.simantics.db.procedure.SyncListener;\r
+import org.simantics.db.request.Write;\r
+import org.simantics.db.service.SessionEventSupport;\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.spreadsheet.Adaptable;\r
+import org.simantics.spreadsheet.CellEditor;\r
+import org.simantics.spreadsheet.ClientModel;\r
+import org.simantics.spreadsheet.ClientModel.OperationMode;\r
+import org.simantics.spreadsheet.SheetCommands;\r
+import org.simantics.spreadsheet.common.logging.Logger;\r
+import org.simantics.spreadsheet.event.model.RemoveCellHandler;\r
+import org.simantics.spreadsheet.resource.SpreadsheetResource;\r
+import org.simantics.ui.selection.WorkbenchSelectionUtils;\r
+import org.simantics.utils.datastructures.Pair;\r
+import org.simantics.utils.strings.AlphanumComparator;\r
+import org.simantics.utils.threads.logger.ITask;\r
+import org.simantics.utils.threads.logger.ThreadLogger;\r
+\r
+import gnu.trove.map.hash.THashMap;\r
+import gnu.trove.map.hash.TObjectIntHashMap;\r
+\r
+class FilteredVariableProperties extends UnaryRead<Variable, Collection<Pair<String,Variable>>> {\r
+\r
+       final static String CLASSIFICATION = SpreadsheetResource.URIs.Attribute;\r
+       \r
+    public FilteredVariableProperties(Variable variable) {\r
+        super(variable);\r
+    }\r
+\r
+    @Override\r
+    public Collection<Pair<String,Variable>> perform(ReadGraph graph) throws DatabaseException {\r
+       ArrayList<Pair<String,Variable>> result = new ArrayList<Pair<String,Variable>>();\r
+       for(Variable var : parameter.getProperties(graph, CLASSIFICATION)) {\r
+               String name = var.getName(graph);\r
+               String uri = var.getURI(graph);\r
+               result.add(Pair.make(name, var));\r
+               Variable expression = var.getPossibleProperty(graph, "expression");\r
+               if(expression != null)\r
+                   result.add(Pair.make(name + "#expression", expression));\r
+               Variable editable = var.getPossibleProperty(graph, "editable");\r
+            if(editable != null)\r
+                result.add(Pair.make(name + "#editable", editable));\r
+       }\r
+       return result;\r
+    }\r
+\r
+}\r
+\r
+public class GraphUI implements Adaptable, ListenerSupport, AsyncListenerSupport, SyncListenerSupport {\r
+\r
+       final public static boolean DEBUG = false;\r
+       \r
+    final private RequestProcessor processor;\r
+    \r
+    private CellEditor<Write> cellEditor;\r
+    \r
+    private Variable run;\r
+    private ClientModel client;\r
+\r
+    private Map<String, PropertyListener> listenerCache = new THashMap<>();\r
+\r
+    public GraphUI(RequestProcessor processor) {\r
+        this.processor = processor;\r
+    }\r
+    \r
+    public void addCell(ReadGraph graph, Pair<String, Variable> child, final ClientModel client) throws DatabaseException {\r
+\r
+               if(DEBUG) System.out.println("GraphUI adds cell  " + child.second.getURI(graph));\r
+\r
+       final String childName = child.second.getName(graph);\r
+       Boolean immutable = child.second.getPossiblePropertyValue(graph, "immutable", Bindings.BOOLEAN);\r
+       if(immutable != null && immutable) {\r
+               Collection<Variable> properties = child.second.getProperties(graph, FilteredVariableProperties.CLASSIFICATION);\r
+               addProperties(graph, properties, client, childName);\r
+       } else {\r
+           PropertyListener listener = listenerCache.get(child.first); \r
+           if (listener == null) {\r
+                   listener = propertyListener(client, childName);\r
+                   listenerCache.put(child.first, listener);\r
+           }\r
+               graph.asyncRequest(new FilteredVariableProperties(child.second), listener);\r
+       }\r
+\r
+    }\r
+\r
+    public void removeCell(ReadGraph graph, Pair<String, Variable> child, final ClientModel client) throws DatabaseException {\r
+\r
+               if(DEBUG) System.out.println("GraphUI removed cell " + child.first);\r
+               \r
+               client.clear(child.first);\r
+               PropertyListener listener = listenerCache.remove(child.first);\r
+               if (listener != null)\r
+                   listener.dispose();\r
+\r
+    }\r
+\r
+    public void loadCells(ReadGraph graph, Variable container, boolean immutable, final ClientModel client) throws DatabaseException {\r
+       \r
+               if(DEBUG) System.out.println("GraphUI loads cells from " + container.getURI(graph));\r
+               \r
+               if(immutable) {\r
+                       for(Pair<String, Variable> cell : graph.syncRequest(new Cells(container), TransientCacheAsyncListener.<Collection<Pair<String, Variable>>>instance())) { \r
+                               addCell(graph, cell, client);\r
+                       }\r
+               } else {\r
+               graph.syncRequest(new Cells(container), new SingleSetSyncListenerDelegate<Pair<String, Variable>>(GraphUI.this) {\r
+       \r
+                   @Override\r
+                   public void add(ReadGraph graph, final Pair<String, Variable> child) throws DatabaseException {\r
+                       addCell(graph, child, client);\r
+                   }\r
+       \r
+                   @Override\r
+                   public void remove(ReadGraph graph, final Pair<String, Variable> child) throws DatabaseException {\r
+                       removeCell(graph, child, client);\r
+                   }\r
+               });\r
+               }\r
+       \r
+    }\r
+    \r
+    private SessionEventListenerAdapter listener;\r
+    \r
+    private String currentSource;\r
+\r
+    private boolean disposed;\r
+    \r
+    public Resource load(final Variable variable, final ClientModel client) throws DatabaseException {\r
+       \r
+//        for (PropertyListener listener : listenerCache.values())\r
+//            listener.dispose();\r
+//        \r
+//        listenerCache.clear();\r
+        \r
+        \r
+        \r
+       assert(variable != null);\r
+       \r
+       this.run = variable;\r
+       this.client = client;\r
+       \r
+       SessionEventSupport support = processor.getService(SessionEventSupport.class);\r
+       \r
+       for (PropertyListener listener : listenerCache.values()) {\r
+           listener.dispose();\r
+       }\r
+       listenerCache.clear();\r
+       \r
+       if(listener != null)\r
+               support.removeListener(listener);\r
+       \r
+       listener = new SessionEventListenerAdapter() {\r
+               \r
+               @Override\r
+               public void writeTransactionFinished() {\r
+                       client.flush();\r
+               }\r
+               \r
+       }; \r
+       \r
+       support.addListener(listener);\r
+\r
+        this.cellEditor = processor.sync(new VariableRead<CellEditor>(variable) {\r
+\r
+                       @Override\r
+                       public CellEditor perform(ReadGraph graph) throws DatabaseException {\r
+                               SpreadsheetResource SHEET = SpreadsheetResource.getInstance(graph);\r
+                               return variable.getPropertyValue(graph, SHEET.cellEditor);\r
+                       }\r
+               \r
+        });\r
+       \r
+               final ITask task = ThreadLogger.getInstance().begin("GraphUI.init");\r
+\r
+               client.clearAll();\r
+\r
+               Map<String,Variable> sources = processor.syncRequest(new Sources(variable));\r
+\r
+               List<String> sheetList = processor.syncRequest(new Sheets(variable));\r
+               String currentSheet = processor.syncRequest(new VariableName(variable));\r
+               \r
+               Map<String, Resource> stateList = processor.syncRequest(new SpreadsheetStates(variable));\r
+\r
+               if(currentSource == null) currentSource = "Sheet";\r
+               \r
+               ArrayList<String> sourceList = new ArrayList<String>(sources.keySet());\r
+               \r
+               Collections.sort(sourceList, AlphanumComparator.CASE_INSENSITIVE_COMPARATOR);\r
+               if(!sourceList.contains(currentSource)) sourceList.add(currentSource);\r
+               \r
+               client.setProperty(ClientModel.SOURCES, ClientModel.SOURCES_AVAILABLE, sourceList.toArray(new String[sourceList.size()]));\r
+               client.setProperty(ClientModel.SOURCES, ClientModel.SOURCES_CURRENT, currentSource);\r
+\r
+               client.setProperty(ClientModel.SHEETS, ClientModel.SHEETS_AVAILABLE, sheetList.toArray(new String[sheetList.size()]));\r
+               client.setProperty(ClientModel.SHEETS, ClientModel.SHEETS_CURRENT, currentSheet);\r
+               \r
+               client.setProperty(ClientModel.STATES, ClientModel.STATES_AVAILABLE, stateList.keySet().toArray(new String[stateList.size()]));\r
+               \r
+               client.setProperty(ClientModel.CONTEXT, ClientModel.CONTEXT_CURRENT, variable);\r
+               \r
+               client.setProperty(ClientModel.MODE, ClientModel.MODE_CURRENT, OperationMode.OPERATION);\r
+               \r
+               String currentState = processor.syncRequest(new UniqueRead<String>() {\r
+\r
+            @Override\r
+            public String perform(ReadGraph graph) throws DatabaseException {\r
+                Resource book = variable.getParent(graph).getRepresents(graph);\r
+                Resource ic = graph.getPossibleObject(book, SpreadsheetResource.getInstance(graph).Book_HasDefaultInitialCondition);\r
+                if (ic == null)\r
+                       return "";\r
+                return graph.getRelatedValue2(ic, Layer0.getInstance(graph).HasName, Bindings.STRING);\r
+            }\r
+        });\r
+               \r
+               client.setProperty(ClientModel.STATES, ClientModel.STATES_CURRENT, currentState);\r
+\r
+        processor.syncRequest(new ReadRequest() {\r
+\r
+            @Override\r
+            public void run(ReadGraph graph) throws DatabaseException {\r
+\r
+               loadCells(graph, variable, false, client);\r
+\r
+               graph.syncRequest(new Ranges(variable), new SingleSetSyncListenerDelegate<Variable>(GraphUI.this) {\r
+\r
+                    @Override\r
+                    public void add(ReadGraph graph, final Variable range) throws DatabaseException {\r
+\r
+                               if(DEBUG) System.out.println("GraphUI adds range  " + range.getURI(graph));\r
+\r
+                       Boolean immutable = range.getPossiblePropertyValue(graph, "immutable", Bindings.BOOLEAN);\r
+                       loadCells(graph, range, immutable != null && immutable, client);\r
+\r
+                    }\r
+\r
+                    @Override\r
+                    public void remove(ReadGraph graph, final Variable range) throws DatabaseException {\r
+\r
+                    }\r
+                    \r
+               });\r
+               \r
+               \r
+               graph.syncRequest(new SheetLines(variable), new SingleSetSyncListenerDelegate<Variable>(GraphUI.this) {\r
+\r
+                    @Override\r
+                    public void add(ReadGraph graph, final Variable range) throws DatabaseException {\r
+\r
+                               if(DEBUG) System.out.println("GraphUI adds line  " + range.getURI(graph));\r
+\r
+                       Boolean immutable = range.getPossiblePropertyValue(graph, "immutable", Bindings.BOOLEAN);\r
+                       loadCells(graph, range, immutable != null && immutable, client);\r
+\r
+                    }\r
+\r
+                    @Override\r
+                    public void remove(ReadGraph graph, final Variable range) throws DatabaseException {\r
+\r
+                    }\r
+               });\r
+\r
+            }\r
+\r
+//            @Override\r
+//            public void remove(ReadGraph graph, Variable child) throws DatabaseException {\r
+//\r
+//             String location = locations.get(cellResource);\r
+//             assert(location != null);\r
+//\r
+//             client.setProperty(location, "Label", null);\r
+//             client.setProperty(location, "Expression", null);\r
+//\r
+//            }\r
+\r
+        });\r
+        \r
+\r
+               task.finish();\r
+               client.flush();\r
+               \r
+               return null;\r
+\r
+    }\r
+    \r
+    private static class PropertyListener extends SingleSetSyncListenerDelegate<Pair<String,Variable>> {\r
+\r
+        private ClientModel client;\r
+        private String childName;\r
+        private boolean listenerDisposed;\r
+\r
+        public PropertyListener(AsyncListenerSupport support, ClientModel client, String childName) {\r
+            super(support);\r
+            this.client = client;\r
+            this.childName = childName;\r
+        }\r
+        \r
+        @Override\r
+        public void add(ReadGraph graph, final Pair<String,Variable> property) throws DatabaseException {\r
+\r
+            if(DEBUG)\r
+                System.out.println("GraphUI adds property  " + property.second.getURI(graph));\r
+\r
+            graph.asyncRequest(new CellValue(property.second), new SyncListener<Object>() {\r
+\r
+                @Override\r
+                public void execute(ReadGraph graph, final Object value) throws DatabaseException {\r
+\r
+                    String propertyName = property.first;\r
+\r
+                    if(DEBUG)\r
+                        System.out.println("GraphUI detected content change(1) at  " + childName + " - " + propertyName + " -> " + value);\r
+                    client.setProperty(childName, propertyName, value);\r
+                    \r
+                }\r
+\r
+                @Override\r
+                public void exception(ReadGraph graph, Throwable throwable) throws DatabaseException {\r
+                    \r
+                    Logger.defaultLogError(throwable);\r
+                    \r
+                    String propertyName = property.first;\r
+                    if("content".equals(propertyName)) {\r
+                        if(throwable == null) throwable = new Exception();\r
+                        String message = throwable.getMessage();\r
+                        if(message == null) message = throwable.toString();\r
+                        client.setProperty(childName, propertyName, Variant.ofInstance(message));\r
+                    } else {\r
+                        client.setProperty(childName, propertyName, null);\r
+                    }\r
+                    \r
+                }\r
+\r
+                @Override\r
+                public boolean isDisposed() {\r
+                    return listenerDisposed;\r
+                }\r
+\r
+            });\r
+        }\r
+\r
+        public void dispose() {\r
+            listenerDisposed = true;\r
+        }\r
+        \r
+        @Override\r
+        public String toString() {\r
+            return super.toString() + ":" + childName;\r
+        }\r
+        \r
+    }\r
+    \r
+    private PropertyListener propertyListener(final ClientModel client, final String childName) {\r
+       return new PropertyListener(this, client, childName);\r
+    }\r
+    \r
+    private void addProperties(ReadGraph graph, final Collection<Variable> properties, final ClientModel client, final String childName) throws DatabaseException {\r
+\r
+       for(Variable property : properties) {\r
+               \r
+               if(DEBUG) System.out.println("GraphUI adds immutable property  " + property.getURI(graph));\r
+\r
+               final String propertyName = property.getName(graph);\r
+               \r
+               Object value = property.getValue(graph);\r
+\r
+               if(DEBUG) System.out.println("GraphUI detected change at  " + childName + " - " + propertyName + " -> " + value);\r
+               client.setProperty(childName, propertyName, value);\r
+               \r
+               String expression = property.getPossiblePropertyValue(graph, "expression", Bindings.STRING);\r
+               if(expression != null) {\r
+                       if(DEBUG) System.out.println("GraphUI detected change at  " + childName + " - " + (propertyName + "#expression") + " -> " + value);\r
+                       client.setProperty(childName, propertyName + "#expression", expression);\r
+               }\r
+               \r
+            Boolean editable = property.getPossiblePropertyValue(graph, "editable", Bindings.STRING);\r
+            if(editable != null) {\r
+                if(DEBUG) System.out.println("GraphUI detected change at  " + childName + " - " + (propertyName + "#editable") + " -> " + value);\r
+                client.setProperty(childName, propertyName + "#editable", editable);\r
+            }\r
+       \r
+       }\r
+\r
+    }\r
+    \r
+    @SuppressWarnings("unchecked")\r
+    @Override\r
+    public <T> T getAdapter(Class<T> clazz) {\r
+\r
+       if(Variable.class == clazz) {\r
+\r
+               return (T)run;\r
+               \r
+       } else if(RemoveCellHandler.class == clazz) {\r
+               \r
+            return (T) new RemoveCellHandler() {\r
+\r
+                               @Override\r
+                               public void handle(final String location) {\r
+                                       \r
+                               processor.asyncRequest(new ReadRequest() {\r
+\r
+                                   @Override\r
+                                   public void run(ReadGraph graph) throws DatabaseException {\r
+                                       \r
+                                                       Variable cellVariable = run.getPossibleChild(graph, location);\r
+                                                       if(cellVariable != null) {\r
+                                                               final Resource config = cellVariable.getPossiblePropertyValue(graph, "Represents");\r
+                                                               if(config != null) {\r
+                                                                       \r
+                                                                       graph.asyncRequest(new WriteRequest() {\r
+\r
+                                                                               @Override\r
+                                                                               public void perform(WriteGraph graph) throws DatabaseException {\r
+                                                                                       \r
+                                                                                       Layer0 l0 = Layer0.getInstance(graph);\r
+//                                                                                     SpreadsheetResource sr = SpreadsheetResource.getInstance(graph);\r
+                                                                                       graph.deny(config, l0.PartOf);\r
+//                                                                                     graph.deny(config, sr.RowOf);\r
+//                                                                                     graph.deny(config, sr.ColumnOf);\r
+                                                                                       \r
+                                                                               }\r
+                                                                               \r
+                                                                       });\r
+                                                                       \r
+                                                               }\r
+                                                       }\r
+                                                       \r
+                                   }\r
+                                   \r
+                               });\r
+                                       \r
+                               }\r
+               \r
+            };\r
+\r
+       } else if(CellEditor.class == clazz) {\r
+       \r
+               return (T)new CellEditor<Write>() {\r
+\r
+                               @Override\r
+                               public <T> void edit(Transaction<Write> transaction, String location, String property, T value, Binding binding, Consumer<?> callback) {\r
+                                       \r
+                                   if (ClientModel.ITERATION_ENABLED.equals(location)) {\r
+                                       \r
+                                   }\r
+                                   \r
+                                   if (ClientModel.MODE.equals(location)) {\r
+                                       if (ClientModel.MODE_CURRENT.equals(property)) {\r
+                                           client.setProperty(location, property, value);\r
+                                           client.flush();\r
+                                           return;\r
+                                       }\r
+                                   }\r
+                                   \r
+                                   if (ClientModel.CONTEXT.equals(location)) {\r
+                                       if(ClientModel.CONTEXT_CURRENT.equals(property)) {\r
+                            if(value instanceof String) {\r
+                                try {\r
+                                    Variable newContext = processor.syncRequest(new UnaryRead<String, Variable>((String)value) {\r
+\r
+                                        @Override\r
+                                        public Variable perform(ReadGraph graph) throws DatabaseException {\r
+                                      \r
+                                            String sheetName = run.getName(graph);\r
+                                            \r
+                                            Variable book = Variables.getContext(graph, run);\r
+                                            Resource bookResource = book.getRepresents(graph);\r
+                                            \r
+                                            Variable input = Variables.getVariable(graph, parameter);\r
+                                            Variable proxy = ProxyVariables.makeProxyVariable(graph, Variables.getVariable(graph, bookResource), input);\r
+                                            \r
+                                            return proxy.getChild(graph, sheetName);\r
+                                            \r
+//                                            return variable.getParent(graph).getChild(graph, parameter);\r
+                                        }\r
+\r
+                                    });\r
+                                    \r
+                                    load(newContext, client);\r
+                                    return;\r
+                                } catch (DatabaseException e) {\r
+                                    Logger.defaultLogError(e);\r
+                                }\r
+                            }\r
+                                       }\r
+                                   }\r
+                                   \r
+                                       if(ClientModel.SHEETS.equals(location)) {\r
+                                               if(ClientModel.SHEETS_CURRENT.equals(property)) {\r
+                                                       \r
+                                                       if(value instanceof String) {\r
+\r
+                                                               try {\r
+\r
+                                                                       Variable newInput = processor.syncRequest(new UnaryRead<String, Variable>((String)value) {\r
+\r
+                                                                               @Override\r
+                                                                               public Variable perform(ReadGraph graph) throws DatabaseException {\r
+                                                                                       return run.getParent(graph).getChild(graph, parameter);\r
+                                                                               }\r
+\r
+                                                                       });\r
+\r
+                                                                       load(newInput, client);\r
+                                                                       return;\r
+                                                               } catch (DatabaseException e) {\r
+                                                                       Logger.defaultLogError(e);\r
+                                                               }\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                                       \r
+                   if(ClientModel.STATES.equals(location)) {\r
+                        if(ClientModel.STATES_CURRENT.equals(property)) {\r
+                            if(value instanceof String) {\r
+                                final String parameter = (String) value;\r
+                                try {\r
+                                    \r
+                                    String uri = processor.syncRequest(new WriteResultRequest<String>() {\r
+                \r
+                                        @Override\r
+                                        public String perform(WriteGraph graph) throws DatabaseException {\r
+                                            \r
+                                            Map<String, Resource> states = graph.syncRequest(new SpreadsheetStates(run));\r
+                                            \r
+                                            Resource state = null;\r
+                                            for (Map.Entry<String, Resource> entry : states.entrySet()) {\r
+                                                if (entry.getKey().equals(parameter)) {\r
+                                                    state = entry.getValue();\r
+                                                    break;\r
+                                                }\r
+                                            }\r
+                                            if (state != null) {\r
+                                                Variable context = Variables.getContext(graph, run);\r
+                                                Resource bookResource = context.getRepresents(graph);\r
+                                                SpreadsheetGraphUtils.setDefaultInitialConditionForBook(graph, bookResource, state);\r
+                                                \r
+                                                String contextURI = context.getURI(graph);\r
+                                                \r
+                                                String sessionName = context.getParent(graph).getURI(graph);\r
+                                                SpreadsheetSessionManager.getInstance().removeRealm(sessionName);\r
+                                                SpreadsheetSessionManager.getInstance().getOrCreateRealm(graph, sessionName);\r
+                                            }\r
+                                            \r
+                                            return run.getURI(graph);\r
+                                        }\r
+                                    });\r
+                                    Variable newInput = processor.syncRequest(new PossibleURIVariable(uri));\r
+                                    load(newInput, client);\r
+//                                    fullSynchronize();\r
+                                    return;\r
+                                } catch (DatabaseException e) {\r
+                                    Logger.defaultLogError(e);\r
+                                }\r
+                            }\r
+                        }\r
+                    }\r
+\r
+                                       if(ClientModel.SOURCES.equals(location)) {\r
+                                               if(ClientModel.SOURCES_CURRENT.equals(property)) {\r
+                                                       try {\r
+                                                               Resource res = WorkbenchSelectionUtils.getPossibleResource(value);\r
+                                                               if(res != null) {\r
+                                                                       \r
+                                                                       Variable newInput = processor.syncRequest(new ResourceRead<Variable>(res) {\r
+\r
+                                                                               @Override\r
+                                                                               public Variable perform(ReadGraph graph) throws DatabaseException {\r
+                                                                                       Variable base = ProxyVariables.proxyVariableBase(graph, run);\r
+                                                                                       Variable in = Variables.getVariable(graph, resource);\r
+                                                                                       currentSource = in.getURI(graph);\r
+                                                                                       return ProxyVariables.makeProxyVariable(graph, base, in);\r
+                                                                               }\r
+                                               \r
+                                                                       });\r
+                                                                       \r
+                                                                       load(newInput, client);\r
+                                                                       \r
+                                                                       return;\r
+\r
+                                                               } else if(value instanceof String) {\r
+                                                                       \r
+                                                                       Variable newInput = processor.syncRequest(new UnaryRead<String, Variable>((String)value) {\r
+\r
+                                                                               @Override\r
+                                                                               public Variable perform(ReadGraph graph) throws DatabaseException {\r
+                                                                                       \r
+                                                                                       Variable base = ProxyVariables.proxyVariableBase(graph, run);\r
+                                                                                       Map<String,Variable> sources = graph.syncRequest(new Sources(base));\r
+\r
+                                                                                       Variable found = sources.get(parameter);\r
+                                                                                       if(found == null) return null;\r
+                                                                                       \r
+                                                                                       currentSource = parameter;\r
+\r
+                                                                                       return ProxyVariables.makeProxyVariable(graph, base, found);\r
+                                                                                       \r
+                                                                               }\r
+                                               \r
+                                                                       });\r
+                                                                       \r
+                                                                       load(newInput, client);\r
+                                                                       return;\r
+                                                               }\r
+                                                               \r
+                                                       } catch (DatabaseException e) {\r
+                                                               Logger.defaultLogError(e);\r
+                                                       }\r
+                                               }\r
+                                               return;\r
+                                       }\r
+                                       boolean needsCommit = false;\r
+                                       if (transaction == null) {\r
+                                           OperationMode mode = client.getPropertyAt(ClientModel.MODE, ClientModel.MODE_CURRENT);\r
+                                           transaction = startTransaction(mode);\r
+//                                         if (mode.equals(OperationMode.OPERATION))\r
+                                       transaction.setContext(run);\r
+                                           needsCommit = true;\r
+                                       }\r
+                                       final Transaction<Write> finalTransaction = transaction;\r
+                                       cellEditor.edit(transaction, location, property, value, binding, new Consumer<Object>() {\r
+                        \r
+                        @Override\r
+                        public void accept(Object param) {\r
+                            if (finalTransaction.needSynchronization() != null)\r
+                                synchronize(finalTransaction.needSynchronization());\r
+                        }\r
+                                       });\r
+                                       if (needsCommit)\r
+                                           transaction.commit();\r
+                               }\r
+\r
+                               @Override\r
+                               public void edit(Transaction<Write> transaction, String location, Variant variant, Consumer<?> callback) {\r
+                                   boolean needsCommit = false;\r
+                                   if (transaction == null) {\r
+                                       OperationMode mode = client.getPropertyAt(ClientModel.MODE, ClientModel.MODE_CURRENT);\r
+                                       transaction = startTransaction(mode);\r
+//                                     if (mode.equals(OperationMode.OPERATION))\r
+                                   transaction.setContext(run);\r
+                                       needsCommit = true;\r
+                                   }\r
+                                   final Transaction<Write> finalTransaction = transaction;\r
+                                       cellEditor.edit(transaction, location, variant, new Consumer<Object>() {\r
+                        \r
+                        @Override\r
+                        public void accept(Object param) {\r
+                            if (finalTransaction.needSynchronization() != null)\r
+                                synchronize(finalTransaction.needSynchronization());\r
+                        }\r
+                    });\r
+                                       if (needsCommit)\r
+                                           transaction.commit();\r
+                               }\r
+\r
+                               @Override\r
+                               public void copy(final Transaction<Write> transaction, String location, MutableVariant variant, Consumer<?> callback) {\r
+                                       cellEditor.edit(transaction, location, variant, new Consumer<Object>() {\r
+                        \r
+                        @Override\r
+                        public void accept(Object param) {\r
+                            if (transaction.needSynchronization() != null)\r
+                                synchronize(transaction.needSynchronization());\r
+                        }\r
+                                       });\r
+                               }\r
+\r
+                               @Override\r
+                               public Transaction<Write> startTransaction(OperationMode mode) {\r
+                                       return cellEditor.startTransaction(mode);\r
+                               }\r
+                               \r
+               };\r
+               \r
+        } else if (SheetCommands.class == clazz ) {\r
+            \r
+            return (T) new SheetCommands() {\r
+                \r
+                @Override\r
+                public void saveState() {\r
+                    \r
+                    Simantics.getSession().asyncRequest(new ReadRequest() {\r
+                        \r
+                        @Override\r
+                        public void run(ReadGraph graph) throws DatabaseException {\r
+                            IEclipseContext context = PlatformUI.getWorkbench().getService(IEclipseContext.class);\r
+                            \r
+                            Resource uiContextResource = run.getRepresents(graph);\r
+                            Resource bookResource = Variables.getContext(graph, run).getRepresents(graph);\r
+                            Layer0 L0 = Layer0.getInstance(graph);\r
+                            String uiContextName = graph.getRelatedValue2(uiContextResource, L0.HasName, Bindings.STRING);\r
+                            String bookName = graph.getRelatedValue2(bookResource, L0.HasName, Bindings.STRING);\r
+                            \r
+                            UISynchronize synchronizer = context.get(UISynchronize.class);\r
+                            synchronizer.asyncExec(() -> {\r
+                                Pair<String, Resource>[] pairs = new Pair[] {Pair.make(uiContextName, uiContextResource), Pair.make(bookName, bookResource) };\r
+                                SaveSpreadsheetStateDialog dialog = new SaveSpreadsheetStateDialog(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor().getSite(), "Save Spreadsheet state", pairs);\r
+                                if (dialog.open() == Dialog.OK) {\r
+                                    Object[] result = dialog.getSelection();\r
+                                    if (result != null) {\r
+                                        Pair<Resource, String> p = (Pair<Resource, String>) result[0];\r
+                                        Simantics.getSession().asyncRequest(new WriteRequest() {\r
+                                            \r
+                                            @Override\r
+                                            public void perform(WriteGraph graph) throws DatabaseException {\r
+                                                \r
+                                                Variable parent = run.getParent(graph);\r
+                                                Variable base = ProxyVariables.proxyVariableBase(graph, parent);\r
+                                                SpreadsheetGraphUtils.saveInitialCondition(graph, parent, p.first, p.second);\r
+                                            }\r
+                                        });\r
+                                    }\r
+                                } else {\r
+                                    return;\r
+                                }\r
+                            });\r
+                        }\r
+                    });\r
+                }\r
+            };\r
+        }\r
+\r
+        return null;\r
+\r
+    }\r
+\r
+    @Override\r
+    public void exception(Throwable t) {\r
+        t.printStackTrace();\r
+    }\r
+\r
+    @Override\r
+    public boolean isDisposed() {\r
+        return disposed;\r
+    }\r
+\r
+    @Override\r
+    public void exception(AsyncReadGraph graph, Throwable t) {\r
+       Logger.defaultLogError("Failed to read properties.", t);\r
+    }\r
+\r
+    @Override\r
+    public void exception(ReadGraph graph, Throwable t) {\r
+       Logger.defaultLogError("Failed to read properties.", t);\r
+    }\r
+\r
+    public void dispose() {\r
+        for (PropertyListener listener : listenerCache.values())\r
+            listener.dispose();\r
+        \r
+        listenerCache.clear();\r
+        SessionEventSupport support = processor.getService(SessionEventSupport.class);\r
+        support.removeListener(listener);\r
+        disposed = true;\r
+    }\r
+    \r
+    private void synchronize(List<Object> list) {\r
+        Simantics.getSession().asyncRequest(new FullSynchronizeBook(run, list));\r
+    }\r
+    \r
+    public static class FullSynchronizeBook extends ReadRequest {\r
+\r
+        private final Variable run;\r
+        private final List<Object> location;\r
+        \r
+        public FullSynchronizeBook(Variable run, List<Object> cellLocation) {\r
+            this.run = run;\r
+            this.location = cellLocation;\r
+        }\r
+        \r
+        @Override\r
+        public void run(ReadGraph graph) throws DatabaseException {\r
+            String uri = run.getURI(graph);\r
+            String parentUri = run.getParent(graph).getURI(graph);\r
+            System.err.println("Full sync for book " + parentUri);\r
+            \r
+            Resource sheetResource = run.getRepresents(graph);\r
+            Variable sheetVariable = Variables.getVariable(graph, sheetResource);\r
+            \r
+            TObjectIntHashMap<Variable> changes = null;\r
+            if (location != null) {\r
+                changes = new TObjectIntHashMap<>(location.size());\r
+                for (Object loc : location) {\r
+                    Variable var = (Variable) loc;\r
+                    changes.put(var, 1);\r
+                };\r
+            }\r
+            SpreadsheetGraphUtils.partialSynchronization(graph, run.getParent(graph), changes);\r
+        }\r
+        \r
+    }\r
+    \r
+    private SpreadsheetBook getBook(ReadGraph graph) throws DatabaseException {\r
+        String sessionName = run.getParent(graph).getParent(graph).getURI(graph);\r
+        StandardRealm<SheetNode, SpreadsheetBook> realm = SpreadsheetSessionManager.getInstance().getOrCreateRealm(graph, sessionName);\r
+        SpreadsheetBook book = realm.getEngine();\r
+        return book;\r
+    }\r
+    \r
+}\r