예제 #1
0
    def after_notification_of_parent_or_state_from_lists(self, model, prop_name, info):

        # avoid updates because of execution status updates or while multi-actions
        if self.check_no_update_flags_and_return_combined_flag(prop_name, info):
            return

        overview = NotificationOverview(info)

        # avoid updates because of unimportant methods
        if overview.get_cause() not in ['name', 'append', '__setitem__',  # '__delitem__', 'remove',
                                        'group_states', 'ungroup_state', 'change_data_type',
                                        'from_key', 'to_key', 'from_state', 'to_state',
                                        'modify_origin', 'modify_target']:
            if self.model.parent:
                # check for a sibling port change
                if prop_name == 'states' and overview.get_affected_core_element() is self.model.parent.state and \
                        (overview.get_affected_core_element() in self.model.parent.state.states and
                         overview.get_cause() in ['add_input_data_port', 'add_output_data_port'] or
                         overview.get_affected_property() in ['data_port', 'scoped_variable'] and
                         overview.get_cause() in ['name', 'change_data_type']):
                    pass
                else:
                    return
            else:
                return

        try:
            self.update(initiator=str(overview))
        except Exception as e:
            if self.debug_log:
                import traceback
                self.store_debug_log_file(str(overview))
                self.store_debug_log_file(str(traceback.format_exc()))
            logger.error("update of data_flow widget fails while detecting change in state %s %s" %
                         (self.model.state.name, self.model.state.state_id))
예제 #2
0
    def check_info_on_no_update_flags(self, info):
        """Stop updates while multi-actions"""
        # TODO that could need a second clean up
        # avoid updates because of state destruction
        if 'before' in info and info['method_name'] == "remove_state":
            if info.instance is self.model.state:
                self.no_update_state_destruction = True
            else:
                # if the state it self is removed lock the widget to never run updates and relieve all models
                removed_state_id = info.args[1] if len(
                    info.args) > 1 else info.kwargs['state_id']
                if removed_state_id == self.model.state.state_id or \
                        not self.model.state.is_root_state and removed_state_id == self.model.parent.state.state_id:
                    self.no_update_self_or_parent_state_destruction = True
                    self.relieve_all_models()

        elif 'after' in info and info['method_name'] == "remove_state":
            if info.instance.state_id == self.model.state.state_id:
                self.no_update_state_destruction = False

        # reduce NotificationOverview generations by the fact that after could cause False and before could cause True
        if not self.no_update_state_destruction and not self.no_update_self_or_parent_state_destruction and \
                (not self.no_update and 'before' in info or 'after' in info and self.no_update):
            return
        overview = NotificationOverview(info)

        # The method causing the change raised an exception, thus nothing was changed and updates are allowed
        if 'after' in info and isinstance(overview.get_result(), Exception):
            self.no_update = False
            self.no_update_state_destruction = False
            # self.no_update_self_or_parent_state_destruction = False
            return

        if overview.get_cause() in [
                'group_states', 'ungroup_state', "change_state_type",
                "change_root_state_type"
        ]:
            instance_is_self = self.model.state is overview.get_affected_core_element(
            )
            instance_is_parent = self.model.parent and self.model.parent.state is overview.get_affected_core_element(
            )
            instance_is_parent_parent = self.model.parent and self.model.parent.parent and self.model.parent.parent.state is overview.get_affected_core_element(
            )
            # print("no update flag: ", True if 'before' in info and (instance_is_self or instance_is_parent or instance_is_parent_parent) else False)
            if instance_is_self or instance_is_parent or instance_is_parent_parent:
                self.no_update = True if 'before' in info else False

            if overview.get_affected_property() == 'state' and overview.get_cause() in ["change_state_type"] and \
                    self.model.get_state_machine_m() is not None:
                changed_model = self.model.get_state_machine_m(
                ).get_state_model_by_path(
                    overview.get_method_args()[1].get_path())
                if changed_model not in self._model_observed:
                    self.observe_model(changed_model)
예제 #3
0
    def states_update(self, model, prop_name, info):
        overview = NotificationOverview(info)
        if not overview.caused_modification():
            return

        if overview.get_affected_property() == 'state' and \
                overview.get_cause() in ["name"]:  # , "add_state", "remove_state"]:
            self.update_tree_store_row(overview.get_affected_model())
        # TODO check the work around for get_library_root_state -> maybe the notifications can be avoided if upper lib
        elif overview.get_affected_property() == 'state' and not overview.get_affected_model().state.get_next_upper_library_root_state() and \
                overview.get_cause() in ["add_state", "remove_state"]:
            self.update(overview.get_affected_model())
예제 #4
0
    def after_notification_of_parent_or_state(self, model, prop_name, info):

        # avoid updates because of execution status updates or while multi-actions
        if self.check_no_update_flags_and_return_combined_flag(prop_name, info):
            return

        overview = NotificationOverview(info)

        if overview.get_cause() == 'parent' and overview.get_affected_core_element() is self.model.state or \
                overview.get_affected_core_element() in [self.model.state, self.model.state.parent] and \
                overview.get_cause() in ['name', 'group_states', 'ungroup_state', 'change_data_type',
                                                "remove_input_data_port", "remove_output_data_port",
                                                "remove_scoped_variable", "remove_data_flow"]:
            self.update(initiator=str(overview))
예제 #5
0
    def states_update(self, model, prop_name, info):

        if is_execution_status_update_notification_from_state_machine_model(prop_name, info) or \
                self._ongoing_complex_actions:
            return

        overview = NotificationOverview(info)

        if overview.get_affected_property() == 'state' and \
                overview.get_cause() in ["name"]:  # , "add_state", "remove_state"]:
            self.update_tree_store_row(overview.get_affected_model())
        # TODO check the work around for get_library_root_state -> maybe the notifications can be avoided if upper lib
        elif overview.get_affected_property() == 'state' and not overview.get_affected_model().state.get_next_upper_library_root_state() and \
                overview.get_cause() in ["add_state", "remove_state"]:
            self.update(overview.get_affected_model())
예제 #6
0
    def assign_notification_states_before(self, model, prop_name, info):
        if self.busy:  # if proceeding undo or redo
            return
        else:
            # avoid to vast computation time
            if 'kwargs' in info and 'method_name' in info['kwargs'] and \
                    info['kwargs']['method_name'] in BY_EXECUTION_TRIGGERED_OBSERVABLE_STATE_METHODS:
                return

            overview = NotificationOverview(info)

            # skipped state modifications
            if not overview.get_change(
            ) == 'state_change' or overview.get_cause() == 'parent':
                return

            # increase counter and generate new action if not locked by action that is performed
            if self.locked:
                self.before_count()
            else:
                if self.start_new_action(overview):
                    self.before_count()
                else:
                    logger.error(
                        "FAILED to start NEW HISTORY ELEMENT [states]")
예제 #7
0
    def assign_notification_root_state_after(self, model, prop_name, info):
        """
        This method is called, when any state, transition, data flow, etc. within the state machine modifications. This
        then typically requires a redraw of the graphical editor, to display these modifications immediately.
        :param model: The state machine model
        :param prop_name: The property that was changed
        :param info: Information about the change
        """
        # execution_status-changes are not observed
        if self.busy or info.method_name in BY_EXECUTION_TRIGGERED_OBSERVABLE_STATE_METHODS:
            return
        else:
            overview = NotificationOverview(info)

            # handle interrupts of action caused by exceptions
            if overview.get_result() == "CRASH in FUNCTION" or isinstance(
                    overview.get_result(), Exception):
                if self.count_before == 1:
                    return self._interrupt_active_action(info)
                pass

            # modifications of parent are not observed
            if overview.get_cause() == 'parent':
                return

            # decrease counter and finish action when reaching count=0
            if self.locked:
                self.after_count()
                if self.count_before == 0:
                    self.finish_new_action(overview)
            else:
                logger.error(
                    "HISTORY after not count [root_state] -> For every before there should be a after."
                )
예제 #8
0
    def after_notification_of_parent_or_state_from_lists(
            self, model, prop_name, info):
        """ Activates the update after update if outcomes, transitions or states list has been changed.
        """
        # avoid updates because of execution status updates or while multi-actions
        if self.check_no_update_flags_and_return_combined_flag(
                prop_name, info):
            return

        overview = NotificationOverview(info)
        if overview.get_cause() not in [
                'name',
                'append',
                '__setitem__',  # '__delitem__', 'remove'
                'from_outcome',
                'to_outcome',
                'from_state',
                'to_state',
                'modify_origin',
                'modify_target'
        ]:
            if self.model.parent:
                # check for sibling port change
                if prop_name == 'states' and overview.get_affected_core_element() is self.model.parent.state and \
                        (overview.get_affected_core_element() in self.model.parent.state.states and
                         overview.get_cause() in ['add_outcome'] or
                         overview.get_affected_property() in ['outcome'] and
                         overview.get_cause() in ['name']):
                    pass
                else:
                    return
            else:
                return

        try:
            self.update(initiator=str(overview))
        except KeyError as e:
            if self.debug_log:
                import traceback
                self.store_debug_log_file(str(overview))
                self.store_debug_log_file(str(traceback.format_exc()))
            logger.error(
                "update of transition widget fails while detecting list change of state %s %s %s\n%s"
                % (self.model.state.name, self.model.state.state_id, e, self))
예제 #9
0
    def states_update_before(self, model, prop_name, info):
        overview = NotificationOverview(info)
        if not overview.caused_modification():
            return

        if overview.get_affected_property() == 'state' and \
                overview.get_cause() in ["change_state_type"]:
            changed_model = self._selected_sm_model.get_state_model_by_path(
                overview.get_method_args()[1].get_path())
            self.observe_model(changed_model)
예제 #10
0
    def states_update_before(self, model, prop_name, info):

        if is_execution_status_update_notification_from_state_machine_model(prop_name, info):
            return

        overview = NotificationOverview(info, False, self.__class__.__name__)

        if overview['prop_name'][-1] == 'state' and \
                overview.get_cause() in ["change_state_type"]:
            changed_model = self._selected_sm_model.get_state_model_by_path(overview['args'][-1][1].get_path())
            self.observe_model(changed_model)
예제 #11
0
 def notify_state_name_change(self, model, prop_name, info):
     """Checks whether the name of a state was changed and change the tab label accordingly
     """
     overview = NotificationOverview(info)
     # avoid updates or checks because of execution status updates
     if not overview.caused_modification():
         return
     changed_model = overview.get_affected_model()
     method_name = overview.get_cause()
     if isinstance(changed_model, AbstractStateModel) and method_name in ['name', 'script_text']:
         self.update_tab_label(changed_model)
예제 #12
0
    def notify_state_name_change(self, model, prop_name, info):
        """Checks whether the name of a state was changed and change the tab label accordingly
        """
        # avoid updates or checks because of execution status updates
        if is_execution_status_update_notification_from_state_machine_model(prop_name, info):
            return

        overview = NotificationOverview(info, False, self.__class__.__name__)
        changed_model = overview['model'][-1]
        method_name = overview.get_cause()
        if isinstance(changed_model, AbstractStateModel) and method_name in ['name', 'script_text']:
            self.update_tab_label(changed_model)
예제 #13
0
    def on_state_execution_status_changed_after(self, model, prop_name, info):
        """ Show current execution status in the widget

        This function specifies what happens if the state machine execution status of a state changes
        
        :param model: the model of the state that has changed (most likely its execution status)
        :param prop_name: property name that has been changed
        :param info: notification info dictionary
        :return:
        """
        from rafcon.gui.utils.notification_overview import NotificationOverview
        from rafcon.core.states.state import State

        def name_and_next_state(state):
            assert isinstance(state, State)
            if state.is_root_state_of_library:
                return state.parent.parent, state.parent.name
            else:
                return state.parent, state.name

        def create_path(state, n=3, separator='/'):
            next_parent, name = name_and_next_state(state)
            path = separator + name
            n -= 1
            while n > 0 and isinstance(next_parent, State):
                next_parent, name = name_and_next_state(next_parent)
                path = separator + name + path
                n -= 1
            if isinstance(next_parent, State):
                path = separator + '..' + path
            return path

        if 'kwargs' in info and 'method_name' in info['kwargs']:
            overview = NotificationOverview(info)
            if overview.get_cause() == 'state_execution_status':
                active_state = overview.get_affected_model().state
                assert isinstance(active_state, State)

                path_depth = rafcon.gui.singleton.global_gui_config.get_config_value(
                    "EXECUTION_TICKER_PATH_DEPTH", 3)

                message = self._fix_text_of_label + create_path(
                    active_state, path_depth)
                if rafcon.gui.singleton.main_window_controller.view is not None:
                    self.ticker_text_label.set_text(message)
                else:
                    logger.warning("Not initialized yet")
예제 #14
0
    def assign_notification_root_state_before(self, model, prop_name, info):
        # execution_status-changes are not observed
        if self.busy or info.method_name in BY_EXECUTION_TRIGGERED_OBSERVABLE_STATE_METHODS:
            return
        # first element should be prop_name="state_machine", instance=StateMachine and model=StateMachineModel
        # second element should be Prop_name="states" if root_state child elements are changed
        # --- for root_state elements it has to be prop_name in ["data_flows", "transitions", "input_data_ports",
        #                                                        "output_data_ports", "scoped_variables"]
        # third (and last element) should be prop_name in ["data_flow", "transition", ...
        else:
            overview = NotificationOverview(info)
            # modifications of parent are not observed
            if overview.get_cause() == 'parent':
                return

            # increase counter and generate new action if not locked by action that is performed
            if self.locked:
                self.before_count()
            else:
                if self.start_new_action(overview):
                    self.before_count()
                else:
                    logger.error(
                        "FAILED to start NEW HISTORY ELEMENT [root_state]")
예제 #15
0
 def execution_change(self, model, prop_name, info):
     from rafcon.gui.utils.notification_overview import NotificationOverview
     overview = NotificationOverview(info)
     if overview.get_cause() == 'state_execution_status':
         self.last_execution_change_at_state = overview.get_affected_model(
         ).state.get_path()