From bd58462684596a2130c0782db60fe2eb6ca895c2 Mon Sep 17 00:00:00 2001 From: lempinen Date: Thu, 3 Jun 2010 14:25:43 +0000 Subject: [PATCH] Experiment control for basic simulation and simulate on change. Needs refactoring. git-svn-id: https://www.simantics.org/svn/simantics/sysdyn/trunk@16032 ac1ea38d-2e2b-0410-8846-a27921b304fc --- org.simantics.sysdyn.ui/META-INF/MANIFEST.MF | 5 +- org.simantics.sysdyn.ui/adapters.xml | 4 +- org.simantics.sysdyn.ui/icons/chart_bar.png | Bin 0 -> 541 bytes .../icons/control_eject.png | Bin 0 -> 603 bytes .../icons/control_eject_blue.png | Bin 0 -> 727 bytes .../icons/control_play_blue.png | Bin 0 -> 717 bytes .../icons/control_repeat.png | Bin 0 -> 422 bytes .../icons/control_repeat_blue.png | Bin 0 -> 750 bytes org.simantics.sysdyn.ui/icons/disk.png | Bin 0 -> 620 bytes org.simantics.sysdyn.ui/icons/time.png | Bin 0 -> 793 bytes org.simantics.sysdyn.ui/plugin.xml | 142 ++++++++++++--- .../sysdyn/ui/actions/ToggleSimulation.java | 54 +++--- .../ui/browser/contributions/Experiment.java | 21 ++- .../contributions/ExperimentImager.java | 17 ++ .../contributions/ExperimentLabeler.java | 6 +- .../ui/browser/nodes/ExperimentNode.java | 22 ++- .../sysdyn/ui/equation/EquationView.java | 6 +- .../sysdyn/ui/handlers/DisposeExperiment.java | 35 ++++ .../sysdyn/ui/handlers/NewModelHandler.java | 47 ++--- .../ui/handlers/RunBasicExperiment.java | 47 +++++ .../ui/handlers/SaveResultsHandler.java | 24 +++ .../handlers/SysdynExperimentActivator.java | 162 ++++++++++++++++++ .../listeners/SysdynExperimentListener.java | 40 +++++ .../SysdynExperimentManagerListener.java | 96 +++++++++++ .../sysdyn/ui/project/SysdynProject.java | 8 + .../ui/project/SysdynProjectLifeCycle.java | 156 +++++++++++++++++ .../simantics/sysdyn/ui/trend/TrendView.java | 5 +- org.simantics.sysdyn/META-INF/MANIFEST.MF | 8 +- org.simantics.sysdyn/adapters.xml | 23 +++ .../org/simantics/sysdyn/SysdynResource.java | 15 ++ .../sysdyn/manager/SysdynExperiment.java | 143 ++++++++++++++++ .../simantics/sysdyn/manager/SysdynModel.java | 25 ++- .../sysdyn}/simulation/SimulationJob.java | 6 +- .../simulation/SimulationScheduler.java | 7 +- sysdyn_ontologies/sysdyn.graph | 21 +++ 35 files changed, 1058 insertions(+), 87 deletions(-) create mode 100644 org.simantics.sysdyn.ui/icons/chart_bar.png create mode 100644 org.simantics.sysdyn.ui/icons/control_eject.png create mode 100644 org.simantics.sysdyn.ui/icons/control_eject_blue.png create mode 100644 org.simantics.sysdyn.ui/icons/control_play_blue.png create mode 100644 org.simantics.sysdyn.ui/icons/control_repeat.png create mode 100644 org.simantics.sysdyn.ui/icons/control_repeat_blue.png create mode 100644 org.simantics.sysdyn.ui/icons/disk.png create mode 100644 org.simantics.sysdyn.ui/icons/time.png create mode 100644 org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/browser/contributions/ExperimentImager.java create mode 100644 org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/handlers/DisposeExperiment.java create mode 100644 org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/handlers/RunBasicExperiment.java create mode 100644 org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/handlers/SaveResultsHandler.java create mode 100644 org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/handlers/SysdynExperimentActivator.java create mode 100644 org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/listeners/SysdynExperimentListener.java create mode 100644 org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/listeners/SysdynExperimentManagerListener.java create mode 100644 org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/project/SysdynProjectLifeCycle.java create mode 100644 org.simantics.sysdyn/adapters.xml create mode 100644 org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynExperiment.java rename {org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui => org.simantics.sysdyn/src/org/simantics/sysdyn}/simulation/SimulationJob.java (91%) rename {org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui => org.simantics.sysdyn/src/org/simantics/sysdyn}/simulation/SimulationScheduler.java (86%) diff --git a/org.simantics.sysdyn.ui/META-INF/MANIFEST.MF b/org.simantics.sysdyn.ui/META-INF/MANIFEST.MF index a253c602..8454a01d 100644 --- a/org.simantics.sysdyn.ui/META-INF/MANIFEST.MF +++ b/org.simantics.sysdyn.ui/META-INF/MANIFEST.MF @@ -31,6 +31,9 @@ Require-Bundle: org.simantics.h2d;bundle-version="1.0.0", org.simantics.modeling;bundle-version="1.0.0", org.simantics.mapping;bundle-version="1.0.0", org.simantics.structural.stubs;bundle-version="1.0.0", - gnu.trove2;bundle-version="2.0.4" + gnu.trove2;bundle-version="2.0.4", + org.simantics.simulation;bundle-version="1.0.0", + org.simantics.data;bundle-version="0.6.3", + org.simantics.message;bundle-version="0.9.0" Bundle-Activator: org.simantics.sysdyn.ui.Activator Bundle-ActivationPolicy: lazy diff --git a/org.simantics.sysdyn.ui/adapters.xml b/org.simantics.sysdyn.ui/adapters.xml index 61ee59d8..49125c61 100644 --- a/org.simantics.sysdyn.ui/adapters.xml +++ b/org.simantics.sysdyn.ui/adapters.xml @@ -16,7 +16,7 @@ - + - + \ No newline at end of file diff --git a/org.simantics.sysdyn.ui/icons/chart_bar.png b/org.simantics.sysdyn.ui/icons/chart_bar.png new file mode 100644 index 0000000000000000000000000000000000000000..9051fbc609b92b15af9be410e368b7adc20283b8 GIT binary patch literal 541 zcmV+&0^V&qIn(Wzh!))n z^W^$!aM&X3bCX~Vo|JLOLCb!-`g!yN7b-yh!|sbVZ|M~fElQAyiB?lO%sjz z7TJ==TTk%_A{ znxkIa+E~RC#EKF{U0G~y<6)R9(uCp7&f7|JN}RHwEO@{EgbF~D3a1<@ip|9yZb^6$ fo@6A$W#9P^w2GuX0-m@}00000NkvXXu0mjfB69Bi literal 0 HcmV?d00001 diff --git a/org.simantics.sysdyn.ui/icons/control_eject.png b/org.simantics.sysdyn.ui/icons/control_eject.png new file mode 100644 index 0000000000000000000000000000000000000000..924d817bb6dba773de390723aa4ad985a9821713 GIT binary patch literal 603 zcmV-h0;K(kP)Z_%TCJAaY&Mm8y)OMIz{xTv zv-NsS=ku8!kB7kNbfU##LA6?qRjXC`TY(o@zh19|h5c|ikgn@=xm-jHqLoTTFPF>m z7lD^;W{`Kg9c{N;S}s?#-|uO&*$`YABC4vgLZKj;0=!W)hfz>i`(r+i9|v(1^AeR0PN$?YPB*gBP$$Dr&9sLMLZsV3p5%H6&*(z zAR#L<0v3x!z~yq$WHJ$x84iaOi^bk0@cAnE`FuV_2CvskilUIm<1u%{Mxznk?{_Md zN)(Ai-c96lm5Rk8Ll3YFyAU0Z$AXBgNPurnW*pL&iN~IVtNi+^ULCu&uzdXc=%tD#Ux p3j_ihC#gQ4PvPIvUti*a1jn*n;#uCM}X>FjAph?v>HMSz1 zf;3HmQp)fUut1?Oj4&`TKsnC2z=)5XlYE)v=6sKH?ztlXFfxpDv!GF+Q=nI1=tJK> z)BIUKOgy7Nd;3kr=-fVHy#5%we{jeLLt%bvH^RPlC7E$Y*@!h*`a}?GjY$GGq&7@a%@Tx%C8vwF8lXfELN2$TzXkYy*Ch+<~�$xF_*&%15 zB*T_3AX-q$zz}$UIw`+p!e)WS?n33<^>s&1&I(xCtWah->dvT zlk;@30hM|iP6P?&m*26-MFB%#|A5C~VO%V{IK>h&5)otfwqcaoAZ=g@xqS*twq+i< zM8F>m5dn;kMH#-KMn+dml*sqcOVNV)g;%P8{>x676~rb~r8XfEXT=e5{>~?YOAmbz zKdzITiDd+!tv0mR{WeIgd~}QXa<5RRwMm-P ziA0tOonx6Yn5=ejf?oZ#NW-f*bxx-)TO!p6i!Q&%N5)kR|pVJuNho7M&@5o@ZpsgYXg z6pCpqAEgW*0v6~{n89ISU>M4A&V?DNy7MOQX68Ka`MBqf0l?U(ZY+X9l}VLZ)#Om- z;Wxvd@uT21RmKNz1dH$Bj0zp6>Db9B7mX*l{i7uPYA;7kd3g)QVC)rxA$;8vC|jea zS%$3%AWB_OF8f4{mJFo|55c22v$T`7VytGO85j|cC%=pBjskcjxd*)11x{77(<9$R zNrwG!M09PX(8Nd#urDkdGiz{FkfHKZhPUAguyq;A^$wKyj&8EE8)WXSvDl6Q4NN}z z2Zd#i!U*1a7=Vq#3W3jRZ6Z9$+&MVBAqrVEFbBV-XzUqFMNrFnb9RsDb%-T!q1pza zrNBj9g5~vhG_q(g8Ht^6IILQuOJK}cdY)autaf$;u_Hxz{;liNSF+ zP7JVo4aPtM&mF+{jGz3=veK}ME-bIS)D6sEz9#6p*nx(m=)Gd##2kGE&YZW%&7_NU zaJbxh3nsTeLlsIj==Xtu`3s4ZJ3jM?zzC+xEl8DG(CzhM_b>rg=Lda=hWnnX#UBVW zoG_R&W`Q?ax-3JI?gr8ns1oY(%Y_9|I!G4+85=MXv^z2{WgQJlI?w zaoVx2#b| zLX6^UF84fh?wy$kBLC~BD2js0>zp+XR}r`}LU#$3n|fVSTQ&_fqK z-dP1W_0w_)Fx(96Hd?S$6Ag!Gb0{2;SA#|hQKxxo4lC@GkWvoF>433OT)ML_c*YrK zxk(GV+5xw=j}C#*d_)ZQm|^vSE$e_Rfi{EB*{sr@#u0%!GuA`kT6eip5)*9h(VoI2 z7I~jC*1{1PRmB(0C&t&XN#G6@eBuONxMW%!n+~_GQB^!(14SOFz%!m0KGcES_nU0K zx*VUU%kcb!9C_-b+%XxB2spb0jf9EGvCrBTt7=&<*|?4A1r-;+e)BJV19u#CG)&jc Qk^lez07*qoM6N<$f+7R3%K!iX literal 0 HcmV?d00001 diff --git a/org.simantics.sysdyn.ui/icons/control_repeat_blue.png b/org.simantics.sysdyn.ui/icons/control_repeat_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..406ec333bc036690d4639cbec70e8f586e977699 GIT binary patch literal 750 zcmV`dI4bfJkF0x@cXCL|Igq$5O2KprVjQ%O+X7O;#( z4BD1bI(<+cEez0UoerJ8pvUZH<2j7y zcZNUt)xrxJYFpmPCdcPpZrKy&*VZ>ApFbcitp@qg#TeIQPnn2A+}{k&#TSQNduHE8 zR1lLg6t#%bX_+CDEg*4_f_v33^v*=h#I2ZA3~EX24{j>CdV}A=`*V zT4vz!`I!OrPI2eFNk)w9XPLPE(JbD&MP{&ll+#ia(bqqy8yG)*4e)6tkBnME*Ypl9 z-y3DbfrSJUUwt@@D-R}c|4op+OgNr~#cI=AsIxgE+;$>~av4mxb*QrFQBlRSu^2P( z#4-pavM8REG5;k1bN7TkM8nPocv)tTbCDe=Sn=D!1EK%memuVc8qO zwkWfiP|txa2~#c~+AY08Q|E`jSGoE#-RjvgwZ5L>o_F>0mY3bqi%w2z>#*|89S-gW g7yS2U`k(Lo6ZXgk;$VJhmjD0&07*qoM6N<$g5UmA*#H0l literal 0 HcmV?d00001 diff --git a/org.simantics.sysdyn.ui/icons/disk.png b/org.simantics.sysdyn.ui/icons/disk.png new file mode 100644 index 0000000000000000000000000000000000000000..99d532e8b1750115952f97302a92d713c0486f97 GIT binary patch literal 620 zcmV-y0+aoTP)~H+MJzd|s z^YP1Hc07G_>)Lgir!F1{Qn4GcTg%?koHo<=1qRN{}nPDolOeI^o4N5I>! zU$N=L=sg~ zDx#dOA*B0N~cqPsWI(^rbbkh)DS0_H_UN0C4l_kvWIm2#Kyy6%BCh z(yIUf003&1xdx>t$*eR2ZvXxT0001Z_R$y3Iju92q*wg58};}zm(OaAH=p|y0002M zh5O5#fxp|~jc?yi@+7$`d4Q6Hl%z;WiWG??NXR{Hx%)pMd~SE0000OQI literal 0 HcmV?d00001 diff --git a/org.simantics.sysdyn.ui/icons/time.png b/org.simantics.sysdyn.ui/icons/time.png new file mode 100644 index 0000000000000000000000000000000000000000..911da3f1d31fca4494a4beb22014e5c5c724c236 GIT binary patch literal 793 zcmV+!1LpjRP)`EB*FHYdKr%;k=xO&(k^EfNlSiKZ>5l+xr|%SFOV@6-ysFmD2F5 ze93OiS+LaQym;|2f6tbH%~V`D+ND?vc>4J^KSLxEMifJQ`8>*~y^+pGr&o-n=LJ zGWB(yB#;DR8&Lhqi{0(#wc#SwSB~jZKzIFx`8od>2Fo-Pfe7*M8^q#qw2yTxiXzd~ zRaz|F*rr78G`JZXG*YX~5K@5k>G@0HdlBo-6v1jHye?%qRwO@+-hO7J^4LlPG>@A1#{ zQFl4x7tnG)+cz_2Mq_f*H!U)kgg{iHqxT)Yr3ec@K!`)z_%h1c0Y2Eu(dMPkrhq5v zY+bKWfx|sTiOEB71HuwS*CDzA%ReBv4*7Zy7RM0n6`5#chfOJK`ze)Y6>d6Z?UmyNHH!3DdsP-ARyDo}1HO+>7_um7 zx_gj{+_aU_OUH_~Jd?KI#ICZujD`of2mDpCv_zFGE%6}tfL|j!WGu_i-u>4%{%d{$ X7`zMSfT21V00000NkvXXu0mjfkBx0` literal 0 HcmV?d00001 diff --git a/org.simantics.sysdyn.ui/plugin.xml b/org.simantics.sysdyn.ui/plugin.xml index 45c158ba..bb6143f7 100644 --- a/org.simantics.sysdyn.ui/plugin.xml +++ b/org.simantics.sysdyn.ui/plugin.xml @@ -106,37 +106,97 @@ - - - - + locationURI="toolbar:org.eclipse.ui.main.toolbar"> + id="org.simantics.sysdyn.ui.experimentControlToolbar"> + + + + + + + + + + - + tooltip="Simulate On Change"> + + + + + + + + + + + - - + variable="activeContexts"> + + + + + + + + + + + + + + + + + + + id="org.simantics.sysdyn.ui.toggleSimulation.state"> + + + + + + + + @@ -386,6 +465,10 @@ class="org.simantics.sysdyn.ui.browser.contributions.ModelChildren" preference="2.0"> + + + + + + + + + + diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/actions/ToggleSimulation.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/actions/ToggleSimulation.java index ff731f51..d92a2de7 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/actions/ToggleSimulation.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/actions/ToggleSimulation.java @@ -11,25 +11,29 @@ *******************************************************************************/ package org.simantics.sysdyn.ui.actions; + +import java.util.Map; + import org.eclipse.core.commands.AbstractHandler; import org.eclipse.core.commands.Command; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.commands.State; -import org.eclipse.ui.IEditorInput; -import org.eclipse.ui.IEditorPart; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.commands.ICommandService; -import org.simantics.sysdyn.manager.SysdynModel; -import org.simantics.sysdyn.manager.SysdynModelManager; -import org.simantics.sysdyn.ui.editor.SysdynDiagramEditor; +import org.eclipse.ui.commands.IElementUpdater; +import org.eclipse.ui.menus.UIElement; +import org.simantics.simulation.experiment.IDynamicExperiment; +import org.simantics.simulation.experiment.IExperiment; +import org.simantics.simulation.project.IExperimentManager; +import org.simantics.sysdyn.manager.SysdynExperiment; +import org.simantics.sysdyn.ui.handlers.RunBasicExperiment; import org.simantics.ui.SimanticsUI; -import org.simantics.ui.workbench.ResourceEditorInput; -public class ToggleSimulation extends AbstractHandler { +public class ToggleSimulation extends AbstractHandler implements IElementUpdater { - public static final String COMMAND = "org.simantics.sysdyn.ui.simulate"; - public static final String STATE = "org.simantics.sysdyn.ui.simulate.state"; + public static final String COMMAND = "org.simantics.sysdyn.ui.toggleSimulation"; + public static final String STATE = "org.simantics.sysdyn.ui.toggleSimulation.state"; @Override public Object execute(ExecutionEvent event) throws ExecutionException { @@ -39,19 +43,20 @@ public class ToggleSimulation extends AbstractHandler { Boolean value = (Boolean) state.getValue(); value = !value; state.setValue(value); - // If turned back on, simulate to apply any changes - if(value) { - IEditorPart editor = - PlatformUI.getWorkbench() - .getActiveWorkbenchWindow().getActivePage().getActiveEditor(); - if (editor instanceof SysdynDiagramEditor) { - IEditorInput input = editor.getEditorInput(); - ResourceEditorInput rei = (ResourceEditorInput) input; - SysdynModelManager sdm = SysdynModelManager.getInstance(SimanticsUI.getSession()); - SysdynModel model = sdm.getModel(rei.getResource()); - model.domainModified(); + service.refreshElements(RunBasicExperiment.COMMAND, null); + + IExperimentManager manager = + SimanticsUI.getProject().getHint(IExperimentManager.KEY_EXPERIMENT_MANAGER); + IExperiment experiment = manager.getActiveExperiment(); + if(experiment instanceof SysdynExperiment) { + if(getState()) { + ((SysdynExperiment)experiment).toggleSimulation(true); + } else { + ((SysdynExperiment)experiment).toggleSimulation(false); } } + + return null; } @@ -62,4 +67,13 @@ public class ToggleSimulation extends AbstractHandler { return (Boolean)state.getValue(); } + @SuppressWarnings("unchecked") + @Override + public void updateElement(UIElement element, Map parameters) { + ICommandService commandService = + (ICommandService) PlatformUI.getWorkbench().getService(ICommandService.class); + Command command = commandService.getCommand(COMMAND); + boolean checked = (Boolean) command.getState(STATE).getValue(); + element.setChecked(checked); + } } diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/browser/contributions/Experiment.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/browser/contributions/Experiment.java index 4d5766a4..34bc6adc 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/browser/contributions/Experiment.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/browser/contributions/Experiment.java @@ -11,20 +11,31 @@ *******************************************************************************/ package org.simantics.sysdyn.ui.browser.contributions; +import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; - import org.simantics.browsing.ui.graph.contributor.viewpoint.ViewpointContributor; +import org.simantics.db.Builtins; import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.common.request.ObjectsWithType; import org.simantics.db.exception.DatabaseException; +import org.simantics.sysdyn.ui.browser.nodes.AbstractNode; import org.simantics.sysdyn.ui.browser.nodes.ExperimentsFolder; public class Experiment extends ViewpointContributor { @Override - public Collection getContribution(ReadGraph graph, ExperimentsFolder input) throws DatabaseException { - // hasExperiment or something - return Collections.EMPTY_LIST; + public Collection getContribution(ReadGraph graph, ExperimentsFolder experimentsFolder) throws DatabaseException { + ArrayList result = new ArrayList(); + Builtins b = graph.getBuiltins(); + for(Resource r : graph.syncRequest(new ObjectsWithType(experimentsFolder.resource, b.ConsistsOf, b.Experiment))) { + try { + result.add(graph.adapt(r, AbstractNode.class)); + } catch(DatabaseException e) { + e.printStackTrace(); + } + } + return result; } @Override diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/browser/contributions/ExperimentImager.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/browser/contributions/ExperimentImager.java new file mode 100644 index 00000000..a4262231 --- /dev/null +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/browser/contributions/ExperimentImager.java @@ -0,0 +1,17 @@ +package org.simantics.sysdyn.ui.browser.contributions; + +import org.eclipse.jface.resource.ImageDescriptor; +import org.simantics.browsing.ui.swt.ImagerContributor; +import org.simantics.db.ReadGraph; +import org.simantics.db.exception.DatabaseException; +import org.simantics.sysdyn.ui.Activator; +import org.simantics.sysdyn.ui.browser.nodes.ExperimentNode; + +public class ExperimentImager extends ImagerContributor { + + @Override + public ImageDescriptor getDescriptor(ReadGraph graph, ExperimentNode experiment) throws DatabaseException { + return ImageDescriptor.createFromURL(Activator.getDefault().getBundle().getResource("icons/time.png")); + } + +} diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/browser/contributions/ExperimentLabeler.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/browser/contributions/ExperimentLabeler.java index f78e77ea..2e7b49f9 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/browser/contributions/ExperimentLabeler.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/browser/contributions/ExperimentLabeler.java @@ -20,9 +20,9 @@ import org.simantics.sysdyn.ui.browser.nodes.ExperimentNode; public class ExperimentLabeler extends LabelerContributor{ @Override - public String getLabel(ReadGraph graph, ExperimentNode input) throws DatabaseException { - // TODO Auto-generated method stub - return null; + public String getLabel(ReadGraph graph, ExperimentNode experiment) throws DatabaseException { + String name = graph.getPossibleRelatedValue(experiment.resource, graph.getBuiltins().HasName); + return name == null ? "Experiment (no name)" : name; } } diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/browser/nodes/ExperimentNode.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/browser/nodes/ExperimentNode.java index adea16cd..e7286e1f 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/browser/nodes/ExperimentNode.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/browser/nodes/ExperimentNode.java @@ -11,12 +11,32 @@ *******************************************************************************/ package org.simantics.sysdyn.ui.browser.nodes; +import org.simantics.browsing.ui.common.node.IDoubleClickableNode; import org.simantics.db.Resource; +import org.simantics.project.IProject; +import org.simantics.simulation.project.IExperimentManager; +import org.simantics.sysdyn.ui.handlers.SysdynExperimentActivator; +import org.simantics.ui.SimanticsUI; +import org.simantics.utils.ui.ErrorLogger; -public class ExperimentNode extends AbstractNode { +public class ExperimentNode extends AbstractNode implements IDoubleClickableNode{ public ExperimentNode(Resource resource) { super(resource); } + @Override + public boolean handleDoubleClick() { + if (resource == null) + return false; + IProject project = SimanticsUI.getProject(); + IExperimentManager experimentManager = project.getHint(IExperimentManager.KEY_EXPERIMENT_MANAGER); + if (experimentManager == null) { + ErrorLogger.defaultLogWarning("Experiment manager not available.", new Exception()); + return false; + } + SysdynExperimentActivator.scheduleActivation(SimanticsUI.getSession(), project, experimentManager, resource); + return true; + } + } diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/equation/EquationView.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/equation/EquationView.java index 967fc89c..4404ca06 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/equation/EquationView.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/equation/EquationView.java @@ -184,9 +184,7 @@ public class EquationView extends ViewPart implements ISelectionListener { variable = resource; a.configuration = graph.getPossibleObject(variable, b.PartOf); a.name = graph.getPossibleRelatedValue(resource, b.HasName); - a.isVariable = graph.isInstanceOf(variable, sr.Auxiliary) || - graph.isInstanceOf(variable, sr.Stock) || - graph.isInstanceOf(variable, sr.Valve); + a.isVariable = graph.isInstanceOf(variable, sr.IndependentVariable); if(a.name == null) a.name = ""; return a; @@ -252,7 +250,7 @@ public class EquationView extends ViewPart implements ISelectionListener { unitSelector.clear(); // empty units shortcutTabs.updateTables(variable); expressionController.setExpressionTypes(null); - nameComposite.setName(result.name); + nameComposite.setName(""); expressionComposite.resetExpressionView(variable); } } diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/handlers/DisposeExperiment.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/handlers/DisposeExperiment.java new file mode 100644 index 00000000..13bc387c --- /dev/null +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/handlers/DisposeExperiment.java @@ -0,0 +1,35 @@ +package org.simantics.sysdyn.ui.handlers; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.simantics.project.IExperimentDescriptor; +import org.simantics.project.IProject; +import org.simantics.project.ProjectKeys; +import org.simantics.simulation.experiment.IExperiment; +import org.simantics.simulation.project.IExperimentManager; +import org.simantics.ui.SimanticsUI; + +public class DisposeExperiment extends AbstractHandler { + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + IProject project = SimanticsUI.getProject(); + IExperimentManager manager = + project.getHint(IExperimentManager.KEY_EXPERIMENT_MANAGER); + IExperiment experiment = manager.getActiveExperiment(); + if (experiment != null) + experiment.shutdown(); + + /* + // Keep the UI happy. + IExperimentDescriptor ed = project.getHint(ProjectKeys.KEY_SELECTED_UI_EXPERIMENT); + if (ed != null) { + ed.getParent().removeHint(ProjectKeys.KEY_SELECTED_EXPERIMENT); + project.removeHint(ProjectKeys.KEY_SELECTED_UI_EXPERIMENT); + } + */ + return null; + } + +} diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/handlers/NewModelHandler.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/handlers/NewModelHandler.java index 2168b7b6..0d4047a5 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/handlers/NewModelHandler.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/handlers/NewModelHandler.java @@ -26,37 +26,44 @@ public class NewModelHandler extends AbstractHandler { SimanticsUI.getSession().asyncRequest(new WriteRequest() { @Override - public void perform(WriteGraph graph) throws DatabaseException { + public void perform(WriteGraph g) throws DatabaseException { // Same as in SysdynProject.java. Should use the same code, not copy. - Builtins b = graph.getBuiltins(); - SysdynResource sr = SysdynResource.getInstance(graph); - ModelingResources mr = ModelingResources.getInstance(graph); - ModelingUtils mu = new ModelingUtils(graph); + Builtins b = g.getBuiltins(); + SysdynResource sr = SysdynResource.getInstance(g); + ModelingResources mr = ModelingResources.getInstance(g); + ModelingUtils mu = new ModelingUtils(g); - Resource model = graph.newResource(); - graph.claimValue(model, b.HasName, "Model1"); - graph.claimValue(model, b.HasLabel, "Model1"); - graph.claim(model, b.InstanceOf, sr.SysdynModel); - graph.claim(model, b.PartOf, SimanticsUI.getProject().get()); + Resource model = g.newResource(); + g.claimValue(model, b.HasName, "Model1"); + g.claimValue(model, b.HasLabel, "Model1"); + g.claim(model, b.InstanceOf, sr.SysdynModel); + g.claim(model, b.PartOf, SimanticsUI.getProject().get()); - Resource diagram = OrderedSetUtils.create(graph, sr.ConfigurationDiagram); - GraphLayer l = new GraphLayerUtil(graph).createLayer(DiagramConstants.DEFAULT_LAYER_NAME, true); - graph.claim(diagram, mu.dr.HasLayer, l.getLayer()); - graph.claimValue(diagram, b.HasName, "Diagrammi", StringJavaBinding.INSTANCE); + Resource diagram = OrderedSetUtils.create(g, sr.ConfigurationDiagram); + GraphLayer l = new GraphLayerUtil(g).createLayer(DiagramConstants.DEFAULT_LAYER_NAME, true); + g.claim(diagram, mu.dr.HasLayer, l.getLayer()); + g.claimValue(diagram, b.HasName, "Diagrammi", StringJavaBinding.INSTANCE); - Resource conf = GraphUtils.create2(graph, + Resource conf = GraphUtils.create2(g, sr.Configuration, b.HasName, "Configuration", sr.HasStartTime, 0.0, sr.HasStopTime, 10.0); - graph.claim(conf, mr.CompositeToDiagram, diagram); - graph.claim(model, b.HasConfiguration, conf); + g.claim(conf, mr.CompositeToDiagram, diagram); + g.claim(model, b.HasConfiguration, conf); - Resource mapping = graph.newResource(); - graph.claim(mapping, b.InstanceOf, null, sr.DiagramToCompositeMapping); - graph.claim(diagram, b.HasTrigger, mapping); + Resource mapping = g.newResource(); + g.claim(mapping, b.InstanceOf, null, sr.DiagramToCompositeMapping); + g.claim(diagram, b.HasTrigger, mapping); + + Resource report = GraphUtils.create2(g, mu.b.Report, mu.b.HasDocumentation, "===Report==="); + + Resource experiment = GraphUtils.create2(g, mu.b.Experiment, + mu.b.HasName, "Experiment", + mu.b.HasReportFactory, report, + mu.b.PartOf, model); } }); return null; diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/handlers/RunBasicExperiment.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/handlers/RunBasicExperiment.java new file mode 100644 index 00000000..8b81ffc1 --- /dev/null +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/handlers/RunBasicExperiment.java @@ -0,0 +1,47 @@ +package org.simantics.sysdyn.ui.handlers; + + +import java.util.Map; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.Command; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.commands.ICommandService; +import org.eclipse.ui.commands.IElementUpdater; +import org.eclipse.ui.menus.UIElement; +import org.simantics.simulation.experiment.IDynamicExperiment; +import org.simantics.simulation.experiment.IExperiment; +import org.simantics.simulation.project.IExperimentManager; +import org.simantics.sysdyn.ui.actions.ToggleSimulation; +import org.simantics.ui.SimanticsUI; + +public class RunBasicExperiment extends AbstractHandler implements IElementUpdater { + + public static final String COMMAND = "org.simantics.sysdyn.ui.run"; + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + IExperimentManager manager = + SimanticsUI.getProject().getHint(IExperimentManager.KEY_EXPERIMENT_MANAGER); + IExperiment experiment = manager.getActiveExperiment(); + if(experiment instanceof IDynamicExperiment) + ((IDynamicExperiment)experiment).simulate(true); + return null; + } + + @SuppressWarnings("unchecked") + @Override + public void updateElement(UIElement element, Map parameters) { + ICommandService commandService = + (ICommandService) PlatformUI.getWorkbench().getService(ICommandService.class); + Command command = commandService.getCommand(ToggleSimulation.COMMAND); + boolean checked = (Boolean) command.getState(ToggleSimulation.STATE).getValue(); + if(checked) + this.setBaseEnabled(false); + else + this.setBaseEnabled(true); + + } +} diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/handlers/SaveResultsHandler.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/handlers/SaveResultsHandler.java new file mode 100644 index 00000000..9d7beedf --- /dev/null +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/handlers/SaveResultsHandler.java @@ -0,0 +1,24 @@ +package org.simantics.sysdyn.ui.handlers; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.simantics.simulation.experiment.IDynamicExperiment; +import org.simantics.simulation.experiment.IExperiment; +import org.simantics.simulation.project.IExperimentManager; +import org.simantics.ui.SimanticsUI; + +public class SaveResultsHandler extends AbstractHandler { + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + IExperimentManager manager = + SimanticsUI.getProject().getHint(IExperimentManager.KEY_EXPERIMENT_MANAGER); + IExperiment experiment = manager.getActiveExperiment(); + if(experiment instanceof IDynamicExperiment) { + ((IDynamicExperiment)experiment).saveState(); + } + return null; + } + +} diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/handlers/SysdynExperimentActivator.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/handlers/SysdynExperimentActivator.java new file mode 100644 index 00000000..4b681603 --- /dev/null +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/handlers/SysdynExperimentActivator.java @@ -0,0 +1,162 @@ +package org.simantics.sysdyn.ui.handlers; + +import java.util.concurrent.Semaphore; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.simantics.db.ReadGraph; +import org.simantics.db.RequestProcessor; +import org.simantics.db.Resource; +import org.simantics.db.exception.AdaptionException; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.request.Read; +import org.simantics.layer0.utils.direct.GraphUtils; +import org.simantics.message.MessageService; +import org.simantics.project.IExperimentDescriptor; +import org.simantics.project.IModelDescriptor; +import org.simantics.project.IProject; +import org.simantics.project.IProjectElement; +import org.simantics.project.ProjectKeys; +import org.simantics.project.exception.ProjectException; +import org.simantics.simulation.experiment.IExperiment; +import org.simantics.simulation.model.ExperimentLoadingFailed; +import org.simantics.simulation.project.IExperimentActivationListener; +import org.simantics.simulation.project.IExperimentManager; +import org.simantics.sysdyn.ui.listeners.SysdynExperimentManagerListener; +import org.simantics.utils.DataContainer; +import org.simantics.utils.ui.ErrorLogger; +import org.simantics.utils.ui.ExceptionUtils; +import org.simantics.utils.ui.dialogs.ShowMessage; + +public class SysdynExperimentActivator { + /** + * @param project + * @param experimentManager + * @param experiment + */ + public static void scheduleActivation(RequestProcessor processor, final IProject project, final IExperimentManager experimentManager, final Resource experiment) { + String jobName = "Activate Experiment"; + String experimentName = getName(processor, experiment); + if (experimentName != null) + jobName += " '" + experimentName + "'"; + + scheduleActivation(jobName, project, experimentManager, experiment); + } + + /** + * @param project + * @param experimentManager + * @param experiment + */ + public static void scheduleActivation(String jobName, final IProject project, final IExperimentManager experimentManager, final Resource experiment) { + new Job(jobName) { + @Override + protected IStatus run(final IProgressMonitor monitor) { + return SysdynExperimentActivator.activate(monitor, project, experimentManager, experiment); + } + }.schedule(); + } + + public static IStatus activate(IProgressMonitor monitor, IProject project, IExperimentManager experimentManager, Resource experiment) { + return new SysdynExperimentActivator().activateExperiment(monitor, project, experimentManager, experiment); + } + + private static String getName(RequestProcessor processor, final Resource resource) { + try { + return processor.syncRequest(new Read() { + @Override + public String perform(ReadGraph graph) throws DatabaseException { + try { + return graph.adapt(resource, String.class); + } catch (AdaptionException e) { + return GraphUtils.getReadableName(graph, resource); + } + } + }); + } catch (DatabaseException e) { + ErrorLogger.defaultLogWarning(e); + return null; + } + } + + private IStatus activateExperiment(final IProgressMonitor monitor, final IProject project, final IExperimentManager manager, final Resource experimentResource) { + monitor.beginTask("Activating experiment", IProgressMonitor.UNKNOWN); + try { + SysdynExperimentManagerListener.listenManager(manager); + final Semaphore activated = new Semaphore(0); + final DataContainer problem = new DataContainer(); + manager.startExperiment(experimentResource, new IExperimentActivationListener() { + + @Override + public void onExperimentActivated(final IExperiment experiment) { + + MessageService.defaultLog(new org.eclipse.core.runtime.Status(IStatus.INFO, "org.simantics.simulation.ui", 0, "Activated experiment " + experiment.getIdentifier() , null)); + + + activated.release(); + // Set the selected experiment into the the model descriptor. + new Thread("Set Selected Experiment") { + @Override + public void run() { + setSelectedExperiment(project, experimentResource); + } + }.start(); + } + @Override + public void onFailure(Throwable e) { + problem.set(e); + activated.release(); + } + @Override + public void onMessage(IStatus message) { + MessageService.getDefault().log(message); + /*ILogger logger = MessageService.getDefault(); + MultiStatus init = new MultiStatus(Activator.PLUGIN_ID, 0, "Activating experiment", null); + for (String msg : messages) { + init.add(new Status(IStatus.INFO, Activator.PLUGIN_ID, msg)); + } + logger.log(init);*/ + } + }, true); + try { + activated.acquire(); + Throwable t = problem.get(); + if (t != null) { + if (t instanceof ExperimentLoadingFailed) { + ErrorLogger.defaultLogError(t); + ShowMessage.showError("Experiment Activation Failed", t.getMessage()); + } else { + ExceptionUtils.logAndShowError(t); + } + } + + return Status.OK_STATUS; + //return new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Experiment activation failed, see exception for details.", problem.get()); + } catch (InterruptedException e) { + return Status.CANCEL_STATUS; + } + } finally { + monitor.done(); + } + } + + private void setSelectedExperiment(IProject project, Resource experiment) { + try { + for (IProjectElement model : project.members()) { + if (model instanceof IModelDescriptor) { + for (IProjectElement member : ((IModelDescriptor) model).members()) { + if (member instanceof IExperimentDescriptor && experiment.equals(member.get())) { + model.setHint(ProjectKeys.KEY_SELECTED_EXPERIMENT, member); + project.setHint(ProjectKeys.KEY_SELECTED_UI_EXPERIMENT, member); + break; + } + } + } + } + } catch (ProjectException e) { + ErrorLogger.defaultLogError(e); + } + } +} diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/listeners/SysdynExperimentListener.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/listeners/SysdynExperimentListener.java new file mode 100644 index 00000000..bd81f37a --- /dev/null +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/listeners/SysdynExperimentListener.java @@ -0,0 +1,40 @@ +package org.simantics.sysdyn.ui.listeners; + +import org.eclipse.core.commands.Command; +import org.eclipse.core.commands.State; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.commands.ICommandService; +import org.eclipse.ui.contexts.IContextActivation; +import org.simantics.simulation.experiment.ExperimentState; +import org.simantics.simulation.experiment.IExperimentListener; +import org.simantics.sysdyn.ui.actions.ToggleSimulation; +import org.simantics.sysdyn.ui.handlers.RunBasicExperiment; + +public class SysdynExperimentListener implements IExperimentListener { + + IContextActivation contextActivation; + + @Override + public void stateChanged(final ExperimentState state) { + PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() { + + @Override + public void run() { + ICommandService commandService = + (ICommandService) PlatformUI.getWorkbench().getService(ICommandService.class); + Command command = commandService.getCommand(ToggleSimulation.COMMAND); + State buttonState = command.getState(ToggleSimulation.STATE); + + switch(state) { + case DISPOSED: + buttonState.setValue(false); + break; + } + commandService.refreshElements(command.getId(), null); + commandService.refreshElements(RunBasicExperiment.COMMAND, null); + } + + }); + } + +} diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/listeners/SysdynExperimentManagerListener.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/listeners/SysdynExperimentManagerListener.java new file mode 100644 index 00000000..5c385fd3 --- /dev/null +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/listeners/SysdynExperimentManagerListener.java @@ -0,0 +1,96 @@ +package org.simantics.sysdyn.ui.listeners; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.contexts.IContextActivation; +import org.eclipse.ui.contexts.IContextService; +import org.simantics.simulation.experiment.IExperiment; +import org.simantics.simulation.project.IExperimentManager; +import org.simantics.simulation.project.IExperimentManagerListener; + +public class SysdynExperimentManagerListener implements IExperimentManagerListener{ + + public static final String BASIC_EXPERIMENT_CONTEXT = "org.simantics.sysdyn.ui.basicExperiment"; + + static Set managers = + new HashSet(); + + IExperimentManager manager; + + Collection contextActivations = + new ArrayList(); + + public SysdynExperimentManagerListener(IExperimentManager manager) { + this.manager = manager; + } + + public static void listenManager(IExperimentManager manager) { + synchronized(managers) { + if(managers.contains(manager)) + return; + SysdynExperimentManagerListener listener = + new SysdynExperimentManagerListener(manager); + manager.addListener(listener); + managers.add(manager); + } + } + + @Override + public void activeExperimentLoaded(final IExperiment experiment) { + experiment.addListener(new SysdynExperimentListener()); + + PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() { + + @Override + public void run() { + IContextService contextService = + (IContextService)PlatformUI.getWorkbench() + .getActiveWorkbenchWindow().getService(IContextService.class); + synchronized(contextActivations) { + contextActivations.add(contextService.activateContext(BASIC_EXPERIMENT_CONTEXT)); + } + } + + }); + } + + @Override + public void activeExperimentUnloaded() { + + synchronized(contextActivations) { + final Collection oldContextActivations = + contextActivations; + + contextActivations = new ArrayList(); + + final IWorkbench workbench = PlatformUI.getWorkbench(); + workbench.getDisplay().asyncExec(new Runnable() { + + @Override + public void run() { + if (workbench.isClosing()) + return; + + IContextService contextService = + (IContextService)workbench.getActiveWorkbenchWindow().getService(IContextService.class); + contextService.deactivateContexts(oldContextActivations); + } + + }); + } + + } + + @Override + public void managerDisposed() { + synchronized(managers) { + managers.remove(manager); + } + } + +} diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/project/SysdynProject.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/project/SysdynProject.java index 178089b8..3ccec206 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/project/SysdynProject.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/project/SysdynProject.java @@ -25,6 +25,7 @@ import org.simantics.db.service.LifecycleSupport; import org.simantics.diagram.DiagramConstants; import org.simantics.diagram.synchronization.graph.layer.GraphLayer; import org.simantics.diagram.synchronization.graph.layer.GraphLayerUtil; +import org.simantics.layer0.utils.direct.GraphUtils; import org.simantics.modeling.ModelingResources; import org.simantics.modeling.ModelingUtils; import org.simantics.project.ProjectElementType; @@ -105,7 +106,14 @@ public class SysdynProject extends AbstractProjectFeature { Resource mapping = g.newResource(); g.claim(mapping, b.InstanceOf, null, mr.DiagramToCompositeMapping); g.claim(diagram, b.HasTrigger, mapping); + + Resource report = GraphUtils.create2(g, mu.b.Report, mu.b.HasDocumentation, "===Report==="); + Resource experiment = GraphUtils.create2(g, mu.b.Experiment, + mu.b.HasName, "Experiment", + mu.b.HasReportFactory, report, + mu.b.PartOf, model); + callback.run(model); } catch(Exception e) { errorCallback.run(e); diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/project/SysdynProjectLifeCycle.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/project/SysdynProjectLifeCycle.java new file mode 100644 index 00000000..d0127081 --- /dev/null +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/project/SysdynProjectLifeCycle.java @@ -0,0 +1,156 @@ +package org.simantics.sysdyn.ui.project; + +import java.util.Timer; + +import org.simantics.databoard.accessor.Accessor; +import org.simantics.db.Builtins; +import org.simantics.db.RequestProcessor; +import org.simantics.db.Resource; +import org.simantics.db.Session; +import org.simantics.db.VirtualGraph; +import org.simantics.db.WriteGraph; +import org.simantics.db.common.procedure.single.SingleSetListener; +import org.simantics.db.common.request.ObjectsWithType; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.adapter.ActivationManager; +import org.simantics.db.layer0.adapter.RuntimeValuations; +import org.simantics.db.layer0.adapter.TrendVariable; +import org.simantics.db.layer0.adapter.ValuationVirtualGraph; +import org.simantics.db.layer0.util.Simantics; +import org.simantics.db.management.ISessionContext; +import org.simantics.db.service.VirtualGraphSupport; +import org.simantics.project.IProject; +import org.simantics.project.IProjectLifeCycle; +import org.simantics.simulation.experiment.IExperiment; +import org.simantics.simulation.project.IExperimentManager; +import org.simantics.ui.SimanticsUI; +import org.simantics.utils.datastructures.hints.IHintContext.Key; +import org.simantics.utils.datastructures.hints.IHintContext.KeyOf; + +public class SysdynProjectLifeCycle implements IProjectLifeCycle{ + + public static final Key INITIALIZED = new KeyOf(Boolean.class, "SYSDYN_LIFECYCLE_INITIALIZED"); + + static Timer timer = new Timer(); + + @Override + public void onCreate(WriteGraph g, Resource project) { +// System.out.println("onCreate Apros Project: " + GraphUtils.getReadableName(g, project)); + } + + @Override + public void onDestroy(WriteGraph g, Resource project) { +// System.out.println("onDestroy Apros Project: " + GraphUtils.getReadableName(g, project)); + } + + @Override + public void onActivated(RequestProcessor processor, final IProject project) { + +// System.out.println("onActivated DEVS Project"); + + ISessionContext context = SimanticsUI.getSessionContext(); + if (context.getHint(INITIALIZED) == null) { + + try { + + Resource projectResource = project.get(); + + final Session session = context.getSession(); + + session.registerService(RuntimeValuations.class, new RuntimeValuations() { + + @Override + public boolean supports(String valuation) { + + IExperimentManager expMan = project.getHint(IExperimentManager.KEY_EXPERIMENT_MANAGER); + IExperiment experiment = expMan.getExperiment(valuation); + + return experiment != null; + + } + + @Override + public Accessor getAccessor(String variableIdentityPrefix, String valuation, String suffix) { + return null; + } + + @Override + public TrendVariable getVariable(String variableIdentityPrefix, String valuation, String suffix) { + + return null; + + } + + }); + + +// System.out.println("A1"); + + Builtins b = session.getBuiltins(); + ActivationManager activationManager = session.getService(ActivationManager.class); + if (activationManager != null) { + activationManager.activate(processor, projectResource); + } + +// System.out.println("A2"); + + VirtualGraphSupport support = session.getService(VirtualGraphSupport.class); + final VirtualGraph graph = support.create(); + session.registerService(VirtualGraph.class, graph); + +// System.out.println("A3"); + + session.asyncRequest(new ObjectsWithType(projectResource, b.ConsistsOf, b.Model), new SingleSetListener() { + + @Override + public void add(final Resource model) { + // FIXME: +// System.out.println("A4"); + Simantics.async(new Runnable() { + + @Override + public void run() { + try { +// System.out.println("A5 " + model); + graph.register(new ValuationVirtualGraph(session, model)); + } catch (DatabaseException e) { + e.printStackTrace(); + } + } + + }); + } + + @Override + public void exception(Throwable t) { + t.printStackTrace(); + } + + @Override + public boolean isDisposed() { + return false; + } + + }); + + support.resume("experiments"); + + } catch (DatabaseException e) { + + e.printStackTrace(); + + } + + + + context.setHint(INITIALIZED, Boolean.TRUE); + + } + + } + + @Override + public void onDeactivated(IProject project) { +// System.out.println("onDeactivated Apros Project: " + project.getName()); + } +} diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/trend/TrendView.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/trend/TrendView.java index 0a04685d..13b91a11 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/trend/TrendView.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/trend/TrendView.java @@ -45,7 +45,6 @@ import org.simantics.sysdyn.manager.SysdynModel; import org.simantics.sysdyn.manager.SysdynModelManager; import org.simantics.sysdyn.representation.IElement; import org.simantics.sysdyn.representation.Variable; -import org.simantics.sysdyn.ui.simulation.SimulationScheduler; import org.simantics.ui.SimanticsUI; import org.simantics.utils.ui.ISelectionUtils; import org.simantics.utils.ui.jface.ActiveSelectionProvider; @@ -209,7 +208,7 @@ public class TrendView extends ViewPart { if(model == null) { model = SysdynModelManager.getInstance(g.getSession()).getModel(g, configuration); - SimulationScheduler.start(model); + // SimulationScheduler.start(model); Don't want this to operate simulation model.addResultListener(updater); models.put(configuration, model); } @@ -229,6 +228,8 @@ public class TrendView extends ViewPart { Resource configuration = g.getPossibleObject(resource, b.PartOf); if(g.isInstanceOf(configuration, sr.Configuration)) { SysdynModel model = getModel(g, configuration); + if(model == null) + return null; IElement element = model.getElement(resource); if(element instanceof Variable) { Variable var = (Variable)element; diff --git a/org.simantics.sysdyn/META-INF/MANIFEST.MF b/org.simantics.sysdyn/META-INF/MANIFEST.MF index c7a329ca..d10349c0 100644 --- a/org.simantics.sysdyn/META-INF/MANIFEST.MF +++ b/org.simantics.sysdyn/META-INF/MANIFEST.MF @@ -7,11 +7,17 @@ Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Require-Bundle: org.simantics.objmap;bundle-version="0.1.0", org.simantics.db;bundle-version="0.6.2", org.simantics.modelica;bundle-version="1.0.0", - org.simantics.db.common;bundle-version="0.8.0" + org.simantics.db.common;bundle-version="0.8.0", + org.simantics.simulation;bundle-version="1.0.0", + org.simantics.data;bundle-version="0.6.3", + org.eclipse.ui.console;bundle-version="3.4.0", + org.eclipse.core.runtime;bundle-version="3.5.0", + org.eclipse.jface;bundle-version="3.5.2" Export-Package: org.simantics.sysdyn, org.simantics.sysdyn.expressionParser, org.simantics.sysdyn.manager, org.simantics.sysdyn.modelica, org.simantics.sysdyn.representation, org.simantics.sysdyn.representation.visitors, + org.simantics.sysdyn.simulation, org.simantics.sysdyn.tableParser diff --git a/org.simantics.sysdyn/adapters.xml b/org.simantics.sysdyn/adapters.xml new file mode 100644 index 00000000..1bd89531 --- /dev/null +++ b/org.simantics.sysdyn/adapters.xml @@ -0,0 +1,23 @@ + + + + + + + + + + \ No newline at end of file diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/SysdynResource.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/SysdynResource.java index c8231e16..668279e1 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/SysdynResource.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/SysdynResource.java @@ -22,6 +22,7 @@ public class SysdynResource { public final Resource Auxiliary; public final Resource AuxiliarySymbol; + public final Resource BasicExperiment; public final Resource Cloud; public final Resource Configuration; public final Resource ConfigurationDiagram; @@ -29,8 +30,10 @@ public class SysdynResource { public final Resource DelayExpression; public final Resource Dependency; public final Resource DiagramToCompositeMapping; + public final Resource Experiment; public final Resource Expression; public final Resource Flow; + public final Resource GameExperiment; public final Resource HasAngle; public final Resource HasEquation; public final Resource HasExpression; @@ -58,11 +61,13 @@ public class SysdynResource { public final Resource ParameterExpression; public final Resource PhantomTerminal; public final Resource RefersTo; + public final Resource SimulateOnChangeExperiment; public final Resource Stock; public final Resource StockExpression; public final Resource StockSymbol; public final Resource SysdynConnectionType; public final Resource SysdynModel; + public final Resource SysdynModelManager; public final Resource SysdynProject; public final Resource SysdynSymbols; public final Resource Terminal; @@ -74,6 +79,7 @@ public class SysdynResource { public static class URIs { public static final String Auxiliary = "http://www.simantics.org/Sysdyn-1.0/Auxiliary"; public static final String AuxiliarySymbol = "http://www.simantics.org/Sysdyn-1.0/AuxiliarySymbol"; + public static final String BasicExperiment = "http://www.simantics.org/Sysdyn-1.0/BasicExperiment"; public static final String Cloud = "http://www.simantics.org/Sysdyn-1.0/Cloud"; public static final String Configuration = "http://www.simantics.org/Sysdyn-1.0/Configuration"; public static final String ConfigurationDiagram = "http://www.simantics.org/Sysdyn-1.0/ConfigurationDiagram"; @@ -81,8 +87,10 @@ public class SysdynResource { public static final String DelayExpression = "http://www.simantics.org/Sysdyn-1.0/DelayExpression"; public static final String Dependency = "http://www.simantics.org/Sysdyn-1.0/Dependency"; public static final String DiagramToCompositeMapping = "http://www.simantics.org/Sysdyn-1.0/DiagramToCompositeMapping"; + public static final String Experiment = "http://www.simantics.org/Sysdyn-1.0/Experiment"; public static final String Expression = "http://www.simantics.org/Sysdyn-1.0/Expression"; public static final String Flow = "http://www.simantics.org/Sysdyn-1.0/Flow"; + public static final String GameExperiment = "http://www.simantics.org/Sysdyn-1.0/GameExperiment"; public static final String HasAngle = "http://www.simantics.org/Sysdyn-1.0/HasAngle"; public static final String HasEquation = "http://www.simantics.org/Sysdyn-1.0/HasEquation"; public static final String HasExpression = "http://www.simantics.org/Sysdyn-1.0/HasExpression"; @@ -110,11 +118,13 @@ public class SysdynResource { public static final String ParameterExpression = "http://www.simantics.org/Sysdyn-1.0/ParameterExpression"; public static final String PhantomTerminal = "http://www.simantics.org/Sysdyn-1.0/PhantomTerminal"; public static final String RefersTo = "http://www.simantics.org/Sysdyn-1.0/RefersTo"; + public static final String SimulateOnChangeExperiment = "http://www.simantics.org/Sysdyn-1.0/SimulateOnChangeExperiment"; public static final String Stock = "http://www.simantics.org/Sysdyn-1.0/Stock"; public static final String StockExpression = "http://www.simantics.org/Sysdyn-1.0/StockExpression"; public static final String StockSymbol = "http://www.simantics.org/Sysdyn-1.0/StockSymbol"; public static final String SysdynConnectionType = "http://www.simantics.org/Sysdyn-1.0/SysdynConnectionType"; public static final String SysdynModel = "http://www.simantics.org/Sysdyn-1.0/SysdynModel"; + public static final String SysdynModelManager = "http://www.simantics.org/Sysdyn-1.0/SysdynModelManager"; public static final String SysdynProject = "http://www.simantics.org/Sysdyn-1.0/SysdynProject"; public static final String SysdynSymbols = "http://www.simantics.org/Sysdyn-1.0/SysdynSymbols"; public static final String Terminal = "http://www.simantics.org/Sysdyn-1.0/Terminal"; @@ -136,6 +146,7 @@ public class SysdynResource { public SysdynResource(ReadGraph graph) { Auxiliary = getResourceOrNull(graph, URIs.Auxiliary); AuxiliarySymbol = getResourceOrNull(graph, URIs.AuxiliarySymbol); + BasicExperiment = getResourceOrNull(graph, URIs.BasicExperiment); Cloud = getResourceOrNull(graph, URIs.Cloud); Configuration = getResourceOrNull(graph, URIs.Configuration); ConfigurationDiagram = getResourceOrNull(graph, URIs.ConfigurationDiagram); @@ -143,8 +154,10 @@ public class SysdynResource { DelayExpression = getResourceOrNull(graph, URIs.DelayExpression); Dependency = getResourceOrNull(graph, URIs.Dependency); DiagramToCompositeMapping = getResourceOrNull(graph, URIs.DiagramToCompositeMapping); + Experiment = getResourceOrNull(graph, URIs.Experiment); Expression = getResourceOrNull(graph, URIs.Expression); Flow = getResourceOrNull(graph, URIs.Flow); + GameExperiment = getResourceOrNull(graph, URIs.GameExperiment); HasAngle = getResourceOrNull(graph, URIs.HasAngle); HasEquation = getResourceOrNull(graph, URIs.HasEquation); HasExpression = getResourceOrNull(graph, URIs.HasExpression); @@ -172,11 +185,13 @@ public class SysdynResource { ParameterExpression = getResourceOrNull(graph, URIs.ParameterExpression); PhantomTerminal = getResourceOrNull(graph, URIs.PhantomTerminal); RefersTo = getResourceOrNull(graph, URIs.RefersTo); + SimulateOnChangeExperiment = getResourceOrNull(graph, URIs.SimulateOnChangeExperiment); Stock = getResourceOrNull(graph, URIs.Stock); StockExpression = getResourceOrNull(graph, URIs.StockExpression); StockSymbol = getResourceOrNull(graph, URIs.StockSymbol); SysdynConnectionType = getResourceOrNull(graph, URIs.SysdynConnectionType); SysdynModel = getResourceOrNull(graph, URIs.SysdynModel); + SysdynModelManager = getResourceOrNull(graph, URIs.SysdynModelManager); SysdynProject = getResourceOrNull(graph, URIs.SysdynProject); SysdynSymbols = getResourceOrNull(graph, URIs.SysdynSymbols); Terminal = getResourceOrNull(graph, URIs.Terminal); diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynExperiment.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynExperiment.java new file mode 100644 index 00000000..5a1a29f9 --- /dev/null +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynExperiment.java @@ -0,0 +1,143 @@ +package org.simantics.sysdyn.manager; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.Session; +import org.simantics.db.common.request.ReadRequest; +import org.simantics.db.exception.DatabaseException; +import org.simantics.simulation.experiment.Experiment; +import org.simantics.simulation.experiment.ExperimentState; +import org.simantics.simulation.experiment.IDynamicExperiment; +import org.simantics.sysdyn.simulation.SimulationScheduler; + +public class SysdynExperiment extends Experiment implements IDynamicExperiment { + + Session session; + Runnable modificationListener; + + public SysdynExperiment(Resource model) { + super(model); + // TODO Auto-generated constructor stub + } + + @Override + public void rewindTo(double time) { + // TODO Auto-generated method stub + System.out.println("rewindTo"); + } + + @Override + public void saveState() { + // TODO Auto-generated method stub + System.out.println("saveState"); + } + + /** + * enabled: is simulate on change enabled + */ + @Override + public void simulate(boolean enabled) { + System.out.println("simulate"); + if(enabled) { + changeState(ExperimentState.STOPPED); + session.asyncRequest(new ReadRequest() { + + @Override + public void run(ReadGraph graph) throws DatabaseException { + final Resource configuration = graph.getPossibleObject(model, graph.getBuiltins().HasConfiguration); + SysdynModel sysdynmodel = + SysdynModelManager.getInstance(session).getModel(graph, configuration); + SimulationScheduler.start(sysdynmodel); + } + }); + } + + } + + public void toggleSimulation(boolean enabled) { + if(enabled) { + changeState(ExperimentState.RUNNING); + if(modificationListener == null) { + try { + session.syncRequest(new ReadRequest() { + + @Override + public void run(ReadGraph graph) throws DatabaseException { + final Resource configuration = graph.getPossibleObject(model, graph.getBuiltins().HasConfiguration); + SysdynModel sysdynmodel = + SysdynModelManager.getInstance(session).getModel(graph, configuration); + SimulationScheduler.start(sysdynmodel); + + modificationListener = new Runnable() { + + @Override + public void run() { + session.asyncRequest(new ReadRequest() { + + @Override + public void run(ReadGraph graph) throws DatabaseException { + if(getState() == ExperimentState.RUNNING) { + SysdynModel sysdynmodel = + SysdynModelManager.getInstance(session).getModel(graph, configuration); + SimulationScheduler.start(sysdynmodel); + } + + } + }); + + }; + }; + sysdynmodel.addModificationListener(modificationListener); + }}); + } catch (DatabaseException e) { + e.printStackTrace(); + } + } + } + else { + changeState(ExperimentState.STOPPED); + } + + } + + @Override + public void simulateDuration(double duration) { + // TODO Auto-generated method stub + System.out.println("simulateDuartion"); + } + + @Override + public void refresh(Session session) { + // TODO Auto-generated method stub + System.out.println("refresh"); + } + + public void init(ReadGraph g) { + System.out.println("init"); + changeState(ExperimentState.STOPPED); + this.session = g.getSession(); + } + + @Override + protected void localStateChange() { + ExperimentState state = getState(); + switch(state) { + case DISPOSED: + session.asyncRequest(new ReadRequest() { + + @Override + public void run(ReadGraph graph) throws DatabaseException { + final Resource configuration = graph.getPossibleObject(model, graph.getBuiltins().HasConfiguration); + SysdynModel sysdynmodel = + SysdynModelManager.getInstance(session).getModel(graph, configuration); + sysdynmodel.removeModificationListener(modificationListener); + modificationListener = null; + + } + }); + break; + } + } + + +} diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynModel.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynModel.java index 28c98110..65d31d32 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynModel.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynModel.java @@ -27,6 +27,9 @@ import org.simantics.modelica.data.SimulationResult; import org.simantics.objmap.IMapping; import org.simantics.objmap.IMappingListener; import org.simantics.objmap.Mappings; +import org.simantics.simulation.experiment.IExperiment; +import org.simantics.simulation.model.IModel; +import org.simantics.simulation.project.IExperimentActivationListener; import org.simantics.sysdyn.modelica.ModelicaWriter; import org.simantics.sysdyn.representation.Configuration; import org.simantics.sysdyn.representation.IElement; @@ -36,7 +39,7 @@ import org.simantics.sysdyn.representation.SysdynSchema; * Maintains a Java representation of system dynamic model. * @author Hannu Niemistö */ -public class SysdynModel implements IMappingListener { +public class SysdynModel implements IMappingListener, IModel { Session session; Resource configurationResource; @@ -69,6 +72,14 @@ public class SysdynModel implements IMappingListener { e.printStackTrace(); } } + + + /* + * some dummy(?) stuff for experiments + */ + public SysdynModel(Resource configurationResource) { + this.configurationResource = configurationResource; + } public synchronized void simulate(IModelicaMonitor monitor) throws IOException { try { @@ -169,4 +180,16 @@ public class SysdynModel implements IMappingListener { } } + @Override + public IExperiment loadExperiment(ReadGraph g, Resource experiment, IExperimentActivationListener listener) { + SysdynExperiment exp = new SysdynExperiment(configurationResource); + try { + exp.init(g); + listener.onExperimentActivated(exp); + return exp; + } catch(Exception e) { + listener.onFailure(e); + return null; + } + } } diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/simulation/SimulationJob.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/simulation/SimulationJob.java similarity index 91% rename from org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/simulation/SimulationJob.java rename to org.simantics.sysdyn/src/org/simantics/sysdyn/simulation/SimulationJob.java index afeb86b0..5b086659 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/simulation/SimulationJob.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/simulation/SimulationJob.java @@ -9,7 +9,7 @@ * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ -package org.simantics.sysdyn.ui.simulation; +package org.simantics.sysdyn.simulation; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; @@ -22,7 +22,6 @@ import org.eclipse.ui.console.MessageConsole; import org.eclipse.ui.console.MessageConsoleStream; import org.simantics.modelica.IModelicaMonitor; import org.simantics.sysdyn.manager.SysdynModel; -import org.simantics.sysdyn.ui.actions.ToggleSimulation; public class SimulationJob extends Job { @@ -40,8 +39,7 @@ public class SimulationJob extends Job { this.monitor.clearConsole(); try { model.update(); - if(ToggleSimulation.getState()) - model.simulate(this.monitor); + model.simulate(this.monitor); } catch (Exception e) { e.printStackTrace(); return new Status( diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/simulation/SimulationScheduler.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/simulation/SimulationScheduler.java similarity index 86% rename from org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/simulation/SimulationScheduler.java rename to org.simantics.sysdyn/src/org/simantics/sysdyn/simulation/SimulationScheduler.java index b90d68e5..cd048be4 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/simulation/SimulationScheduler.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/simulation/SimulationScheduler.java @@ -9,7 +9,7 @@ * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ -package org.simantics.sysdyn.ui.simulation; +package org.simantics.sysdyn.simulation; import org.simantics.sysdyn.manager.SysdynModel; @@ -25,6 +25,8 @@ public class SimulationScheduler { private void start() { job.schedule(); + /* + * Don't want this behavior. Use this in simulate on change or somewhere model.addModificationListener(new Runnable() { @Override @@ -33,6 +35,7 @@ public class SimulationScheduler { } }); + */ } public static synchronized SimulationScheduler start(SysdynModel model) { @@ -41,6 +44,8 @@ public class SimulationScheduler { scheduler = new SimulationScheduler(model); model.addService(SimulationScheduler.class, scheduler); scheduler.start(); + } else { + scheduler.start(); } return scheduler; } diff --git a/sysdyn_ontologies/sysdyn.graph b/sysdyn_ontologies/sysdyn.graph index 1256c67e..69216fb4 100644 --- a/sysdyn_ontologies/sysdyn.graph +++ b/sysdyn_ontologies/sysdyn.graph @@ -32,6 +32,8 @@ Sysdyn @ "Sysdyn-1.0" : L0.Ontology Symbols : L0.Library SysdynProject : PROJ.Feature + PROJ.LifecycleFeature + SysdynProject L0.HasLabel "System Dynamics Project" : L0.String L0.HasDescription """System dynamics modelling project. Create system dynamics models and simulate them with OpenModelica.""" : L0.String L0.PartOf Sysdyn @@ -42,6 +44,13 @@ SysdynProject : PROJ.Feature PROJ.RequiresNamespace "http://www.simantics.org/Sysdyn-1.0" : L0.URI SysdynSymbols + PROJ.ExperimentControl + SysdynModelManager : PROJ.Feature + L0.PartOf Sysdyn + L0.HasLabel "Sysdyn Model Manager" : L0.String + L0.HasDescription "Sysdyn Model Manager." : L0.String + PROJ.RequiresFeature MOD.ModelingProject + PROJ.RequiresFeature PROJ.ExperimentControl SysdynSymbols : PROJ.Feature L0.PartOf Sysdyn @@ -232,6 +241,18 @@ WithLookupExpression