*******************************************************************************/\r
package org.simantics.sysdyn.ui.properties;\r
\r
-import org.eclipse.jface.dialogs.IInputValidator;\r
import org.eclipse.jface.layout.GridDataFactory;\r
import org.eclipse.jface.layout.GridLayoutFactory;\r
import org.eclipse.swt.SWT;\r
import org.simantics.sysdyn.ui.properties.widgets.factories.DoublePropertyFactory;\r
import org.simantics.sysdyn.ui.properties.widgets.factories.DoublePropertyModifier;\r
import org.simantics.ui.utils.AdaptionUtils;\r
+import org.simantics.utils.ui.validators.DoubleValidator;\r
\r
+/**\r
+ * Information tab for additional information of variables. \r
+ * @author Teemu Lempinen\r
+ *\r
+ */\r
public class VariableInformationTab extends LabelPropertyTabContributor implements Widget {\r
Composite orientationComposite;\r
WidgetSupport support;\r
informationGroup.setText("Information");\r
GridDataFactory.fillDefaults().grab(false, true).applyTo(informationGroup);\r
GridLayoutFactory.fillDefaults().margins(3, 3).applyTo(informationGroup);\r
-\r
+ \r
+ // Textual format documentation\r
TrackedText information = new TrackedText(informationGroup, support, SWT.MULTI | SWT.BORDER);\r
information.setTextFactory(new StringPropertyFactory(Layer0.URIs.HasDescription));\r
information.addModifyListener(new StringPropertyModifier(context, Layer0.URIs.HasDescription));\r
GridDataFactory.fillDefaults().grab(true, true).applyTo(information.getWidget());\r
\r
+ // Orientation information for valves\r
orientationComposite = new Composite(composite, SWT.NONE);\r
GridDataFactory.fillDefaults().span(1, 2).applyTo(orientationComposite);\r
GridLayoutFactory.fillDefaults().margins(3,3).applyTo(orientationComposite);\r
\r
+ // Range of a variable (e.g. from 0 to 10). Does not affect simulation, but the infor can be used for example in charts\r
Group rangeGroup = new Group(composite, SWT.SHADOW_ETCHED_IN);\r
rangeGroup.setText("Range");\r
GridDataFactory.fillDefaults().applyTo(rangeGroup);\r
rangeStep.setInputValidator(new DoubleValidator());\r
GridDataFactory.fillDefaults().grab(true, false).applyTo(rangeStep.getWidget());\r
\r
-\r
-\r
- }\r
-\r
- private class DoubleValidator implements IInputValidator {\r
-\r
- @Override\r
- public String isValid(String newText) {\r
- for(int i = 0; i < newText.length(); i++){\r
- if(!Character.isDigit(newText.charAt(i))){\r
- if(newText.charAt(i) != '.') {\r
- return "Invalid character '" + newText.charAt(i) + "'";\r
- } else if(newText.indexOf('.') != newText.lastIndexOf('.')) {\r
- return "There can be only one '.'";\r
- }\r
- }\r
- }\r
- return null;\r
- }\r
}\r
\r
@Override\r
public void setInput(ISessionContext context, Object input) {\r
final Resource valve = AdaptionUtils.adaptToSingle(input, Resource.class);\r
+ // is the displayed variable a valve?\r
Boolean isValve = false;\r
try {\r
isValve = context.getSession().syncRequest(new Read<Boolean>() {\r
} catch (DatabaseException e) {\r
e.printStackTrace();\r
}\r
+ // if it is a valve, display the orientation information\r
if(isValve) {\r
ValveOrientationGroup vog = new ValveOrientationGroup(orientationComposite, context, support, SWT.NONE);\r
vog.setInput(context, input);\r
*******************************************************************************/\r
package org.simantics.sysdyn.ui.properties.widgets;\r
\r
-import java.util.List;\r
-\r
import org.simantics.db.ReadGraph;\r
import org.simantics.db.Resource;\r
-import org.simantics.db.common.utils.OrderedSetUtils;\r
import org.simantics.db.exception.DatabaseException;\r
import org.simantics.db.request.Read;\r
import org.simantics.sysdyn.SysdynResource;\r
import org.simantics.ui.SimanticsUI;\r
\r
+/**\r
+ * Expression type representations\r
+ * @author Teemu Lempinen\r
+ *\r
+ */\r
public class ExpressionTypes {\r
\r
public static enum ExpressionType {Auxiliary, Parameter, Constant, Lookup, WithLookup, Stock, Delay, Empty};\r
ExpressionType.Auxiliary, \r
ExpressionType.Parameter, \r
ExpressionType.Constant, \r
+ ExpressionType.Delay,\r
// ExpressionType.Lookup, \r
ExpressionType.WithLookup};\r
\r
ExpressionType.Auxiliary, \r
ExpressionType.Parameter, \r
ExpressionType.Constant, \r
+ ExpressionType.Delay,\r
ExpressionType.WithLookup};\r
\r
public static ExpressionType[] stockExpressions = new ExpressionType[] {\r
import org.simantics.ui.SimanticsUI;\r
import org.simantics.ui.utils.AdaptionUtils;\r
\r
+/**\r
+ * Widget for displaying an expression. Widget creates the IExpression for displaying\r
+ * properties for each expression type and adds validation, saving and other services\r
+ * to the active IExpression.\r
+ * \r
+ * @author Teemu Lempinen\r
+ *\r
+ */\r
public class ExpressionWidget implements Widget {\r
\r
private Resource expr;\r
private FocusListener focusListener;\r
private Table variableTable;\r
private VerifyKeyListener verifyKeyListener;\r
- private Timer updateChartTimer;\r
+ private Timer validationTimer;\r
private static int VALIDATION_DELAY_TIME = 500;\r
\r
+ /**\r
+ * Create a new expression widget\r
+ * @param parent\r
+ * @param support\r
+ * @param style\r
+ */\r
public ExpressionWidget(Composite parent, WidgetSupport support, int style) {\r
support.register(this);\r
this.parent = parent;\r
this.data = new HashMap<String, Object>();\r
\r
- updateChartTimer = new Timer(VALIDATION_DELAY_TIME, new ActionListener() {\r
+ /*\r
+ * Create a validation timer for expression fields. Validation timer\r
+ * validates the field as the modeler is typing an expression \r
+ */\r
+ validationTimer = new Timer(VALIDATION_DELAY_TIME, new ActionListener() {\r
\r
@Override\r
public void actionPerformed(ActionEvent e) {\r
});\r
}\r
});\r
- updateChartTimer.setRepeats(false);\r
+ validationTimer.setRepeats(false);\r
}\r
\r
@Override\r
public void setInput(ISessionContext context, Object input) { \r
+ // Update IExpression based on the newly selected expression\r
expr = AdaptionUtils.adaptToSingle(input, Resource.class);\r
ExpressionType et = ExpressionTypes.getExpressionType(expr);\r
displayExpression(et.toString(), true);\r
}\r
\r
+ /**\r
+ * Displays IExpression corresponding to expressionType.\r
+ * @param expressionType Expression type\r
+ * @param original Is the displayed expression for a newly selected expression (true) or did the\r
+ * expression change its type (false) \r
+ */\r
public void displayExpression(String expressionType, boolean original) {\r
if(expressionType == null) {\r
return;\r
}\r
\r
+ // Get up-to-date data to data-map\r
if(this.expression != null) expression.updateData(data);\r
+ \r
+ // Create the new expression\r
ExpressionType et = ExpressionType.valueOf(expressionType);\r
IExpression exp = null;\r
switch (et) {\r
case Stock: \r
exp = new StockExpression(); break;\r
case Delay: \r
- exp = new DelayExpression(); break;\r
+ exp = new DelayExpression(expr); break;\r
default: \r
exp = new EmptyExpression();\r
}\r
\r
if (exp != null) {\r
+ // If expression was created, remove the old one\r
for(Control c : parent.getChildren()) {\r
c.dispose();\r
} \r
\r
+ // If a completely new expression was selected, read data\r
if(original) \r
exp.readData(expr, data);\r
\r
+ // Create the visual representation of the expression type\r
exp.createExpressionFields(parent, data);\r
+ \r
+ // Add listeners\r
if(modifyListener != null)\r
exp.addModifyListener(modifyListener);\r
if(focusListener != null)\r
} \r
}\r
\r
+ /**\r
+ * Get current IExpression\r
+ * @return current IExpression\r
+ */\r
public IExpression getExpression() {\r
return expression;\r
}\r
\r
+ /**\r
+ * Set the variable table that contains information about variables that are connected \r
+ * to this expression\r
+ * @param table\r
+ */\r
public void setVariableTable(Table table) {\r
this.variableTable = table;\r
}\r
\r
-\r
+ /**\r
+ * Set timed field validation with default delay time\r
+ */\r
public void validateFieldsTimed() { \r
validateFieldsTimed(VALIDATION_DELAY_TIME);\r
}\r
\r
+ /**\r
+ * Set timed field validation\r
+ * @param delay Delay time for validation\r
+ */\r
public void validateFieldsTimed(int delay) {\r
- updateChartTimer.setDelay(delay);\r
- if(!updateChartTimer.isRunning())\r
- updateChartTimer.start();\r
+ validationTimer.setDelay(delay);\r
+ if(!validationTimer.isRunning())\r
+ validationTimer.start();\r
else\r
- updateChartTimer.restart();\r
+ validationTimer.restart();\r
}\r
\r
- \r
+ /**\r
+ * Validates expression fields in current IExpression\r
+ */\r
public void validateFields() {\r
if(this.variableTable == null) return;\r
\r
try {\r
+ // Find the variable for this experession\r
Resource variable = SimanticsUI.getSession().syncRequest(new Read<Resource>() {\r
\r
@Override\r
return variable;\r
}\r
});\r
+ // Validate the variable\r
if(variable != null)\r
ExpressionUtils.validateExpressionFields(variable, expression, variableTable);\r
} catch (DatabaseException e) {\r
- // TODO Auto-generated catch block\r
e.printStackTrace();\r
}\r
\r
package org.simantics.sysdyn.ui.properties.widgets.expressions;\r
\r
import java.util.Arrays;\r
+import java.util.Collection;\r
import java.util.List;\r
import java.util.Map;\r
\r
import org.simantics.sysdyn.ui.utils.ExpressionUtils;\r
import org.simantics.ui.SimanticsUI;\r
\r
+/**\r
+ * Basic expression that is used with parameter, auxiliary and constant\r
+ * @author Teemu Lempinen\r
+ *\r
+ */\r
public class BasicExpression implements IExpression {\r
\r
private ExpressionField expression;\r
\r
@Override\r
public void createExpressionFields(Composite parent, Map<String, Object> data) {\r
+ // Create the single field\r
GridLayoutFactory.fillDefaults().numColumns(2).applyTo(parent);\r
String equation = data.get("equation") != null ? (String)data.get("equation") : "";\r
\r
throws DatabaseException {\r
SysdynResource sr = SysdynResource.getInstance(g);\r
Layer0 l0 = Layer0.getInstance(g);\r
- \r
+\r
+ // Force change to parameter, if the equation is a parameter\r
if(ExpressionUtils.isParameter(currentText)) {\r
if(!expressionType.equals(sr.ConstantExpression))\r
expressionType = sr.ParameterExpression;\r
} else {\r
expressionType = sr.NormalExpression;\r
}\r
+ \r
+ // If nothing has changed, do nothing\r
if (oldEquation != null \r
&& expression != null \r
&& g.isInstanceOf(expression, expressionType) \r
return;\r
}\r
\r
+ // If the current expression type is different than the target expression type, create a new expression\r
if(!g.isInstanceOf(expression, expressionType)) {\r
- Resource ownerList = OrderedSetUtils.getSingleOwnerList(g, expression);\r
+ Collection<Resource> ownerLists = OrderedSetUtils.getOwnerLists(g, expression, l0.OrderedSet);\r
+ if(ownerLists.size() != 1)\r
+ return;\r
+ Resource ownerList = ownerLists.iterator().next();\r
final Resource newExpression = GraphUtils.create2(g, expressionType, \r
sr.HasEquation, currentText);\r
String arrayRange = g.getPossibleRelatedValue(expression, sr.HasArrayRange, Bindings.STRING);\r
}\r
);\r
} else {\r
+ // Claim value for the expression\r
g.claimLiteral(expression, sr.HasEquation, currentText);\r
}\r
}\r
*******************************************************************************/\r
package org.simantics.sysdyn.ui.properties.widgets.expressions;\r
\r
+import java.util.Arrays;\r
import java.util.List;\r
import java.util.Map;\r
\r
+import org.eclipse.jface.layout.GridDataFactory;\r
+import org.eclipse.jface.layout.GridLayoutFactory;\r
+import org.eclipse.jface.text.BadLocationException;\r
+import org.eclipse.jface.text.IDocument;\r
+import org.eclipse.swt.SWT;\r
import org.eclipse.swt.custom.VerifyKeyListener;\r
+import org.eclipse.swt.events.FocusAdapter;\r
+import org.eclipse.swt.events.FocusEvent;\r
import org.eclipse.swt.events.FocusListener;\r
import org.eclipse.swt.events.KeyListener;\r
import org.eclipse.swt.events.ModifyListener;\r
+import org.eclipse.swt.events.SelectionAdapter;\r
+import org.eclipse.swt.events.SelectionEvent;\r
+import org.eclipse.swt.graphics.Point;\r
import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Label;\r
+import org.eclipse.swt.widgets.Spinner;\r
+import org.simantics.databoard.Bindings;\r
+import org.simantics.db.ReadGraph;\r
import org.simantics.db.Resource;\r
+import org.simantics.db.VirtualGraph;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.common.request.WriteRequest;\r
+import org.simantics.db.common.utils.OrderedSetUtils;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.request.Read;\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.layer0.utils.direct.GraphUtils;\r
+import org.simantics.sysdyn.SysdynResource;\r
+import org.simantics.ui.SimanticsUI;\r
\r
+/**\r
+ * IExpression for displaying fields of DelayExpression\r
+ * @author Teemu Lempinen\r
+ *\r
+ */\r
public class DelayExpression implements IExpression {\r
\r
+ private ExpressionField equation, delayTime, initialValue;\r
+ private ExpressionField lastSelectedText = equation;\r
+ private Spinner order;\r
+ private Resource expression;\r
+\r
+ /**\r
+ * Creates a new DelayExpression\r
+ * @param expression\r
+ */\r
+ public DelayExpression(Resource expression) {\r
+ this.expression = expression;\r
+ }\r
+\r
+ /**\r
+ * Displays the fields for delayExpression\r
+ */\r
@Override\r
- public void createExpressionFields(Composite parent, Map<String, Object> data) {\r
- // TODO Auto-generated method stub\r
- \r
+ public void createExpressionFields(Composite parent, final Map<String, Object> data) {\r
+ // Get possible existing data\r
+ GridLayoutFactory.fillDefaults().numColumns(2).applyTo(parent);\r
+ String eq = data.get("equation") != null ? (String)data.get("equation") : "";\r
+ String dt = data.get("delayTime") != null ? (String)data.get("delayTime") : "";\r
+ String iv = data.get("initialValue") != null ? (String)data.get("initialValue") : "";\r
+ int o = data.get("order") != null ? (Integer)data.get("order") : 3;\r
+\r
+ Label l = new Label(parent, SWT.NONE);\r
+ l.setText("expression");\r
+\r
+ // Equation that is delayed\r
+ equation = new ExpressionField(parent, SWT.BORDER);\r
+ equation.setExpression(eq);\r
+ GridDataFactory.fillDefaults().grab(true, true).applyTo(equation);\r
+ equation.getSourceViewer().getTextWidget().addFocusListener(new FocusAdapter() {\r
+\r
+ @Override\r
+ public void focusLost(FocusEvent e) {\r
+ lastSelectedText = equation;\r
+ }\r
+ });\r
+\r
+ l = new Label(parent, SWT.NONE);\r
+ l.setText("delay time");\r
+\r
+ // How much the equation is delayed\r
+ delayTime = new ExpressionField(parent, SWT.BORDER);\r
+ delayTime.setExpression(dt);\r
+ GridDataFactory.fillDefaults().grab(true, true).applyTo(delayTime);\r
+\r
+ delayTime.getSourceViewer().getTextWidget().addFocusListener(new FocusAdapter() {\r
+\r
+ @Override\r
+ public void focusLost(FocusEvent e) {\r
+ lastSelectedText = delayTime;\r
+ }\r
+ });\r
+\r
+ l = new Label(parent, SWT.NONE);\r
+ l.setText("initial value");\r
+\r
+ // What is the initial value of the delay (empty == same as equation)\r
+ initialValue = new ExpressionField(parent, SWT.BORDER);\r
+ initialValue.setExpression(iv);\r
+ GridDataFactory.fillDefaults().grab(true, true).applyTo(initialValue);\r
+\r
+ initialValue.getSourceViewer().getTextWidget().addFocusListener(new FocusAdapter() {\r
+\r
+ @Override\r
+ public void focusLost(FocusEvent e) {\r
+ lastSelectedText = initialValue;\r
+ }\r
+ });\r
+\r
+\r
+ l = new Label(parent, SWT.NONE);\r
+ l.setText("order");\r
+\r
+ // The order of the delay (default == 3)\r
+ order = new Spinner(parent, SWT.BORDER);\r
+ order.setMinimum(1);\r
+ order.setSelection(o);\r
+ order.addSelectionListener(new SelectionAdapter() {\r
+ @Override\r
+ public void widgetSelected(SelectionEvent e) {\r
+ save(expression, data);\r
+ }\r
+ });\r
+ GridDataFactory.fillDefaults().applyTo(order);\r
}\r
\r
@Override\r
public void focus() {\r
- // TODO Auto-generated method stub\r
- \r
+ equation.setFocus();\r
}\r
\r
@Override\r
public List<ExpressionField> getExpressionFields() {\r
- // TODO Auto-generated method stub\r
- return null;\r
+ return Arrays.asList(equation, delayTime);\r
}\r
\r
@Override\r
- public void readData(Resource variable, Map<String, Object> data) {\r
- // TODO Auto-generated method stub\r
- \r
+ public void readData(final Resource expression, Map<String, Object> data) {\r
+ class Auxiliary {\r
+ String equation, delayTime, initialValue;\r
+ Integer order;\r
+ }\r
+\r
+ Auxiliary results = null;\r
+\r
+ try {\r
+ results = SimanticsUI.getSession().syncRequest(new Read<Auxiliary>() {\r
+\r
+ @Override\r
+ public Auxiliary perform(ReadGraph graph) throws DatabaseException {\r
+ Auxiliary results = new Auxiliary();\r
+ SysdynResource sr = SysdynResource.getInstance(graph);\r
+ if (expression != null && graph.isInstanceOf(expression, sr.DelayExpression)) {\r
+ results.equation = graph.getPossibleRelatedValue(expression, sr.DelayExpression_expression);\r
+ results.delayTime = graph.getPossibleRelatedValue(expression, sr.DelayExpression_delayTime);\r
+ results.initialValue = graph.getPossibleRelatedValue(expression, sr.DelayExpression_initialValue);\r
+ results.order = graph.getPossibleRelatedValue(expression, sr.DelayExpression_order);\r
+ } else {\r
+ results.equation = "";\r
+ results.delayTime = "";\r
+ results.order = 1;\r
+ }\r
+ return results;\r
+ }\r
+ });\r
+ } catch (DatabaseException e1) {\r
+ e1.printStackTrace();\r
+ }\r
+ if(results.equation != null)\r
+ data.put("equation", results.equation);\r
+ if(results.delayTime != null)\r
+ data.put("delayTime", results.delayTime);\r
+ if(results.initialValue != null)\r
+ data.put("initialValue", results.initialValue);\r
+ if(results.order != null)\r
+ data.put("order", results.order);\r
}\r
\r
@Override\r
public void replaceSelection(String var) {\r
- // TODO Auto-generated method stub\r
- \r
+ if(lastSelectedText != null) {\r
+ IDocument doc = lastSelectedText.getDocument();\r
+ try {\r
+ Point selection = lastSelectedText.getSelection();\r
+ doc.replace(selection.x, selection.y, var);\r
+ lastSelectedText.setSelection(selection.x + var.length());\r
+ } catch (BadLocationException e) {\r
+ e.printStackTrace();\r
+ }\r
+ } \r
}\r
\r
@Override\r
- public void save(Resource variable, Map<String, Object> data) {\r
- // TODO Auto-generated method stub\r
- \r
+ public void save(Resource expr, Map<String, Object> data) {\r
+ this.expression = expr;\r
+ final String currentEquation = this.equation.getExpression();\r
+ final String currentDelayTime = this.delayTime.getExpression();\r
+ final String currentInitialValue = this.initialValue.getExpression();\r
+ final Integer currentOrder = this.order.getSelection();\r
+\r
+ String oldEquation = (String)data.get("equation");\r
+ String oldDelayTime = (String)data.get("delayTime");\r
+ String oldInitialValue = (String)data.get("initialValue");\r
+ Integer oldOrder = (Integer)data.get("order");\r
+\r
+ if((oldEquation == null || oldDelayTime == null || oldOrder == null || oldInitialValue == null) ||\r
+ !oldEquation.equals(currentEquation) || !oldDelayTime.equals(currentDelayTime) ||\r
+ !oldOrder.equals(currentOrder) || !oldInitialValue.equals(currentInitialValue)) {\r
+ // old value was null or value has changed -> Do save\r
+\r
+ data.putAll(data);\r
+ data.put("equation", currentEquation);\r
+ data.put("delayTime", currentDelayTime);\r
+ data.put("initialValue", currentInitialValue);\r
+ data.put("order", currentOrder);\r
+\r
+ SimanticsUI.getSession().asyncRequest(new WriteRequest() {\r
+ @Override\r
+ public void perform(WriteGraph g)\r
+ throws DatabaseException {\r
+ SysdynResource sr = SysdynResource.getInstance(g);\r
+ Layer0 l0 = Layer0.getInstance(g);\r
+\r
+ if(!g.isInstanceOf(expression, sr.DelayExpression)) {\r
+ // Create a new DelayExpression, if the old expression was something else\r
+ Resource ownerList = OrderedSetUtils.getSingleOwnerList(g, expression);\r
+ final Resource newExpression = GraphUtils.create2(g, sr.DelayExpression);\r
+ String arrayRange = g.getPossibleRelatedValue(expression, sr.HasArrayRange, Bindings.STRING);\r
+ if(arrayRange != null)\r
+ g.claimLiteral(newExpression, sr.HasArrayRange, arrayRange);\r
+\r
+ final Resource variable = g.getSingleObject(ownerList, sr.HasExpressions_Inverse);\r
+ OrderedSetUtils.replace(g, ownerList, expression, newExpression);\r
+ g.deny(expression, l0.PartOf);\r
+ g.claim(newExpression, l0.PartOf, variable);\r
+\r
+ VirtualGraph runtime = g.getService(VirtualGraph.class);\r
+ g.syncRequest(new WriteRequest(runtime) {\r
+ @Override\r
+ public void perform(WriteGraph graph) throws DatabaseException {\r
+ SysdynResource sr = SysdynResource.getInstance(graph);\r
+ if(graph.hasStatement(variable, sr.HasActiveExpression))\r
+ graph.deny(variable, sr.HasActiveExpression);\r
+ graph.claim(variable, sr.HasActiveExpression, newExpression);\r
+ }\r
+ }\r
+ );\r
+ expression = newExpression;\r
+ }\r
+ \r
+ // Claim values\r
+ g.claimLiteral(expression, sr.DelayExpression_expression, currentEquation);\r
+ g.claimLiteral(expression, sr.DelayExpression_delayTime, currentDelayTime);\r
+ g.claimLiteral(expression, sr.DelayExpression_initialValue, currentInitialValue);\r
+ g.claimLiteral(expression, sr.DelayExpression_order, currentOrder);\r
+ }\r
+ });\r
+ }\r
+\r
}\r
\r
@Override\r
public void updateData(Map<String, Object> data) {\r
- // TODO Auto-generated method stub\r
- \r
+ if(this.equation != null && this.equation.getExpression() != null)\r
+ data.put("equation", this.equation.getExpression());\r
+ if(this.delayTime != null && this.delayTime.getExpression() != null)\r
+ data.put("delayTime", this.delayTime.getExpression()); \r
+ if(this.initialValue != null && this.initialValue.getExpression() != null)\r
+ data.put("initialValue", this.initialValue.getExpression()); \r
+ if(this.order != null)\r
+ data.put("order", this.order.getSelection()); \r
}\r
\r
@Override\r
public void addKeyListener(KeyListener listener) {\r
- // TODO Auto-generated method stub\r
- \r
+ this.equation.getSourceViewer().getTextWidget().addKeyListener(listener);\r
+ this.delayTime.getSourceViewer().getTextWidget().addKeyListener(listener);\r
+ this.initialValue.getSourceViewer().getTextWidget().addKeyListener(listener);\r
}\r
\r
@Override\r
public void addModifyListener(ModifyListener listener) {\r
- // TODO Auto-generated method stub\r
- \r
+ this.equation.getSourceViewer().getTextWidget().addModifyListener(listener);\r
+ this.delayTime.getSourceViewer().getTextWidget().addModifyListener(listener);\r
+ this.initialValue.getSourceViewer().getTextWidget().addModifyListener(listener);\r
}\r
\r
@Override\r
public void addFocusListener(FocusListener listener) {\r
- // TODO Auto-generated method stub\r
- \r
+ this.equation.getSourceViewer().getTextWidget().addFocusListener(listener);\r
+ this.delayTime.getSourceViewer().getTextWidget().addFocusListener(listener);\r
+ this.initialValue.getSourceViewer().getTextWidget().addFocusListener(listener);\r
}\r
\r
- @Override\r
- public void addVerifyKeyListener(VerifyKeyListener listener) {\r
- // TODO Auto-generated method stub\r
- \r
- }\r
+ @Override\r
+ public void addVerifyKeyListener(VerifyKeyListener listener) {\r
+ this.equation.getSourceViewer().getTextWidget().addVerifyKeyListener(listener);\r
+ this.delayTime.getSourceViewer().getTextWidget().addVerifyKeyListener(listener);\r
+ this.initialValue.getSourceViewer().getTextWidget().addVerifyKeyListener(listener);\r
+ }\r
\r
}\r
import org.simantics.objmap.schema.MappingSchemas;\r
import org.simantics.objmap.schema.SimpleSchema;\r
import org.simantics.sysdyn.representation.expressions.ConstantExpression;\r
+import org.simantics.sysdyn.representation.expressions.DelayExpression;\r
import org.simantics.sysdyn.representation.expressions.Expressions;\r
import org.simantics.sysdyn.representation.expressions.LookupExpression;\r
import org.simantics.sysdyn.representation.expressions.NormalExpression;\r
addLinkType(MappingSchemas.fromAnnotations(g, Book.class));\r
addLinkType(MappingSchemas.fromAnnotations(g, Sheet.class));\r
addLinkType(MappingSchemas.fromAnnotations(g, DiagramContainerDummy.class));\r
+ addLinkType(MappingSchemas.fromAnnotations(g, DelayExpression.class));\r
} catch (DatabaseException e) {\r
e.printStackTrace();\r
} catch (InstantiationException e) {\r
*******************************************************************************/\r
package org.simantics.sysdyn.representation.expressions;\r
\r
+import java.util.ArrayList;\r
+import java.util.Iterator;\r
+\r
import org.simantics.objmap.annotations.GraphType;\r
+import org.simantics.objmap.annotations.RelatedValue;\r
+import org.simantics.sysdyn.representation.ArrayIndexes;\r
+import org.simantics.sysdyn.representation.Enumeration;\r
+import org.simantics.sysdyn.representation.IndependentVariable;\r
+import org.simantics.sysdyn.representation.Variable;\r
+import org.simantics.sysdyn.representation.utils.FormatUtils;\r
+import org.simantics.sysdyn.representation.utils.IndexUtils;\r
\r
+/**\r
+ * Representation of a delay expression. The order of the \r
+ * delay can be 1-n.\r
+ * \r
+ * Delay with n = 3:\r
+ * \r
+ * DELAY3=LV3/DL\r
+ * LV3=INTEG(RT2-DELAY3,DL*input)\r
+ * RT2=LV2/DL\r
+ * LV2=INTEG(RT1-RT2,LV3)\r
+ * RT1=LV1/DL\r
+ * LV1=INTEG(input-RT1,LV3)\r
+ * DL=delay time/3\r
+ * \r
+ * DELAY3I=LV3/DL\r
+ * LV3=INTEG(RT2-DELAY3I,initial value*DL) \r
+ * RT2=LV2/DL\r
+ * LV2=INTEG(RT1-RT2,LV3)\r
+ * RT1=LV1/DL\r
+ * LV1=INTEG(input-RT1,LV3)\r
+ * DL=delay time/3\r
+ * \r
+ * @author Teemu Lempinen\r
+ *\r
+ */\r
@GraphType("http://www.simantics.org/Sysdyn-1.1/DelayExpression")\r
public class DelayExpression extends Expression {\r
\r
+ @RelatedValue("http://www.simantics.org/Sysdyn-1.1/DelayExpression/initialValue")\r
+ private String initialValue;\r
+\r
+ @RelatedValue("http://www.simantics.org/Sysdyn-1.1/DelayExpression/delayTime")\r
+ private String delayTime;\r
+\r
+ @RelatedValue("http://www.simantics.org/Sysdyn-1.1/DelayExpression/order")\r
+ private Integer order;\r
+\r
+ @RelatedValue("http://www.simantics.org/Sysdyn-1.1/DelayExpression/expression")\r
+ private String equation;\r
+\r
+ @Override\r
+ public String getDeclaration(IndependentVariable variable) {\r
+\r
+ // Calculate range for the variable\r
+ ArrayIndexes ai = variable.getArrayIndexes();\r
+ ArrayList<Enumeration> enumerations = null;\r
+ if(ai != null) \r
+ enumerations = ai.getEnumerations();\r
+\r
+ String range = "";\r
+ if(enumerations != null && enumerations.size() > 0) {\r
+ StringBuilder sb = new StringBuilder();\r
+ sb.append("[");\r
+ Iterator<Enumeration> iterator = enumerations.iterator();\r
+ while(iterator.hasNext()) {\r
+ sb.append(iterator.next().getName() + ".size");\r
+ if(iterator.hasNext()) {\r
+ sb.append(", ");\r
+ }\r
+ }\r
+ sb.append("]");\r
+ range = sb.toString();\r
+ }\r
+ \r
+ /* Build the declaration */\r
+ StringBuilder declaration = new StringBuilder();\r
+ // Variable declaration\r
+ declaration.append(" " + variable.getType() + " " + variable.getName() + range + ";\n");\r
+ // Delay declaration\r
+ declaration.append(" " + variable.getName() + "_delayClass " + variable.getName() + "_delayClass_instance");\r
+ // Change enumeration sizes from the delay class. Supports overridden enumerations in modules.\r
+ if(range.length() > 0) {\r
+ declaration.append("(");\r
+ String[] ranges = range.substring(1, range.length() - 1).split(",");\r
+ for(int i = 0; i < ranges.length; i++ ) {\r
+ String r = ranges[i];\r
+ declaration.append(r.replace(".size", "size") + " = " + r);\r
+ if(i < ranges.length - 1) {\r
+ declaration.append(", ");\r
+ }\r
+ }\r
+ declaration.append(")");\r
+ }\r
+ declaration.append(";\n");\r
+ \r
+ // Write the delay class\r
+ declaration.append(getDelayClass(variable, range, order));\r
+ return declaration.toString();\r
+ }\r
+\r
+ /**\r
+ * Creates a class that is used to implement the delay. Class contains\r
+ * a basic delay structure with "stocks and flows". The number of \r
+ * stocks and flows is determined by the order of the delay\r
+ * \r
+ * @param variable The variable for which the delay is created\r
+ * @param range Array range\r
+ * @param n Order of the delay\r
+ * @return\r
+ */\r
+ private String getDelayClass(Variable variable, String range, int n) {\r
+ StringBuilder sb = new StringBuilder();\r
+\r
+ sb.append("class " + variable.getName() + "_delayClass\n");\r
+ \r
+ // Auxiliary variable\r
+ sb.append("\tReal DL;\n");\r
+ // Delay time\r
+ sb.append("\tReal delayTime;\n");\r
+\r
+ // Enumeration sizes as parameters. Sizes correspond the enumeration sizes of variable\r
+ if(range.length() > 0) {\r
+ range = range.replaceAll(".size", "size");\r
+ for(String r : range.substring(1, range.length() - 1).split(",")) {\r
+ sb.append("\t parameter Integer " + r + ";\n");\r
+ }\r
+ }\r
+\r
+ if(initialValue == null || initialValue.length() == 0)\r
+ // Use "random" number as initial value, if initial value is not set\r
+ sb.append("\tReal" + range + " initialValue = " + (range.length() > 0 ? "fill(-137543," + range.substring(1, range.length() - 1) + ")" : -137543) + ";\n");\r
+ else\r
+ // Initial value\r
+ sb.append("\tReal" + range + " initialValue = " + initialValue + ";\n");\r
+ \r
+ // First valve\r
+ sb.append("\tReal" + range + " delay0;\n");\r
+\r
+ // Stocks and valves. Valves are the delayed values of the variable\r
+ for(int i = 1; i <= n; i++) {\r
+ sb.append("\tReal" + range + " LV" + i + "(" + (range.length() > 0 ? "each " : "") + "fixed=false);\n");\r
+ sb.append("\tReal" + range + " delay" + i + ";\n");\r
+ }\r
+\r
+ sb.append("initial equation\n");\r
+ \r
+ // "Generic" structure selection. If the "random" number is not used in initial value, use delay0 as initial value\r
+ sb.append("\tLV" + n +" = DL * " + \r
+ (range.length() > 0 ? "(if max(initialValue) < -137543 or max(initialValue) > -137543 then initialValue else delay0)" :\r
+ "(if initialValue < -137543 or initialValue > -137543 then initialValue else delay0)") + ";\n");\r
+ \r
+ // Each stock gets the same initial value\r
+ for(int i = 1; i < n; i++)\r
+ sb.append("\tLV" + i + " = LV" + n + ";\n");\r
+\r
+ sb.append("equation\n");\r
+ sb.append("\tDL = delayTime/" + n + ";\n");\r
+\r
+ // Valves and stocks\r
+ for(int i = 1; i <= n; i++) {\r
+ sb.append("\tder(LV" + i + ") = - delay" + i + " + delay" + (i - 1) + ";\n");\r
+ sb.append("\tdelay" + i + " = LV" + i + "/DL;\n");\r
+ }\r
+\r
+ sb.append("end " + variable.getName() + "_delayClass;\n");\r
+ return sb.toString();\r
+ }\r
+\r
+ @Override\r
+ public String getEquation(IndependentVariable variable) {\r
+ String equation = FormatUtils.formatExpressionForModelica(variable, this.equation);\r
+\r
+ // Set delay properties\r
+ StringBuilder sb = new StringBuilder();\r
+ sb.append(" " + variable.getName() + "_delayClass_instance.delayTime = " + delayTime + ";\n");\r
+ sb.append(" " + variable.getName() + "_delayClass_instance.delay0 = " + equation + ";\n");\r
+\r
+ // Use the delay in the value of variable\r
+ String range = IndexUtils.rangeToIndexes(variable, this.getArrayRange());\r
+ sb.append(" " + variable.getName() + (range.equals("[:]") ? "" : range) + " = " + variable.getName() + "_delayClass_instance.delay" + order + ";\n");\r
+ return sb.toString();\r
+ }\r
+\r
+\r
}\r