Browse Source

Working communication with subprocess

Yentl Van Tendeloo 6 years ago
parent
commit
21cfc47e56
4 changed files with 379 additions and 88 deletions
  1. 30 23
      classes/main_app.xml
  2. 114 6
      classes/window/process_enact.xml
  3. 232 59
      frontend.py
  4. 3 0
      run_plotter.sh

+ 30 - 23
classes/main_app.xml

@@ -177,23 +177,29 @@
                                 <transition target="../wait_subprocess">
                                     <parameter name="result"/>
                                     <script>
-                                        self.subprocess = subprocess.Popen(data['spawn'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
-
-                                        # If you are using Windows, then this ugly code is for you!
-                                        # Windows does not allow asynchronous reading of stdin and stdout, so we have to mess around with threads.
-                                        # Interestingly, threads don't work well with SCCD, so this is a gamble.
-                                        # On UNIX systems, a simple "select" statement would have sufficed in the SCCD condition, but Windows doesn't like elegant solutions...
-                                        def enqueue_output(out, queue):
-                                            print("Waiting for output")
-                                            for line in iter(out.readline, b''):
-                                                print("Getting input: " + str(line))
-                                                queue.append(line)
-                                            out.close()
-
-                                        self.output_queue = []
-                                        p = threading.Thread(target=enqueue_output, args=[self.subprocess.stdout, self.output_queue])
-                                        p.daemon = True
-                                        p.start()
+                                        if data['spawn'] != "":
+                                            print("Spawning " + str(data['spawn']))
+                                            self.subprocess = subprocess.Popen(data['spawn'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+
+                                            # If you are using Windows, then this ugly code is for you!
+                                            # Windows does not allow asynchronous reading of stdin and stdout, so we have to mess around with threads.
+                                            # Interestingly, threads don't work well with SCCD, so this is a gamble.
+                                            # On UNIX systems, a simple "select" statement would have sufficed in the SCCD condition, but Windows doesn't like elegant solutions...
+                                            def enqueue_output(out, queue):
+                                                print("Waiting for output")
+                                                for line in iter(out.readline, b''):
+                                                    print("Getting input: " + str(line))
+                                                    queue.append(line)
+                                                out.close()
+
+                                            self.output_queue = []
+                                            p = threading.Thread(target=enqueue_output, args=[self.subprocess.stdout, self.output_queue])
+                                            p.daemon = True
+                                            p.start()
+                                        else:
+                                            print("Empty spawn for task " + data['taskname'])
+                                            self.subprocess = None
+                                            self.output_queue = []
                                     </script>
                                 </transition>
                             </state>
@@ -203,10 +209,10 @@
                                     <parameter name="value"/>
                                     <script>
                                         # Send data to the spawned subprocess
-                                        print("Write to stdin")
-                                        self.subprocess.stdin.write(value + "\n")
-                                        self.subprocess.stdin.flush()
-                                        print("Write OK")
+                                        if self.subprocess is not None:
+                                            print("Sending data to spawn: " + str(value))
+                                            self.subprocess.stdin.write(value + "\n")
+                                            self.subprocess.stdin.flush()
                                     </script>
                                 </transition>
 
@@ -222,11 +228,12 @@
 
                                 <transition event="mv_response" target="../stopping">
                                     <script>
-                                        self.subprocess.terminate()
+                                        if self.subprocess is not None:
+                                            self.subprocess.terminate()
                                     </script>
                                 </transition>
 
-                                <transition cond="self.subprocess.poll() is not None" target="../stopping">
+                                <transition cond="self.subprocess is not None and self.subprocess.poll() is not None" target="../stopping">
                                     <script>
                                         print("Finished execution of activity!")
                                     </script>

+ 114 - 6
classes/window/process_enact.xml

@@ -29,7 +29,7 @@
             self.activity = None
 
             self.exec_input_signature = {}
-            self.exec_output_signature = {}
+            self.activity_spawn = {}
         </body>
     </constructor>
 
@@ -185,6 +185,105 @@
                     </state>
                 </state>
 
+                <state id="search_subtasks" initial="query">
+                    <state id="query">
+                        <onentry>
+                            <raise event="mv_request" scope="broad">
+                                <parameter expr="'all_instances'"/>
+                                <parameter expr="[self.activity, 'Exec']"/>
+                            </raise>
+                        </onentry>
+
+                        <transition event="mv_response" target="../decide_next">
+                            <parameter name="instances"/>
+                            <script>
+                                self.activities = instances
+                            </script>
+                        </transition>
+                    </state>
+
+                    <state id="decide_next">
+                        <transition cond="self.activities" target="../query_name">
+                            <script>
+                                self.counter += 1
+                            </script>
+                        </transition>
+                        <transition cond="not self.activities" target="../../ready"/>
+                    </state>
+
+                    <state id="query_name">
+                        <onentry>
+                            <raise event="mv_request" scope="broad">
+                                <parameter expr="'read_attrs'"/>
+                                <parameter expr="[self.activity, self.activities.pop()]"/>
+                            </raise>
+                        </onentry>
+                        
+                        <transition event="mv_response" target="../create_label">
+                            <parameter name="result"/>
+                            <script>
+                                print("Got attrs: " + str(result))
+                                self.current = result["name"][1:-1]
+                            </script>
+                        </transition>
+                    </state>
+
+                    <state id="create_label">
+                        <onentry>
+                            <raise event="create_instance" scope="cd">
+                                <parameter expr="'model_browse_label'"/>
+                                <parameter expr="'Label'"/>
+                                <parameter expr="{'parent': self.input_frame, 'text': str(self.current)}"/>
+                            </raise>
+                        </onentry>
+
+                        <transition event="instance_created" target="../pack_label">
+                            <parameter name="assoc_name"/>
+                            <raise event="start_instance" scope="cd">
+                                <parameter expr="assoc_name"/>
+                            </raise>
+                        </transition>
+                    </state>
+
+                    <state id="pack_label">
+                        <transition event="tk_widget" target="../create_entry">
+                            <parameter name="tk_widget"/>
+                            <script>
+                                tk_widget.grid(row=self.counter,column=0)
+                            </script>
+                        </transition>
+                    </state>
+
+                    <state id="create_entry">
+                        <onentry>
+                            <raise event="create_instance" scope="cd">
+                                <parameter expr="'model_browse_entry'"/>
+                                <parameter expr="'Entry'"/>
+                                <parameter expr="{'parent': self.input_frame, 'name': 'activity_%s' % self.current, 'value': '', 'readonly': False}"/>
+                            </raise>
+                        </onentry>
+
+                        <transition event="instance_created" target="../pack_entry">
+                            <parameter name="assoc_name"/>
+                            <raise event="start_instance" scope="cd">
+                                <parameter expr="assoc_name"/>
+                            </raise>
+                            <script>
+                                self.stored_associations["activity_%s" % self.current] = assoc_name
+                            </script>
+                        </transition>
+                    </state>
+
+                    <state id="pack_entry">
+                        <transition event="tk_widget" target="../decide_next">
+                            <parameter name="tk_widget"/>
+                            <script>
+                                tk_widget.grid(row=self.counter, column=1)
+                            </script>
+                        </transition>
+                    </state>
+                </state>
+
                 <state id="ready">
                     <transition event="button_pressed" cond="event_name == 'browse_activity'" target="../browse_activity">
                         <parameter name="event_name"/>
@@ -196,13 +295,22 @@
                             self.required_type = [self.input_signature[event_name.split("input_", 1)[1]]]
                         </script>
                     </transition>
-                    <transition event="changed_entry" target=".">
+                    <transition event="changed_entry" cond="event_name.startswith('input_')" target=".">
                         <parameter name="event_name"/>
                         <parameter name="value"/>
                         <script>
                             self.exec_input_signature[event_name.split("input_", 1)[1]] = value
                         </script>
                     </transition>
+                    <transition event="changed_entry" cond="event_name.startswith('activity_')" target=".">
+                        <parameter name="event_name"/>
+                        <parameter name="value"/>
+                        <script>
+                            self.activity_spawn[event_name.split("activity_", 1)[1]] = value
+                            print("Updating activity_spawn to " + str(value))
+                            print(" for act: " + event_name.split("activity_", 1)[1])
+                        </script>
+                    </transition>
                     <transition event="button_pressed" cond="event_name == 'execute'" target="../execute">
                         <parameter name="event_name"/>
                     </transition>
@@ -231,7 +339,9 @@
                             <parameter name="result"/>
                             <script>
                                 taskname, operation = result
-                                subprocess.Popen([sys.executable, sys.argv[0], "--address", data['mv_address'], "--username", data['username'], "--password", data['password'], "--taskname", taskname, "--spawn", "./run_chatwindow.py"])
+                                print("Executing operation: " + str(operation))
+                                print("   on task: " + taskname)
+                                subprocess.Popen([sys.executable, sys.argv[0], "--address", data['mv_address'], "--username", data['username'], "--password", data['password'], "--taskname", taskname, "--spawn", self.activity_spawn.get(operation, "")])
                             </script>
                         </transition>
                     </state>
@@ -344,7 +454,7 @@
                                     self.current = self.input_signature_iter.popitem()
                                 </script>
                             </transition>
-                            <transition cond="not self.input_signature_iter" target="../../../ready"/>
+                            <transition cond="not self.input_signature_iter" target="../../../search_subtasks"/>
                         </state>
 
                         <state id="create_label">
@@ -455,8 +565,6 @@
                             <script>
                                 if self.current.startswith('input_'):
                                     self.exec_input_signature[self.current.split("input_", 1)[1]] = model
-                                else:
-                                    self.exec_output_signature[self.current.split("output_", 1)[1]] = model
                             </script>
                             <raise event="change_value" scope="narrow" target="self.stored_associations[self.current]">
                                 <parameter expr="model"/>

+ 232 - 59
frontend.py

@@ -1,7 +1,7 @@
 """
 Generated by Statechart compiler by Glenn De Jonghe, Joeri Exelmans, Simon Van Mierlo, and Yentl Van Tendeloo (for the inspiration)
 
-Date:   Wed Nov 15 13:46:08 2017
+Date:   Fri Nov 17 11:37:21 2017
 
 Model author: Yentl Van Tendeloo
 Model name:   Modelverse Visual Editor - Tkinter Version 
@@ -536,31 +536,37 @@ class MainApp(RuntimeClassBase):
         return self.subprocess.poll() is not None
     
     def _parallel_behaviour_init_modelverse_conversing_execute_SC_spawn_0_exec(self, parameters):
-        self.subprocess = subprocess.Popen(data['spawn'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
-        
-        # If you are using Windows, then this ugly code is for you!
-        # Windows does not allow asynchronous reading of stdin and stdout, so we have to mess around with threads.
-        # Interestingly, threads don't work well with SCCD, so this is a gamble.
-        # On UNIX systems, a simple "select" statement would have sufficed in the SCCD condition, but Windows doesn't like elegant solutions...
-        def enqueue_output(out, queue):
-            print("Waiting for output")
-            for line in iter(out.readline, b''):
-                print("Getting input: " + str(line))
-                queue.append(line)
-            out.close()
-        
-        self.output_queue = []
-        p = threading.Thread(target=enqueue_output, args=[self.subprocess.stdout, self.output_queue])
-        p.daemon = True
-        p.start()
+        if data['spawn'] != "":
+            print("Spawning " + str(data['spawn']))
+            self.subprocess = subprocess.Popen(data['spawn'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+        
+            # If you are using Windows, then this ugly code is for you!
+            # Windows does not allow asynchronous reading of stdin and stdout, so we have to mess around with threads.
+            # Interestingly, threads don't work well with SCCD, so this is a gamble.
+            # On UNIX systems, a simple "select" statement would have sufficed in the SCCD condition, but Windows doesn't like elegant solutions...
+            def enqueue_output(out, queue):
+                print("Waiting for output")
+                for line in iter(out.readline, b''):
+                    print("Getting input: " + str(line))
+                    queue.append(line)
+                out.close()
+        
+            self.output_queue = []
+            p = threading.Thread(target=enqueue_output, args=[self.subprocess.stdout, self.output_queue])
+            p.daemon = True
+            p.start()
+        else:
+            print("Empty spawn for task " + data['taskname'])
+            self.subprocess = None
+            self.output_queue = []
     
     def _parallel_behaviour_init_modelverse_conversing_execute_SC_wait_subprocess_0_exec(self, parameters):
         value = parameters[0]
         # Send data to the spawned subprocess
-        print("Write to stdin")
-        self.subprocess.stdin.write(value + "\n")
-        self.subprocess.stdin.flush()
-        print("Write OK")
+        if self.subprocess is not None:
+            print("Sending data to spawn: " + str(value))
+            self.subprocess.stdin.write(value + "\n")
+            self.subprocess.stdin.flush()
     
     def _parallel_behaviour_init_modelverse_conversing_execute_SC_wait_subprocess_1_exec(self, parameters):
         print("Got output on stdout: " + self.output_queue[0])
@@ -570,13 +576,14 @@ class MainApp(RuntimeClassBase):
         return self.output_queue
     
     def _parallel_behaviour_init_modelverse_conversing_execute_SC_wait_subprocess_2_exec(self, parameters):
-        self.subprocess.terminate()
+        if self.subprocess is not None:
+            self.subprocess.terminate()
     
     def _parallel_behaviour_init_modelverse_conversing_execute_SC_wait_subprocess_3_exec(self, parameters):
         print("Finished execution of activity!")
     
     def _parallel_behaviour_init_modelverse_conversing_execute_SC_wait_subprocess_3_guard(self, parameters):
-        return self.subprocess.poll() is not None
+        return self.subprocess is not None and self.subprocess.poll() is not None
     
     def _parallel_behaviour_init_modelverse_logging_in_modelverse_prompt_username_0_exec(self, parameters):
         association_name = parameters[0]
@@ -1583,6 +1590,11 @@ class Modelverse(RuntimeClassBase):
         _initialized_behaviour_operations_store_on_scripted_transformation_add_send_metadata_0.setTrigger(None)
         _initialized_behaviour_operations_store_on_scripted_transformation_add_send_metadata_0.setGuard(self._initialized_behaviour_operations_store_on_scripted_transformation_add_send_metadata_0_guard)
         self.states["/initialized/behaviour/operations/store_on_scripted/transformation_add/send_metadata"].addTransition(_initialized_behaviour_operations_store_on_scripted_transformation_add_send_metadata_0)
+        _initialized_behaviour_operations_store_on_scripted_transformation_add_send_metadata_1 = Transition(self, self.states["/initialized/behaviour/operations/store_on_scripted/transformation_add/send_metadata"], [self.states["/initialized/behaviour/operations/store_on_scripted/transformation_add/upload_changes"]])
+        _initialized_behaviour_operations_store_on_scripted_transformation_add_send_metadata_1.setAction(self._initialized_behaviour_operations_store_on_scripted_transformation_add_send_metadata_1_exec)
+        _initialized_behaviour_operations_store_on_scripted_transformation_add_send_metadata_1.setTrigger(None)
+        _initialized_behaviour_operations_store_on_scripted_transformation_add_send_metadata_1.setGuard(self._initialized_behaviour_operations_store_on_scripted_transformation_add_send_metadata_1_guard)
+        self.states["/initialized/behaviour/operations/store_on_scripted/transformation_add/send_metadata"].addTransition(_initialized_behaviour_operations_store_on_scripted_transformation_add_send_metadata_1)
         
         # transition /initialized/behaviour/operations/store_on_scripted/transformation_add/wait_for_user
         _initialized_behaviour_operations_store_on_scripted_transformation_add_wait_for_user_0 = Transition(self, self.states["/initialized/behaviour/operations/store_on_scripted/transformation_add/wait_for_user"], [self.states["/initialized/behaviour/operations/store_on_scripted/transformation_add/upload_changes"]])
@@ -3142,6 +3154,13 @@ class Modelverse(RuntimeClassBase):
     def _initialized_behaviour_operations_store_on_scripted_transformation_add_send_metadata_0_guard(self, parameters):
         return self.expect_response_partial('Please edit this model before sending next input: ', pop=False)
     
+    def _initialized_behaviour_operations_store_on_scripted_transformation_add_send_metadata_1_exec(self, parameters):
+        self.raiseInternalEvent(Event("result", None, [None]))
+        self.raiseInternalEvent(Event("request", None, [self.parameters[3]]))
+    
+    def _initialized_behaviour_operations_store_on_scripted_transformation_add_send_metadata_1_guard(self, parameters):
+        return self.expect_response('Waiting for code constructors...')
+    
     def _initialized_behaviour_operations_store_on_scripted_transformation_add_wait_for_user_0_exec(self, parameters):
         self.inputs[None].pop(0)
         self.raiseInternalEvent(Event("request", None, [True]))
@@ -8436,7 +8455,7 @@ class ProcessEnactor(RuntimeClassBase, tk.Toplevel, SCCDWidget):
         self.activity = None
         
         self.exec_input_signature = {}
-        self.exec_output_signature = {}
+        self.activity_spawn = {}
     
     def user_defined_destructor(self):
         self.destroy()
@@ -8509,99 +8528,127 @@ class ProcessEnactor(RuntimeClassBase, tk.Toplevel, SCCDWidget):
         # state /all/all/create_progressbar/pack
         self.states["/all/all/create_progressbar/pack"] = State(17, "/all/all/create_progressbar/pack", self)
         
+        # state /all/all/search_subtasks
+        self.states["/all/all/search_subtasks"] = State(18, "/all/all/search_subtasks", self)
+        
+        # state /all/all/search_subtasks/query
+        self.states["/all/all/search_subtasks/query"] = State(19, "/all/all/search_subtasks/query", self)
+        self.states["/all/all/search_subtasks/query"].setEnter(self._all_all_search_subtasks_query_enter)
+        
+        # state /all/all/search_subtasks/decide_next
+        self.states["/all/all/search_subtasks/decide_next"] = State(20, "/all/all/search_subtasks/decide_next", self)
+        
+        # state /all/all/search_subtasks/query_name
+        self.states["/all/all/search_subtasks/query_name"] = State(21, "/all/all/search_subtasks/query_name", self)
+        self.states["/all/all/search_subtasks/query_name"].setEnter(self._all_all_search_subtasks_query_name_enter)
+        
+        # state /all/all/search_subtasks/create_label
+        self.states["/all/all/search_subtasks/create_label"] = State(22, "/all/all/search_subtasks/create_label", self)
+        self.states["/all/all/search_subtasks/create_label"].setEnter(self._all_all_search_subtasks_create_label_enter)
+        
+        # state /all/all/search_subtasks/pack_label
+        self.states["/all/all/search_subtasks/pack_label"] = State(23, "/all/all/search_subtasks/pack_label", self)
+        
+        # state /all/all/search_subtasks/create_entry
+        self.states["/all/all/search_subtasks/create_entry"] = State(24, "/all/all/search_subtasks/create_entry", self)
+        self.states["/all/all/search_subtasks/create_entry"].setEnter(self._all_all_search_subtasks_create_entry_enter)
+        
+        # state /all/all/search_subtasks/pack_entry
+        self.states["/all/all/search_subtasks/pack_entry"] = State(25, "/all/all/search_subtasks/pack_entry", self)
+        
         # state /all/all/ready
-        self.states["/all/all/ready"] = State(18, "/all/all/ready", self)
+        self.states["/all/all/ready"] = State(26, "/all/all/ready", self)
         
         # state /all/all/execute
-        self.states["/all/all/execute"] = State(19, "/all/all/execute", self)
+        self.states["/all/all/execute"] = State(27, "/all/all/execute", self)
         
         # state /all/all/execute/execute
-        self.states["/all/all/execute/execute"] = State(20, "/all/all/execute/execute", self)
+        self.states["/all/all/execute/execute"] = State(28, "/all/all/execute/execute", self)
         self.states["/all/all/execute/execute"].setEnter(self._all_all_execute_execute_enter)
         
         # state /all/all/execute/in_context
-        self.states["/all/all/execute/in_context"] = State(21, "/all/all/execute/in_context", self)
+        self.states["/all/all/execute/in_context"] = State(29, "/all/all/execute/in_context", self)
         
         # state /all/all/execute/alter_context_result
-        self.states["/all/all/execute/alter_context_result"] = State(22, "/all/all/execute/alter_context_result", self)
+        self.states["/all/all/execute/alter_context_result"] = State(30, "/all/all/execute/alter_context_result", self)
         
         # state /all/all/execute/alter_context_result/check_next
-        self.states["/all/all/execute/alter_context_result/check_next"] = State(23, "/all/all/execute/alter_context_result/check_next", self)
+        self.states["/all/all/execute/alter_context_result/check_next"] = State(31, "/all/all/execute/alter_context_result/check_next", self)
         
         # state /all/all/execute/alter_context_result/add
-        self.states["/all/all/execute/alter_context_result/add"] = State(24, "/all/all/execute/alter_context_result/add", self)
+        self.states["/all/all/execute/alter_context_result/add"] = State(32, "/all/all/execute/alter_context_result/add", self)
         self.states["/all/all/execute/alter_context_result/add"].setEnter(self._all_all_execute_alter_context_result_add_enter)
         
         # state /all/all/browse_activity
-        self.states["/all/all/browse_activity"] = State(25, "/all/all/browse_activity", self)
+        self.states["/all/all/browse_activity"] = State(33, "/all/all/browse_activity", self)
         
         # state /all/all/browse_activity/create_browser
-        self.states["/all/all/browse_activity/create_browser"] = State(26, "/all/all/browse_activity/create_browser", self)
+        self.states["/all/all/browse_activity/create_browser"] = State(34, "/all/all/browse_activity/create_browser", self)
         self.states["/all/all/browse_activity/create_browser"].setEnter(self._all_all_browse_activity_create_browser_enter)
         
         # state /all/all/browse_activity/waiting_for_decision
-        self.states["/all/all/browse_activity/waiting_for_decision"] = State(27, "/all/all/browse_activity/waiting_for_decision", self)
+        self.states["/all/all/browse_activity/waiting_for_decision"] = State(35, "/all/all/browse_activity/waiting_for_decision", self)
         
         # state /all/all/redraw_signature
-        self.states["/all/all/redraw_signature"] = State(28, "/all/all/redraw_signature", self)
+        self.states["/all/all/redraw_signature"] = State(36, "/all/all/redraw_signature", self)
         
         # state /all/all/redraw_signature/clear_previous
-        self.states["/all/all/redraw_signature/clear_previous"] = State(29, "/all/all/redraw_signature/clear_previous", self)
+        self.states["/all/all/redraw_signature/clear_previous"] = State(37, "/all/all/redraw_signature/clear_previous", self)
         
         # state /all/all/redraw_signature/read_signature
-        self.states["/all/all/redraw_signature/read_signature"] = State(30, "/all/all/redraw_signature/read_signature", self)
+        self.states["/all/all/redraw_signature/read_signature"] = State(38, "/all/all/redraw_signature/read_signature", self)
         self.states["/all/all/redraw_signature/read_signature"].setEnter(self._all_all_redraw_signature_read_signature_enter)
         
         # state /all/all/redraw_signature/add_input
-        self.states["/all/all/redraw_signature/add_input"] = State(31, "/all/all/redraw_signature/add_input", self)
+        self.states["/all/all/redraw_signature/add_input"] = State(39, "/all/all/redraw_signature/add_input", self)
         self.states["/all/all/redraw_signature/add_input"].setEnter(self._all_all_redraw_signature_add_input_enter)
         
         # state /all/all/redraw_signature/add_input/check_next
-        self.states["/all/all/redraw_signature/add_input/check_next"] = State(32, "/all/all/redraw_signature/add_input/check_next", self)
+        self.states["/all/all/redraw_signature/add_input/check_next"] = State(40, "/all/all/redraw_signature/add_input/check_next", self)
         
         # state /all/all/redraw_signature/add_input/create_label
-        self.states["/all/all/redraw_signature/add_input/create_label"] = State(33, "/all/all/redraw_signature/add_input/create_label", self)
+        self.states["/all/all/redraw_signature/add_input/create_label"] = State(41, "/all/all/redraw_signature/add_input/create_label", self)
         self.states["/all/all/redraw_signature/add_input/create_label"].setEnter(self._all_all_redraw_signature_add_input_create_label_enter)
         
         # state /all/all/redraw_signature/add_input/pack_label
-        self.states["/all/all/redraw_signature/add_input/pack_label"] = State(34, "/all/all/redraw_signature/add_input/pack_label", self)
+        self.states["/all/all/redraw_signature/add_input/pack_label"] = State(42, "/all/all/redraw_signature/add_input/pack_label", self)
         
         # state /all/all/redraw_signature/add_input/create_entry
-        self.states["/all/all/redraw_signature/add_input/create_entry"] = State(35, "/all/all/redraw_signature/add_input/create_entry", self)
+        self.states["/all/all/redraw_signature/add_input/create_entry"] = State(43, "/all/all/redraw_signature/add_input/create_entry", self)
         self.states["/all/all/redraw_signature/add_input/create_entry"].setEnter(self._all_all_redraw_signature_add_input_create_entry_enter)
         
         # state /all/all/redraw_signature/add_input/pack_entry
-        self.states["/all/all/redraw_signature/add_input/pack_entry"] = State(36, "/all/all/redraw_signature/add_input/pack_entry", self)
+        self.states["/all/all/redraw_signature/add_input/pack_entry"] = State(44, "/all/all/redraw_signature/add_input/pack_entry", self)
         
         # state /all/all/redraw_signature/add_input/create_button
-        self.states["/all/all/redraw_signature/add_input/create_button"] = State(37, "/all/all/redraw_signature/add_input/create_button", self)
+        self.states["/all/all/redraw_signature/add_input/create_button"] = State(45, "/all/all/redraw_signature/add_input/create_button", self)
         self.states["/all/all/redraw_signature/add_input/create_button"].setEnter(self._all_all_redraw_signature_add_input_create_button_enter)
         
         # state /all/all/redraw_signature/add_input/pack_button
-        self.states["/all/all/redraw_signature/add_input/pack_button"] = State(38, "/all/all/redraw_signature/add_input/pack_button", self)
+        self.states["/all/all/redraw_signature/add_input/pack_button"] = State(46, "/all/all/redraw_signature/add_input/pack_button", self)
         
         # state /all/all/browse_model
-        self.states["/all/all/browse_model"] = State(39, "/all/all/browse_model", self)
+        self.states["/all/all/browse_model"] = State(47, "/all/all/browse_model", self)
         
         # state /all/all/browse_model/create_browser
-        self.states["/all/all/browse_model/create_browser"] = State(40, "/all/all/browse_model/create_browser", self)
+        self.states["/all/all/browse_model/create_browser"] = State(48, "/all/all/browse_model/create_browser", self)
         self.states["/all/all/browse_model/create_browser"].setEnter(self._all_all_browse_model_create_browser_enter)
         
         # state /all/all/browse_model/waiting_for_decision
-        self.states["/all/all/browse_model/waiting_for_decision"] = State(41, "/all/all/browse_model/waiting_for_decision", self)
+        self.states["/all/all/browse_model/waiting_for_decision"] = State(49, "/all/all/browse_model/waiting_for_decision", self)
         
         # state /all/all/closing
-        self.states["/all/all/closing"] = State(42, "/all/all/closing", self)
+        self.states["/all/all/closing"] = State(50, "/all/all/closing", self)
         
         # state /all/all/closed
-        self.states["/all/all/closed"] = State(43, "/all/all/closed", self)
+        self.states["/all/all/closed"] = State(51, "/all/all/closed", self)
         self.states["/all/all/closed"].setEnter(self._all_all_closed_enter)
         
         # state /all/wait_for_deletion
-        self.states["/all/wait_for_deletion"] = State(44, "/all/wait_for_deletion", self)
+        self.states["/all/wait_for_deletion"] = State(52, "/all/wait_for_deletion", self)
         
         # state /all/wait_for_deletion/init
-        self.states["/all/wait_for_deletion/init"] = State(45, "/all/wait_for_deletion/init", self)
+        self.states["/all/wait_for_deletion/init"] = State(53, "/all/wait_for_deletion/init", self)
         
         # add children
         self.states[""].addChild(self.states["/all"])
@@ -8612,6 +8659,7 @@ class ProcessEnactor(RuntimeClassBase, tk.Toplevel, SCCDWidget):
         self.states["/all/all"].addChild(self.states["/all/all/create_activity_browse_button"])
         self.states["/all/all"].addChild(self.states["/all/all/create_exec"])
         self.states["/all/all"].addChild(self.states["/all/all/create_progressbar"])
+        self.states["/all/all"].addChild(self.states["/all/all/search_subtasks"])
         self.states["/all/all"].addChild(self.states["/all/all/ready"])
         self.states["/all/all"].addChild(self.states["/all/all/execute"])
         self.states["/all/all"].addChild(self.states["/all/all/browse_activity"])
@@ -8629,6 +8677,13 @@ class ProcessEnactor(RuntimeClassBase, tk.Toplevel, SCCDWidget):
         self.states["/all/all/create_exec"].addChild(self.states["/all/all/create_exec/pack"])
         self.states["/all/all/create_progressbar"].addChild(self.states["/all/all/create_progressbar/create"])
         self.states["/all/all/create_progressbar"].addChild(self.states["/all/all/create_progressbar/pack"])
+        self.states["/all/all/search_subtasks"].addChild(self.states["/all/all/search_subtasks/query"])
+        self.states["/all/all/search_subtasks"].addChild(self.states["/all/all/search_subtasks/decide_next"])
+        self.states["/all/all/search_subtasks"].addChild(self.states["/all/all/search_subtasks/query_name"])
+        self.states["/all/all/search_subtasks"].addChild(self.states["/all/all/search_subtasks/create_label"])
+        self.states["/all/all/search_subtasks"].addChild(self.states["/all/all/search_subtasks/pack_label"])
+        self.states["/all/all/search_subtasks"].addChild(self.states["/all/all/search_subtasks/create_entry"])
+        self.states["/all/all/search_subtasks"].addChild(self.states["/all/all/search_subtasks/pack_entry"])
         self.states["/all/all/execute"].addChild(self.states["/all/all/execute/execute"])
         self.states["/all/all/execute"].addChild(self.states["/all/all/execute/in_context"])
         self.states["/all/all/execute"].addChild(self.states["/all/all/execute/alter_context_result"])
@@ -8657,6 +8712,7 @@ class ProcessEnactor(RuntimeClassBase, tk.Toplevel, SCCDWidget):
         self.states["/all/all/create_activity_browse_button"].default_state = self.states["/all/all/create_activity_browse_button/create"]
         self.states["/all/all/create_exec"].default_state = self.states["/all/all/create_exec/create"]
         self.states["/all/all/create_progressbar"].default_state = self.states["/all/all/create_progressbar/create"]
+        self.states["/all/all/search_subtasks"].default_state = self.states["/all/all/search_subtasks/query"]
         self.states["/all/all/execute"].default_state = self.states["/all/all/execute/execute"]
         self.states["/all/all/execute/alter_context_result"].default_state = self.states["/all/all/execute/alter_context_result/check_next"]
         self.states["/all/all/browse_activity"].default_state = self.states["/all/all/browse_activity/create_browser"]
@@ -8725,6 +8781,53 @@ class ProcessEnactor(RuntimeClassBase, tk.Toplevel, SCCDWidget):
         _all_all_create_progressbar_pack_0.setTrigger(Event("tk_widget", None))
         self.states["/all/all/create_progressbar/pack"].addTransition(_all_all_create_progressbar_pack_0)
         
+        # transition /all/all/search_subtasks/query
+        _all_all_search_subtasks_query_0 = Transition(self, self.states["/all/all/search_subtasks/query"], [self.states["/all/all/search_subtasks/decide_next"]])
+        _all_all_search_subtasks_query_0.setAction(self._all_all_search_subtasks_query_0_exec)
+        _all_all_search_subtasks_query_0.setTrigger(Event("mv_response", None))
+        self.states["/all/all/search_subtasks/query"].addTransition(_all_all_search_subtasks_query_0)
+        
+        # transition /all/all/search_subtasks/decide_next
+        _all_all_search_subtasks_decide_next_0 = Transition(self, self.states["/all/all/search_subtasks/decide_next"], [self.states["/all/all/search_subtasks/query_name"]])
+        _all_all_search_subtasks_decide_next_0.setAction(self._all_all_search_subtasks_decide_next_0_exec)
+        _all_all_search_subtasks_decide_next_0.setTrigger(None)
+        _all_all_search_subtasks_decide_next_0.setGuard(self._all_all_search_subtasks_decide_next_0_guard)
+        self.states["/all/all/search_subtasks/decide_next"].addTransition(_all_all_search_subtasks_decide_next_0)
+        _all_all_search_subtasks_decide_next_1 = Transition(self, self.states["/all/all/search_subtasks/decide_next"], [self.states["/all/all/ready"]])
+        _all_all_search_subtasks_decide_next_1.setTrigger(None)
+        _all_all_search_subtasks_decide_next_1.setGuard(self._all_all_search_subtasks_decide_next_1_guard)
+        self.states["/all/all/search_subtasks/decide_next"].addTransition(_all_all_search_subtasks_decide_next_1)
+        
+        # transition /all/all/search_subtasks/query_name
+        _all_all_search_subtasks_query_name_0 = Transition(self, self.states["/all/all/search_subtasks/query_name"], [self.states["/all/all/search_subtasks/create_label"]])
+        _all_all_search_subtasks_query_name_0.setAction(self._all_all_search_subtasks_query_name_0_exec)
+        _all_all_search_subtasks_query_name_0.setTrigger(Event("mv_response", None))
+        self.states["/all/all/search_subtasks/query_name"].addTransition(_all_all_search_subtasks_query_name_0)
+        
+        # transition /all/all/search_subtasks/create_label
+        _all_all_search_subtasks_create_label_0 = Transition(self, self.states["/all/all/search_subtasks/create_label"], [self.states["/all/all/search_subtasks/pack_label"]])
+        _all_all_search_subtasks_create_label_0.setAction(self._all_all_search_subtasks_create_label_0_exec)
+        _all_all_search_subtasks_create_label_0.setTrigger(Event("instance_created", None))
+        self.states["/all/all/search_subtasks/create_label"].addTransition(_all_all_search_subtasks_create_label_0)
+        
+        # transition /all/all/search_subtasks/pack_label
+        _all_all_search_subtasks_pack_label_0 = Transition(self, self.states["/all/all/search_subtasks/pack_label"], [self.states["/all/all/search_subtasks/create_entry"]])
+        _all_all_search_subtasks_pack_label_0.setAction(self._all_all_search_subtasks_pack_label_0_exec)
+        _all_all_search_subtasks_pack_label_0.setTrigger(Event("tk_widget", None))
+        self.states["/all/all/search_subtasks/pack_label"].addTransition(_all_all_search_subtasks_pack_label_0)
+        
+        # transition /all/all/search_subtasks/create_entry
+        _all_all_search_subtasks_create_entry_0 = Transition(self, self.states["/all/all/search_subtasks/create_entry"], [self.states["/all/all/search_subtasks/pack_entry"]])
+        _all_all_search_subtasks_create_entry_0.setAction(self._all_all_search_subtasks_create_entry_0_exec)
+        _all_all_search_subtasks_create_entry_0.setTrigger(Event("instance_created", None))
+        self.states["/all/all/search_subtasks/create_entry"].addTransition(_all_all_search_subtasks_create_entry_0)
+        
+        # transition /all/all/search_subtasks/pack_entry
+        _all_all_search_subtasks_pack_entry_0 = Transition(self, self.states["/all/all/search_subtasks/pack_entry"], [self.states["/all/all/search_subtasks/decide_next"]])
+        _all_all_search_subtasks_pack_entry_0.setAction(self._all_all_search_subtasks_pack_entry_0_exec)
+        _all_all_search_subtasks_pack_entry_0.setTrigger(Event("tk_widget", None))
+        self.states["/all/all/search_subtasks/pack_entry"].addTransition(_all_all_search_subtasks_pack_entry_0)
+        
         # transition /all/all/ready
         _all_all_ready_0 = Transition(self, self.states["/all/all/ready"], [self.states["/all/all/browse_activity"]])
         _all_all_ready_0.setTrigger(Event("button_pressed", None))
@@ -8738,11 +8841,17 @@ class ProcessEnactor(RuntimeClassBase, tk.Toplevel, SCCDWidget):
         _all_all_ready_2 = Transition(self, self.states["/all/all/ready"], [self.states["/all/all/ready"]])
         _all_all_ready_2.setAction(self._all_all_ready_2_exec)
         _all_all_ready_2.setTrigger(Event("changed_entry", None))
+        _all_all_ready_2.setGuard(self._all_all_ready_2_guard)
         self.states["/all/all/ready"].addTransition(_all_all_ready_2)
-        _all_all_ready_3 = Transition(self, self.states["/all/all/ready"], [self.states["/all/all/execute"]])
-        _all_all_ready_3.setTrigger(Event("button_pressed", None))
+        _all_all_ready_3 = Transition(self, self.states["/all/all/ready"], [self.states["/all/all/ready"]])
+        _all_all_ready_3.setAction(self._all_all_ready_3_exec)
+        _all_all_ready_3.setTrigger(Event("changed_entry", None))
         _all_all_ready_3.setGuard(self._all_all_ready_3_guard)
         self.states["/all/all/ready"].addTransition(_all_all_ready_3)
+        _all_all_ready_4 = Transition(self, self.states["/all/all/ready"], [self.states["/all/all/execute"]])
+        _all_all_ready_4.setTrigger(Event("button_pressed", None))
+        _all_all_ready_4.setGuard(self._all_all_ready_4_guard)
+        self.states["/all/all/ready"].addTransition(_all_all_ready_4)
         
         # transition /all/all/execute/execute
         _all_all_execute_execute_0 = Transition(self, self.states["/all/all/execute/execute"], [self.states["/all/all/execute/in_context"]])
@@ -8809,7 +8918,7 @@ class ProcessEnactor(RuntimeClassBase, tk.Toplevel, SCCDWidget):
         _all_all_redraw_signature_add_input_check_next_0.setTrigger(None)
         _all_all_redraw_signature_add_input_check_next_0.setGuard(self._all_all_redraw_signature_add_input_check_next_0_guard)
         self.states["/all/all/redraw_signature/add_input/check_next"].addTransition(_all_all_redraw_signature_add_input_check_next_0)
-        _all_all_redraw_signature_add_input_check_next_1 = Transition(self, self.states["/all/all/redraw_signature/add_input/check_next"], [self.states["/all/all/ready"]])
+        _all_all_redraw_signature_add_input_check_next_1 = Transition(self, self.states["/all/all/redraw_signature/add_input/check_next"], [self.states["/all/all/search_subtasks"]])
         _all_all_redraw_signature_add_input_check_next_1.setTrigger(None)
         _all_all_redraw_signature_add_input_check_next_1.setGuard(self._all_all_redraw_signature_add_input_check_next_1_guard)
         self.states["/all/all/redraw_signature/add_input/check_next"].addTransition(_all_all_redraw_signature_add_input_check_next_1)
@@ -8902,6 +9011,18 @@ class ProcessEnactor(RuntimeClassBase, tk.Toplevel, SCCDWidget):
     def _all_all_create_progressbar_create_enter(self):
         self.big_step.outputEventOM(Event("create_instance", None, [self, 'progressbar', 'ProgressBar', {'parent': self.exec_frame}]))
     
+    def _all_all_search_subtasks_query_enter(self):
+        self.big_step.outputEventOM(Event("broad_cast", None, [self, Event("mv_request", None, ['all_instances', [self.activity, 'Exec']])]))
+    
+    def _all_all_search_subtasks_query_name_enter(self):
+        self.big_step.outputEventOM(Event("broad_cast", None, [self, Event("mv_request", None, ['read_attrs', [self.activity, self.activities.pop()]])]))
+    
+    def _all_all_search_subtasks_create_label_enter(self):
+        self.big_step.outputEventOM(Event("create_instance", None, [self, 'model_browse_label', 'Label', {'parent': self.input_frame, 'text': str(self.current)}]))
+    
+    def _all_all_search_subtasks_create_entry_enter(self):
+        self.big_step.outputEventOM(Event("create_instance", None, [self, 'model_browse_entry', 'Entry', {'parent': self.input_frame, 'name': 'activity_%s' % self.current, 'value': '', 'readonly': False}]))
+    
     def _all_all_execute_execute_enter(self):
         self.big_step.outputEventOM(Event("broad_cast", None, [self, Event("mv_request", None, ['process_execute', [self.activity, self.exec_input_signature]])]))
         self.big_step.outputEventOM(Event("narrow_cast", None, [self, 'progressbar', Event("start", None, [])]))
@@ -8978,6 +9099,41 @@ class ProcessEnactor(RuntimeClassBase, tk.Toplevel, SCCDWidget):
         tk_widget = parameters[0]
         tk_widget.pack(fill=tk.X)
     
+    def _all_all_search_subtasks_query_0_exec(self, parameters):
+        instances = parameters[0]
+        self.activities = instances
+    
+    def _all_all_search_subtasks_decide_next_0_exec(self, parameters):
+        self.counter += 1
+    
+    def _all_all_search_subtasks_decide_next_0_guard(self, parameters):
+        return self.activities
+    
+    def _all_all_search_subtasks_decide_next_1_guard(self, parameters):
+        return not self.activities
+    
+    def _all_all_search_subtasks_query_name_0_exec(self, parameters):
+        result = parameters[0]
+        print("Got attrs: " + str(result))
+        self.current = result["name"][1:-1]
+    
+    def _all_all_search_subtasks_create_label_0_exec(self, parameters):
+        assoc_name = parameters[0]
+        self.big_step.outputEventOM(Event("start_instance", None, [self, assoc_name]))
+    
+    def _all_all_search_subtasks_pack_label_0_exec(self, parameters):
+        tk_widget = parameters[0]
+        tk_widget.grid(row=self.counter,column=0)
+    
+    def _all_all_search_subtasks_create_entry_0_exec(self, parameters):
+        assoc_name = parameters[0]
+        self.big_step.outputEventOM(Event("start_instance", None, [self, assoc_name]))
+        self.stored_associations["activity_%s" % self.current] = assoc_name
+    
+    def _all_all_search_subtasks_pack_entry_0_exec(self, parameters):
+        tk_widget = parameters[0]
+        tk_widget.grid(row=self.counter, column=1)
+    
     def _all_all_ready_0_guard(self, parameters):
         event_name = parameters[0]
         return event_name == 'browse_activity'
@@ -8996,7 +9152,24 @@ class ProcessEnactor(RuntimeClassBase, tk.Toplevel, SCCDWidget):
         value = parameters[1]
         self.exec_input_signature[event_name.split("input_", 1)[1]] = value
     
+    def _all_all_ready_2_guard(self, parameters):
+        event_name = parameters[0]
+        value = parameters[1]
+        return event_name.startswith('input_')
+    
+    def _all_all_ready_3_exec(self, parameters):
+        event_name = parameters[0]
+        value = parameters[1]
+        self.activity_spawn[event_name.split("activity_", 1)[1]] = value
+        print("Updating activity_spawn to " + str(value))
+        print(" for act: " + event_name.split("activity_", 1)[1])
+    
     def _all_all_ready_3_guard(self, parameters):
+        event_name = parameters[0]
+        value = parameters[1]
+        return event_name.startswith('activity_')
+    
+    def _all_all_ready_4_guard(self, parameters):
         event_name = parameters[0]
         return event_name == 'execute'
     
@@ -9007,7 +9180,9 @@ class ProcessEnactor(RuntimeClassBase, tk.Toplevel, SCCDWidget):
     def _all_all_execute_in_context_1_exec(self, parameters):
         result = parameters[0]
         taskname, operation = result
-        subprocess.Popen([sys.executable, sys.argv[0], "--address", data['mv_address'], "--username", data['username'], "--password", data['password'], "--taskname", taskname, "--spawn", "./run_chatwindow.py"])
+        print("Executing operation: " + str(operation))
+        print("   on task: " + taskname)
+        subprocess.Popen([sys.executable, sys.argv[0], "--address", data['mv_address'], "--username", data['username'], "--password", data['password'], "--taskname", taskname, "--spawn", self.activity_spawn.get(operation, "")])
     
     def _all_all_execute_in_context_1_guard(self, parameters):
         result = parameters[0]
@@ -9084,8 +9259,6 @@ class ProcessEnactor(RuntimeClassBase, tk.Toplevel, SCCDWidget):
         model = parameters[0]
         if self.current.startswith('input_'):
             self.exec_input_signature[self.current.split("input_", 1)[1]] = model
-        else:
-            self.exec_output_signature[self.current.split("output_", 1)[1]] = model
         self.big_step.outputEventOM(Event("narrow_cast", None, [self, self.stored_associations[self.current], Event("change_value", None, [model])]))
     
     def _all_all_browse_model_waiting_for_decision_1_exec(self, parameters):

+ 3 - 0
run_plotter.sh

@@ -0,0 +1,3 @@
+#!/bin/bash
+cd ../modelverse/interface/simple_plot
+python main.py