#!/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 .
##
###########################################################################
"""This configuration contains base modules and classes that may be used
by specific TaurusGui-based GUIs"""
__docformat__ = 'restructuredtext'
import os,sys
from lxml import etree
from taurus.qt.qtgui.util import ExternalAppAction
from taurus.qt.qtgui.util import TaurusWidgetFactory
from taurus.core.util.log import Logger
#this is here only for backwards compatibility. It should not be used at all
class Qt_Qt:
LeftDockWidgetArea = 1
RightDockWidgetArea = 2
BottomDockWidgetArea = 3
TopDockWidgetArea = 4
TAURUSGUI_AREAS = {'Left':Qt_Qt.LeftDockWidgetArea,
'Right':Qt_Qt.RightDockWidgetArea,
'Top':Qt_Qt.TopDockWidgetArea,
'Bottom':Qt_Qt.BottomDockWidgetArea}
class ExternalApp(object):
'''
A description of an external application.
Uses the same initialization as that of :class:`ExternalAppAction`
Use :meth:`getAction` to obtain an instance of a :class:`ExternalAppAction`
'''
def __init__(self, *args, **kwargs):
''' see :meth:`ExternalAppAction.__init__`'''
self.args = args
self.kwargs = kwargs
def getAction(self):
'''
Returns a :class:`ExternalAppAction` with the values used when
initializing this ExternalApp instance
:return: (ExternalAppAction)
'''
return ExternalAppAction(*self.args, **self.kwargs)
@staticmethod
def fromXml(xmlstring):
''' returns a ExternalApp object based on the xml string provided
:param xmlstring: (unicode) XML code defining the values for the
cmdargs, text, icon and parent variables
:return: (ExternalApp) an instance of ExternalApp
'''
try:
root = etree.fromstring(xmlstring)
except:
raise ValueError('Invalid XML syntax')
commandNode = root.find("command")
if (commandNode is not None) and (commandNode.text is not None):
command = commandNode.text
else:
raise ValueError('Invalid XML: is mandatory')
paramsNode = root.find("params")
if (paramsNode is not None) and (paramsNode.text is not None):
params = paramsNode.text
else:
params = ''
textNode = root.find("text")
if (textNode is not None) and (textNode.text is not None):
text = textNode.text
else:
text = None
iconNode = root.find("icon")
if (iconNode is not None) and (iconNode.text is not None):
icon = iconNode.text
else:
icon = None
return ExternalApp(" ".join((command,params)), text=text, icon=icon)
class TaurusGuiComponentDescription(object):
'''
A base class for describing a taurusgui component.
'''
def __init__(self,name, classname=None, modulename=None, widgetname=None,
sharedDataWrite=None, sharedDataRead=None,
model=None, floating=True, **kwargs):
self._name = name
self._modulename = modulename
self.setClassname(classname)
self.setWidgetname(widgetname)
if self.classname is None and (self.modulename is None or self.widgetname is None) :
raise ValueError('Module info must be given (except if passing a Taurus class name)')
self._floating = floating
if sharedDataWrite is None: sharedDataWrite = {}
self._sharedDataWrite = sharedDataWrite
if sharedDataRead is None: sharedDataRead = {}
self._sharedDataRead = sharedDataRead
self._model = model
def getName(self):
return self._name
def setName(self, name):
self._name = name
def getClassname(self):
return self._classname
def setClassname(self, classname):
if classname is not None and '.' in classname:
modulename,classname = classname.rsplit('.',1)
self.setModulename(modulename)
self._classname = classname
def getModulename(self):
return self._modulename
def setModulename(self, modulename):
self._modulename = modulename
def getWidgetname(self):
return self._widgetname
def setWidgetname(self, widgetname):
if widgetname is not None and '.' in widgetname:
modulename,widgetname = widgetname.rsplit('.',1)
self.setModulename(modulename)
self._widgetname = widgetname
def getArea(self):
raise DeprecationWarning('getArea is deprecated')
return self._area
def setArea(self, area):
raise DeprecationWarning('setArea is deprecated')
self._area = area
def isFloating(self):
return self._floating
def setFloating(self, floating):
self._floating = floating
def getSharedDataWrite(self):
return self._sharedDataWrite
def setSharedDataWrite(self, sharedDataWrite):
self._sharedDataWrite = sharedDataWrite
def getSharedDataRead(self):
return self._sharedDataRead
def setSharedDataRead(self, sharedDataRead):
self._sharedDataRead = sharedDataRead
def getModel(self):
return self._model
def setModel(self, model):
self._model = model
def getWidget(self, sdm=None, setModel=True):
''' Returns the widget to be inserted in the panel
:param sdm: (SharedDataManager) if given, the widget will be registered as reader
and/or writer in this manager as defined by the sharedDataRead and sharedDataWrite properties
:param setModel: (bool) if True (default) the widget will be given the model deined in the model property
:return: (QWidget) a new widget instance matching the description
'''
#instantiate the widget
if self.modulename is None:
klass = TaurusWidgetFactory().getWidgetClass(self.classname)
w = klass()
else:
module = __import__(self.modulename, fromlist=[''])
if self.classname is None:
w = getattr(module, self.widgetname)
else:
klass = getattr(module, self.classname)
w = klass()
#set the model if setModel is True
if self.model is not None and setModel:
w.setModel(self.model)
#connect (if an sdm is given)
if sdm is not None:
for dataUID,signalname in self.sharedDataWrite.iteritems():
sdm.connectWriter(dataUID, w, signalname)
for dataUID,slotname in self.sharedDataRead.iteritems():
sdm.connectReader(dataUID, getattr(w,slotname))
#set the name
w.name = self.name
return w
def toXml(self):
'''Returns a (unicode) XML code defining the PanelDescription object
:return: xmlstring
'''
root = etree.Element("PanelDescription")
name = etree.SubElement(root, "name")
name.text = self._name
classname = etree.SubElement(root, "classname")
classname.text = self._classname
modulename = etree.SubElement(root, "modulename")
modulename.text = self._modulename
widgetname = etree.SubElement(root, "widgetname")
widgetname.text = self._widgetname
floating = etree.SubElement(root, "floating")
floating.text = str(self._floating)
sharedDataWrite = etree.SubElement(root, "sharedDataWrite")
for k,v in self._sharedDataWrite.iteritems():
item = etree.SubElement(sharedDataWrite, "item" ,datauid=k,signalName=v)
sharedDataRead = etree.SubElement(root, "sharedDataRead")
for k,v in self._sharedDataRead.iteritems():
item = etree.SubElement(sharedDataRead, "item" ,datauid=k,slotName=v)
model = etree.SubElement(root, "model")
model.text = self._model
return etree.tostring(root, pretty_print=True)
@staticmethod
def fromXml(xmlstring):
'''returns a PanelDescription object based on the xml string provided
:param xmlstring: (unicode) XML code defining the values for the args
needed to initialize PanelDescription.
:return: (PanelDescription) object
'''
try:
root = etree.fromstring(xmlstring)
except:
return None
nameNode = root.find("name")
if (nameNode is not None) and (nameNode.text is not None):
name = nameNode.text
else:
return None
classnameNode = root.find("classname")
if (classnameNode is not None) and (classnameNode.text is not None):
classname = classnameNode.text
else:
classname = None
modulenameNode = root.find("modulename")
if (modulenameNode is not None) and (modulenameNode.text is not None):
modulename = modulenameNode.text
else:
modulename = None
widgetnameNode = root.find("widgetname")
if (widgetnameNode is not None) and (widgetnameNode.text is not None):
widgetname = widgetnameNode.text
else:
widgetname = None
floatingNode = root.find("floating")
if (floatingNode is not None) and (floatingNode.text is not None):
floating = floatingNode.text == str(True)
else:
floating = True
sharedDataWrite = {}
sharedDataWriteNode = root.find("sharedDataWrite")
if (sharedDataWriteNode is not None) and (sharedDataWriteNode.text is not None):
for child in sharedDataWriteNode:
if (child.get("datauid") is not None) and (child.get("signalName") is not None):
sharedDataWrite[child.get("datauid")] = child.get("signalName")
if not len(sharedDataWrite):
sharedDataWrite = None
sharedDataRead = {}
sharedDataReadNode = root.find("sharedDataRead")
if (sharedDataReadNode is not None) and (sharedDataReadNode.text is not None):
for child in sharedDataReadNode:
if (child.get("datauid") is not None) and (child.get("slotName") is not None):
sharedDataRead[child.get("datauid")] = child.get("slotName")
if not len(sharedDataRead):
sharedDataRead = None
modelNode = root.find("model")
if (modelNode is not None) and (modelNode.text is not None):
model = modelNode.text
else:
model = None
return PanelDescription(name, classname=classname, modulename=modulename, widgetname=widgetname,
floating=floating, sharedDataWrite=sharedDataWrite, sharedDataRead=sharedDataRead,
model=model)
#===============================================================================
# Properties
#===============================================================================
name = property(fget=getName, fset=setName)
classname = property(fget=getClassname, fset=setClassname)
modulename = property(fget=getModulename, fset=setModulename)
widgetname = property(fget=getWidgetname, fset=setWidgetname)
floating = property(fget=isFloating, fset=setFloating)
sharedDataWrite = property(fget=getSharedDataWrite, fset=setSharedDataWrite)
sharedDataRead = property(fget=getSharedDataRead, fset=setSharedDataRead)
model = property(fget=getModel, fset=setModel)
class PanelDescription(TaurusGuiComponentDescription):
'''
A description of a taurusgui panel.
This class is not a panel, but a container of the information required to
build a panel.
'''
def __init__(self, *args, **kwargs):
self.instrumentkey = kwargs.pop('instrumentkey', None)
TaurusGuiComponentDescription.__init__(self, *args, **kwargs)
@staticmethod
def fromPanel(panel):
name = str(panel.objectName())
classname = panel.getWidgetClassName()
modulename = panel.getWidgetModuleName()
# in the case of classes known to the TaurusWidgetFactory,
# do not store the modulename
if modulename.startswith('taurus.') and \
classname in TaurusWidgetFactory().getWidgetClassNames():
modulename = None
widgetname = None
floating = panel.isFloating()
sharedDataWrite = None
sharedDataRead = None
model = getattr(panel.widget(),'model',None)
if model is None or isinstance(model, basestring):
pass
elif hasattr(model,'__iter__'):
# if model is a sequence, convert to space-separated string
try:
model = " ".join(model)
except Exception, e:
msg = ('Cannot convert %s to a space-separated string: %s' %
(model, e))
Logger().debug(msg)
model = None
else:
# ignore other "model" attributes (they are not from Taurus)
model = None
return PanelDescription(name, classname=classname,
modulename=modulename, widgetname=widgetname,
floating=floating,
sharedDataWrite=sharedDataWrite,
sharedDataRead=sharedDataRead, model=model)
class ToolBarDescription(TaurusGuiComponentDescription):
'''
A description of a toolbar to be inserted in a TaurusGUI.
'''
pass
class AppletDescription(TaurusGuiComponentDescription):
'''
A description of a widget to be inserted in the "applets bar" of the TaurusGUI.
'''
pass