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