# import system modules import sys # import project classes # import names from dialin.squish import utils, denaliMessages from dialin.squish.denaliMessages import txStates, EResponse # Import PySide2 classes from PySide2.QtUiTools import QUiLoader from PySide2 import QtCore, QtWidgets from PySide2.QtCore import QFile, Slot from PySide2.QtGui import qApp from PySide2.QtCore import QTimer class RunTimeWidget: """ the parent class of all the run time loadable widgets """ loader: QUiLoader window: QtWidgets.QWidget def __init__(self, ui_name: str): self.ui_name = ui_name self.loader = QUiLoader() self.__load_ui() def __load_ui(self): """ loads the ui file of the GUI at run time :return: none """ ui_file = QFile(self.ui_name) ui_file.open(QFile.ReadOnly) self.window = self.loader.load(ui_file) # assert if the ui file can't be loaded error = self.loader.errorString() assert len(error) == 0, error ui_file.close() def show(self): """ shows the main container window :return: none """ self.window.show() def __find_child(self, child_type, child_name: str) -> QtWidgets.QWidget: """ finds a child in the loaded ui and returns the reference to it if found otherwise quits the application :param child_type: (var) type of the child :param child_name: (str) name of the child :return: (QtWidgets.QWidget) reference to the child """ child: QtWidgets.QWidget = self.window.findChild(child_type, child_name) assert child is not None, "child name '{}' with type '{}' can't be found.".format(child_name, child_type) return child def find_label(self, name: str) -> QtWidgets.QLabel: """ convenient method of find_child for QLabel :param name: (str) name of the QLabel Object :return: (QLabel) reference to the QLabel """ child = self.__find_child(QtWidgets.QLabel, name) return child def find_button(self, name: str) -> QtWidgets.QPushButton: """ convenient method of find_child for QPushButton :param name: (str) name of the QPushButton Object :return: (QPushButton) reference to the QPushButton """ child = self.__find_child(QtWidgets.QPushButton, name) return child def find_combobox(self, name: str) -> QtWidgets.QComboBox: """ convenient method of find_child for QComboBox :param name: (str) name of the QComboBox Object :return: (QPushButton) reference to the QComboBox """ child = self.__find_child(QtWidgets.QComboBox, name) return child def find_spinbox(self, name: str) -> QtWidgets.QSpinBox: """ convenient method of find_child for QSpinBox :param name: (str) name of the QSpinBox Object :return: (QSpinBox) reference to the QSpinBox """ child = self.__find_child(QtWidgets.QSpinBox, name) return child def find_slider(self, name: str) -> QtWidgets.QSlider: """ convenient method of find_child for QSlider :param name: (str) name of the QSlider Object :return: (QSlider) reference to the QSlider """ child = self.__find_child(QtWidgets.QSlider, name) return child def find_table_widget(self, name: str) -> QtWidgets.QTableWidget: """ convenient method of find_child for QTableWidget :param name: (str) name of the QTableWidget Object :return: (QTableWidget) reference to the QTableWidget """ child: QtWidgets.QTableWidget = self.__find_child(QtWidgets.QTableWidget, name) return child class Simulator(RunTimeWidget): """ The simulator class which loads the ui file dynamically and initializes the objects and can be eventually shown. """ # global variables declarations ui_file_name = "Simulator.ui" timer: QTimer # pushbutton btnSalineAccept: QtWidgets.QPushButton btnSalineReject: QtWidgets.QPushButton btnUfPauseAccept: QtWidgets.QPushButton btnUfPauseReject: QtWidgets.QPushButton btnUfResumeAccept: QtWidgets.QPushButton btnUfResumeReject: QtWidgets.QPushButton btnUfEditAccept: QtWidgets.QPushButton btnUfEditReject: QtWidgets.QPushButton # label lblSalineAction: QtWidgets.QLabel lblUfPauseAction: QtWidgets.QLabel lblUfResumeAction: QtWidgets.QLabel lblUfEditAction: QtWidgets.QLabel # spinbox spnSalineRejectReason: QtWidgets.QSpinBox spnUfPauseRejectReason: QtWidgets.QSpinBox spnUfResumeRejectReason: QtWidgets.QSpinBox spnUfEditRejectReason: QtWidgets.QSpinBox spnDurationMin: QtWidgets.QSpinBox spnDurationMax: QtWidgets.QSpinBox spnUFVolumeMin: QtWidgets.QSpinBox spnUFVolumeMax: QtWidgets.QSpinBox spnDialysateMin: QtWidgets.QSpinBox spnDialysateMax: QtWidgets.QSpinBox # combobox cmbSalineAcceptTarget: QtWidgets.QComboBox # sliders sldSalineTarget: QtWidgets.QSlider sldSalineCumulative: QtWidgets.QSlider sldSalineVolume: QtWidgets.QSlider sldUfVolume: QtWidgets.QSlider # tables tblSalineSubMode: QtWidgets.QTableWidget tblSalineUFStates: QtWidgets.QTableWidget tblSalineSalineStates: QtWidgets.QTableWidget # static class variables saline_requested_state: txStates def __init__(self): super().__init__(Simulator.ui_file_name) self.saline_requested_state = txStates.SALINE_BOLUS_STATE_IDLE self.initialize() def setup_ranges(self): """ sets up the treatment ranges timer and 1 sec interval :return: none """ self.spnDurationMin = self.find_spinbox('spnDurationMin') self.spnDurationMax = self.find_spinbox('spnDurationMax') self.spnUFVolumeMin = self.find_spinbox('spnUFVolumeMin') self.spnUFVolumeMax = self.find_spinbox('spnUFVolumeMax') self.spnDialysateMin = self.find_spinbox('spnDialysateMin') self.spnDialysateMax = self.find_spinbox('spnDialysateMax') self.timer = QTimer() self.timer.start(1000) self.timer.timeout.connect(self.do_ranges_data) def setup_uf_adjustment(self): """ sets up the treatment Ultrafiltration adjustment GUI section :return: none """ self.btnUfPauseAccept = self.find_button('btnUfPauseAccept') self.btnUfPauseReject = self.find_button('btnUfPauseReject') self.btnUfResumeAccept = self.find_button('btnUfResumeAccept') self.btnUfResumeReject = self.find_button('btnUfResumeReject') self.btnUfEditAccept = self.find_button('btnUfEditAccept') self.btnUfEditReject = self.find_button('btnUfEditReject') self.lblUfPauseAction = self.find_label('lblUfPauseAction') self.lblUfResumeAction = self.find_label('lblUfResumeAction') self.lblUfEditAction = self.find_label('lblUfEditAction') self.spnUfPauseRejectReason = self.find_spinbox('spnUfPauseRejectReason') self.spnUfResumeRejectReason = self.find_spinbox('spnUfResumeRejectReason') self.spnUfEditRejectReason = self.find_spinbox('spnUfEditRejectReason') self.sldUfVolume = self.find_slider('sldUfVolume') self.btnUfPauseAccept.clicked.connect(self.do_uf_pause_accept) self.btnUfPauseReject.clicked.connect(self.do_uf_pause_reject) self.btnUfResumeAccept.clicked.connect(self.do_uf_resume_accept) self.btnUfResumeReject.clicked.connect(self.do_uf_resume_reject) self.btnUfEditAccept.clicked.connect(self.do_uf_edit_accept) self.btnUfEditReject.clicked.connect(self.do_uf_edit_reject) self.sldUfVolume.valueChanged.connect(self.do_uf_volume_data) def setup_saline_adjustment(self): """ sets up the treatment saline bolus adjustment GUI section :return: none """ self.btnSalineAccept = self.find_button('btnSalineAccept') self.btnSalineReject = self.find_button('btnSalineReject') self.lblSalineAction = self.find_label('lblSalineAction') self.spnSalineRejectReason = self.find_spinbox('spnSalineRejectReason') self.cmbSalineAcceptTarget = self.find_combobox('cmbSalineAcceptTarget') self.btnSalineAccept.clicked.connect(self.do_sb_accept) self.btnSalineReject.clicked.connect(self.do_sb_reject) def setup_saline_data(self): """ sets up the treatment saline bolus data sender GUI section :return: none """ self.sldSalineTarget = self.find_slider('sldSalineTarget') self.sldSalineCumulative = self.find_slider('sldSalineCumulative') self.sldSalineVolume = self.find_slider('sldSalineVolume') self.sldSalineTarget.valueChanged.connect(self.do_saline_data) self.sldSalineCumulative.valueChanged.connect(self.do_saline_data) self.sldSalineVolume.valueChanged.connect(self.do_saline_data) def setup_treatment_states(self): """ sets up the treatment saline bolus states GUI section :return: none """ self.tblSalineSubMode = self.find_table_widget('tblSalineSubMode') self.tblSalineUFStates = self.find_table_widget('tblSalineUFStates') self.tblSalineSalineStates = self.find_table_widget('tblSalineSalineStates') self.tblSalineSubMode.setCurrentCell(0, 0) self.tblSalineUFStates.setCurrentCell(0, 0) self.tblSalineSalineStates.setCurrentCell(0, 0) self.tblSalineSubMode.cellClicked.connect(self.do_saline_saline_state) self.tblSalineUFStates.cellClicked.connect(self.do_saline_saline_state) self.tblSalineSalineStates.cellClicked.connect(self.do_saline_saline_state) @Slot() def do_sb_accept(self): """ the slot for accept saline bolus button :return: none """ # toggle the saline requested state if self.saline_requested_state == txStates.SALINE_BOLUS_STATE_IN_PROGRESS: self.saline_requested_state = txStates.SALINE_BOLUS_STATE_IDLE else: self.saline_requested_state = txStates.SALINE_BOLUS_STATE_IN_PROGRESS target = self.cmbSalineAcceptTarget.currentText() denaliMessages.setSalineBolusResponse(True, 0, target, self.saline_requested_state) self.lblSalineAction.setText('Accepted ' + target) @Slot() def do_sb_reject(self): """ the slot for accept saline bolus button :return: none """ reason = self.spnSalineRejectReason.value() denaliMessages.setSalineBolusResponse(False, reason, 0, self.saline_requested_state) self.lblSalineAction.setText('Rejected ' + "{}".format(reason)) @Slot() def do_uf_pause_accept(self): """ the slot for accept ultrafiltration pause button :return: none """ denaliMessages.setTreatmentAdjustUltrafiltrationStateResponse( EResponse.Accepted, 0, txStates.UF_PAUSED_STATE) self.lblUfPauseAction.setText('Accepted ') @Slot() def do_uf_pause_reject(self): """ the slot for reject ultrafiltration pause button :return: none """ reason = self.spnUfPauseRejectReason.value() denaliMessages.setTreatmentAdjustUltrafiltrationStateResponse( EResponse.Rejected, reason, txStates.UF_RUNNING_STATE) self.lblUfPauseAction.setText('Rejected ' + "{}".format(reason)) @Slot() def do_uf_resume_accept(self): """ the slot for accept ultrafiltration resume accept :return: none """ denaliMessages.setTreatmentAdjustUltrafiltrationStateResponse( EResponse.Accepted, 0, txStates.UF_RUNNING_STATE) self.lblUfResumeAction.setText('Accepted ') @Slot() def do_uf_resume_reject(self): """ the slot for reject ultrafiltration resume button :return: none """ reason = self.spnUfResumeRejectReason.value() denaliMessages.setTreatmentAdjustUltrafiltrationStateResponse( EResponse.Rejected, reason, txStates.UF_PAUSED_STATE) self.lblUfResumeAction.setText('Rejected ' + "{}".format(reason)) @Slot() def do_uf_edit_accept(self): """ the slot for accept ultrafiltration next button :return: none """ denaliMessages.setTreatmentAdjustUltrafiltrationEditResponse( EResponse.Accepted, 0, 2500, 60, 0, 10, 0, 10) self.lblUfEditAction.setText('Accepted ') @Slot() def do_uf_edit_reject(self): """ the slot for reject ultrafiltration next button :return: none """ reason = self.spnUfEditRejectReason.value() denaliMessages.setTreatmentAdjustUltrafiltrationEditResponse( EResponse.Rejected, reason, 2500, 60, 0, 10, 0, 10) self.lblUfEditAction.setText('Rejected ' + "{}".format(reason)) @Slot() def do_saline_saline_state(self): """ the slot for saline bolus state change :return: none """ sub_mode = self.tblSalineSubMode.verticalHeaderItem(self.tblSalineSubMode.currentRow()).text() uf_state = self.tblSalineUFStates.verticalHeaderItem(self.tblSalineUFStates.currentRow()).text() saline = self.tblSalineSalineStates.verticalHeaderItem(self.tblSalineSalineStates.currentRow()).text() denaliMessages.setTreatmentStatesData(sub_mode, uf_state, saline) @Slot() def do_saline_data(self): """ the slot which is called to send the saline bolus data by calling the denaliMessage API setTreatmentSalineBolusData :return: none """ denaliMessages.setTreatmentSalineBolusData(self.sldSalineTarget.value(), self.sldSalineCumulative.value(), self.sldSalineVolume.value()) @Slot() def do_uf_volume_data(self): """ sends the ultrafiltration delivered volume message :return: none """ denaliMessages.setTreatmentUltrafiltration(self.sldUfVolume.value(), 0, 0, 0, 0, 0, 0) @Slot() def do_ranges_data(self): """ sends the treatment ranges message with given value on the screen :return: none """ denaliMessages.setTreatmentParamRanges( self.spnDurationMin.value(), self.spnDurationMax.value(), self.spnUFVolumeMin.value(), self.spnUFVolumeMax.value(), self.spnDialysateMin.value(), self.spnDialysateMax.value() ) def initialize(self): """ initializes the class by calling it's initializer methods to make objects ready :return: none """ self.setup_ranges() self.setup_saline_adjustment() self.setup_saline_data() self.setup_uf_adjustment() self.setup_treatment_states() def main(): """ the main function which initializes the Simulator and starts it. :return: none """ utils.tstStart(__file__) # create qt application QtWidgets.QApplication(sys.argv) simulator = Simulator() simulator.show() utils.tstDone() # start qt application main loop sys.exit(qApp.exec_()) if __name__ == "__main__": QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_ShareOpenGLContexts) main()