--- /dev/null
+/*******************************************************************************\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