Source code for lavuelib.sourceWidget
# Copyright (C) 2017 DESY, Notkestr. 85, D-22607 Hamburg
#
# lavue is an image viewing program for photon science imaging detectors.
# Its usual application is as a live viewer using hidra as data source.
#
# This program 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 in version 2
# of the License.
#
# This program 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 this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301, USA.
#
# Authors:
# Christoph Rosemann <christoph.rosemann@desy.de>
# Jan Kotanski <jan.kotanski@desy.de>
#
""" image source selection """
from .qtuic import uic
from pyqtgraph import QtCore, QtGui
import os
import socket
import json
import re
import logging
try:
from pyqtgraph import QtWidgets
except Exception:
from pyqtgraph import QtGui as QtWidgets
from . import imageField
from . import imageFileHandler
_testformclass, _testbaseclass = uic.loadUiType(
os.path.join(os.path.dirname(os.path.abspath(__file__)),
"ui", "TestSourceWidget.ui"))
_httpformclass, _httpbaseclass = uic.loadUiType(
os.path.join(os.path.dirname(os.path.abspath(__file__)),
"ui", "HTTPSourceWidget.ui"))
_hidraformclass, _hidrabaseclass = uic.loadUiType(
os.path.join(os.path.dirname(os.path.abspath(__file__)),
"ui", "HidraSourceWidget.ui"))
_asapoformclass, _asapobaseclass = uic.loadUiType(
os.path.join(os.path.dirname(os.path.abspath(__file__)),
"ui", "ASAPOSourceWidget.ui"))
_tangoattrformclass, _tangoattrbaseclass = uic.loadUiType(
os.path.join(os.path.dirname(os.path.abspath(__file__)),
"ui", "TangoAttrSourceWidget.ui"))
_tangoeventsformclass, _tangoeventsbaseclass = uic.loadUiType(
os.path.join(os.path.dirname(os.path.abspath(__file__)),
"ui", "TangoEventsSourceWidget.ui"))
_tangofileformclass, _tangofilebaseclass = uic.loadUiType(
os.path.join(os.path.dirname(os.path.abspath(__file__)),
"ui", "TangoFileSourceWidget.ui"))
_nxsfileformclass, _nxsfilebaseclass = uic.loadUiType(
os.path.join(os.path.dirname(os.path.abspath(__file__)),
"ui", "NXSFileSourceWidget.ui"))
_zmqformclass, _zmqbaseclass = uic.loadUiType(
os.path.join(os.path.dirname(os.path.abspath(__file__)),
"ui", "ZMQSourceWidget.ui"))
_doocspropformclass, _doocspropbaseclass = uic.loadUiType(
os.path.join(os.path.dirname(os.path.abspath(__file__)),
"ui", "DOOCSPropSourceWidget.ui"))
_tinepropformclass, _tinepropbaseclass = uic.loadUiType(
os.path.join(os.path.dirname(os.path.abspath(__file__)),
"ui", "TinePropSourceWidget.ui"))
_epicspvformclass, _epicspvbaseclass = uic.loadUiType(
os.path.join(os.path.dirname(os.path.abspath(__file__)),
"ui", "EpicsPVSourceWidget.ui"))
__all__ = [
'SourceBaseWidget',
'HidraSourceWidget',
'HTTPSourceWidget',
'TangoAttrSourceWidget',
'TangoEventsSourceWidget',
'TangoFileSourceWidget',
'DOOCSPropSourceWidget',
'ZMQSourceWidget',
'NXSFileSourceWidget',
'TinePropSourceWidget',
'EpicsPVSourceWidget',
'ASAPOSourceWidget',
# 'FixTestSourceWidget',
'TestSourceWidget',
'swproperties'
]
logger = logging.getLogger("lavue")
[docs]class SourceBaseWidget(QtWidgets.QWidget):
""" general source widget """
#: (:class:`pyqtgraph.QtCore.pyqtSignal`) push button enabled signal
buttonEnabled = QtCore.pyqtSignal(bool)
#: (:class:`pyqtgraph.QtCore.pyqtSignal`) source state signal
sourceStateChanged = QtCore.pyqtSignal(int)
#: (:class:`pyqtgraph.QtCore.pyqtSignal`) source label name signal
sourceLabelChanged = QtCore.pyqtSignal()
#: (:class:`pyqtgraph.QtCore.pyqtSignal`) add Icon Clicked
addIconClicked = QtCore.pyqtSignal(str, str)
#: (:class:`pyqtgraph.QtCore.pyqtSignal`) remove Icon Clicked
removeIconClicked = QtCore.pyqtSignal(str, str)
#: (:obj:`str`) source name
name = "Test"
#: (:obj:`str`) source alias
alias = "test"
#: (:obj:`tuple` <:obj:`str`>) capitalized required packages
requires = ()
#: (:obj:`str`) datasource class name
datasource = "BaseSource"
def __init__(self, sourceid=0, parent=None):
""" constructor
:param sourceid: source id
:type sourceid: :obj:`int`
:param parent: parent object
:type parent: :class:`pyqtgraph.QtCore.QObject`
"""
QtWidgets.QWidget.__init__(self, parent)
#: (:obj:`int`) source id
self._sourceid = sourceid
#: (:obj:`list` <:obj:`str`>) subwidget object names
self.widgetnames = []
#: (:obj:`list` <:class:`PyQt5.QtWidgets.QWidget`>) subwidget objects
self.widgets = []
#: (:obj:`bool`) source widget active
self.active = False
#: (:obj:`bool`) expertmode flag
self.expertmode = False
#: (:obj:`bool`) source widget connected
self._connected = False
#: (:class:`Ui_SourceBaseWidget')
#: ui_sourcewidget object from qtdesigner
self._ui = None
#: (:obj:`bool`) source widget detached
self.__detached = False
[docs] def setActive(self, active=True):
""" set active flag
:param active: active flag
:type active: :obj:`bool`
"""
self.active = active
[docs] @QtCore.pyqtSlot()
def updateButton(self):
""" update slot for test source
"""
if not self.active:
return
self.buttonEnabled.emit(True)
[docs] def updateMetaData(self, **kargs):
""" update source input parameters
:param kargs: source widget input parameter dictionary
:type kargs: :obj:`dict` < :obj:`str`, :obj:`any`>
"""
self.sourceLabelChanged.emit()
[docs] @QtCore.pyqtSlot()
def updateComboBox(self):
""" abstract updateComboBox
"""
self.updateButton()
[docs] def connectWidget(self):
""" connects widget
"""
self._connected = True
self.sourceLabelChanged.emit()
def _detachWidgets(self):
""" detaches the form widgets from the gridLayout
"""
for wnm in self.widgetnames:
if hasattr(self._ui, wnm):
wg = getattr(self._ui, wnm)
if hasattr(self._ui, "gridLayout"):
self._ui.gridLayout.removeWidget(wg)
self.widgets.append(wg)
self.__detached = True
[docs] def configure(self, configuration):
""" set configuration for the current image source
:param configuration: configuration string
:type configuration: :obj:`str`
"""
[docs] def configuration(self):
""" provides configuration for the current image source
:returns configuration: configuration string
:rtype configuration: :obj:`str`
"""
return ""
[docs] def label(self):
""" return a label of the current detector
:return: label of the current detector
:rtype: :obj:`str`
"""
return self.name
[docs] def eventObjectFilter(self, event, combobox, varname, atdict, atlist):
""" event filter
:param obj: qt object
:type obj: :class: `pyqtgraph.QtCore.QObject`
:param event: qt event
:type event: :class: `pyqtgraph.QtCore.QEvent`
:returns: status flag
:rtype: :obj:`bool`
"""
if event.type() in \
[QtCore.QEvent.MouseButtonPress]:
if event.buttons() and QtCore.Qt.LeftButton and \
combobox.isEnabled() and self.expertmode and \
event.x() < 30:
currentattr = str(combobox.currentText()).strip()
attrs = sorted(atdict.keys())
if currentattr in attrs:
if QtWidgets.QMessageBox.question(
combobox, "Removing Label",
'Would you like to remove "%s"" ?' %
(currentattr),
QtWidgets.QMessageBox.Yes
| QtWidgets.QMessageBox.No,
QtWidgets.QMessageBox.Yes) == \
QtWidgets.QMessageBox.No:
return False
value = str(atdict.pop(currentattr)).strip()
if value not in atlist:
atlist.append(value)
self._updateComboBox(combobox, atdict, atlist, value)
self.removeIconClicked.emit(varname, currentattr)
elif currentattr in atlist:
self.addIconClicked.emit(varname, currentattr)
elif currentattr:
self.addIconClicked.emit(varname, currentattr)
return False
def _connectComboBox(self, combobox):
combobox.lineEdit().textEdited.connect(
self.updateButton)
combobox.lineEdit().editingFinished.connect(
self.updateComboBox)
combobox.currentIndexChanged.connect(
self.updateButton)
def _disconnectComboBox(self, combobox):
combobox.lineEdit().textEdited.disconnect(
self.updateButton)
combobox.lineEdit().editingFinished.disconnect(
self.updateComboBox)
combobox.currentIndexChanged.disconnect(
self.updateButton)
def _updateComboBox(self, combobox, atdict, atlist, currentattr=None):
""" updates a value of attr combo box
"""
self._disconnectComboBox(combobox)
currentattr = currentattr or str(combobox.currentText()).strip()
combobox.clear()
attrs = sorted(atdict.keys())
mkicon = QtGui.QIcon.fromTheme("starred")
if mkicon.isNull():
mkicon = QtGui.QIcon(":/star2.png")
umkicon = QtGui.QIcon.fromTheme("non-starred")
if umkicon.isNull():
umkicon = QtGui.QIcon(":/star1.png")
for mt in attrs:
combobox.addItem(mt)
iid = combobox.findText(mt)
combobox.setItemData(
iid, str(atdict[mt]), QtCore.Qt.ToolTipRole)
combobox.setItemIcon(iid, mkicon)
for mt in list(atlist):
if mt not in atdict.values():
combobox.addItem(mt)
iid = combobox.findText(mt)
combobox.setItemIcon(iid, umkicon)
else:
atlist = [mmt for mmt in atlist if mmt != mt]
if mt == currentattr:
for nm, vl in atdict.items():
if mt == vl:
currentattr = nm
break
if currentattr not in attrs and currentattr not in atlist:
combobox.addItem(currentattr)
iid = combobox.findText(currentattr)
combobox.setItemIcon(iid, umkicon)
if currentattr:
ind = combobox.findText(currentattr)
else:
ind = 0
combobox.setCurrentIndex(ind)
self._connectComboBox(combobox)
[docs]class TestSourceWidget(SourceBaseWidget):
""" test source widget """
def __init__(self, sourceid=0, parent=None):
""" constructor
:param sourceid: source id
:type sourceid: :obj:`int`
:param parent: parent object
:type parent: :class:`pyqtgraph.QtCore.QObject`
"""
SourceBaseWidget.__init__(self, sourceid, parent)
self._ui = _testformclass()
self._ui.setupUi(self)
self._detachWidgets()
class FixTestSourceWidget(SourceBaseWidget):
""" test source widget """
#: (:obj:`str`) source name
name = "Fix Test"
#: (:obj:`str`) datasource class name
datasource = "FixTestSource"
#: (:obj:`str`) source alias
alias = "fixtest"
def __init__(self, sourceid=0, parent=None):
""" constructor
:param sourceid: source id
:type sourceid: :obj:`int`
:param parent: parent object
:type parent: :class:`pyqtgraph.QtCore.QObject`
"""
SourceBaseWidget.__init__(self, sourceid, parent)
self._ui = _testformclass()
self._ui.setupUi(self)
self._detachWidgets()
[docs]class HTTPSourceWidget(SourceBaseWidget):
""" test source widget """
#: (:obj:`str`) source name
name = "HTTP response"
#: (:obj:`tuple` <:obj:`str`>) capitalized required packages
requires = ("REQUESTS",)
#: (:obj:`str`) datasource class name
datasource = "HTTPSource"
#: (:obj:`str`) source alias
alias = "http"
def __init__(self, sourceid=0, parent=None):
""" constructor
:param sourceid: source id
:type sourceid: :obj:`int`
:param parent: parent object
:type parent: :class:`pyqtgraph.QtCore.QObject`
"""
SourceBaseWidget.__init__(self, sourceid, parent)
self._ui = _httpformclass()
self._ui.setupUi(self)
#: (:obj:`list` <:obj:`str`>) subwidget object names
self.widgetnames = ["httpLabel", "httpComboBox"]
#: (:obj:`dict` <:obj:`str`, :obj:`str`>) dictionary with
#: (label, url) items
self.__urls = {}
#: (:obj:`list` <:obj:`str`>) user urls
self.__userurls = []
self._detachWidgets()
#: (:obj:`str`) default tip
self.__defaulttip = self._ui.httpComboBox.toolTip()
self._connectComboBox(self._ui.httpComboBox)
self._ui.httpComboBox.installEventFilter(self)
[docs] def eventFilter(self, obj, event):
""" event filter
:param obj: qt object
:type obj: :class: `pyqtgraph.QtCore.QObject`
:param event: qt event
:type event: :class: `pyqtgraph.QtCore.QEvent`
:returns: status flag
:rtype: :obj:`bool`
"""
return self.eventObjectFilter(
event,
combobox=self._ui.httpComboBox,
varname="httpurls",
atdict=self.__urls,
atlist=self.__userurls
)
[docs] @QtCore.pyqtSlot()
def updateButton(self):
""" update slot for HTTP response source
"""
if not self.active:
return
url = self.configuration()
if not url:
self.buttonEnabled.emit(False)
else:
self.buttonEnabled.emit(True)
self.sourceLabelChanged.emit()
[docs] def configuration(self):
""" provides configuration for the current image source
:returns configuration: configuration string
:rtype configuration: :obj:`str`
"""
url = str(self._ui.httpComboBox.currentText()).strip()
if url in self.__urls.keys():
url = str(self.__urls[url]).strip()
if not url.startswith("http://") and not url.startswith("https://"):
surl = url.split("/")
if len(surl) == 2 and surl[0] and surl[1]:
url = "http://%s/monitor/api/%s/images/monitor" \
% (surl[0], surl[1])
else:
url = None
return url
[docs] def updateMetaData(self, httpurls=None, **kargs):
""" update source input parameters
:param httpurls: json dictionary with
(label, http urls) items
:type httpurls: :obj:`str`
:param kargs: source widget input parameter dictionary
:type kargs: :obj:`dict` < :obj:`str`, :obj:`any`>
"""
if httpurls is not None:
self.__urls = json.loads(httpurls)
self.updateComboBox()
self.sourceLabelChanged.emit()
[docs] @QtCore.pyqtSlot()
def updateComboBox(self):
""" updates ComboBox
"""
self._updateComboBox(
self._ui.httpComboBox, self.__urls, self.__userurls)
self.updateButton()
[docs] def configure(self, configuration):
""" set configuration for the current image source
:param configuration: configuration string
:type configuration: :obj:`str`
"""
iid = self._ui.httpComboBox.findText(configuration)
if iid == -1:
self._ui.httpComboBox.addItem(configuration)
iid = self._ui.httpComboBox.findText(configuration)
self._ui.httpComboBox.setCurrentIndex(iid)
[docs] def connectWidget(self):
""" connects widget
"""
self._connected = True
self._ui.httpComboBox.lineEdit().setReadOnly(True)
self._ui.httpComboBox.setEnabled(False)
currenturl = str(self._ui.httpComboBox.currentText()).strip()
urls = self.__urls.keys()
if currenturl not in urls and currenturl not in self.__userurls:
self.__userurls.append(currenturl)
self._updateComboBox(
self._ui.httpComboBox, self.__urls, self.__userurls)
[docs] def disconnectWidget(self):
""" disconnects widget
"""
self._connected = False
self._ui.httpComboBox.lineEdit().setReadOnly(False)
self._ui.httpComboBox.setEnabled(True)
[docs] def label(self):
""" return a label of the current detector
:return: label of the current detector
:rtype: :obj:`str`
"""
label = str(self._ui.httpComboBox.currentText()).strip()
return re.sub("[^a-zA-Z0-9_]+", "_", label)
[docs]class HidraSourceWidget(SourceBaseWidget):
""" test source widget """
#: (:obj:`str`) source name
name = "Hidra"
#: (:obj:`str`) source alias
alias = "hidra"
#: (:obj:`tuple` <:obj:`str`>) capitalized required packages
requires = ("HIDRA",)
#: (:obj:`str`) datasource class name
datasource = "HiDRASource"
def __init__(self, sourceid=0, parent=None):
""" constructor
:param sourceid: source id
:type sourceid: :obj:`int`
:param parent: parent object
:type parent: :class:`pyqtgraph.QtCore.QObject`
"""
SourceBaseWidget.__init__(self, sourceid, parent)
self._ui = _hidraformclass()
self._ui.setupUi(self)
#: (:obj:`list` <:obj:`str`>) subwidget object names
self.widgetnames = [
"serverLabel", "serverComboBox",
"hostLabel", "currenthostLabel"
]
#: (:obj:`dict` < :obj:`str`, :obj:`list` <:obj:`str`> >)
#: server dictionary
self.__serverdict = {}
#: (:obj:`str`) hidra port number
self.__portnumber = "50001"
self._bumptheport()
#: (:obj:`str`) hidra client server
self.__targetname = socket.getfqdn()
#: (:obj:`list` <:obj:`str`> >) sorted server list
self.__sortedserverlist = []
self._detachWidgets()
self._ui.currenthostLabel.setText(
"%s:%s" % (self.__targetname, self.__portnumber))
self._connectComboBox(self._ui.serverComboBox)
def _bumptheport(self, portgap=200):
""" it bumps the hidra port by source id
:param offset: port gap for multi image sources
:type name: :obj:`int`
"""
try:
if self._sourceid:
self.__portnumber = str(
int(self.__portnumber) + self._sourceid * portgap)
except Exception as e:
logger.warning(str(e))
[docs] @QtCore.pyqtSlot()
def updateButton(self):
""" update slot for Hidra source
"""
if not self.active:
return
if self._ui.serverComboBox.currentText() == "Pick a server" \
or not self._ui.serverComboBox.currentText():
self.buttonEnabled.emit(False)
else:
self.buttonEnabled.emit(True)
self.sourceLabelChanged.emit()
[docs] def configuration(self):
""" provides configuration for the current image source
:returns configuration: configuration string
:rtype configuration: :obj:`str`
"""
return "%s,%s,%s" % (
str(self._ui.serverComboBox.currentText()),
self.__targetname,
self.__portnumber
)
[docs] def updateMetaData(self, serverdict=None, hidraport=None, **kargs):
""" update source input parameters
:param serverdict: server dictionary
:type serverdict: :obj:`dict` < :obj:`str`, :obj:`list` <:obj:`str`> >
:param hidaraport: list of hidra ports
:type hidraport: :obj:`list` < :obj:`str` >
:param kargs: source widget input parameter dictionary
:type kargs: :obj:`dict` < :obj:`str`, :obj:`any`>
"""
if isinstance(serverdict, dict):
self._ui.serverComboBox.currentIndexChanged.disconnect(
self.updateButton)
self.__serverdict = serverdict
self.__sortServerList(self.__targetname)
for i in reversed(range(0, self._ui.serverComboBox.count())):
self._ui.serverComboBox.removeItem(i)
self._ui.serverComboBox.addItems(self.__sortedserverlist)
self._ui.serverComboBox.currentIndexChanged.connect(
self.updateButton)
self._ui.serverComboBox.setCurrentIndex(0)
if hidraport:
try:
hports = json.loads(hidraport)
if len(hports) > self._sourceid:
self.__portnumber = hports[self._sourceid]
self._ui.currenthostLabel.setText(
"%s:%s" % (self.__targetname, self.__portnumber))
elif len(hports) > 0:
self.__portnumber = hports[0]
self._bumptheport()
self._ui.currenthostLabel.setText(
"%s:%s" % (self.__targetname, self.__portnumber))
except Exception as e:
logger.warning(str(e))
self.sourceLabelChanged.emit()
def __sortServerList(self, name):
""" small function to sort out the server list details.
It searches the hostname for a
string and return only the elements in the list that fit
:param name: beamline name
:type name: :obj:`str`
"""
#
beamlines = ['p03', 'p08', 'p09', 'p10', 'p11']
self.__sortedserverlist = []
for bl in beamlines:
if bl in name and bl in self.__serverdict.keys():
self.__sortedserverlist.extend(self.__serverdict[bl])
self.__sortedserverlist.extend(self.__serverdict["pool"])
self.__sortedserverlist = sorted(self.__sortedserverlist)
[docs] def connectWidget(self):
""" connects widget
"""
self._connected = True
self._ui.serverComboBox.setEnabled(False)
[docs] def disconnectWidget(self):
""" disconnects widget
"""
self._connected = False
self._ui.serverComboBox.setEnabled(True)
[docs] def configure(self, configuration):
""" set configuration for the current image source
:param configuration: configuration string
:type configuration: :obj:`str`
"""
configuration = configuration.split(" ")
if configuration:
configuration = configuration[0]
iid = self._ui.serverComboBox.findText(configuration)
if iid == -1:
self._ui.serverComboBox.addItem(configuration)
iid = self._ui.serverComboBox.findText(configuration)
self._ui.serverComboBox.setCurrentIndex(iid)
[docs] def label(self):
""" return a label of the current detector
:return: label of the current detector
:rtype: :obj:`str`
"""
if self._ui.serverComboBox.currentText() == "Pick a server":
return ""
else:
label = str(self._ui.serverComboBox.currentText()).strip()
return re.sub("[^a-zA-Z0-9_]+", "_", label)
[docs]class ASAPOSourceWidget(SourceBaseWidget):
""" test source widget """
#: (:obj:`str`) source name
name = "ASAPO"
#: (:obj:`str`) source alias
alias = "asapo"
#: (:obj:`tuple` <:obj:`str`>) capitalized required packages
requires = ("ASAPO",)
#: (:obj:`str`) datasource class name
datasource = "ASAPOSource"
def __init__(self, sourceid=0, parent=None):
""" constructor
:param sourceid: source id
:type sourceid: :obj:`int`
:param parent: parent object
:type parent: :class:`pyqtgraph.QtCore.QObject`
"""
SourceBaseWidget.__init__(self, sourceid, parent)
self._ui = _asapoformclass()
self._ui.setupUi(self)
#: (:obj:`list` <:obj:`str`>) subwidget object names
self.widgetnames = [
"asapodatasourceLabel", "asapodatasourceComboBox",
"asapostreamLabel", "asapostreamComboBox",
]
#: (:obj:`str`>) asapo server i.e. host:port
self.__server = ""
#: (:obj:`str`>) beamtime id
self.__beamtime = ""
#: (:obj:`str`>) source path
self.__sourcepath = ""
#: (:obj:`str`>) asapo token
self.__token = ""
#: (:obj:`list` <:obj:`str`> >) datasource list
self.__datasources = []
#: (:obj:`list` <:obj:`str`> >) asapo streams
self.__streams = []
#: (:obj:`bool`) updating flag
self.__updating = False
#: (:class:`pyqtgraph.QtCore.QMutex`) update mutex
self.__udmutex = QtCore.QMutex()
#: (:class:`pyqtgraph.QtCore.QMutex`) zmq datasource mutex
self.__mutex = QtCore.QMutex()
self._detachWidgets()
self._ui.asapodatasourceComboBox.addItems(["detector"])
self._ui.asapostreamComboBox.addItems(["default", "**ALL**"])
self._ui.asapodatasourceComboBox.currentIndexChanged.connect(
self.updateButton)
# self._connectComboBox()
self._ui.asapostreamComboBox.currentIndexChanged.connect(
self._updateStreamComboBox)
[docs] @QtCore.pyqtSlot()
def updateButton(self, disconnect=True):
""" update slot for Asapo source
"""
with QtCore.QMutexLocker(self.__udmutex):
if not self.active or self.__updating:
return
else:
self.__updating = True
with QtCore.QMutexLocker(self.__mutex):
if disconnect:
self._ui.asapostreamComboBox.\
currentIndexChanged.disconnect(
self._updateStreamComboBox)
if not self._ui.asapostreamComboBox.count() \
or not self._ui.asapodatasourceComboBox.currentText() \
or not self.__server \
or not self.__token \
or not self.__beamtime:
self.buttonEnabled.emit(False)
else:
self.buttonEnabled.emit(True)
self.sourceLabelChanged.emit()
if disconnect:
self._ui.asapostreamComboBox.\
currentIndexChanged.connect(
self._updateStreamComboBox)
with QtCore.QMutexLocker(self.__udmutex):
self.__updating = False
[docs] def configuration(self):
""" provides configuration for the current image source
:returns configuration: configuration string
:rtype configuration: :obj:`str`
"""
return "%s,%s,%s,%s,%s,%s" % (
self.__server,
str(self._ui.asapodatasourceComboBox.currentText()),
str(self._ui.asapostreamComboBox.currentText()),
self.__beamtime,
self.__sourcepath,
self.__token
)
[docs] def updateMetaData(self, asaposerver=None, asapotoken=None,
asapobeamtime=None,
asapodatasources=None, asapostreams=None,
asaposourcepath=None,
disconnect=True,
**kargs):
""" update source input parameters
:param asaposervers asapo servers, i.e. host:port
:type asaposervers: :obj:`str`
:param asapotoken: asapo token
:type asapotoken: :obj:`str`
:param asapobeamtime: beamtime id
:type asapobeamtime: :obj:`str`
:param asapodatasources: asapo datasource names
:type asapodatasources: :obj:`list` <:obj:`str`> >
:param asapostreams: asapo stream names
:type asapostreams: :obj:`list` <:obj:`str`> >
:param asaposourcepath: source path
:type asaposourcepath: :obj:`str`
:param disconnect: disconnect on update
:type disconnect: :obj:`bool`
:param kargs: source widget input parameter dictionary
:type kargs: :obj:`dict` < :obj:`str`, :obj:`any`>
"""
if disconnect:
with QtCore.QMutexLocker(self.__mutex):
self._ui.asapostreamComboBox.currentIndexChanged.\
disconnect(self._updateStreamComboBox)
text = None
if isinstance(asapodatasources, list):
self._ui.asapodatasourceComboBox.currentIndexChanged.disconnect(
self.updateButton)
self.__datasources = asapodatasources
for i in reversed(
range(0, self._ui.asapodatasourceComboBox.count())):
self._ui.asapodatasourceComboBox.removeItem(i)
if not asapodatasources:
self._ui.asapodatasourceComboBox.addItems(["detector"])
self._ui.asapodatasourceComboBox.addItems(self.__datasources)
self._ui.asapodatasourceComboBox.currentIndexChanged.connect(
self.updateButton)
self._ui.asapodatasourceComboBox.setCurrentIndex(0)
if asaposerver is not None:
self.__server = asaposerver
if asapotoken is not None:
self.__token = asapotoken
if asapobeamtime is not None:
self.__beamtime = asapobeamtime
if asaposourcepath is not None:
self.__sourcepath = asaposourcepath
updatecombo = False
if isinstance(asapostreams, list):
with QtCore.QMutexLocker(self.__mutex):
text = str(
self._ui.asapostreamComboBox.currentText())
if not text or text not in asapostreams:
if text not in ["default", "**ALL**"]:
text = None
self.__streams = asapostreams
updatecombo = True
if updatecombo is True:
with QtCore.QMutexLocker(self.__mutex):
for i in reversed(
range(0, self._ui.asapostreamComboBox.count())):
self._ui.asapostreamComboBox.removeItem(i)
if not self.__streams or \
"default" not in self.__streams:
self._ui.asapostreamComboBox.addItem("default")
self._ui.asapostreamComboBox.addItems(
sorted(self.__streams))
if not self.__streams or \
"**ALL**" not in self.__streams:
self._ui.asapostreamComboBox.addItem("**ALL**")
if text:
tid = self._ui.asapostreamComboBox.findText(text)
if tid > -1:
self._ui.asapostreamComboBox.setCurrentIndex(tid)
if disconnect:
self.updateButton(disconnect=False)
with QtCore.QMutexLocker(self.__mutex):
self._ui.asapostreamComboBox.currentIndexChanged.connect(
self._updateStreamComboBox)
if updatecombo is True and text is None:
self._updateStreamComboBox()
self.sourceLabelChanged.emit()
@QtCore.pyqtSlot()
def _updateStreamComboBox(self):
""" update ASAPO substream combobox
"""
disconnected = False
if self._connected:
disconnected = True
self.sourceStateChanged.emit(0)
self.updateButton()
if disconnected:
self.sourceStateChanged.emit(-1)
[docs] def connectWidget(self):
""" connects widget
"""
self._connected = True
self._ui.asapodatasourceComboBox.setEnabled(False)
[docs] def disconnectWidget(self):
""" disconnects widget
"""
self._connected = False
self._ui.asapodatasourceComboBox.setEnabled(True)
[docs] def configure(self, configuration):
""" set configuration for the current image source
:param configuration: configuration string
:type configuration: :obj:`str`
"""
cnflst = configuration.split(",")
datasource = cnflst[0] if cnflst else ""
stream = ""
if len(cnflst) > 1:
stream = cnflst[1]
if not stream:
stream = "default"
iid = self._ui.asapodatasourceComboBox.findText(datasource)
if iid == -1:
self._ui.asapodatasourceComboBox.addItem(datasource)
iid = self._ui.asapodatasourceComboBox.findText(datasource)
self._ui.asapodatasourceComboBox.setCurrentIndex(iid)
if stream:
iid = self._ui.asapostreamComboBox.findText(stream)
if iid == -1:
self._ui.asapostreamComboBox.addItem(stream)
iid = self._ui.asapostreamComboBox.findText(stream)
self._ui.asapostreamComboBox.setCurrentIndex(iid)
[docs] def label(self):
""" return a label of the current detector
:return: label of the current detector
:rtype: :obj:`str`
"""
label = str(self._ui.asapostreamComboBox.currentText()).strip()
return re.sub("[^a-zA-Z0-9_]+", "_", label)
[docs]class TangoAttrSourceWidget(SourceBaseWidget):
""" test source widget """
#: (:obj:`str`) source name
name = "Tango Attribute"
#: (:obj:`str`) source alias
alias = "tangoattr"
#: (:obj:`tuple` <:obj:`str`>) capitalized required packages
requires = ("TANGO",)
#: (:obj:`str`) datasource class name
datasource = "TangoAttrSource"
def __init__(self, sourceid=0, parent=None):
""" constructor
:param sourceid: source id
:type sourceid: :obj:`int`
:param parent: parent object
:type parent: :class:`pyqtgraph.QtCore.QObject`
"""
SourceBaseWidget.__init__(self, sourceid, parent)
self._ui = _tangoattrformclass()
self._ui.setupUi(self)
#: (:obj:`list` <:obj:`str`>) subwidget object names
self.widgetnames = [
"attrLabel", "attrComboBox"
]
#: (:obj:`dict` <:obj:`str`, :obj:`str`>) dictionary with
#: (label, tango attribute) items
self.__tangoattrs = {}
#: (:obj:`list` <:obj:`str`>) user tango attributes
self.__userattrs = []
self._detachWidgets()
#: (:obj:`str`) default tip
self.__defaulttip = self._ui.attrComboBox.toolTip()
self._connectComboBox(self._ui.attrComboBox)
self._ui.attrComboBox.installEventFilter(self)
[docs] def eventFilter(self, obj, event):
""" event filter
:param obj: qt object
:type obj: :class: `pyqtgraph.QtCore.QObject`
:param event: qt event
:type event: :class: `pyqtgraph.QtCore.QEvent`
:returns: status flag
:rtype: :obj:`bool`
"""
return self.eventObjectFilter(
event,
combobox=self._ui.attrComboBox,
varname="tangoattrs",
atdict=self.__tangoattrs,
atlist=self.__userattrs
)
[docs] @QtCore.pyqtSlot()
def updateButton(self):
""" update slot for Tango attribute source
"""
if not self.active:
return
currentattr = self.configuration()
if not currentattr:
self.buttonEnabled.emit(False)
else:
self.buttonEnabled.emit(True)
self.sourceLabelChanged.emit()
self._ui.attrComboBox.setToolTip(currentattr or self.__defaulttip)
[docs] def configuration(self):
""" provides configuration for the current image source
:returns configuration: configuration string
:rtype configuration: :obj:`str`
"""
currentattr = str(self._ui.attrComboBox.currentText()).strip()
if currentattr in self.__tangoattrs.keys():
currentattr = str(self.__tangoattrs[currentattr]).strip()
return currentattr
[docs] def updateMetaData(self, tangoattrs=None, **kargs):
""" update source input parameters
:param tangoattrs: json dictionary with
(label, tango attribute) items
:type tangoattrs: :obj:`str`
:param kargs: source widget input parameter dictionary
:type kargs: :obj:`dict` < :obj:`str`, :obj:`any`>
"""
if tangoattrs is not None:
self.__tangoattrs = json.loads(tangoattrs)
self._updateComboBox(
self._ui.attrComboBox, self.__tangoattrs, self.__userattrs)
self.sourceLabelChanged.emit()
[docs] def configure(self, configuration):
""" set configuration for the current image source
:param configuration: configuration string
:type configuration: :obj:`str`
"""
iid = self._ui.attrComboBox.findText(configuration)
if iid == -1:
self._ui.attrComboBox.addItem(configuration)
iid = self._ui.attrComboBox.findText(configuration)
self._ui.attrComboBox.setCurrentIndex(iid)
[docs] @QtCore.pyqtSlot()
def updateComboBox(self):
""" updates ComboBox
"""
self._updateComboBox(
self._ui.attrComboBox, self.__tangoattrs, self.__userattrs)
self.updateButton()
[docs] def disconnectWidget(self):
""" disconnects widget
"""
self._connected = False
self._ui.attrComboBox.lineEdit().setReadOnly(False)
self._ui.attrComboBox.setEnabled(True)
[docs] def connectWidget(self):
""" connects widget
"""
self._connected = True
self._ui.attrComboBox.lineEdit().setReadOnly(True)
self._ui.attrComboBox.setEnabled(False)
currentattr = str(self._ui.attrComboBox.currentText()).strip()
attrs = self.__tangoattrs.keys()
if currentattr not in attrs and currentattr not in self.__userattrs:
self.__userattrs.append(currentattr)
self._updateComboBox(
self._ui.attrComboBox, self.__tangoattrs, self.__userattrs)
[docs] def label(self):
""" return a label of the current detector
:return: label of the current detector
:rtype: :obj:`str`
"""
label = str(self._ui.attrComboBox.currentText()).strip()
return re.sub("[^a-zA-Z0-9_]+", "_", label)
[docs]class TinePropSourceWidget(SourceBaseWidget):
""" test source widget """
#: (:obj:`str`) source name
name = "Tine Property"
#: (:obj:`str`) source alias
alias = "tineprop"
#: (:obj:`tuple` <:obj:`str`>) capitalized required packages
requires = ("PYTINE",)
#: (:obj:`str`) datasource class name
datasource = "TinePropSource"
def __init__(self, sourceid=0, parent=None):
""" constructor
:param sourceid: source id
:type sourceid: :obj:`int`
:param parent: parent object
:type parent: :class:`pyqtgraph.QtCore.QObject`
"""
SourceBaseWidget.__init__(self, sourceid, parent)
self._ui = _tinepropformclass()
self._ui.setupUi(self)
#: (:obj:`list` <:obj:`str`>) subwidget object names
self.widgetnames = [
"tinepropLabel", "tinepropComboBox"
]
#: (:obj:`dict` <:obj:`str`, :obj:`str`>) dictionary with
#: (label, tine properties) items
self.__tineprops = {}
#: (:obj:`list` <:obj:`str`>) user tine property
self.__userprops = []
self._detachWidgets()
#: (:obj:`str`) default tip
self.__defaulttip = self._ui.tinepropComboBox.toolTip()
self._connectComboBox(self._ui.tinepropComboBox)
self._ui.tinepropComboBox.installEventFilter(self)
[docs] def eventFilter(self, obj, event):
""" event filter
:param obj: qt object
:type obj: :class: `pyqtgraph.QtCore.QObject`
:param event: qt event
:type event: :class: `pyqtgraph.QtCore.QEvent`
:returns: status flag
:rtype: :obj:`bool`
"""
return self.eventObjectFilter(
event,
combobox=self._ui.tinepropComboBox,
varname="tineprops",
atdict=self.__tineprops,
atlist=self.__userprops
)
[docs] @QtCore.pyqtSlot()
def updateButton(self):
""" update slot for Tine property source
"""
if not self.active:
return
currentprop = self.configuration()
if not currentprop:
self.buttonEnabled.emit(False)
else:
self.buttonEnabled.emit(True)
self.sourceLabelChanged.emit()
self._ui.tinepropComboBox.setToolTip(
currentprop or self.__defaulttip)
[docs] def configuration(self):
""" provides configuration for the current image source
:returns: configuration string
:rtype: :obj:`str`
"""
currentprop = str(self._ui.tinepropComboBox.currentText()).strip()
if currentprop in self.__tineprops.keys():
currentprop = str(self.__tineprops[currentprop]).strip()
return currentprop
[docs] def updateMetaData(self, tineprops=None, **kargs):
""" update source input parameters
:param tineprops: json dictionary with
(label, tine property) items
:type tineprops: :obj:`str`
:param kargs: source widget input parameter dictionary
:type kargs: :obj:`dict` < :obj:`str`, :obj:`any`>
"""
if tineprops is not None:
self.__tineprops = json.loads(tineprops)
self._updateComboBox(
self._ui.tinepropComboBox,
self.__tineprops,
self.__userprops)
self.sourceLabelChanged.emit()
[docs] def configure(self, configuration):
""" set configuration for the current image source
:param configuration: configuration string
:type configuration: :obj:`str`
"""
iid = self._ui.tinepropComboBox.findText(configuration)
if iid == -1:
self._ui.tinepropComboBox.addItem(configuration)
iid = self._ui.tinepropComboBox.findText(configuration)
self._ui.tinepropComboBox.setCurrentIndex(iid)
[docs] @QtCore.pyqtSlot()
def updateComboBox(self):
""" updates ComboBox
"""
self._updateComboBox(
self._ui.tinepropComboBox, self.__tineprops, self.__userprops)
self.updateButton()
[docs] def disconnectWidget(self):
""" disconnects widget
"""
self._connected = False
self._ui.tinepropComboBox.lineEdit().setReadOnly(False)
self._ui.tinepropComboBox.setEnabled(True)
[docs] def connectWidget(self):
""" connects widget
"""
self._connected = True
self._ui.tinepropComboBox.lineEdit().setReadOnly(True)
self._ui.tinepropComboBox.setEnabled(False)
currentprop = str(self._ui.tinepropComboBox.currentText()).strip()
props = self.__tineprops.keys()
if currentprop not in props and currentprop not in self.__userprops:
self.__userprops.append(currentprop)
self._updateComboBox(
self._ui.tinepropComboBox,
self.__tineprops, self.__userprops)
[docs] def label(self):
""" return a label of the current detector
:return: label of the current detector
:rtype: :obj:`str`
"""
label = str(self._ui.tinepropComboBox.currentText()).strip()
return re.sub("[^a-zA-Z0-9_]+", "_", label)
[docs]class TangoEventsSourceWidget(SourceBaseWidget):
""" test source widget """
#: (:obj:`str`) source name
name = "Tango Events"
#: (:obj:`str`) source alias
alias = "tangoevents"
#: (:obj:`tuple` <:obj:`str`>) capitalized required packages
requires = ("TANGO",)
#: (:obj:`str`) datasource class name
datasource = "TangoEventsSource"
def __init__(self, sourceid=0, parent=None):
""" constructor
:param sourceid: source id
:type sourceid: :obj:`int`
:param parent: parent object
:type parent: :class:`pyqtgraph.QtCore.QObject`
"""
SourceBaseWidget.__init__(self, sourceid, parent)
self._ui = _tangoeventsformclass()
self._ui.setupUi(self)
#: (:obj:`list` <:obj:`str`>) subwidget object names
self.widgetnames = [
"evattrLabel", "evattrComboBox"
]
#: (:obj:`dict` <:obj:`str`, :obj:`str`>) dictionary with
#: (label, tango attribute) items
self.__tangoevattrs = {}
#: (:obj:`list` <:obj:`str`>) user tango attributes
self.__userevattrs = []
self._detachWidgets()
#: (:obj:`str`) default tip
self.__defaulttip = self._ui.evattrComboBox.toolTip()
self._connectComboBox(self._ui.evattrComboBox)
self._ui.evattrComboBox.installEventFilter(self)
[docs] def eventFilter(self, obj, event):
""" event filter
:param obj: qt object
:type obj: :class: `pyqtgraph.QtCore.QObject`
:param event: qt event
:type event: :class: `pyqtgraph.QtCore.QEvent`
:returns: status flag
:rtype: :obj:`bool`
"""
return self.eventObjectFilter(
event,
combobox=self._ui.evattrComboBox,
varname="tangoevattrs",
atdict=self.__tangoevattrs,
atlist=self.__userevattrs
)
[docs] @QtCore.pyqtSlot()
def updateButton(self):
""" update slot for Tango attribute source
"""
if not self.active:
return
currentattr = self.configuration()
if not currentattr:
self.buttonEnabled.emit(False)
else:
self.buttonEnabled.emit(True)
self.sourceLabelChanged.emit()
self._ui.evattrComboBox.setToolTip(currentattr or self.__defaulttip)
[docs] def configuration(self):
""" provides configuration for the current image source
:returns configuration: configuration string
:rtype configuration: :obj:`str`
"""
currentattr = str(self._ui.evattrComboBox.currentText()).strip()
if currentattr in self.__tangoevattrs.keys():
currentattr = str(self.__tangoevattrs[currentattr]).strip()
return currentattr
[docs] def updateMetaData(self, tangoevattrs=None, **kargs):
""" update source input parameters
:param tangoevattrs: json dictionary with
(label, tango attribute) items
:type tangoevattrs: :obj:`str`
:param kargs: source widget input parameter dictionary
:type kargs: :obj:`dict` < :obj:`str`, :obj:`any`>
"""
if tangoevattrs is not None:
self.__tangoevattrs = json.loads(tangoevattrs)
self.updateComboBox()
self.sourceLabelChanged.emit()
[docs] @QtCore.pyqtSlot()
def updateComboBox(self):
""" updates ComboBox
"""
self._updateComboBox(
self._ui.evattrComboBox,
self.__tangoevattrs, self.__userevattrs)
self.updateButton()
[docs] def configure(self, configuration):
""" set configuration for the current image source
:param configuration: configuration string
:type configuration: :obj:`str`
"""
iid = self._ui.evattrComboBox.findText(configuration)
if iid == -1:
self._ui.evattrComboBox.addItem(configuration)
iid = self._ui.evattrComboBox.findText(configuration)
self._ui.evattrComboBox.setCurrentIndex(iid)
[docs] def disconnectWidget(self):
""" disconnects widget
"""
self._connected = False
self._ui.evattrComboBox.lineEdit().setReadOnly(False)
self._ui.evattrComboBox.setEnabled(True)
[docs] def connectWidget(self):
""" connects widget
"""
self._connected = True
self._ui.evattrComboBox.lineEdit().setReadOnly(True)
self._ui.evattrComboBox.setEnabled(False)
currentattr = str(self._ui.evattrComboBox.currentText()).strip()
attrs = self.__tangoevattrs.keys()
if currentattr not in attrs and currentattr not in self.__userevattrs:
self.__userevattrs.append(currentattr)
self._updateComboBox(
self._ui.evattrComboBox,
self.__tangoevattrs, self.__userevattrs)
[docs] def label(self):
""" return a label of the current detector
:return: label of the current detector
:rtype: :obj:`str`
"""
label = str(self._ui.evattrComboBox.currentText()).strip()
return re.sub("[^a-zA-Z0-9_]+", "_", label)
[docs]class TangoFileSourceWidget(SourceBaseWidget):
""" test source widget """
#: (:obj:`str`) source name
name = "Tango File"
#: (:obj:`str`) source alias
alias = "tangofile"
#: (:obj:`tuple` <:obj:`str`>) capitalized required packages
requires = ("TANGO",)
#: (:obj:`str`) datasource class name
datasource = "TangoFileSource"
def __init__(self, sourceid=0, parent=None):
""" constructor
:param sourceid: source id
:type sourceid: :obj:`int`
:param parent: parent object
:type parent: :class:`pyqtgraph.QtCore.QObject`
"""
SourceBaseWidget.__init__(self, sourceid, parent)
self._ui = _tangofileformclass()
self._ui.setupUi(self)
#: (:obj:`list` <:obj:`str`>) subwidget object names
self.widgetnames = [
"fileattrLabel", "fileattrComboBox",
"dirattrLabel", "dirattrComboBox"
]
#: (:obj:`str`) json dictionary with directory
#: and file name translation
self.__dirtrans = '{"/ramdisk/": "/gpfs/"}'
#: (:obj:`dict` <:obj:`str`, :obj:`str`>) dictionary with
#: (label, file tango attribute) items
self.__tangofileattrs = {}
#: (:obj:`list` <:obj:`str`>) user file tango attributes
self.__userfileattrs = []
#: (:obj:`dict` <:obj:`str`, :obj:`str`>) dictionary with
#: (label, dir tango attribute) items
self.__tangodirattrs = {}
#: (:obj:`list` <:obj:`str`>) user dir tango attributes
self.__userdirattrs = []
#: (:obj:`bool`) nexus file source keeps the file open
self.__nxsopen = False
#: (:obj:`bool`) nexus file source starts from the last image
self.__nxslast = False
self._detachWidgets()
#: (:obj:`str`) default file tip
self.__defaultfiletip = self._ui.fileattrComboBox.toolTip()
#: (:obj:`str`) default dir tip
self.__defaultdirtip = self._ui.dirattrComboBox.toolTip()
self._connectComboBox(self._ui.fileattrComboBox)
self._connectComboBox(self._ui.dirattrComboBox)
self._ui.fileattrComboBox.installEventFilter(self)
self._ui.dirattrComboBox.installEventFilter(self)
[docs] def eventFilter(self, obj, event):
""" event filter
:param obj: qt object
:type obj: :class: `pyqtgraph.QtCore.QObject`
:param event: qt event
:type event: :class: `pyqtgraph.QtCore.QEvent`
:returns: status flag
:rtype: :obj:`bool`
"""
if obj == self._ui.fileattrComboBox:
return self.eventObjectFilter(
event,
combobox=self._ui.fileattrComboBox,
varname="tangofileattrs",
atdict=self.__tangofileattrs,
atlist=self.__userfileattrs
)
if obj == self._ui.dirattrComboBox:
return self.eventObjectFilter(
event,
combobox=self._ui.dirattrComboBox,
varname="tangodirattrs",
atdict=self.__tangodirattrs,
atlist=self.__userdirattrs
)
return False
[docs] @QtCore.pyqtSlot()
def updateButton(self):
""" update slot for Tango file source
"""
if not self.active:
return
fattr, dattr, dt, no, nl = self.__configuration()
if not fattr:
self.buttonEnabled.emit(False)
else:
self.buttonEnabled.emit(True)
self.sourceLabelChanged.emit()
self._ui.fileattrComboBox.setToolTip(fattr or self.__defaultfiletip)
self._ui.dirattrComboBox.setToolTip(dattr or self.__defaultdirtip)
def __configuration(self):
""" provides configuration for the current image source
:returns configuration: configuration tuple
:rtype configuration: :obj:`tuple`
"""
dattr = str(self._ui.dirattrComboBox.currentText()).strip()
fattr = str(self._ui.fileattrComboBox.currentText()).strip()
if fattr in self.__tangofileattrs.keys():
fattr = str(self.__tangofileattrs[fattr]).strip()
if dattr in self.__tangodirattrs.keys():
dattr = str(self.__tangodirattrs[dattr]).strip()
dt = self.__dirtrans
return (fattr, dattr, dt, self.__nxsopen, self.__nxslast)
[docs] def configuration(self):
""" provides configuration for the current image source
:returns configuration: configuration string
:rtype configuration: :obj:`str`
"""
return "%s,%s,%s,%s,%s" % self.__configuration()
[docs] def updateMetaData(self, tangofileattrs=None, tangodirattrs=None,
dirtrans=None, nxsopen=None, nxslast=None, **kargs):
""" update source input parameters
:param tangofileattrs: json dictionary with
(label, file tango attribute) items
:type tangofileattrs: :obj:`str`
:param tangodirattrs: json dictionary with
(label, dir tango attribute) items
:type tangodirattrs: :obj:`str`
:param dirtrans: json dictionary with directory
and file name translation
:type dirtrans: :obj:`str`
:param nxsopen: nexus file source keeps the file open
:type nxsopen: :obj:`bool`
:param nxslast: nexus file source starts from the last image
:type nxslast: :obj:`bool`
:param kargs: source widget input parameter dictionary
:type kargs: :obj:`dict` < :obj:`str`, :obj:`any`>
"""
if tangofileattrs is not None:
self.__tangofileattrs = json.loads(tangofileattrs)
self._updateComboBox(
self._ui.fileattrComboBox, self.__tangofileattrs,
self.__userfileattrs)
if tangodirattrs is not None:
self.__tangodirattrs = json.loads(tangodirattrs)
self._updateComboBox(
self._ui.dirattrComboBox, self.__tangodirattrs,
self.__userdirattrs)
if dirtrans is not None:
self.__dirtrans = dirtrans
if nxsopen is not None:
self.__nxsopen = nxsopen
if nxslast is not None:
self.__nxslast = nxslast
self.sourceLabelChanged.emit()
[docs] @QtCore.pyqtSlot()
def updateComboBox(self):
""" updates ComboBox
"""
self._updateComboBox(
self._ui.fileattrComboBox, self.__tangofileattrs,
self.__userfileattrs)
self._updateComboBox(
self._ui.dirattrComboBox, self.__tangodirattrs,
self.__userdirattrs)
self.updateButton()
[docs] def connectWidget(self):
""" connects widget
"""
self._connected = True
self._ui.fileattrComboBox.lineEdit().setReadOnly(True)
self._ui.fileattrComboBox.setEnabled(False)
fattr = str(self._ui.fileattrComboBox.currentText()).strip()
attrs = self.__tangofileattrs.keys()
if fattr not in attrs and fattr not in self.__userfileattrs:
self.__userfileattrs.append(fattr)
self._updateComboBox(
self._ui.fileattrComboBox, self.__tangofileattrs,
self.__userfileattrs)
self._ui.dirattrComboBox.lineEdit().setReadOnly(True)
self._ui.dirattrComboBox.setEnabled(False)
dattr = str(self._ui.dirattrComboBox.currentText()).strip()
attrs = self.__tangodirattrs.keys()
if dattr not in attrs and dattr not in self.__userdirattrs:
self.__userdirattrs.append(dattr)
self._updateComboBox(
self._ui.dirattrComboBox, self.__tangodirattrs,
self.__userdirattrs)
[docs] def disconnectWidget(self):
""" disconnects widget
"""
self._connected = False
self._ui.fileattrComboBox.lineEdit().setReadOnly(False)
self._ui.fileattrComboBox.setEnabled(True)
self._ui.dirattrComboBox.lineEdit().setReadOnly(False)
self._ui.dirattrComboBox.setEnabled(True)
[docs] def configure(self, configuration):
""" set configuration for the current image source
:param configuration: configuration string
:type configuration: :obj:`str`
"""
cnflst = configuration.split(",")
filecnf = cnflst[0] if cnflst else ""
dircnf = cnflst[1] if len(cnflst) > 1 else ""
iid = self._ui.fileattrComboBox.findText(filecnf)
if iid == -1:
self._ui.fileattrComboBox.addItem(filecnf)
iid = self._ui.fileattrComboBox.findText(filecnf)
self._ui.fileattrComboBox.setCurrentIndex(iid)
iid = self._ui.dirattrComboBox.findText(dircnf)
if iid == -1:
self._ui.dirattrComboBox.addItem(dircnf)
iid = self._ui.dirattrComboBox.findText(dircnf)
self._ui.dirattrComboBox.setCurrentIndex(iid)
[docs] def label(self):
""" return a label of the current detector
:return: label of the current detector
:rtype: :obj:`str`
"""
label = str(self._ui.dirattrComboBox.currentText()).strip()
return re.sub("[^a-zA-Z0-9_]+", "_", label)
[docs]class EpicsPVSourceWidget(SourceBaseWidget):
""" test source widget """
#: (:obj:`str`) source name
name = "Epics PV"
#: (:obj:`str`) source alias
alias = "epicspv"
#: (:obj:`tuple` <:obj:`str`>) capitalized required packages
requires = ("PYEPICS",)
#: (:obj:`str`) datasource class name
datasource = "EpicsPVSource"
def __init__(self, sourceid=0, parent=None):
""" constructor
:param sourceid: source id
:type sourceid: :obj:`int`
:param parent: parent object
:type parent: :class:`pyqtgraph.QtCore.QObject`
"""
SourceBaseWidget.__init__(self, sourceid, parent)
self._ui = _epicspvformclass()
self._ui.setupUi(self)
#: (:obj:`list` <:obj:`str`>) subwidget object names
self.widgetnames = [
"pvnameLabel", "pvnameComboBox",
"pvshapeLabel", "pvshapeComboBox"
]
#: (:obj:`dict` <:obj:`str`, :obj:`str`>) dictionary with
#: (label, pv name) items
self.__epicspvnames = {}
#: (:obj:`list` <:obj:`str`>) user pv names
self.__userpvnames = []
#: (:obj:`dict` <:obj:`str`, :obj:`str`>) dictionary with
#: (label, pv shape) items
self.__epicspvshapes = {}
#: (:obj:`list` <:obj:`str`>) user pv shapes
self.__userpvshapes = []
self._detachWidgets()
#: (:obj:`str`) default pv name tip
self.__defaultpvnametip = self._ui.pvnameComboBox.toolTip()
#: (:obj:`str`) default dir tip
self.__defaultpvshapetip = self._ui.pvshapeComboBox.toolTip()
self._connectComboBox(self._ui.pvnameComboBox)
self._connectComboBox(self._ui.pvshapeComboBox)
self._ui.pvnameComboBox.installEventFilter(self)
self._ui.pvshapeComboBox.installEventFilter(self)
[docs] def eventFilter(self, obj, event):
""" event filter
:param obj: qt object
:type obj: :class: `pyqtgraph.QtCore.QObject`
:param event: qt event
:type event: :class: `pyqtgraph.QtCore.QEvent`
:returns: status flag
:rtype: :obj:`bool`
"""
if obj == self._ui.pvnameComboBox:
return self.eventObjectFilter(
event,
combobox=self._ui.pvnameComboBox,
varname="epicspvnames",
atdict=self.__epicspvnames,
atlist=self.__userpvnames
)
if obj == self._ui.pvshapeComboBox:
return self.eventObjectFilter(
event,
combobox=self._ui.pvshapeComboBox,
varname="epicspvshapes",
atdict=self.__epicspvshapes,
atlist=self.__userpvshapes
)
return False
[docs] @QtCore.pyqtSlot()
def updateButton(self):
""" update slot for Epics file source
"""
if not self.active:
return
pvnm, pvsh = self.__configuration()
if not pvnm:
self.buttonEnabled.emit(False)
else:
self.buttonEnabled.emit(True)
self.sourceLabelChanged.emit()
self._ui.pvnameComboBox.setToolTip(pvnm or self.__defaultpvnametip)
self._ui.pvshapeComboBox.setToolTip(pvsh or self.__defaultpvshapetip)
def __configuration(self):
""" provides configuration for the current image source
:returns configuration: configuration tuple
:rtype configuration: :obj:`tuple`
"""
pvsh = str(self._ui.pvshapeComboBox.currentText()).strip()
pvnm = str(self._ui.pvnameComboBox.currentText()).strip()
if pvnm in self.__epicspvnames.keys():
pvnm = str(self.__epicspvnames[pvnm]).strip()
if pvsh in self.__epicspvshapes.keys():
pvsh = str(self.__epicspvshapes[pvsh]).strip()
return (pvnm, pvsh)
[docs] def configuration(self):
""" provides configuration for the current image source
:returns configuration: configuration string
:rtype configuration: :obj:`str`
"""
return "%s,[%s]" % self.__configuration()
[docs] def updateMetaData(self, epicspvnames=None, epicspvshapes=None, **kargs):
""" update source input parameters
:param epicspvnames: json dictionary with
(label, file epics attribute) items
:type epicspvnames: :obj:`str`
:param epicspvshapes: json dictionary with
(label, dir epics attribute) items
:type epicspvshapes: :obj:`str`
:param kargs: source widget input parameter dictionary
:type kargs: :obj:`dict` < :obj:`str`, :obj:`any`>
"""
if epicspvnames is not None:
self.__epicspvnames = json.loads(epicspvnames)
self._updateComboBox(
self._ui.pvnameComboBox, self.__epicspvnames,
self.__userpvnames)
if epicspvshapes is not None:
self.__epicspvshapes = json.loads(epicspvshapes)
self._updateComboBox(
self._ui.pvshapeComboBox, self.__epicspvshapes,
self.__userpvshapes)
self.sourceLabelChanged.emit()
[docs] @QtCore.pyqtSlot()
def updateComboBox(self):
""" updates ComboBox
"""
self._updateComboBox(
self._ui.pvnameComboBox, self.__epicspvnames,
self.__userpvnames)
self._updateComboBox(
self._ui.pvshapeComboBox, self.__epicspvshapes,
self.__userpvshapes)
self.updateButton()
[docs] def connectWidget(self):
""" connects widget
"""
self._connected = True
self._ui.pvnameComboBox.lineEdit().setReadOnly(True)
self._ui.pvnameComboBox.setEnabled(False)
pvnm = str(self._ui.pvnameComboBox.currentText()).strip()
attrs = self.__epicspvnames.keys()
if pvnm not in attrs and pvnm not in self.__userpvnames:
self.__userpvnames.append(pvnm)
self._updateComboBox(
self._ui.pvnameComboBox, self.__epicspvnames,
self.__userpvnames)
self._ui.pvshapeComboBox.lineEdit().setReadOnly(True)
self._ui.pvshapeComboBox.setEnabled(False)
pvsh = str(self._ui.pvshapeComboBox.currentText()).strip()
attrs = self.__epicspvshapes.keys()
if pvsh not in attrs and pvsh not in self.__userpvshapes:
self.__userpvshapes.append(pvsh)
self._updateComboBox(
self._ui.pvshapeComboBox, self.__epicspvshapes,
self.__userpvshapes)
[docs] def disconnectWidget(self):
""" disconnects widget
"""
self._connected = False
self._ui.pvnameComboBox.lineEdit().setReadOnly(False)
self._ui.pvnameComboBox.setEnabled(True)
self._ui.pvshapeComboBox.lineEdit().setReadOnly(False)
self._ui.pvshapeComboBox.setEnabled(True)
[docs] def configure(self, configuration):
""" set configuration for the current image source
:param configuration: configuration string
:type configuration: :obj:`str`
"""
cnflst = configuration.split(",", 1)
pvnm = cnflst[0] if cnflst else ""
shcnf = cnflst[1] if len(cnflst) > 1 else ""
iid = self._ui.pvnameComboBox.findText(pvnm)
if iid == -1:
self._ui.pvnameComboBox.addItem(pvnm)
iid = self._ui.pvnameComboBox.findText(pvnm)
self._ui.pvnameComboBox.setCurrentIndex(iid)
iid = self._ui.pvshapeComboBox.findText(shcnf)
if iid == -1:
try:
json.loads(shcnf)
shcnf = shcnf[1:-1]
except Exception:
shcnf = ""
self._ui.pvshapeComboBox.addItem(shcnf)
iid = self._ui.pvshapeComboBox.findText(shcnf)
self._ui.pvshapeComboBox.setCurrentIndex(iid)
[docs] def label(self):
""" return a label of the current detector
:return: label of the current detector
:rtype: :obj:`str`
"""
label = str(self._ui.pvshapeComboBox.currentText()).strip()
return re.sub("[^a-zA-Z0-9_]+", "_", label)
[docs]class NXSFileSourceWidget(SourceBaseWidget):
""" test source widget """
#: (:obj:`str`) source name
name = "NeXus File"
#: (:obj:`str`) source alias
alias = "nxsfile"
#: (:obj:`str`) datasource class name
datasource = "NXSFileSource"
def __init__(self, sourceid=0, parent=None):
""" constructor
:param sourceid: source id
:type sourceid: :obj:`int`
:param parent: parent object
:type parent: :class:`pyqtgraph.QtCore.QObject`
"""
SourceBaseWidget.__init__(self, sourceid, parent)
self._ui = _nxsfileformclass()
self._ui.setupUi(self)
#: (:obj:`list` <:obj:`str`>) subwidget object names
self.widgetnames = [
"nxsFileLabel", "nxsFileLineEdit",
"nxsFieldLabel", "nxsFieldLineEdit",
"nxsDimLabel", "nxsDimSpinBox",
"nxsFrameLabel", "nxsFrameSpinBox"
]
#: (:obj:`bool`) nexus file source keeps the file open
self.__nxsopen = False
#: (:obj:`bool`) nexus file source starts from the last image
self.__nxslast = False
#: (:obj:`str`) the last nexus file
self.__nxslastfile = "."
self._detachWidgets()
self._ui.nxsFileLineEdit.textEdited.connect(self.updateButton)
self._ui.nxsFieldLineEdit.textEdited.connect(self.updateButton)
self._ui.nxsFrameSpinBox.valueChanged.connect(
self._updateFrameSpinBox)
self._ui.nxsDimSpinBox.valueChanged.connect(self.updateButton)
self._ui.nxsFileLineEdit.installEventFilter(self)
self._ui.nxsFieldLineEdit.installEventFilter(self)
@QtCore.pyqtSlot()
def _updateFrameSpinBox(self):
""" update nexus frame combobox
"""
disconnected = False
if self._connected:
disconnected = True
self.sourceStateChanged.emit(0)
self.updateButton()
if disconnected:
self.sourceStateChanged.emit(-1)
[docs] def eventFilter(self, obj, event):
""" event filter
:param obj: qt object
:type obj: :class: `pyqtgraph.QtCore.QObject`
:param event: qt event
:type event: :class: `pyqtgraph.QtCore.QEvent`
:returns: status flag
:rtype: :obj:`bool`
"""
if not self._ui.nxsDimSpinBox.isEnabled():
return False
if obj not in [self._ui.nxsFileLineEdit, self._ui.nxsFieldLineEdit]:
return False
if event.type() in [QtCore.QEvent.MouseButtonDblClick]:
fileDialog = QtWidgets.QFileDialog()
fileout = fileDialog.getOpenFileName(
self._ui.nxsFileLineEdit, 'Load file', self.__nxslastfile)
if isinstance(fileout, tuple):
filename = str(fileout[0])
else:
filename = str(fileout)
fieldpath = ""
growing = 0
if filename:
if filename.endswith(".nxs") or filename.endswith(".h5") \
or filename.endswith(".nx") or filename.endswith(".ndf"):
try:
# self.__settings.filename = filename
handler = imageFileHandler.NexusFieldHandler(
str(filename))
fields = handler.findImageFields()
except Exception as e:
logger.warning(str(e))
# print(str(e))
fields = None
if fields:
imgfield = imageField.ImageField(self)
imgfield.fields = fields
imgfield.createGUI()
if imgfield.exec_():
fieldpath = imgfield.field
growing = imgfield.growing
# frame = imgfield.frame
self._ui.nxsFileLineEdit.setText(filename)
self.__nxslastfile = filename
if fieldpath:
self._ui.nxsFieldLineEdit.setText(fieldpath)
self._ui.nxsDimSpinBox.setValue(growing)
self.updateButton()
return True
return False
[docs] @QtCore.pyqtSlot()
def updateButton(self):
""" update slot for nexus file source
"""
if not self.active:
return
nfl, nfd, nsb, nfm, nxsopen, nxslast = self.__configuration()
if not nfl or not nfd:
self.buttonEnabled.emit(False)
else:
self.buttonEnabled.emit(True)
self.sourceLabelChanged.emit()
def __configuration(self):
""" provides configuration for the current image source
:returns configuration: configuration tuple
:rtype configuration: :obj:`tuple`
"""
nfl = str(self._ui.nxsFileLineEdit.text()).strip()
nfd = str(self._ui.nxsFieldLineEdit.text()).strip()
nfm = int(self._ui.nxsFrameSpinBox.value())
nsb = int(self._ui.nxsDimSpinBox.value())
return (nfl, nfd, nfm, nsb, self.__nxsopen, self.__nxslast)
[docs] def configuration(self):
""" provides configuration for the current image source
:returns configuration: configuration string
:rtype configuration: :obj:`str`
"""
return "%s,%s,%s,%s,%s,%s" % self.__configuration()
[docs] def connectWidget(self):
""" connects widget
"""
self._connected = True
self._ui.nxsFileLineEdit.setReadOnly(True)
self._ui.nxsFieldLineEdit.setReadOnly(True)
self._ui.nxsDimSpinBox.setEnabled(False)
[docs] def disconnectWidget(self):
""" disconnects widget
"""
self._connected = False
self._ui.nxsFileLineEdit.setReadOnly(False)
self._ui.nxsFieldLineEdit.setReadOnly(False)
self._ui.nxsDimSpinBox.setEnabled(True)
[docs] def updateMetaData(self, nxsopen=None, nxslast=None, **kargs):
""" update source input parameters
:param nxsopen: nexus file source keeps the file open
:type nxsopen: :obj:`bool`
:param nxslast: nexus file source starts from the last image
:type nxslast: :obj:`bool`
:param kargs: source widget input parameter dictionary
:type kargs: :obj:`dict` < :obj:`str`, :obj:`any`>
"""
update = False
if nxsopen is not None:
if self.__nxsopen != nxsopen:
self.__nxsopen = nxsopen
update = True
if nxslast is not None:
if self.__nxslast != nxslast:
self.__nxslast = nxslast
update = True
if update:
self.updateButton()
self.sourceLabelChanged.emit()
[docs] def configure(self, configuration):
""" set configuration for the current image source
:param configuration: configuration string
:type configuration: :obj:`str`
"""
cnflst = configuration.split(",")
filecnf = cnflst[0] if cnflst else ""
if ":/" in filecnf:
filecnf, fieldcnf = filecnf.split(":/", 1)
else:
fieldcnf = ""
try:
growcnf = int(cnflst[1])
except Exception:
growcnf = 0
try:
nfm = int(cnflst[2].replace("m", "-"))
except Exception:
nfm = -1
self._ui.nxsFileLineEdit.setText(filecnf)
self._ui.nxsFieldLineEdit.setText(fieldcnf)
self._ui.nxsDimSpinBox.setValue(growcnf)
self._ui.nxsFrameSpinBox.setValue(nfm)
self.updateButton()
[docs] def label(self):
""" return a label of the current detector
:return: label of the current detector
:rtype: :obj:`str`
"""
label = str(self._ui.nxsFileLineEdit.text()).strip() + \
":/" + str(self._ui.nxsFieldLineEdit.text()).strip()
if label == ":/":
return ""
return re.sub("[^a-zA-Z0-9_]+", "_", label)
[docs]class ZMQSourceWidget(SourceBaseWidget):
""" test source widget """
#: (:obj:`str`) source name
name = "ZMQ Stream"
#: (:obj:`str`) source alias
alias = "zmq"
#: (:obj:`str`) datasource class name
datasource = "ZMQSource"
def __init__(self, sourceid=0, parent=None):
""" constructor
:param sourceid: source id
:type sourceid: :obj:`int`
:param parent: parent object
:type parent: :class:`pyqtgraph.QtCore.QObject`
"""
SourceBaseWidget.__init__(self, sourceid, parent)
self._ui = _zmqformclass()
self._ui.setupUi(self)
#: (:obj:`list` <:obj:`str`>) subwidget object names
self.widgetnames = [
"pickleLabel", "pickleComboBox",
"pickleTopicLabel", "pickleTopicComboBox"
]
#: (:obj:`list` <:obj:`str`> >) zmq source datasources
self.__zmqtopics = []
#: (:obj:`bool`) automatic zmq topics enabled
self.__autozmqtopics = False
#: (:obj:`dict` <:obj:`str`, :obj:`str`>) dictionary with
#: (label, server:port) items
self.__servers = {}
#: (:obj:`list` <:obj:`str`>) user servers
self.__userservers = []
#: (:class:`pyqtgraph.QtCore.QMutex`) zmq datasource mutex
self.__mutex = QtCore.QMutex()
#: (:class:`pyqtgraph.QtCore.QMutex`) update mutex
self.__udmutex = QtCore.QMutex()
#: (:obj:`bool`) updating flag
self.__updating = False
self._detachWidgets()
#: (:obj:`str`) default tip
self.__defaulttip = self._ui.pickleComboBox.toolTip()
self._connectComboBox(self._ui.pickleComboBox)
self._ui.pickleComboBox.installEventFilter(self)
self._ui.pickleTopicComboBox.currentIndexChanged.connect(
self._updateZMQComboBox)
[docs] def eventFilter(self, obj, event):
""" event filter
:param obj: qt object
:type obj: :class: `pyqtgraph.QtCore.QObject`
:param event: qt event
:type event: :class: `pyqtgraph.QtCore.QEvent`
:returns: status flag
:rtype: :obj:`bool`
"""
return self.eventObjectFilter(
event,
combobox=self._ui.pickleComboBox,
varname="zmqservers",
atdict=self.__servers,
atlist=self.__userservers
)
[docs] @QtCore.pyqtSlot()
def updateButton(self, disconnect=True):
""" update slot for ZMQ source
"""
with QtCore.QMutexLocker(self.__udmutex):
if not self.active or self.__updating:
return
else:
self.__updating = True
with QtCore.QMutexLocker(self.__mutex):
if disconnect:
self._ui.pickleTopicComboBox.currentIndexChanged.disconnect(
self._updateZMQComboBox)
hosturl = self.configuration()
if hosturl:
self.buttonEnabled.emit(True)
else:
self.buttonEnabled.emit(False)
self._ui.pickleComboBox.setToolTip(hosturl or self.__defaulttip)
if disconnect:
self._ui.pickleTopicComboBox.currentIndexChanged.connect(
self._updateZMQComboBox)
with QtCore.QMutexLocker(self.__udmutex):
self.__updating = False
[docs] def configuration(self):
""" provides configuration for the current image source
:returns configuration: configuration string
:rtype configuration: :obj:`str`
"""
hosturl = str(self._ui.pickleComboBox.currentText()).strip()
if hosturl in self.__servers.keys():
hosturl = str(self.__servers[hosturl]).strip()
if not hosturl or ":" not in hosturl:
hosturl = ""
else:
try:
_, sport = hosturl.split("/")[0].split(":")
port = int(sport)
if port > 65535 or port < 0:
raise Exception("Wrong port")
if self._ui.pickleTopicComboBox.currentIndex() >= 0:
text = self._ui.pickleTopicComboBox.currentText()
if text == "**ALL**":
text = ""
shost = hosturl.split("/")
if len(shost) > 2:
shost[1] = str(text)
else:
shost.append(str(text))
hosturl = "/".join(shost)
except Exception:
hosturl = ""
return hosturl
@QtCore.pyqtSlot()
def _updateZMQComboBox(self):
""" update ZMQ datasource combobox
"""
disconnected = False
if self._connected:
disconnected = True
self.sourceStateChanged.emit(0)
self.updateButton()
if disconnected:
self.sourceStateChanged.emit(-1)
[docs] def updateMetaData(
self,
zmqtopics=None, autozmqtopics=None,
datasources=None, disconnect=True, zmqservers=None,
**kargs):
""" update source input parameters
:param zmqtopics: zmq source topics
:type zmqtopics: :obj:`list` <:obj:`str`> >
:param autozmqtopics: automatic zmq topics enabled
:type autozmqtopics: :obj:`bool`
:param datasources: automatic zmq source topics
:type datasources: :obj:`list` <:obj:`str`> >
:param disconnect: disconnect on update
:type disconnect: :obj:`bool`
:param zmqservers: json dictionary with
(label, zmq servers) items
:type zmqservers: :obj:`str`
:param kargs: source widget input parameter dictionary
:type kargs: :obj:`dict` < :obj:`str`, :obj:`any`>
"""
if disconnect:
with QtCore.QMutexLocker(self.__mutex):
self._ui.pickleTopicComboBox.currentIndexChanged.disconnect(
self._updateZMQComboBox)
text = None
updatecombo = False
if zmqservers is not None:
self.__servers = json.loads(zmqservers)
self._updateComboBox(
self._ui.pickleComboBox, self.__servers, self.__userservers)
if isinstance(zmqtopics, list):
with QtCore.QMutexLocker(self.__mutex):
text = str(self._ui.pickleTopicComboBox.currentText())
if not text or text not in zmqtopics:
text = None
self.__zmqtopics = zmqtopics
updatecombo = True
if autozmqtopics is not None:
self.__autozmqtopics = autozmqtopics
if self.__autozmqtopics:
updatecombo = True
with QtCore.QMutexLocker(self.__mutex):
text = str(self._ui.pickleTopicComboBox.currentText())
if isinstance(datasources, list):
if not text or text not in datasources:
if text != "**ALL**":
text = None
self.__zmqtopics = datasources
if updatecombo is True:
with QtCore.QMutexLocker(self.__mutex):
for i in reversed(
range(0, self._ui.pickleTopicComboBox.count())):
self._ui.pickleTopicComboBox.removeItem(i)
self._ui.pickleTopicComboBox.addItems(self.__zmqtopics)
self._ui.pickleTopicComboBox.addItem("**ALL**")
if text:
tid = self._ui.pickleTopicComboBox.findText(text)
if tid > -1:
self._ui.pickleTopicComboBox.setCurrentIndex(tid)
if disconnect:
self.updateButton(disconnect=False)
with QtCore.QMutexLocker(self.__mutex):
self._ui.pickleTopicComboBox.currentIndexChanged.connect(
self._updateZMQComboBox)
if updatecombo is True and text is None:
self._updateZMQComboBox()
self.sourceLabelChanged.emit()
[docs] def connectWidget(self):
""" connects widget
"""
self._connected = True
self._ui.pickleComboBox.lineEdit().setReadOnly(True)
self._ui.pickleComboBox.setEnabled(False)
server = str(self._ui.pickleComboBox.currentText()).strip()
servers = self.__servers.keys()
if server not in servers and server not in self.__userservers:
self.__userservers.append(server)
self._updateComboBox(
self._ui.pickleComboBox, self.__servers, self.__userservers)
[docs] @QtCore.pyqtSlot()
def updateComboBox(self):
""" updates ComboBox
"""
self._updateComboBox(
self._ui.pickleComboBox, self.__servers, self.__userservers)
self.updateButton()
[docs] def disconnectWidget(self):
""" disconnects widget
"""
self._connected = False
self._ui.pickleComboBox.lineEdit().setReadOnly(False)
self._ui.pickleComboBox.setEnabled(True)
[docs] def configure(self, configuration):
""" set configuration for the current image source
:param configuration: configuration string
:type configuration: :obj:`str`
"""
cnflst = configuration.replace("/", ",").split(",")
srvcnf = cnflst[0] if cnflst else ""
topiccnf = ""
if len(cnflst) > 1:
topiccnf = cnflst[1]
if not topiccnf:
topiccnf = "**ALL**"
iid = self._ui.pickleComboBox.findText(srvcnf)
if iid == -1:
self._ui.pickleComboBox.addItem(srvcnf)
iid = self._ui.pickleComboBox.findText(srvcnf)
self._ui.pickleComboBox.setCurrentIndex(iid)
if topiccnf:
iid = self._ui.pickleTopicComboBox.findText(topiccnf)
if iid == -1:
self._ui.pickleTopicComboBox.addItem(topiccnf)
iid = self._ui.pickleTopicComboBox.findText(topiccnf)
self._ui.pickleTopicComboBox.setCurrentIndex(iid)
[docs] def label(self):
""" return a label of the current detector
:return: label of the current detector
:rtype: :obj:`str`
"""
label = str(self._ui.pickleComboBox.currentText()).strip()
return re.sub("[^a-zA-Z0-9_]+", "_", label)
[docs]class DOOCSPropSourceWidget(SourceBaseWidget):
""" test source widget """
#: (:obj:`str`) source name
name = "DOOCS Property"
#: (:obj:`str`) source alias
alias = "doocsprop"
#: (:obj:`tuple` <:obj:`str`>) capitalized required packages
requires = ("PYDOOCS",)
#: (:obj:`str`) datasource class name
datasource = "DOOCSPropSource"
def __init__(self, sourceid=0, parent=None):
""" constructor
:param sourceid: source id
:type sourceid: :obj:`int`
:param parent: parent object
:type parent: :class:`pyqtgraph.QtCore.QObject`
"""
SourceBaseWidget.__init__(self, sourceid, parent)
self._ui = _doocspropformclass()
self._ui.setupUi(self)
#: (:obj:`list` <:obj:`str`>) subwidget object names
self.widgetnames = [
"doocspropLabel", "doocspropComboBox"
]
#: (:obj:`dict` <:obj:`str`, :obj:`str`>) dictionary with
#: (label, doocs property) items
self.__doocsprops = {}
#: (:obj:`list` <:obj:`str`>) user doocs properites
self.__userprops = []
self._detachWidgets()
#: (:obj:`str`) default tip
self.__defaulttip = self._ui.doocspropComboBox.toolTip()
self._connectComboBox(self._ui.doocspropComboBox)
self._ui.doocspropComboBox.installEventFilter(self)
[docs] def eventFilter(self, obj, event):
""" event filter
:param obj: qt object
:type obj: :class: `pyqtgraph.QtCore.QObject`
:param event: qt event
:type event: :class: `pyqtgraph.QtCore.QEvent`
:returns: status flag
:rtype: :obj:`bool`
"""
return self.eventObjectFilter(
event,
combobox=self._ui.doocspropComboBox,
varname="doocsprops",
atdict=self.__doocsprops,
atlist=self.__userprops
)
[docs] @QtCore.pyqtSlot()
def updateButton(self):
""" update slot for Doocs attribute source
"""
if not self.active:
return
currentprop = self.configuration()
if not currentprop:
self.buttonEnabled.emit(False)
else:
self.buttonEnabled.emit(True)
self.sourceLabelChanged.emit()
self._ui.doocspropComboBox.setToolTip(currentprop or self.__defaulttip)
[docs] def configuration(self):
""" provides configuration for the current image source
:returns configuration: configuration string
:rtype configuration: :obj:`str`
"""
currentprop = str(self._ui.doocspropComboBox.currentText()).strip()
if currentprop in self.__doocsprops.keys():
currentprop = str(self.__doocsprops[currentprop]).strip()
return currentprop
[docs] def updateMetaData(self, doocsprops=None, **kargs):
""" update source input parameters
:param doocsprops: json dictionary with
(label, doocs attribute) items
:type doocsprops: :obj:`str`
:param kargs: source widget input parameter dictionary
:type kargs: :obj:`dict` < :obj:`str`, :obj:`any`>
"""
if doocsprops is not None:
self.__doocsprops = json.loads(doocsprops)
self._updateComboBox(
self._ui.doocspropComboBox,
self.__doocsprops, self.__userprops)
self.sourceLabelChanged.emit()
[docs] def configure(self, configuration):
""" set configuration for the current image source
:param configuration: configuration string
:type configuration: :obj:`str`
"""
iid = self._ui.doocspropComboBox.findText(configuration)
if iid == -1:
self._ui.doocspropComboBox.addItem(configuration)
iid = self._ui.doocspropComboBox.findText(configuration)
self._ui.doocspropComboBox.setCurrentIndex(iid)
[docs] @QtCore.pyqtSlot()
def updateComboBox(self):
""" updates ComboBox
"""
self._updateComboBox(
self._ui.doocspropComboBox, self.__doocsprops, self.__userprops)
self.updateButton()
[docs] def disconnectWidget(self):
""" disconnects widget
"""
self._connected = False
self._ui.doocspropComboBox.lineEdit().setReadOnly(False)
self._ui.doocspropComboBox.setEnabled(True)
[docs] def connectWidget(self):
""" connects widget
"""
self._connected = True
self._ui.doocspropComboBox.lineEdit().setReadOnly(True)
self._ui.doocspropComboBox.setEnabled(False)
currentprop = str(self._ui.doocspropComboBox.currentText()).strip()
attrs = self.__doocsprops.keys()
if currentprop not in attrs and currentprop not in self.__userprops:
self.__userprops.append(currentprop)
self._updateComboBox(
self._ui.doocspropComboBox, self.__doocsprops,
self.__userprops)
[docs] def label(self):
""" return a label of the current detector
:return: label of the current detector
:rtype: :obj:`str`
"""
label = str(self._ui.doocspropComboBox.currentText()).strip()
return re.sub("[^a-zA-Z0-9_]+", "_", label)
#: ( :obj:`dict` < :obj:`str`, any > ) source widget properties
swproperties = []
for nm in __all__:
if nm.endswith("SourceWidget"):
cl = globals()[nm]
swproperties.append(
{
'alias': cl.alias,
'name': cl.name,
'widget': nm,
'requires': cl.requires,
})