Example #1
0
    def __init__(self, parent, meta=None):
        MetaModel.__init__(self, meta)

        self.parent = parent
        self.destruction_signal = Signal()

        # this class is an observer of its own properties:
        self.register_observer(self)
Example #2
0
    def __init__(self, parent_signal=None):
        ModelMT.__init__(self)

        self._selected = set()
        self._input_data_ports = set()
        self._output_data_ports = set()
        self._outcomes = set()
        self._data_flows = set()
        self._transitions = set()
        self._states = set()
        self._scoped_variables = set()
        self.selection_changed_signal = Signal()
        self.focus_signal = Signal()
        self.parent_signal = parent_signal
Example #3
0
    def __init__(self, meta=None):
        ModelMT.__init__(self)

        if isinstance(meta, dict):
            self.meta = Vividict(meta)
        else:
            self.meta = Vividict()
        self.temp = Vividict()

        self.meta_signal = Signal()
Example #4
0
    def __init__(self, state, parent=None, meta=None):
        if type(self) == AbstractStateModel:
            raise NotImplementedError

        MetaModel.__init__(self, meta)
        assert isinstance(state, State)
        self.is_start = False

        self.state = state

        self.parent = parent

        self.meta_signal = Signal()
        self.action_signal = Signal()
        self.destruction_signal = Signal()

        self.register_observer(self)

        self.input_data_ports = []
        self.output_data_ports = []
        self.outcomes = []
        self._load_input_data_port_models()
        self._load_output_data_port_models()
        self._load_outcome_models()
Example #5
0
class StateElementModel(MetaModel, Hashable):
    """This model class serves as base class for all models within a state model (ports, connections)

    Each state element model has a parent, meta and temp data. If observes itself and informs the parent about changes.

    :param rafcon.gui.models.abstract_state.AbstractStateModel parent: The state model of the state element
    :param rafcon.utils.vividict.Vividict meta: The meta data of the state element model
    """

    _parent = None
    meta_signal = Signal()
    destruction_signal = Signal()

    __observables__ = ("meta_signal", "destruction_signal")

    def __init__(self, parent, meta=None):
        MetaModel.__init__(self, meta)

        self.parent = parent
        self.destruction_signal = Signal()

        # this class is an observer of its own properties:
        self.register_observer(self)

    def __eq__(self, other):
        if type(self) != type(other):
            return False
        if self.core_element != other.core_element:
            return False
        if self.meta != other.meta:
            return False
        return True

    def __ne__(self, other):
        return not self.__eq__(other)

    def __cmp__(self, other):
        if isinstance(other, StateElementModel):
            return self.core_element.__cmp__(other.core_element)

    def update_hash(self, obj_hash):
        self.update_hash_from_dict(obj_hash, self.core_element)
        if self.parent and not self.parent.state.get_library_root_state():
            self.update_hash_from_dict(obj_hash, self.meta)

    @property
    def parent(self):
        """Getter for the parent state model of the state element

        :return: None if parent is not defined, else the model of the parent state
        :rtype: rafcon.gui.models.abstract_state.AbstractState
        """
        if not self._parent:
            return None
        return self._parent()

    @parent.setter
    def parent(self, parent_m):
        """Setter for the parent state model of the state element

        :param rafcon.gui.models.abstract_state.AbstractState parent_m: Parent state model or None
        """
        if isinstance(parent_m, AbstractStateModel):
            self._parent = ref(parent_m)
        else:
            self._parent = None

    @property
    def core_element(self):
        """Return the core element represented by this model

        :return: core element of the model
        :rtype: rafcon.core.state_elements.state_element.StateElement
        """
        raise NotImplementedError()

    def get_state_machine_m(self):
        if self.parent:
            return self.parent.get_state_machine_m()
        return None

    def prepare_destruction(self):
        """Prepares the model for destruction

        Unregisters the model from observing itself.
        """
        if self.core_element is None:
            logger.verbose(
                "Multiple calls of prepare destruction for {0}".format(self))
        self.destruction_signal.emit()
        try:
            self.unregister_observer(self)
        except KeyError:  # Might happen if the observer was already unregistered
            pass

    def model_changed(self, model, prop_name, info):
        """This method notifies the parent state about changes made to the state element
        """
        if self.parent is not None:
            self.parent.model_changed(model, prop_name, info)

    @ModelMT.observe("meta_signal", signal=True)
    def meta_changed(self, model, prop_name, info):
        """This method notifies the parent state about changes made to the meta data
        """
        if self.parent is not None:
            msg = info.arg
            # Add information about notification to the signal message
            notification = Notification(model, prop_name, info)
            msg = msg._replace(notification=notification)
            info.arg = msg
            self.parent.meta_changed(model, prop_name, info)
Example #6
0
class Selection(ModelMT):
    """ This class contains the selected models of a state_machine """
    _selected = None
    _input_data_ports = None
    _output_data_ports = None
    _scoped_variables = None
    _outcomes = None
    _data_flows = None
    _transitions = None
    _states = None

    _focus = None

    selection_changed_signal = Signal()
    focus_signal = Signal()

    __observables__ = ("selection_changed_signal", "focus_signal")

    def __init__(self, parent_signal=None):
        ModelMT.__init__(self)

        self._selected = set()
        self._input_data_ports = set()
        self._output_data_ports = set()
        self._outcomes = set()
        self._data_flows = set()
        self._transitions = set()
        self._states = set()
        self._scoped_variables = set()
        self.selection_changed_signal = Signal()
        self.focus_signal = Signal()
        self.parent_signal = parent_signal

    def __str__(self):
        return_string = "Selected: "
        for item in self._selected:
            return_string = "%s, %s" % (return_string, str(item))
        return return_string

    def _check_model_types(self, models):
        """ Check types of passed models for correctness and in case raise exception

        :rtype: set
        :returns: set of models that are valid for the class"""
        if not hasattr(models, "__iter__"):
            models = {models}
        if not all([
                isinstance(model, (AbstractStateModel, StateElementModel))
                for model in models
        ]):
            raise TypeError(
                "The selection supports only models with base class AbstractStateModel or "
                "StateElementModel, see handed elements {0}".format(models))
        return models if isinstance(models, set) else set(models)

    @updates_selection
    def add(self, models):
        """ Adds the passed model(s) to the selection"""
        if models is None:
            return

        models = self._check_model_types(models)
        self._selected.update(models)
        self._selected = reduce_to_parent_states(self._selected)

    @updates_selection
    def remove(self, models):
        """ Removed the passed model(s) from the selection"""
        models = self._check_model_types(models)
        for model in models:
            if model in self._selected:
                self._selected.remove(model)

    @updates_selection
    def set(self, models):
        """ Sets the selection to the passed model(s) """
        # Do not add None values to selection
        if models is None:
            models = set()

        models = self._check_model_types(models)
        if len(models) > 1:
            models = reduce_to_parent_states(models)

        self._selected = set(models)

    @updates_selection
    def clear(self):
        """ Removes all models from the selection """
        self._selected.clear()

    @updates_selection
    def handle_prepared_selection_of_core_class_elements(
            self, core_class, models):
        """Handles the selection for TreeStore widgets maintaining lists of a specific `core_class` elements

        If widgets hold a TreeStore with elements of a specific `core_class`, the local selection of that element
        type is handled by that widget. This method is called to integrate the local selection with the overall
        selection of the state machine.

        If no modifier key (indicating to extend the selection) is pressed, the state machine selection is set to the
        passed selection. If the selection is to be extended, the state machine collection will consist of the widget
        selection plus all previously selected elements not having the core class `core_class`.

        :param State | StateElement core_class: The core class of the elements the widget handles
        :param models: The list of models that are currently being selected locally
        """
        if extend_selection():
            self._selected.difference_update(
                self.get_selected_elements_of_core_class(core_class))
        else:
            self._selected.clear()

        models = self._check_model_types(models)
        if len(models) > 1:
            models = reduce_to_parent_states(models)

        self._selected.update(models)

    @updates_selection
    def handle_new_selection(self, models):
        """Handles the selection for generic widgets

        This is a helper method for generic widgets that want to modify the selection. These widgets can pass a list
        of newly selected (or clicked on) models.

        The method looks at the previous selection, the passed models and the lift of pressed (modifier) keys:

        * If no modifier key is pressed, the previous selection is cleared and the new selection is set to the passed
          models
        * If the extend-selection modifier key is pressed, elements of `models` that are _not_ in the previous
          selection are selected, those that are in the previous selection are deselected

        :param models: The list of models that are newly selected/clicked on
        """
        models = self._check_model_types(models)

        if extend_selection():
            already_selected_elements = models & self._selected
            newly_selected_elements = models - self._selected
            self._selected.difference_update(already_selected_elements)
            self._selected.update(newly_selected_elements)
        else:
            self._selected = models
        self._selected = reduce_to_parent_states(self._selected)

    @property
    def focus(self):
        """ Returns the currently focused element """
        return self._focus

    @focus.setter
    def focus(self, model):
        """Sets the passed model as focused element

        :param ModelMT model: The element to be focused
        """
        if model is None:
            del self.focus
            return

        self._check_model_types(model)
        self.add(model)
        focus_msg = FocusSignalMsg(model, self._focus)
        self._focus = model
        self._selected.add(model)
        self._selected = reduce_to_parent_states(self._selected)
        self.focus_signal.emit(focus_msg)

    @focus.deleter
    def focus(self):
        """ Unsets the focused element """
        focus_msg = FocusSignalMsg(None, self._focus)
        self._focus = None
        self.focus_signal.emit(focus_msg)

    def __iter__(self):
        return self._selected.__iter__()

    def __len__(self):
        return len(self._selected)

    def __contains__(self, item):
        return item in self._selected

    def __getitem__(self, key):
        return [s for s in self._selected][key]

    def update_core_element_lists(self):
        """ Maintains inner lists of selected elements with a specific core element class """
        def get_selected_elements_of_core_class(core_class):
            return set(element for element in self._selected
                       if isinstance(element.core_element, core_class))

        self._states = get_selected_elements_of_core_class(State)
        self._transitions = get_selected_elements_of_core_class(Transition)
        self._data_flows = get_selected_elements_of_core_class(DataFlow)
        self._input_data_ports = get_selected_elements_of_core_class(
            InputDataPort)
        self._output_data_ports = get_selected_elements_of_core_class(
            OutputDataPort)
        self._scoped_variables = get_selected_elements_of_core_class(
            ScopedVariable)
        self._outcomes = get_selected_elements_of_core_class(Outcome)

    @property
    def states(self):
        """Returns all selected states

        :return: Subset of the selection, only containing states
        :rtype: set
        """
        return self._states

    @property
    def transitions(self):
        """Returns all selected transitions

        :return: Subset of the selection, only containing transitions
        :rtype: set
        """
        return self._transitions

    @property
    def data_flows(self):
        """Returns all selected data flows

        :return: Subset of the selection, only containing data flows
        :rtype: set
        """
        return self._data_flows

    @property
    def outcomes(self):
        """Returns all selected outcomes

        :return: Subset of the selection, only containing outcomes
        :rtype: set
        """
        return self._outcomes

    @property
    def input_data_ports(self):
        """Returns all selected input data ports

        :return: Subset of the selection, only containing input data ports
        :rtype: set
        """
        return self._input_data_ports

    @property
    def output_data_ports(self):
        """Returns all selected output data ports

        :return: Subset of the selection, only containing output data ports
        :rtype: set
        """
        return self._output_data_ports

    @property
    def scoped_variables(self):
        """Returns all selected scoped variables

        :return: Subset of the selection, only containing scoped variables
        :rtype: set
        """
        return self._scoped_variables

    def get_selected_elements_of_core_class(self, core_element_type):
        """Returns all selected elements having the specified `core_element_type` as state element class

        :return: Subset of the selection, only containing elements having `core_element_type` as state element class
        :rtype: set
        """
        if core_element_type is Outcome:
            return self.outcomes
        elif core_element_type is InputDataPort:
            return self.input_data_ports
        elif core_element_type is OutputDataPort:
            return self.output_data_ports
        elif core_element_type is ScopedVariable:
            return self.scoped_variables
        elif core_element_type is Transition:
            return self.transitions
        elif core_element_type is DataFlow:
            return self.data_flows
        elif core_element_type is State:
            return self.states
        raise RuntimeError("Invalid core element type: " + core_element_type)

    def is_selected(self, model):
        """Checks whether the given model is selected

        :param model:
        :return: True if the model is within the selection, False else
        :rtype: bool
        """
        if model is None:
            return len(self._selected) == 0
        return model in self._selected

    def get_all(self):
        """Return a copy of the selection

        :return: Copy of the set of selected elements
        :rtype: set
        """
        return set(s for s in self._selected)

    def get_selected_state(self):
        """Return the first state within the selection

        :return: First state within the selection or None if there is none
        :rtype: AbstractStateModel
        """
        if not self.states:
            return None
        else:
            return next(iter(self.states))  # sets don't support indexing

    @ModelMT.observe("destruction_signal", signal=True)
    def on_model_destruct(self, destructed_model, signal, info):
        """ Deselect models that are being destroyed """
        self.remove(destructed_model)
Example #7
0
class AbstractStateModel(MetaModel, Hashable):
    """This is an abstract class serving as base class for state models

    The model class is part of the MVC architecture. It holds the data to be shown (in this case a state).

    :param state: The state to be managed which can be any derivative of rafcon.core.states.state.State.
    :param AbstractStateModel parent: The state to be managed
    :param rafcon.utils.vividict.Vividict meta: The meta data of the state
     """

    _parent = None
    _is_about_to_be_destroyed_recursively = False
    is_start = None
    state = None
    outcomes = []
    input_data_ports = []
    output_data_ports = []
    meta_signal = Signal()
    action_signal = Signal()
    destruction_signal = Signal()

    __observables__ = ("state", "input_data_ports", "output_data_ports",
                       "outcomes", "is_start", "meta_signal", "action_signal",
                       "destruction_signal")

    def __init__(self, state, parent=None, meta=None):
        if type(self) == AbstractStateModel:
            raise NotImplementedError

        MetaModel.__init__(self, meta)
        assert isinstance(state, State)
        self.is_start = False

        self.state = state

        self.parent = parent

        self.meta_signal = Signal()
        self.action_signal = Signal()
        self.destruction_signal = Signal()

        self.register_observer(self)

        self.input_data_ports = []
        self.output_data_ports = []
        self.outcomes = []
        self._load_input_data_port_models()
        self._load_output_data_port_models()
        self._load_outcome_models()

    def __str__(self):
        return "Model of state: {0}".format(self.state)

    def __eq__(self, other):
        if type(self) != type(other):
            return False
        if self.state != other.state:
            return False
        if self.meta != other.meta:
            return False
        for attr in self.state.state_element_attrs:
            # E.g. compare lists of outcomes and data ports. The lists are converted to sets, as those are unordered
            if hasattr(getattr(self, attr), "__radd__"
                       ):  # elements are stored in a list (ObsListWrapper)
                elements = getattr(self, attr)
                other_elements = getattr(other, attr)
            else:  # elements are stored in a dict (ObsMapWrapper)
                elements = getattr(self, attr).items()
                other_elements = getattr(other, attr).items()
            if len(elements) != len(other_elements):
                return False
            if not all(
                [element in other_elements for element in other_elements]):
                return False
        return True

    def __ne__(self, other):
        return not self.__eq__(other)

    def __cmp__(self, other):
        if isinstance(other, AbstractStateModel):
            return self.core_element.__cmp__(other.core_element)

    def __contains__(self, item):
        """Checks whether `item` is an element of the state model

        Following child items are checked: outcomes, input data ports, output data ports

        :param item: :class:`StateModel` or :class:`StateElementModel`
        :return: Whether item is a direct child of this state
        :rtype: bool
        """
        from rafcon.gui.models.state_element import StateElementModel
        if not isinstance(item, StateElementModel):
            return False
        return item in self.outcomes or item in self.input_data_ports or item in self.output_data_ports

    def __copy__(self):
        state = copy(self.state)
        state_m = self.__class__(state,
                                 parent=None,
                                 meta=None,
                                 load_meta_data=False)
        state_m.copy_meta_data_from_state_m(self)
        return state_m

    def __deepcopy__(self, memo=None, _nil=[]):
        return self.__copy__()

    def update_is_start(self):
        """Updates the `is_start` property of the state
        
        A state is a start state, if it is the root state, it has no parent, the parent is a LibraryState or the state's
        state_id is identical with the ContainerState.start_state_id of the ContainerState it is within.
        """
        self.is_start = self.state.is_root_state or \
                        self.parent is None or \
                        isinstance(self.parent.state, LibraryState) or \
                        self.state.state_id == self.state.parent.start_state_id

    @property
    def core_element(self):
        return self.state

    @property
    def hierarchy_level(self):
        # TODO rewrite it to be more efficient -> try a recursive pattern on parent
        return len(self.state.get_path().split('/'))

    @property
    def hierarchy_level(self):
        return len(self.state.get_path().split('/'))

    def prepare_destruction(self, recursive=True):
        """Prepares the model for destruction

        Recursively un-registers all observers and removes references to child models
        """
        if self.state is None:
            logger.verbose(
                "Multiple calls of prepare destruction for {0}".format(self))
        self.destruction_signal.emit()
        try:
            self.unregister_observer(self)
        except KeyError:  # Might happen if the observer was already unregistered
            pass
        if recursive:
            for port in self.input_data_ports[:] + self.output_data_ports[:] + self.outcomes[:]:
                port.prepare_destruction()
        del self.input_data_ports[:]
        del self.output_data_ports[:]
        del self.outcomes[:]
        self.state = None

    def update_hash(self, obj_hash):
        self.update_hash_from_dict(obj_hash, self.core_element)
        for state_element in sorted(self.outcomes[:] +
                                    self.input_data_ports[:] +
                                    self.output_data_ports[:]):
            self.update_hash_from_dict(obj_hash, state_element)
        if not self.state.get_next_upper_library_root_state():
            self.update_hash_from_dict(obj_hash, self.meta)

    def update_meta_data_hash(self, obj_hash):
        super(AbstractStateModel, self).update_meta_data_hash(obj_hash)
        for state_element in sorted(self.outcomes[:] +
                                    self.input_data_ports[:] +
                                    self.output_data_ports[:]):
            state_element.update_meta_data_hash(obj_hash)

    @property
    def parent(self):
        if not self._parent:
            return None
        return self._parent()

    @parent.setter
    def parent(self, parent_m):
        if isinstance(parent_m, AbstractStateModel):
            self._parent = ref(parent_m)
        else:
            self._parent = None
        self.update_is_start()

    @property
    def is_about_to_be_destroyed_recursively(self):
        return self._is_about_to_be_destroyed_recursively

    @is_about_to_be_destroyed_recursively.setter
    def is_about_to_be_destroyed_recursively(self, value):
        if not isinstance(value, bool):
            raise TypeError(
                "The is_about_to_be_destroyed_recursively property has to be boolean."
            )
        self._is_about_to_be_destroyed_recursively = value

    def get_state_machine_m(self, two_factor_check=True):
        """ Get respective state machine model

        Get a reference of the state machine model the state model belongs to. As long as the root state model
        has no direct reference to its state machine model the state machine manager model is checked respective model.

        :rtype: rafcon.gui.models.state_machine.StateMachineModel
        :return: respective state machine model
        """
        from rafcon.gui.singleton import state_machine_manager_model
        state_machine = self.state.get_state_machine()
        if state_machine:
            if state_machine.state_machine_id in state_machine_manager_model.state_machines:
                sm_m = state_machine_manager_model.state_machines[
                    state_machine.state_machine_id]
                if not two_factor_check or sm_m.get_state_model_by_path(
                        self.state.get_path()) is self:
                    return sm_m
                else:
                    logger.debug(
                        "State model requesting its state machine model parent seems to be obsolete. "
                        "This is a hint to duplicated models and dirty coding")

        return None

    def get_input_data_port_m(self, data_port_id):
        """Returns the input data port model for the given data port id

        :param data_port_id: The data port id to search for
        :return: The model of the data port with the given id
        """
        for data_port_m in self.input_data_ports:
            if data_port_m.data_port.data_port_id == data_port_id:
                return data_port_m
        return None

    def get_output_data_port_m(self, data_port_id):
        """Returns the output data port model for the given data port id

        :param data_port_id: The data port id to search for
        :return: The model of the data port with the given id
        """
        for data_port_m in self.output_data_ports:
            if data_port_m.data_port.data_port_id == data_port_id:
                return data_port_m
        return None

    def get_data_port_m(self, data_port_id):
        """Searches and returns the model of a data port of a given state

        The method searches a port with the given id in the data ports of the given state model. If the state model
        is a container state, not only the input and output data ports are looked at, but also the scoped variables.

        :param data_port_id: The data port id to be searched
        :return: The model of the data port or None if it is not found
        """
        from itertools import chain
        data_ports_m = chain(self.input_data_ports, self.output_data_ports)
        for data_port_m in data_ports_m:
            if data_port_m.data_port.data_port_id == data_port_id:
                return data_port_m
        return None

    def get_outcome_m(self, outcome_id):
        """Returns the outcome model for the given outcome id

        :param outcome_id: The outcome id to search for
        :return: The model of the outcome with the given id
        """
        for outcome_m in self.outcomes:
            if outcome_m.outcome.outcome_id == outcome_id:
                return outcome_m
        return False

    def _load_input_data_port_models(self):
        raise NotImplementedError

    def _load_output_data_port_models(self):
        raise NotImplementedError

    def _load_outcome_models(self):
        raise NotImplementedError

    @ModelMT.observe("state", after=True, before=True)
    def model_changed(self, model, prop_name, info):
        """This method notifies parent state about changes made to the state
        """

        # Notify the parent state about the change (this causes a recursive call up to the root state)
        if self.parent is not None:
            self.parent.model_changed(model, prop_name, info)

        if prop_name == 'parent':
            self.update_is_start()

    @ModelMT.observe("action_signal", signal=True)
    def action_signal_triggered(self, model, prop_name, info):
        """This method notifies the parent state and child state models about complex actions
        """
        msg = info.arg
        # print "action_signal_triggered state: ", self.state.state_id, model, prop_name, info
        if msg.action.startswith('sm_notification_'):
            return
        # # affected child propagation from state
        # if hasattr(self, 'states'):
        #     for m in info['arg'].affected_models:
        #         print m, self.states
        #         print [m is mm for mm in self.states.itervalues()], [m in self for m in info['arg'].affected_models], \
        #             [m in self.states.values() for m in info['arg'].affected_models]
        if any([m in self for m in info['arg'].affected_models]):
            if not msg.action.startswith('parent_notification_'):
                new_msg = msg._replace(action='parent_notification_' +
                                       msg.action)
            else:
                new_msg = msg
            for m in info['arg'].affected_models:
                # print '???propagate it to', m, m.parent
                if isinstance(m, AbstractStateModel) and m in self:
                    # print '!!!propagate it from {0} to {1} {2}'.format(self.state.state_id, m.state.state_id, m)
                    m.action_signal.emit(new_msg)

        if msg.action.startswith('parent_notification_'):
            return

        # recursive propagation of action signal TODO remove finally
        if self.parent is not None:
            # Notify parent about change of meta data
            info.arg = msg
            # print "DONE1", self.state.state_id, msg
            self.parent.action_signal_triggered(model, prop_name, info)
            # print "FINISH DONE1", self.state.state_id, msg
        # state machine propagation of action signal (indirect) TODO remove finally
        elif not msg.action.startswith(
                'sm_notification_'):  # Prevent recursive call
            # If we are the root state, inform the state machine model by emitting our own meta signal.
            # To make the signal distinguishable for a change of meta data to our state, the change property of
            # the message is prepended with 'sm_notification_'
            # print "DONE2", self.state.state_id, msg
            new_msg = msg._replace(action='sm_notification_' + msg.action)
            self.action_signal.emit(new_msg)
            # print "FINISH DONE2", self.state.state_id, msg
        else:
            # print "DONE3 NOTHING"
            pass

    @ModelMT.observe("meta_signal", signal=True)
    def meta_changed(self, model, prop_name, info):
        """This method notifies the parent state about changes made to the meta data
        """
        msg = info.arg
        # print "meta_changed state: ", model, prop_name, info
        if msg.notification is None:
            # Meta data of this state was changed, add information about notification to the signal message
            notification = Notification(model, prop_name, info)
            msg = msg._replace(notification=notification)
            # print "DONE0 ", msg

        if self.parent is not None:
            # Notify parent about change of meta data
            info.arg = msg
            self.parent.meta_changed(model, prop_name, info)
            # print "DONE1 ", msg
        elif not msg.change.startswith(
                'sm_notification_'):  # Prevent recursive call
            # If we are the root state, inform the state machine model by emitting our own meta signal.
            # To make the signal distinguishable for a change of meta data to our state, the change property of
            # the message is prepended with 'sm_notification_'
            msg = msg._replace(change='sm_notification_' + msg.change)
            self.meta_signal.emit(msg)
            # print "DONE2 ", msg
        else:
            # print "DONE3 NOTHING"
            pass

    def _mark_state_machine_as_dirty(self):
        state_machine = self.state.get_state_machine()
        if state_machine:
            state_machine_id = state_machine.state_machine_id
            from rafcon.core.singleton import state_machine_manager
            if state_machine_id is not None and state_machine_id in state_machine_manager.state_machines:
                state_machine_manager.state_machines[
                    state_machine_id].marked_dirty = True
        if self.state.get_next_upper_library_root_state():
            lib_state_path = self.state.get_next_upper_library_root_state(
            ).parent.get_path()
            if self.get_state_machine_m().get_state_model_by_path(
                    lib_state_path).is_about_to_be_destroyed_recursively:
                return
            logger.warning(
                "You have modified core property of an inner state of a library state."
            )

    # ---------------------------------------- meta data methods ---------------------------------------------

    def load_meta_data(self, path=None):
        """Load meta data of state model from the file system

        The meta data of the state model is loaded from the file system and stored in the meta property of the model.
        Existing meta data is removed. Also the meta data of all state elements (data ports, outcomes,
        etc) are loaded, as those stored in the same file as the meta data of the state.

        This is either called on the __init__ of a new state model or if a state model for a container state is created,
        which then calls load_meta_data for all its children.

        :param str path: Optional file system path to the meta data file. If not given, the path will be derived from
            the state's path on the filesystem
        :return: if meta data file was loaded True otherwise False
        :rtype: bool
        """
        # TODO: for an Execution state this method is called for each hierarchy level again and again, still?? check it!
        # print "1AbstractState_load_meta_data: ", path, not path
        if not path:
            path = self.state.file_system_path
        # print "2AbstractState_load_meta_data: ", path
        if path is None:
            self.meta = Vividict({})
            return False
        path_meta_data = os.path.join(path, storage.FILE_NAME_META_DATA)

        # TODO: Should be removed with next minor release
        if not os.path.exists(path_meta_data):
            logger.debug(
                "Because meta data was not found in {0} use backup option {1}"
                "".format(path_meta_data,
                          os.path.join(path, storage.FILE_NAME_META_DATA_OLD)))
            path_meta_data = os.path.join(path,
                                          storage.FILE_NAME_META_DATA_OLD)
            # TODO use the following logger message to debug meta data load process and to avoid maybe repetitive loads
            # if not os.path.exists(path_meta_data):
            #     logger.info("path not found {0}".format(path_meta_data))

        try:
            # print "try to load meta data from {0} for state {1}".format(path_meta_data, self.state)
            tmp_meta = storage.load_data_file(path_meta_data)
        except ValueError as e:
            # if no element which is newly generated log a warning
            # if os.path.exists(os.path.dirname(path)):
            #     logger.debug("Because '{1}' meta data of {0} was not loaded properly.".format(self, e))
            if not path.startswith(
                    constants.RAFCON_TEMP_PATH_STORAGE) and not os.path.exists(
                        os.path.dirname(path)):
                logger.debug(
                    "Because '{1}' meta data of {0} was not loaded properly.".
                    format(self, e))
            tmp_meta = {}

        # JSON returns a dict, which must be converted to a Vividict
        tmp_meta = Vividict(tmp_meta)

        if tmp_meta:
            self._parse_for_element_meta_data(tmp_meta)
            # assign the meta data to the state
            self.meta = tmp_meta
            self.meta_signal.emit(MetaSignalMsg("load_meta_data", "all", True))
            return True
        else:
            # print "nothing to parse", tmp_meta
            return False

    def store_meta_data(self, copy_path=None):
        """Save meta data of state model to the file system

        This method generates a dictionary of the meta data of the state together with the meta data of all state
        elements (data ports, outcomes, etc.) and stores it on the filesystem.
        Secure that the store meta data method is called after storing the core data otherwise the last_stored_path is
        maybe wrong or None.
        The copy path is considered to be a state machine file system path but not the current one but e.g.
        of a as copy saved state machine. The meta data will be stored in respective relative state folder in the state
        machine  hierarchy. This folder has to exist.
        Dues the core elements of the state machine has to be stored first.

        :param str copy_path: Optional copy path if meta data is not stored to the file system path of state machine
        """
        if copy_path:
            meta_file_path_json = os.path.join(copy_path,
                                               self.state.get_storage_path(),
                                               storage.FILE_NAME_META_DATA)
        else:
            if self.state.file_system_path is None:
                logger.error(
                    "Meta data of {0} can be stored temporary arbitrary but by default first after the "
                    "respective state was stored and a file system path is set."
                    .format(self))
                return
            meta_file_path_json = os.path.join(self.state.file_system_path,
                                               storage.FILE_NAME_META_DATA)
        meta_data = deepcopy(self.meta)
        self._generate_element_meta_data(meta_data)
        storage_utils.write_dict_to_json(meta_data, meta_file_path_json)

    def copy_meta_data_from_state_m(self, source_state_m):
        """Dismiss current meta data and copy meta data from given state model

        The meta data of the given state model is used as meta data for this state. Also the meta data of all state
        elements (data ports, outcomes, etc.) is overwritten with the meta data of the elements of the given state.

        :param source_state_m: State model to load the meta data from
        """

        self.meta = deepcopy(source_state_m.meta)

        for input_data_port_m in self.input_data_ports:
            source_data_port_m = source_state_m.get_input_data_port_m(
                input_data_port_m.data_port.data_port_id)
            input_data_port_m.meta = deepcopy(source_data_port_m.meta)
        for output_data_port_m in self.output_data_ports:
            source_data_port_m = source_state_m.get_output_data_port_m(
                output_data_port_m.data_port.data_port_id)
            output_data_port_m.meta = deepcopy(source_data_port_m.meta)
        for outcome_m in self.outcomes:
            source_outcome_m = source_state_m.get_outcome_m(
                outcome_m.outcome.outcome_id)
            outcome_m.meta = deepcopy(source_outcome_m.meta)

        self.meta_signal.emit(MetaSignalMsg("copy_state_m", "all", True))

    def _parse_for_element_meta_data(self, meta_data):
        """Load meta data for state elements

        The meta data of the state meta data file also contains the meta data for state elements (data ports,
        outcomes, etc). This method parses the loaded meta data for each state element model. The meta data of the
        elements is removed from the passed dictionary.

        :param meta_data: Dictionary of loaded meta data
        """
        # print "_parse meta data", meta_data
        for data_port_m in self.input_data_ports:
            self._copy_element_meta_data_from_meta_file_data(
                meta_data, data_port_m, "input_data_port",
                data_port_m.data_port.data_port_id)
        for data_port_m in self.output_data_ports:
            self._copy_element_meta_data_from_meta_file_data(
                meta_data, data_port_m, "output_data_port",
                data_port_m.data_port.data_port_id)
        for outcome_m in self.outcomes:
            self._copy_element_meta_data_from_meta_file_data(
                meta_data, outcome_m, "outcome", outcome_m.outcome.outcome_id)

    @staticmethod
    def _copy_element_meta_data_from_meta_file_data(meta_data, element_m,
                                                    element_name, element_id):
        """Helper method to assign the meta of the given element

        The method assigns the meta data of the elements from the given meta data dictionary. The copied meta data is
        then removed from the dictionary.

        :param meta_data: The loaded meta data
        :param element_m: The element model that is supposed to retrieve the meta data
        :param element_name: The name string of the element type in the dictionary
        :param element_id: The id of the element
        """
        meta_data_element_id = element_name + str(element_id)
        meta_data_element = meta_data[meta_data_element_id]
        # print meta_data_element_id, element_m, meta_data_element
        element_m.meta = meta_data_element
        del meta_data[meta_data_element_id]

    def _generate_element_meta_data(self, meta_data):
        """Generate meta data for state elements and add it to the given dictionary

        This method retrieves the meta data of the state elements (data ports, outcomes, etc) and adds it to the
        given meta data dictionary.

        :param meta_data: Dictionary of meta data
        """
        for data_port_m in self.input_data_ports:
            self._copy_element_meta_data_to_meta_file_data(
                meta_data, data_port_m, "input_data_port",
                data_port_m.data_port.data_port_id)
        for data_port_m in self.output_data_ports:
            self._copy_element_meta_data_to_meta_file_data(
                meta_data, data_port_m, "output_data_port",
                data_port_m.data_port.data_port_id)
        for outcome_m in self.outcomes:
            self._copy_element_meta_data_to_meta_file_data(
                meta_data, outcome_m, "outcome", outcome_m.outcome.outcome_id)

    @staticmethod
    def _copy_element_meta_data_to_meta_file_data(meta_data, element_m,
                                                  element_name, element_id):
        """Helper method to generate meta data for meta data file for the given element

        The methods loads teh meta data of the given element and copies it into the given meta data dictionary
        intended for being stored on the filesystem.

        :param meta_data: The meta data to be stored
        :param element_m: The element model to get the meta data from
        :param element_name: The name string of the element type in the dictionary
        :param element_id: The id of the element
        """
        meta_data_element_id = element_name + str(element_id)
        meta_data_element = element_m.meta
        meta_data[meta_data_element_id] = meta_data_element

    def _meta_data_editor_gaphas2opengl(self, vividict):
        vividict = mirror_y_axis_in_vividict_element(vividict, 'rel_pos')
        if 'income' in vividict:
            del vividict['income']
        if 'name' in vividict:
            del vividict['name']
        return vividict

    def _meta_data_editor_opengl2gaphas(self, vividict):
        from rafcon.gui.helpers.meta_data import contains_geometric_info
        vividict = mirror_y_axis_in_vividict_element(vividict, 'rel_pos')
        if contains_geometric_info(vividict['size']):
            self.temp['conversion_from_opengl'] = True
            # Determine income position
            size = vividict['size']
            vividict['income']['rel_pos'] = (0, size[1] / 2.)

            # Determine size and position of NameView
            margin = min(size) / 12.
            name_height = min(size) / 8.
            name_width = size[0] - 2 * margin
            vividict['name']['size'] = (name_width, name_height)
            vividict['name']['rel_pos'] = (margin, margin)
        return vividict