diff options
Diffstat (limited to 'lib/taurus/core/taurusmodel.py')
-rw-r--r-- | lib/taurus/core/taurusmodel.py | 262 |
1 files changed, 262 insertions, 0 deletions
diff --git a/lib/taurus/core/taurusmodel.py b/lib/taurus/core/taurusmodel.py new file mode 100644 index 00000000..4f11b9d8 --- /dev/null +++ b/lib/taurus/core/taurusmodel.py @@ -0,0 +1,262 @@ +#!/usr/bin/env python + +############################################################################# +## +## This file is part of Taurus +## +## http://taurus-scada.org +## +## Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain +## +## Taurus is free software: you can redistribute it and/or modify +## it under the terms of the GNU Lesser General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## Taurus 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 Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public License +## along with Taurus. If not, see <http://www.gnu.org/licenses/>. +## +############################################################################# + +"""This module contains the base TaurusModel class""" + +__all__ = ["TaurusModel"] + +__docformat__ = "restructuredtext" + +import weakref +import operator +import threading + +from .util.log import Logger +from .util.event import CallableRef, BoundMethodWeakref +from .taurusbasetypes import TaurusEventType, MatchLevel + +class TaurusModel(Logger): + + RegularEvent = (TaurusEventType.Change, TaurusEventType.Config, TaurusEventType.Periodic) + + def __init__(self,full_name, parent, serializationMode=None): + v = self.getNameValidator() + self._full_name, self._norm_name, self._simp_name = v.getNames(full_name, self.factory()) + + if self._full_name is None and self._norm_name and self._simp_name is None: + self.trace("invalid name") + + name = self._simp_name or self._norm_name or self._full_name or 'TaurusModel' + self.call__init__(Logger, name, parent) + + if serializationMode is None: + s_obj = parent + if s_obj is None: + s_obj = self.factory() + serializationMode = s_obj.getSerializationMode() + self._serialization_mode = serializationMode + + try: + self._parentObj = weakref.ref(parent) + except Exception: + self._parentObj = None + self._listeners = [] + + def __str__name__(self, name): + return '{0}({1})'.format(self.__class__.__name__, name) + + def __str__(self): + return self.__str__name__(self.getNormalName()) + + def __repr__(self): + return self.__str__name__(self.getFullName()) + + def cleanUp(self): + self.trace("[TaurusModel] cleanUp") + #self._parentObj = None + self._listeners = None + Logger.cleanUp(self) + + #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- + # API for Factory access + #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- + + @classmethod + def factory(cls): + raise RuntimeError("TaurusModel::factory cannot be called") + + #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- + # API for naming + #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- + + @classmethod + def getTaurusElementType(cls): + raise RuntimeError("TaurusModel::getTaurusElementType cannot be called") + + def getFullName(self): + return self._full_name + + def getNormalName(self): + return self._norm_name + + def getSimpleName(self): + return self._simp_name + + @classmethod + def isValid(cls, name, level = MatchLevel.ANY): + return cls.getNameValidator().isValid(name, level) + + @classmethod + def buildModelName(cls, parent_model, relative_name): + raise RuntimeError("TaurusModel::buildModelName cannot be called") + + @classmethod + def getNameValidator(cls): + raise RuntimeError("TaurusModel::getNameValidator cannot be called") + + #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- + # API for hierarchy access + #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- + + def getParentObj(self): + if self._parentObj is None: return None + return self._parentObj() + + def getChildObj(self,child_name): + return None + + #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- + # API for serialization + #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- + + def setSerializationMode(self, mode): + """Sets the serialization mode for the system. + + :param mode: (TaurusSerializationMode) the new serialization mode""" + self._serialization_mode = mode + + def getSerializationMode(self): + """Gives the serialization operation mode. + + :return: (TaurusSerializationMode) the current serialization mode""" + return self._serialization_mode + + #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- + # API for value access + #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- + + def getValueObj(self,cache=True): + raise RuntimeError("TaurusModel::getValueObj cannot be called") + + def getDisplayValue(self,cache=True): + raise RuntimeError("TaurusModel::getDisplayValue cannot be called") + + def getDisplayDescrObj(self,cache=True): + """A brief description of the model. Can be used as tooltip, for example""" + raise RuntimeError("TaurusModel::getDisplayDescrObj cannot be called") + + def getDisplayName(self,cache=True, complete=True): + full_name = self.getFullName() + normal_name = self.getNormalName() + simple_name = self.getSimpleName() + if simple_name: + ret = simple_name + if complete: ret += " (" + normal_name.upper() + ")" + elif normal_name: + ret = normal_name.upper() + else: + ret = full_name.upper() + return ret + + #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- + # API for listeners + #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- + + def _listenerDied(self, weak_listener): + if self._listeners is None: + return + try: + self._listeners.remove(weak_listener) + except Exception,e: + pass + + def _getCallableRef(self, listener, cb = None): + #return weakref.ref(listener, self._listenerDied) + meth = getattr(listener, 'eventReceived', None) + if meth is not None and operator.isCallable(meth): + return weakref.ref(listener, cb) + else: + return CallableRef(listener, cb) + + def addListener(self, listener): + if self._listeners is None or listener is None: + return False + + weak_listener = self._getCallableRef(listener, self._listenerDied) + if weak_listener in self._listeners: + return False + self._listeners.append(weak_listener) + return True + + def removeListener(self, listener): + if self._listeners is None: + return + weak_listener = self._getCallableRef(listener) + try: + self._listeners.remove(weak_listener) + except Exception,e: + return False + return True + + def forceListening(self): + class __DummyListener: + def eventReceived(self, *args): + pass + if not hasattr(self, '__dummyListener') or self.__dummyListener is None: + self.__dummyListener = __DummyListener() + self.addListener(self.__dummyListener) + + def unforceListening(self): + if hasattr(self, '__dummyListener') and self.__dummyListener is not None: + self.removeListener(self.__dummyListener) + self.__dummyListener = None + + def deleteListener(self, listener): + self.deprecated("Use removeListener(listener) instead") + self.removeListener(listener) + + def hasListeners(self): + """ returns True if anybody is listening to events from this attribute """ + if self._listeners is None: + return False + return len(self._listeners) > 0 + + def fireEvent(self, event_type, event_value, listeners=None): + """sends an event to all listeners or a specific one""" + + if listeners is None: + listeners = self._listeners + + if listeners is None: + return + + if not operator.isSequenceType(listeners): + listeners = listeners, + + for listener in listeners: + if isinstance(listener, weakref.ref) or isinstance(listener, BoundMethodWeakref): + l = listener() + else: + l = listener + if l is None: continue + meth = getattr(l, 'eventReceived', None) + if meth is not None and operator.isCallable(meth): + l.eventReceived(self, event_type, event_value) + elif operator.isCallable(l): + l(self, event_type, event_value) + + def isWritable(self): + return False + |