docs: def state_machine_change_after(self, model, prop_name, info):
          """Called on any change within th state machine
  
          This method is called, when any state, transition, data flow, etc. within the state machine changes. This
          then typically requires a redraw of the graphical editor, to display these changes immediately.
  
          :param rafcon.gui.models.state_machine.StateMachineModel model: The state machine model
          :param str prop_name: The property that was changed
          :param dict info: Information about the change
          """
  
          if 'method_name' in info and info['method_name'] == 'root_state_change':
              method_name, model, result, arguments, instance = self._extract_info_data(info['kwargs'])
  
              if self.model.ongoing_complex_actions:
                  return
  
              # The method causing the change raised an exception, thus nothing was changed
              if (isinstance(result, string_types) and "CRASH" in result) or isinstance(result, Exception):
                  return
  
              # avoid to remove views of elements of states which parent state is destroyed recursively
              if 'remove' in method_name:
                  # for remove the model is always a state and in case of remove_state it is the container_state
                  # that performs the operation therefore if is_about_to_be_destroyed_recursively is False
                  # the child state can be removed and for True ignored because its parent will create a notification
                  if model.is_about_to_be_destroyed_recursively:
                      return
  
              # only react to the notification if the model is a model, which has to be drawn
              # if it is a model inside a library state, this is eventually not the case
              if isinstance(model, AbstractStateModel):
                  library_root_state = model.state.get_next_upper_library_root_state()
                  if library_root_state:
                      parent_library_root_state_m = self.model.get_state_model_by_path(library_root_state.get_path())
                      if not parent_library_root_state_m.parent.show_content():
                          return
  
              if method_name == 'state_execution_status':
                  state_v = self.canvas.get_view_for_model(model)
                  if state_v:  # Children of LibraryStates are not modeled, yet
                      self.canvas.request_update(state_v, matrix=False)
              elif method_name == 'add_state':
                  new_state = arguments[1]
                  new_state_m = model.states[new_state.state_id]
                  self.add_state_view_with_meta_data_for_model(new_state_m, model)
                  if not self.perform_drag_and_drop:
                      self.canvas.wait_for_update()
              elif method_name == 'remove_state':
                  state_v = self.canvas.get_view_for_core_element(result)
                  if state_v:
                      parent_v = self.canvas.get_parent(state_v)
                      state_v.remove()
                      if parent_v:
                          self.canvas.request_update(parent_v)
                      self.canvas.wait_for_update()
  
              # ----------------------------------
              #           TRANSITIONS
              # ----------------------------------
              elif method_name == 'add_transition':
                  transitions_models = model.transitions
                  transition_id = result
                  for transition_m in transitions_models:
                      if transition_m.transition.transition_id == transition_id:
                          self.add_transition_view_for_model(transition_m, model)
                          self.canvas.wait_for_update()
                          break
              elif method_name == 'remove_transition':
                  transition_v = self.canvas.get_view_for_core_element(result)
                  if transition_v:
                      state_m = model
                      state_v = self.canvas.get_view_for_model(state_m)
                      transition_v.remove()
                      self.canvas.request_update(state_v, matrix=False)
                      self.canvas.wait_for_update()
              elif method_name == 'transition_change':
                  transition_m = model
                  transition_v = self.canvas.get_view_for_model(transition_m)
                  self._reconnect_transition(transition_v, transition_m, transition_m.parent)
                  self.canvas.wait_for_update()
  
              # ----------------------------------
              #           DATA FLOW
              # ----------------------------------
              elif method_name == 'add_data_flow':
                  data_flow_models = model.data_flows
                  data_flow_id = result
                  for data_flow_m in data_flow_models:
                      if data_flow_m.data_flow.data_flow_id == data_flow_id:
                          self.add_data_flow_view_for_model(data_flow_m, model)
                          self.canvas.wait_for_update()
                          break
              elif method_name == 'remove_data_flow':
                  data_flow_v = self.canvas.get_view_for_core_element(result)
                  if data_flow_v:
                      state_m = model
                      state_v = self.canvas.get_view_for_model(state_m)
                      self.canvas.request_update(state_v, matrix=False)
                      data_flow_v.remove()
                      self.canvas.wait_for_update()
              elif method_name == 'data_flow_change':
                  data_flow_m = model
                  data_flow_v = self.canvas.get_view_for_model(data_flow_m)
                  self._reconnect_data_flow(data_flow_v, data_flow_m, data_flow_m.parent)
                  self.canvas.wait_for_update()
  
              # ----------------------------------
              #           OUTCOMES
              # ----------------------------------
              elif method_name == 'add_outcome':
                  state_m = model
                  state_v = self.canvas.get_view_for_model(state_m)
                  for outcome_m in state_m.outcomes:
                      if outcome_m.outcome.outcome_id == result:
                          state_v.add_outcome(outcome_m)
                          self.canvas.request_update(state_v, matrix=False)
                          self.canvas.wait_for_update()
                          break
              elif method_name == 'remove_outcome':
                  state_m = model
                  state_v = self.canvas.get_view_for_model(state_m)
                  if state_v is None:
                      logger.debug("no state_v found for method_name '{}'".format(method_name))
                  else:
                      outcome_v = self.canvas.get_view_for_core_element(result)
                      if outcome_v:
                          state_v.remove_outcome(outcome_v)
                          self.canvas.request_update(state_v, matrix=False)
                          self.canvas.wait_for_update()
  
              # ----------------------------------
              #           DATA PORTS
              # ----------------------------------
              elif method_name == 'add_input_data_port':
                  state_m = model
                  state_v = self.canvas.get_view_for_model(state_m)
                  for input_data_port_m in state_m.input_data_ports:
                      if input_data_port_m.data_port.data_port_id == result:
                          state_v.add_input_port(input_data_port_m)
                          self.canvas.request_update(state_v, matrix=False)
                          self.canvas.wait_for_update()
                          break
              elif method_name == 'add_output_data_port':
                  state_m = model
                  state_v = self.canvas.get_view_for_model(state_m)
                  for output_data_port_m in state_m.output_data_ports:
                      if output_data_port_m.data_port.data_port_id == result:
                          state_v.add_output_port(output_data_port_m)
                          self.canvas.request_update(state_v, matrix=False)
                          self.canvas.wait_for_update()
                          break
              elif method_name == 'remove_input_data_port':
                  state_m = model
                  state_v = self.canvas.get_view_for_model(state_m)
                  if state_v is None:
                      logger.debug("no state_v found for method_name '{}'".format(method_name))
                  else:
                      input_port_v = self.canvas.get_view_for_core_element(result)
                      if input_port_v:
                          state_v.remove_input_port(input_port_v)
                          self.canvas.request_update(state_v, matrix=False)
                          self.canvas.wait_for_update()
              elif method_name == 'remove_output_data_port':
                  state_m = model
                  state_v = self.canvas.get_view_for_model(state_m)
                  if state_v is None:
                      logger.debug("no state_v found for method_name '{}'".format(method_name))
                  else:
                      output_port_v = self.canvas.get_view_for_core_element(result)
                      if output_port_v:
                          state_v.remove_output_port(output_port_v)
                          self.canvas.request_update(state_v, matrix=False)
                          self.canvas.wait_for_update()
              elif method_name in ['data_type', 'change_data_type']:
                  pass
              elif method_name == 'default_value':
                  pass
  
              # ----------------------------------
              #         SCOPED VARIABLES
              # ----------------------------------
              elif method_name == 'add_scoped_variable':
                  state_m = model
                  state_v = self.canvas.get_view_for_model(state_m)
                  for scoped_variable_m in state_m.scoped_variables:
                      if scoped_variable_m.scoped_variable.data_port_id == result:
                          state_v.add_scoped_variable(scoped_variable_m)
                          self.canvas.request_update(state_v, matrix=False)
                          self.canvas.wait_for_update()
                          break
              elif method_name == 'remove_scoped_variable':
                  state_m = model
                  state_v = self.canvas.get_view_for_model(state_m)
                  if state_v is None:
                      logger.debug("no state_v found for method_name '{}'".format(method_name))
                  else:
                      scoped_variable_v = self.canvas.get_view_for_core_element(result)
                      if scoped_variable_v:
                          state_v.remove_scoped_variable(scoped_variable_v)
                          self.canvas.request_update(state_v, matrix=False)
                          self.canvas.wait_for_update()
  
              # ----------------------------------
              #        STATE MISCELLANEOUS
              # ----------------------------------
              elif method_name == 'name':
                  # The name of a state was changed
                  if not isinstance(model, AbstractStateModel):
                      parent_model = model.parent
                  # The name of a port (input, output, scoped var, outcome) was changed
                  else:
                      parent_model = model
                  state_v = self.canvas.get_view_for_model(parent_model)
                  if parent_model is model:
                      state_v.name_view.name = arguments[1]
                      self.canvas.request_update(state_v.name_view, matrix=False)
                  else:
                      self.canvas.request_update(state_v, matrix=False)
                  self.canvas.wait_for_update()
              elif method_name == 'parent':
                  pass
              elif method_name == 'description':
                  pass
              elif method_name == 'script_text':
                  pass
              # TODO handle the following method calls -> for now those are explicit (in the past implicit) ignored
              # TODO -> correct the complex actions which are used in some test (by test calls or by adapting the model)
              elif method_name in ['input_data_ports', 'output_data_ports', 'outcomes',
                                   'change_root_state_type', 'change_state_type',
                                   'group_states', 'ungroup_state', 'substitute_state']:
                  pass
              else:
                  known_ignore_list = ['set_input_runtime_value', 'set_use_input_runtime_value',  # from library State
                                       'set_output_runtime_value', 'set_use_output_runtime_value',
                                       'input_data_port_runtime_values', 'use_runtime_value_input_data_ports',
                                       'output_data_port_runtime_values', 'use_runtime_value_output_data_ports',
                                       'semantic_data', 'add_semantic_data', 'remove_semantic_data',
                                       'remove_income']
                  if method_name not in known_ignore_list:
                      logger.warning("Method {0} not caught in GraphicalViewer, details: {1}".format(method_name, info))
  
              if method_name in ['add_state', 'add_transition', 'add_data_flow', 'add_outcome', 'add_input_data_port',
                                 'add_output_data_port', 'add_scoped_variable', 'data_flow_change', 'transition_change']:
                  try:
                      self._meta_data_changed(None, model, 'append_to_last_change', True)
                  except Exception as e:
                      logger.exception('Error while trying to emit meta data signal {0} {1}'.format(e, model))