mscelement.py 8.11 KB
Newer Older
Maxime Perrotin's avatar
Maxime Perrotin committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
#******************************************************************************
#
# TASTE Msc Diagram Editor
# http://taste.tuxfamily.org/
#
#  This file is part of TASTE Msc Editor.
#
#  TASTE Msc Diagram Editor is free software: you can redistribute it and/or
#  modify it under the terms of the GNU General Public License as published
#  by the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#
#  TASTE Msc Diagram Editor is distributed in the hope that it will be
#  useful,(but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with TASTE Msc Diagram Editor.  If not, see
#  <http://www.gnu.org/licenses/>.
#
#  Author: Angel Esquinas <aesquina@datsi.fi.upm.es>
#
#  Copyright (c) 2012 European Space Agency
#
#******************************************************************************
"""
.. This docstring is intended to use with sphinx.

The :class:`msccore.MscElement` class is the base class of almost all msc \
elements. This class is intended to be subclassed.

It is a subclass of :class:`QtCore.QObject`, so it can use \
:class:`QtCore.Signal`. The :class:`msccore.MscElement` declares two \
:class:`~QtCore.Signal`: :attr:`MscElement.dataHasChanged` to notify when \
internal data structures or attributes of elements have been modified, and \
:attr:`~MscElement.nameChanged` to notify when the element's name has been
changed.

The :class:`MscElement` has the attribute :attr:`MscElement.Name` to hold \
the name of the element. To modify the name of the element use the method
:meth:`MscElement.setName` and to read the name of the element use
:meth:`MscElement.name`.
"""
45
from PySide.QtCore import QObject, Signal, QRegExp
Maxime Perrotin's avatar
Maxime Perrotin committed
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108

import mscregexp


class MscElement(QObject):
    '''
    Constructs a :class:`MscElement` with the `name` and the given `parent`.

    :param name: default empty string, Name of the element.
    :type name: unicode
    :param parent: default None
    :type parent: QObject

    '''
    # String to print type of object
    TYPE = 'MscElement'

    # Signal that must be emitted when data of the element has changed.
    # dataChangedSignal = Signal()
    dataHasChanged = Signal()
    """
    :attr:`dataHasChanged` notify when internal properties of the
    :class:`MscElement` instance have changed.

    This signal is emitted within :meth:`dataChanged` method. When 
    :attr:`dataHasChanged` is emitted, :attr:`contentsChanged` should also be
    emitted, because if the internal properties of `MscElement` are modified
    this implies that the contents of the object have also changed.

    .. seealso::
       :attr:`MscElement.contentsChanged`, :meth:`MscElement.dataChanged`
    """

    nameChanged = Signal(unicode)
    """:param unicode: The new name.
       :type unicode: unicode"""

    contentsChanged = Signal()
    u"""
    :attr:`contentsChanged` signal is emitted when changes in the its
    child objects or changes in itself exist.

    When data is changed in an element, because of new objects or other change,
    this signal must be emitted. The difference with :attr:`dataHasChanged`
    signal is that dataHasChanged is only emitted when the data is changed
    in the object itself, not if it's changed in any of its child elements.

    .. seealso::

       :meth:`MscElement.dataChanged`, :attr:`MscElement.dataHasChanged`
    """

    deleted = Signal(QObject)
    u"""
    :attr:`deleted` signal is emitted before the :class:`MscElement` object \
    is deleted.

    This signal is emitted within :meth:`MscElement.delete` method.

    .. seealso::
       :meth:`MscElement.delete`
    """

109 110
    _NameRegExp = None

Maxime Perrotin's avatar
Maxime Perrotin committed
111 112 113 114 115 116
    def __init__(self, name='', parent=None, elemType=TYPE):
        '''
        construct
        '''
        super(MscElement, self).__init__(parent)
        self._name = ''
117 118
        if not self._NameRegExp:
            self._NameRegExp = QRegExp('(' + mscregexp.Name + ')')
Maxime Perrotin's avatar
Maxime Perrotin committed
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
        self.elemType = elemType
        self.setName(name)
        self._comment = u""

    def setNameRegExp(self, reg=None):
        u"""
        Set :class:`QtCore.QRegExp` `reg` as the validator to allow the change
        of `name` property using :meth:`MscElement.setName`.

        :param reg: default `None`, :class:Pyside.QtCore.RegExp

        """

        self._NameRegExp = reg

    #  Name
    def getName(self):
        return self.name()

    def name(self):
        u'''
        Return the name of the element

        :rtype: unicode
        '''
        return self._name

    def setName(self, name):
        '''
        Set the name of the element.

        :param unicode name: Name of the element.

        Each :class:`MscElement` object should have a different name.
        The `name` property is changed with the `name` content if the
        :data:`msccore.mscregexp.NameRegExpr` property is not set or in case
        it is, the `name` is  partially or fully accepted.

        By default, this property contains an empty string
        '''
        # isCorrect = self.filterName(name)
        if self._NameRegExp.indexIn(name) > -1:
            accepted = self._NameRegExp.cap(1)
            self._name = accepted
            self.nameChanged.emit(self._name)
        self.dataChanged()

    def setExpression(self, expr):
        u"""
        Sets or changes internal properties based on `expr`.

        :param unicode expr: Expression to obtain the data.

        If this function is needed it has to be subclassed.

        *Example:*
           "process <<in>> extern" could be separated into 3 expressions,
           (process, <<in>>, extern) to set class properties.

        By default, this function calls :meth:`MscElement.setName` with `expr`
        as argument.
        """
        return self.setName(expr)

    # Comment
    def setComment(self, comment=u""):
        u"""
        Set the comment of the object.

        :param commment: unicode

        This property holds the comment of the object.

        By default, this property contains an empty string

        .. note:: After the property has changed this method calls \
        :meth:`MscElement.dataChanged` emitting the \
        :attr:`~MscElement.dataHasChanged` Signal.
        """
        self._comment = comment
        self.dataChanged()

    def comment(self):
        u"""
        Return the comment.

        :rtype: unicode

        This property holds the comment of the object.

        By default, this property contains an empty string
        """
        return self._comment

    def dataChanged(self):
        '''
        This function must be called when internal properties of the object
        have changed. It emits both the "dataChanged" signal
        and 'contentsChanged' signal.
        '''
        self.dataHasChanged.emit()
        self.contentsChanged.emit()
        #self.dataChangedSignal.emit()

    def _contentsChanged(self):
        """
        This function must be called when internal properties of the object
        or any of its childs have changed.

        This function can be overriden to add more functionality.
        """
        self.contentsChanged.emit()

    #Delete
    def delete(self):
        u"""
        This method must be overriden. By default only the signal
        :attr:`MscElement.deleted` is emitted.

        This method should be called inside the overriding method to
        emit the :attr:`MscElement.deleted` before
        any operation is done. This allows any other object that has a
        reference to this object know that it will be deleted and remove
        all of its references.
        """
        self.deleted.emit(self)

    def accept(self, visitor):
        u'''
        Implements the visitor pattern.

        :param visitor:
        :type visitor: msccore.MscVisitor

        .. note:: This function must be overriden in a subclass to use the \
        visitor pattern.
        '''
        pass

    # OUTPUT
    def __str__(self):
        return "<<{0}: {1}. Comment {2}>>".format(self.elemType, self._name,
                                                  self.comment())