docs: def model_changed(self, model, prop_name, info):
          """This method notifies the model lists and the parent state about changes
  
          The method is called each time, the model is changed. This happens, when the state itself changes or one of
          its children (outcomes, ports) changes. Changes of the children cannot be observed directly,
          therefore children notify their parent about their changes by calling this method.
          This method then checks, what has been changed by looking at the method that caused the change. In the
          following, it notifies the list in which the change happened about the change.
          E.g. one input data port changes its name. The model of the port observes itself and notifies the parent (
          i.e. the state model) about the change by calling this method with the information about the change. This
          method recognizes that the method "modify_input_data_port" caused the change and therefore triggers a notify
          on the list if input data port models.
          "_notify_method_before" is used as trigger method when the changing function is entered and
          "_notify_method_after" is used when the changing function returns. This changing function in the example
          would be "modify_input_data_port".
  
          :param model: The model that was changed
          :param prop_name: The property that was changed
          :param info: Information about the change (e.g. the name of the changing function)
          """
          # If this model has been changed (and not one of its child states), then we have to update all child models
          # This must be done before notifying anybody else, because other may relay on the updated models
          if 'after' in info and self.state == info['instance']:
              self.update_models(model, prop_name, info)
  
          # mark the state machine this state belongs to as dirty
          no_save_change = info["method_name"] in BY_EXECUTION_TRIGGERED_OBSERVABLE_STATE_METHODS
          if isinstance(model, AbstractStateModel) and prop_name == "state" and no_save_change:
              # do not track the active flag when marking the sm dirty
              pass
          else:
              # if the state_execution state is changed the sm must not be marked dirty
              if "after" in info and info["method_name"] not in BY_EXECUTION_TRIGGERED_OBSERVABLE_STATE_METHODS:
                  self._mark_state_machine_as_dirty()
  
          changed_list = None
          cause = None
  
          if isinstance(model, DataPortModel) and model.parent is self:
              if model in self.input_data_ports:
                  changed_list = self.input_data_ports
                  cause = "input_data_port_change"
              elif model in self.output_data_ports:
                  changed_list = self.output_data_ports
                  cause = "output_data_port_change"
  
          elif isinstance(info.instance, Income) and self is model.parent:
              changed_list = self.income
              cause = "income_change"
  
          elif isinstance(info.instance, Outcome) and self is model.parent:
              changed_list = self.outcomes
              cause = "outcome_change"
  
          if not (cause is None or cause is "income_change" or changed_list is None):
              if 'before' in info:
                  changed_list._notify_method_before(self.state, cause, (self.state,), info)
              elif 'after' in info:
                  changed_list._notify_method_after(self.state, cause, None, (self.state,), info)
  
          # Notifies parent state
          super(StateModel, self).model_changed(model, prop_name, info)