Index: simulator/plugins/__init__.py =================================================================== diff -u -rc13dc6ba2410716a3f1c446e564085aeb9114a60 -r69b2aacf31c5fdc28e078f87dbdee5c3ab672dd1 --- simulator/plugins/__init__.py (.../__init__.py) (revision c13dc6ba2410716a3f1c446e564085aeb9114a60) +++ simulator/plugins/__init__.py (.../__init__.py) (revision 69b2aacf31c5fdc28e078f87dbdee5c3ab672dd1) @@ -1,7 +1,10 @@ -from .ultrafiltration.loader import Ultrafiltration -from .inlinebloodpressures.loader import InlineBloodPressures -from .salinebolus.loader import SalineBolus -from .treatmentstates.loader import TreatmentStates -from .treatmentranges.loader import TreatmentRanges -from .heparin.loader import Heparin - +""" +the package init file +""" +from .ultrafiltration.loader import Loader as Ultrafiltration +from .inlinebloodpressures.loader import Loader as InlineBloodPressures +from .salinebolus.loader import Loader as SalineBolus +from .treatmentstates.loader import Loader as TreatmentStates +from .treatmentranges.loader import Loader as TreatmentRanges +from .heparin.loader import Loader as Heparin +from .alarms.loader import Loader as Alarms Index: simulator/plugins/alarms/interface.ui =================================================================== diff -u --- simulator/plugins/alarms/interface.ui (revision 0) +++ simulator/plugins/alarms/interface.ui (revision 69b2aacf31c5fdc28e078f87dbdee5c3ab672dd1) @@ -0,0 +1,626 @@ + + + ui_salinebolus + + + + 0 + 0 + 939 + 828 + + + + Heparin + + + + + + background-color: rgb(239, 41, 41); +color: rgb(238, 238, 236); + + + Alarms + + + Qt::AlignCenter + + + + + + + + + + + 65535 + + + + + + + + + + + 0 + 0 + + + + Top : + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + spnTopID + + + + + + + 2 + + + QLayout::SetFixedSize + + + + + false + + + 0 + + + true + + + true + + + true + + + + + + + 1 + + + true + + + true + + + + + + + 2 + + + true + + + true + + + + + + + 3 + + + true + + + true + + + + + + + + + + 0 + 0 + + + + Esclates In (sec) : + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + spnEscalatesIn + + + + + + + + 0 + 0 + + + + Priority : + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + rdoPriorityNone + + + + + + + + 0 + 0 + + + + Mute Timeout (sec): + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + spnMuteTimeout + + + + + + + false + + + Mute + + + Ctrl+Del + + + false + + + + + + + Send + + + Ctrl+Return + + + + + + + + + + + 0 + 0 + + + + + 0 + 200 + + + + QAbstractItemView::NoEditTriggers + + + + systemFault + + + Unchecked + + + ItemIsUserCheckable|ItemIsEnabled + + + + + stop + + + Unchecked + + + ItemIsUserCheckable|ItemIsEnabled + + + + + noClear + + + Unchecked + + + ItemIsUserCheckable|ItemIsEnabled + + + + + noResume + + + Unchecked + + + ItemIsUserCheckable|ItemIsEnabled + + + + + noRinseback + + + Unchecked + + + ItemIsUserCheckable|ItemIsEnabled + + + + + noEndTreatment + + + Unchecked + + + ItemIsUserCheckable|ItemIsEnabled + + + + + noNewTreatment + + + Unchecked + + + ItemIsUserCheckable|ItemIsEnabled + + + + + bypassDialyzer + + + Unchecked + + + ItemIsUserCheckable|ItemIsEnabled + + + + + alarmsToEscalate + + + Unchecked + + + ItemIsUserCheckable|ItemIsEnabled + + + + + alarmsSilenced + + + Unchecked + + + ItemIsUserCheckable|ItemIsEnabled + + + + + userAcknowledged + + + Unchecked + + + ItemIsUserCheckable|ItemIsEnabled + + + + + + + + + + Qt::ScrollBarAlwaysOn + + + Qt::ScrollBarAlwaysOn + + + QAbstractItemView::NoEditTriggers + + + false + + + false + + + true + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + true + + + true + + + true + + + true + + + + + + + + + color: rgb(238, 238, 236); +background-color: rgb(252, 175, 62); + + + Alarm Trigger + + + Qt::AlignCenter + + + + + + + Trigger + + + Shift+Return + + + + + + + false + + + Clear + + + Shift+Del + + + + + + + + + + 0 + 0 + + + + Alarm ID : + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + spnAlarmID + + + + + + + 1 + + + 65535 + + + + + + + + + Qt::ScrollBarAlwaysOn + + + Qt::ScrollBarAlwaysOn + + + QAbstractItemView::NoEditTriggers + + + false + + + false + + + true + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + true + + + true + + + true + + + true + + + + Time + + + + + Alarm ID + + + + + + + + + + color: rgb(238, 238, 236); +background-color: rgb(252, 175, 62); + + + Alarm Status + + + Qt::AlignCenter + + + + + + + + + spnTopID + rdoPriorityNone + rdoPriorityLow + rdoPriorityMed + rdoPriorityHigh + spnEscalatesIn + spnMuteTimeout + lstFlags + spnAlarmID + tblTriggeredIDs + tblStatusIDs + btnSend + btnMute + btnTrigger + btnClear + + + + + rdoPriorityNone + toggled(bool) + rdoPriorityNone + setDisabled(bool) + + + 168 + 141 + + + 174 + 138 + + + + + rdoPriorityLow + toggled(bool) + rdoPriorityLow + setDisabled(bool) + + + 190 + 136 + + + 200 + 144 + + + + + rdoPriorityMed + toggled(bool) + rdoPriorityMed + setDisabled(bool) + + + 217 + 139 + + + 226 + 138 + + + + + rdoPriorityHigh + toggled(bool) + rdoPriorityHigh + setDisabled(bool) + + + 244 + 134 + + + 253 + 137 + + + + + Index: simulator/plugins/alarms/loader.py =================================================================== diff -u --- simulator/plugins/alarms/loader.py (revision 0) +++ simulator/plugins/alarms/loader.py (revision 69b2aacf31c5fdc28e078f87dbdee5c3ab672dd1) @@ -0,0 +1,306 @@ +""" + The Alarms ui loader class container file +""" +import os +from simulator.runtimewidget import RunTimeWidget +from PySide2 import QtWidgets +from PySide2.QtCore import Slot, QObject, Qt, QSize +from dialin.squish import denaliMessages +from datetime import datetime +from dialin.common.prs_defs import AlarmPriority + + +class Loader(RunTimeWidget): + """ + The Alarms ui loader class + """ + + btnTrigger: QtWidgets.QPushButton + btnClear: QtWidgets.QPushButton + spnAlarmID: QtWidgets.QSpinBox + tblStatusIDs: QtWidgets.QTableWidget + + btnSend: QtWidgets.QPushButton + btnMute: QtWidgets.QPushButton + spnTopID: QtWidgets.QSpinBox + rdoPriorityNone: QtWidgets.QToolBox + rdoPriorityLow: QtWidgets.QToolBox + rdoPriorityMed: QtWidgets.QToolBox + rdoPriorityHigh: QtWidgets.QToolBox + spnEscalatesIn: QtWidgets.QSpinBox + spnMuteTimeout: QtWidgets.QSpinBox + lstFlags: QtWidgets.QListWidget + tblTriggeredIDs: QtWidgets.QTableWidget + + priority = 0 + flags = 0 + + eColTime = 0 + eColID = 1 + eColMute = 2 + eColEscalate = 3 + eColFlags = 4 + eColMessage = 5 + eColCount = 6 + # column: (width, text) + fixedLabels = { + eColTime: (70, 'Time'), + eColID: (45, 'Top ID'), + eColMute: (100, 'Mute'), + eColEscalate: (45, 'Escl'), + eColFlags: (150, 'Flags'), + eColMessage: (100, 'Message'), + } + + colors = { + AlarmPriority.ALARM_NONE: Qt.green, + AlarmPriority.ALARM_LOW: Qt.yellow, + AlarmPriority.ALARM_MED: Qt.yellow, + AlarmPriority.ALARM_HIGH: Qt.red + } + styles = { + AlarmPriority.ALARM_NONE: 'rgb(78, 154, 6)', + AlarmPriority.ALARM_LOW: 'rgb(237, 212, 0)', + AlarmPriority.ALARM_MED: 'rgb(237, 212, 0)', + AlarmPriority.ALARM_HIGH: 'rgb(239, 41, 41)' + } + + def __init__(self): + super().__init__(os.path.dirname(__file__)) + self.initialize() + self.init_widgets() + self.init_connections() + + def initialize(self): + """ + finds and creates widgets + :return: none + """ + self.btnSend = self.find_button('btnSend') + self.btnMute = self.find_button('btnMute') + self.spnTopID = self.find_spinbox('spnTopID') + self.rdoPriorityNone = self.find_tool_button('rdoPriorityNone') + self.rdoPriorityLow = self.find_tool_button('rdoPriorityLow') + self.rdoPriorityMed = self.find_tool_button('rdoPriorityMed') + self.rdoPriorityHigh = self.find_tool_button('rdoPriorityHigh') + self.spnEscalatesIn = self.find_spinbox('spnEscalatesIn') + self.spnMuteTimeout = self.find_spinbox('spnMuteTimeout') + self.lstFlags = self.find_list_widget('lstFlags') + self.tblStatusIDs = self.find_table_widget('tblStatusIDs') + + self.btnTrigger = self.find_button('btnTrigger') + self.btnClear = self.find_button('btnClear') + self.spnAlarmID = self.find_spinbox('spnAlarmID') + self.tblTriggeredIDs = self.find_table_widget('tblTriggeredIDs') + + def init_widgets(self): + """ + initializes the widgets' properties + :return: none + """ + self.__populate_status_ids_columns() + self.rdoPriorityNone.setStyleSheet('background-color: {};'.format(self.styles[AlarmPriority.ALARM_NONE])) + self.rdoPriorityLow.setStyleSheet('background-color: {};'.format(self.styles[AlarmPriority.ALARM_LOW])) + self.rdoPriorityMed.setStyleSheet('background-color: {};'.format(self.styles[AlarmPriority.ALARM_MED])) + self.rdoPriorityHigh.setStyleSheet('background-color: {};'.format(self.styles[AlarmPriority.ALARM_HIGH])) + + self.tblTriggeredIDs.setColumnWidth(0, 75) + self.tblTriggeredIDs.setColumnWidth(1, 45) + + def init_connections(self): + """ + initializes the widgets connections + :return: + """ + self.btnTrigger.clicked.connect(self.do_trigger) + self.btnClear.clicked.connect(self.do_clear) + self.tblTriggeredIDs.itemClicked.connect(self.on_trigger_ids_item_clicked) + + self.btnSend.clicked.connect(self.do_send) + self.btnMute.clicked.connect(self.do_mute) # item clicked might be enough + self.tblStatusIDs.itemClicked.connect(self.on_status_ids_item_clicked) + self.rdoPriorityNone.toggled.connect(self.do_set_priority_none) + self.rdoPriorityLow.toggled.connect(self.do_set_priority_low) + self.rdoPriorityMed.toggled.connect(self.do_set_priority_med) + self.rdoPriorityHigh.toggled.connect(self.do_set_priority_high) + + def set_flags(self): + """ + the slot for flags + :return: none + """ + highest = True + lst = self.lstFlags + for i in range(lst.count()): + if highest: + bit = pow(2, 15 - i) + else: + bit = pow(2, i) + + if lst.item(i).checkState() == Qt.Checked: + self.flags |= bit + else: + self.flags &= ~bit + + @Slot() + def do_set_priority_none(self): + """ + the slot for priority buttons + :return: none + """ + self.priority = AlarmPriority.ALARM_NONE + + @Slot() + def do_set_priority_low(self): + """ + the slot for priority buttons + :return: none + """ + self.priority = AlarmPriority.ALARM_LOW + + @Slot() + def do_set_priority_med(self): + """ + the slot for priority buttons + :return: none + """ + self.priority = AlarmPriority.ALARM_MED + + @Slot() + def do_set_priority_high(self): + """ + the slot for priority buttons + :return: none + """ + self.priority = AlarmPriority.ALARM_HIGH + + @Slot() + def do_send(self): + """ + the slot for send button + :return: none + """ + alarm_id = self.spnTopID.value() + escalate = self.spnEscalatesIn.value() + mute_out = self.spnMuteTimeout.value() + if alarm_id >= 0: + self.set_flags() + denaliMessages.setAlarmStatus(self.priority, + alarm_id, + escalate, + mute_out, + self.flags) + self.__append_status_ids_row(alarm_id) + + @Slot() + def do_trigger(self): + """ + the slot for trigger button + :return: none + """ + alarm_id = self.spnAlarmID.value() + if alarm_id: + denaliMessages.setAlarmTriggered(alarm_id) + self.__append_triggered_row(alarm_id) + + @Slot() + def do_clear(self): + """ + the slot for clear button + :return: none + """ + items = self.tblTriggeredIDs.selectedItems() + if len(items): + item: QtWidgets.QTableWidgetItem = items[0] + row = item.row() + model = self.tblTriggeredIDs.model() + alarm_id = model.data(model.index(row, self.eColID)) + denaliMessages.setAlarmCleared(alarm_id) + self.tblTriggeredIDs.removeRow(row) + + @Slot() + def do_mute(self, value): + """ + the slot for mute button + :return: none + """ + print(" --- ", QObject.sender(self).objectName()) + + @Slot() + def on_status_ids_item_clicked(self, item: QtWidgets.QTableWidgetItem): + """ + slot to handle on item clicked + :param item: the clicked item + :return: None + """ + selected = item.isSelected() + self.btnMute.setEnabled(selected) + + @Slot() + def on_trigger_ids_item_clicked(self, item: QtWidgets.QTableWidgetItem): + """ + slot to handle on item clicked + :param item: the clicked item + :return: None + """ + selected = item.isSelected() + self.btnClear.setEnabled(selected) + + def __populate_status_ids_columns(self): + """ + adds alarm flags as columns in the Status alarms table + :return: None + """ + items = sorted(self.fixedLabels.items()) + self.tblStatusIDs.setColumnCount(self.eColCount) + self.tblStatusIDs.setHorizontalHeaderLabels([v[1] for k, v in items]) + for col, item in items: + self.tblStatusIDs.setColumnWidth(col, item[0]) + + def __append_status_ids_row(self, alarm_id): + """ + appends the Status alarm id into the Status list + :return: None + """ + inset_at_top = True + + now = datetime.now().strftime("%H:%M:%S") + + items = self.tblStatusIDs.findItems(str(alarm_id), Qt.MatchExactly) + if len(items): + item: QtWidgets.QTableWidgetItem = items[0] + row = item.row() + else: + row = 0 if inset_at_top else self.tblStatusIDs.rowCount() + self.tblStatusIDs.insertRow(row) + + model = self.tblStatusIDs.model() + model.setData(model.index(row, self.eColTime), now) + model.setData(model.index(row, self.eColID), alarm_id) + model.setData(model.index(row, self.eColMute), self.spnMuteTimeout.value()) + model.setData(model.index(row, self.eColEscalate), self.spnEscalatesIn.value()) + self.tblStatusIDs.item(row, self.eColMute).setCheckState(Qt.Unchecked) + model.setData(model.index(row, self.eColMessage), "N/A") + model.setData(model.index(row, self.eColFlags), '{:016b}'.format(self.flags, 'b')) + self.tblStatusIDs.item(row, self.eColID).setBackground(self.colors[self.priority]) + + def __append_triggered_row(self, alarm_id): + """ + appends the triggered alarm id into the triggered list + :return: None + """ + inset_at_top = True + + now = datetime.now().strftime("%H:%M:%S") + + items = self.tblTriggeredIDs.findItems(str(alarm_id), Qt.MatchExactly) + if len(items): + item: QtWidgets.QTableWidgetItem = items[0] + row = item.row() + else: + row = 0 if inset_at_top else self.tblTriggeredIDs.rowCount() + self.tblTriggeredIDs.insertRow(row) + + model = self.tblTriggeredIDs.model() + model.setData(model.index(row, self.eColTime), now) + model.setData(model.index(row, self.eColID), alarm_id) Index: simulator/plugins/heparin/loader.py =================================================================== diff -u -r2b0ff4367443cf0458594c81c32598df5b6c39cb -r69b2aacf31c5fdc28e078f87dbdee5c3ab672dd1 --- simulator/plugins/heparin/loader.py (.../loader.py) (revision 2b0ff4367443cf0458594c81c32598df5b6c39cb) +++ simulator/plugins/heparin/loader.py (.../loader.py) (revision 69b2aacf31c5fdc28e078f87dbdee5c3ab672dd1) @@ -1,14 +1,15 @@ """ The Heparin ui loader class """ -from runtimewidget import RunTimeWidget +import os +from simulator.runtimewidget import RunTimeWidget from PySide2 import QtWidgets from PySide2.QtCore import Slot from dialin.squish import denaliMessages from dialin.squish.denaliMessages import txStates -class Heparin(RunTimeWidget): +class Loader(RunTimeWidget): """ The Saline Bolus ui loader class """ @@ -23,7 +24,7 @@ requested_state: txStates def __init__(self): - super().__init__("plugins/heparin/interface.ui") + super().__init__(os.path.dirname(__file__)) self.requested_state = txStates.HEPARIN_STATE_PAUSED self.initialize() self.init_widgets() Index: simulator/plugins/inlinebloodpressures/loader.py =================================================================== diff -u -rc13dc6ba2410716a3f1c446e564085aeb9114a60 -r69b2aacf31c5fdc28e078f87dbdee5c3ab672dd1 --- simulator/plugins/inlinebloodpressures/loader.py (.../loader.py) (revision c13dc6ba2410716a3f1c446e564085aeb9114a60) +++ simulator/plugins/inlinebloodpressures/loader.py (.../loader.py) (revision 69b2aacf31c5fdc28e078f87dbdee5c3ab672dd1) @@ -1,16 +1,16 @@ """ The In-Line Blood Pressure ui class """ - -from runtimewidget import RunTimeWidget +import os +from simulator.runtimewidget import RunTimeWidget from PySide2 import QtWidgets -from PySide2.QtCore import QObject, Slot +from PySide2.QtCore import Slot from dialin.squish import denaliMessages from dialin.squish.denaliMessages import txStates, EResponse from dialin.common import Ranges -class InlineBloodPressures(RunTimeWidget): +class Loader(RunTimeWidget): """ The In-Line Blood Pressure ui class """ @@ -35,7 +35,7 @@ sldVenousValue: QtWidgets.QSlider def __init__(self): - super().__init__("plugins/inlinebloodpressures/interface.ui") + super().__init__(os.path.dirname(__file__)) self.saline_requested_state = txStates.SALINE_BOLUS_STATE_IDLE self.initialize() self.init_widgets() Index: simulator/plugins/salinebolus/loader.py =================================================================== diff -u -rc13dc6ba2410716a3f1c446e564085aeb9114a60 -r69b2aacf31c5fdc28e078f87dbdee5c3ab672dd1 --- simulator/plugins/salinebolus/loader.py (.../loader.py) (revision c13dc6ba2410716a3f1c446e564085aeb9114a60) +++ simulator/plugins/salinebolus/loader.py (.../loader.py) (revision 69b2aacf31c5fdc28e078f87dbdee5c3ab672dd1) @@ -1,14 +1,15 @@ """ The Saline Bolus ui loader class """ -from runtimewidget import RunTimeWidget +import os +from simulator.runtimewidget import RunTimeWidget from PySide2 import QtWidgets from PySide2.QtCore import Slot from dialin.squish import denaliMessages -from dialin.squish.denaliMessages import txStates, EResponse +from dialin.squish.denaliMessages import txStates -class SalineBolus(RunTimeWidget): +class Loader(RunTimeWidget): """ The Saline Bolus ui loader class """ @@ -25,7 +26,7 @@ saline_requested_state: txStates def __init__(self): - super().__init__("plugins/salinebolus/interface.ui") + super().__init__(os.path.dirname(__file__)) self.saline_requested_state = txStates.SALINE_BOLUS_STATE_IDLE self.initialize() self.init_widgets() Index: simulator/plugins/treatmentranges/loader.py =================================================================== diff -u -rc13dc6ba2410716a3f1c446e564085aeb9114a60 -r69b2aacf31c5fdc28e078f87dbdee5c3ab672dd1 --- simulator/plugins/treatmentranges/loader.py (.../loader.py) (revision c13dc6ba2410716a3f1c446e564085aeb9114a60) +++ simulator/plugins/treatmentranges/loader.py (.../loader.py) (revision 69b2aacf31c5fdc28e078f87dbdee5c3ab672dd1) @@ -1,15 +1,15 @@ """ The Treatment Ranges ui loader """ -from runtimewidget import RunTimeWidget +import os +from simulator.runtimewidget import RunTimeWidget from PySide2 import QtWidgets from PySide2.QtCore import QTimer from PySide2.QtCore import Slot from dialin.squish import denaliMessages -from dialin.squish.denaliMessages import txStates, EResponse -class TreatmentRanges(RunTimeWidget): +class Loader(RunTimeWidget): """ The Treatment Ranges ui loader """ @@ -25,7 +25,7 @@ sldDurationValue: QtWidgets.QSlider def __init__(self): - super().__init__("plugins/treatmentranges/interface.ui") + super().__init__(os.path.dirname(__file__)) self.initialize() self.init_widgets() self.init_connections() Index: simulator/plugins/treatmentstates/loader.py =================================================================== diff -u -rc13dc6ba2410716a3f1c446e564085aeb9114a60 -r69b2aacf31c5fdc28e078f87dbdee5c3ab672dd1 --- simulator/plugins/treatmentstates/loader.py (.../loader.py) (revision c13dc6ba2410716a3f1c446e564085aeb9114a60) +++ simulator/plugins/treatmentstates/loader.py (.../loader.py) (revision 69b2aacf31c5fdc28e078f87dbdee5c3ab672dd1) @@ -1,14 +1,15 @@ """ The Ultrafiltration ui loader """ -from runtimewidget import RunTimeWidget +import os +from simulator.runtimewidget import RunTimeWidget from PySide2 import QtWidgets from PySide2.QtCore import Slot from dialin.squish import denaliMessages -from dialin.squish.denaliMessages import txStates, EResponse +from dialin.squish.denaliMessages import txStates -class TreatmentStates(RunTimeWidget): +class Loader(RunTimeWidget): """ The Ultrafiltration ui loader """ @@ -18,7 +19,7 @@ tblHeparinStates: QtWidgets.QTableWidget def __init__(self): - super().__init__("plugins/treatmentstates/interface.ui") + super().__init__(os.path.dirname(__file__)) self.initialize() self.init_widgets() self.init_connections() Index: simulator/plugins/ultrafiltration/loader.py =================================================================== diff -u -rc13dc6ba2410716a3f1c446e564085aeb9114a60 -r69b2aacf31c5fdc28e078f87dbdee5c3ab672dd1 --- simulator/plugins/ultrafiltration/loader.py (.../loader.py) (revision c13dc6ba2410716a3f1c446e564085aeb9114a60) +++ simulator/plugins/ultrafiltration/loader.py (.../loader.py) (revision 69b2aacf31c5fdc28e078f87dbdee5c3ab672dd1) @@ -1,14 +1,15 @@ """ The Ultrafiltration ui loader """ -from runtimewidget import RunTimeWidget +import os +from simulator.runtimewidget import RunTimeWidget from PySide2 import QtWidgets from PySide2.QtCore import Slot from dialin.squish import denaliMessages from dialin.squish.denaliMessages import txStates, EResponse -class Ultrafiltration(RunTimeWidget): +class Loader(RunTimeWidget): """ The Ultrafiltration ui loader """ @@ -31,7 +32,7 @@ sldUfVolume: QtWidgets.QSlider def __init__(self): - super().__init__("plugins/ultrafiltration/interface.ui") + super().__init__(os.path.dirname(__file__)) self.initialize() self.init_widgets() self.init_connections() Index: simulator/run.py =================================================================== diff -u -rc13dc6ba2410716a3f1c446e564085aeb9114a60 -r69b2aacf31c5fdc28e078f87dbdee5c3ab672dd1 --- simulator/run.py (.../run.py) (revision c13dc6ba2410716a3f1c446e564085aeb9114a60) +++ simulator/run.py (.../run.py) (revision 69b2aacf31c5fdc28e078f87dbdee5c3ab672dd1) @@ -1,128 +1,13 @@ -# import system modules +""" +the main function +to load the main simulator loader widget +""" import sys - -# import project classes -# import names from dialin.squish import utils -from dialin.squish.denaliMessages import txStates -# Import PySide2 classes from PySide2 import QtCore, QtWidgets -from PySide2.QtCore import Qt +from simulator.loader import Simulator -from runtimewidget import RunTimeWidget -# later it's planed to load all the classes in plugin folder dynamically -# so used * in here to load all -from plugins import * - -class Simulator(RunTimeWidget): - """ - The simulator class which loads the ui file dynamically and initializes the objects - and can be eventually shown. - Note: this class is growing fast and seems like needs to be multiple classes - """ - mdiArea: QtWidgets.QMdiArea - - obj_ultrafiltration: Ultrafiltration - sub_ultrafiltration: QtWidgets.QMdiSubWindow - wgt_ultrafiltration: QtWidgets.QWidget - act_ultrafiltration: QtWidgets.QAction - - obj_inlinebloodpressures: InlineBloodPressures - sub_inlinebloodpressures: QtWidgets.QMdiSubWindow - wgt_inlinebloodpressures: QtWidgets.QWidget - act_inlinebloodpressures: QtWidgets.QAction - - obj_salinebolus: SalineBolus - sub_salinebolus: QtWidgets.QMdiSubWindow - wgt_salinebolus: QtWidgets.QWidget - act_salinebolus: QtWidgets.QAction - - obj_treatmentstates: TreatmentStates - sub_treatmentstates: QtWidgets.QMdiSubWindow - wgt_treatmentstates: QtWidgets.QWidget - act_treatmentstates: QtWidgets.QAction - - obj_treatmentranges: TreatmentRanges - sub_treatmentranges: QtWidgets.QMdiSubWindow - wgt_treatmentranges: QtWidgets.QWidget - act_treatmentranges: QtWidgets.QAction - - obj_heparin: Heparin - sub_heparin: QtWidgets.QMdiSubWindow - wgt_heparin: QtWidgets.QWidget - act_heparin: QtWidgets.QAction - - def __init__(self): - super().__init__("simulator.ui") - self.saline_requested_state = txStates.SALINE_BOLUS_STATE_IDLE - self.initialize() - self.init_widgets() - self.init_connections() - - def initialize(self): - """ - initializes the class by calling it's initializer methods to make objects ready - :return: none - """ - self.mdiArea = self.find_widget(QtWidgets.QMdiArea, 'mdiArea') - - # TODO: this section needs to change to go over the folders in the plugins folder and load each automatically - - self.act_treatmentstates = self.find_action('actTreatmentStates') - self.act_treatmentranges = self.find_action('actTreatmentRanges') - self.act_ultrafiltration = self.find_action('actUltrafiltration') - self.act_salinebolus = self.find_action('actSalineBolus') - self.act_inlinebloodpressures = self.find_action('actInLineBloodPressures') - self.act_heparin = self.find_action('actionHeparin') - - def init_widgets(self): - """ - initializes the widgets' properties - :return: none - """ - # ultrafiltration - self.obj_ultrafiltration = Ultrafiltration() - self.wgt_ultrafiltration = self.obj_ultrafiltration.window - self.sub_ultrafiltration = self.mdiArea.addSubWindow(self.wgt_ultrafiltration) - - self.obj_inlinebloodpressures = InlineBloodPressures() - self.wgt_inlinebloodpressures = self.obj_inlinebloodpressures.window - self.sub_inlinebloodpressures = self.mdiArea.addSubWindow(self.wgt_inlinebloodpressures) - - self.obj_salinebolus = SalineBolus() - self.wgt_salinebolus = self.obj_salinebolus.window - self.sub_salinebolus = self.mdiArea.addSubWindow(self.wgt_salinebolus) - - self.obj_treatmentstates = TreatmentStates() - self.wgt_treatmentstates = self.obj_treatmentstates.window - self.sub_treatmentstates = self.mdiArea.addSubWindow(self.wgt_treatmentstates) - - self.obj_treatmentranges = TreatmentRanges() - self.wgt_treatmentranges = self.obj_treatmentranges.window - self.sub_treatmentranges = self.mdiArea.addSubWindow(self.wgt_treatmentranges) - - self.obj_heparin = Heparin() - self.wgt_heparin = self.obj_heparin.window - self.sub_heparin = self.mdiArea.addSubWindow(self.wgt_heparin) - - for sub in self.mdiArea.subWindowList(): - sub.setWindowFlags(Qt.WindowMinimizeButtonHint | Qt.WindowTitleHint) - sub.setVisible(False) - - def init_connections(self): - """ - initializes the widgets connections - :return: none - """ - self.act_treatmentstates.toggled.connect(self.sub_treatmentstates.setVisible) - self.act_treatmentranges.toggled.connect(self.sub_treatmentranges.setVisible) - self.act_ultrafiltration.toggled.connect(self.sub_ultrafiltration.setVisible) - self.act_salinebolus.toggled.connect(self.sub_salinebolus.setVisible) - self.act_inlinebloodpressures.toggled.connect(self.sub_inlinebloodpressures.setVisible) - self.act_heparin.toggled.connect(self.sub_heparin.setVisible) - - def main(): """ the main function which initializes the Simulator and starts it. Fisheye: Tag 69b2aacf31c5fdc28e078f87dbdee5c3ab672dd1 refers to a dead (removed) revision in file `simulator/runtimewidget.py'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 69b2aacf31c5fdc28e078f87dbdee5c3ab672dd1 refers to a dead (removed) revision in file `simulator/simulator.ui'. Fisheye: No comparison available. Pass `N' to diff? Index: simulator/simulator/interface.ui =================================================================== diff -u --- simulator/simulator/interface.ui (revision 0) +++ simulator/simulator/interface.ui (revision 69b2aacf31c5fdc28e078f87dbdee5c3ab672dd1) @@ -0,0 +1,149 @@ + + + MainWindow + + + + 0 + 0 + 451 + 298 + + + + MainWindow + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + 1 + + + + + + 0 + 0 + + + + QFrame::StyledPanel + + + + + + + + + + QFrame::StyledPanel + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + 0 + 0 + 451 + 22 + + + + + &View + + + + + + &Windows + + + + + + + + + + Cascade + + + + + true + + + Show All + + + + + + + actionCascade + triggered() + mdiArea + cascadeSubWindows() + + + -1 + -1 + + + 600 + 409 + + + + + Index: simulator/simulator/loader.py =================================================================== diff -u --- simulator/simulator/loader.py (revision 0) +++ simulator/simulator/loader.py (revision 69b2aacf31c5fdc28e078f87dbdee5c3ab672dd1) @@ -0,0 +1,129 @@ +""" +the plugin loader class +""" +import os + +from dialin.squish.denaliMessages import txStates +from dialin.squish.utils import check_can0 + +from PySide2 import QtWidgets +from PySide2.QtCore import Qt + +from simulator.runtimewidget import RunTimeWidget + +# later it's planed to load all the classes in plugin folder dynamically +# so used * in here to load all +from plugins import * + + +class Simulator(RunTimeWidget): + """ + The simulator class which loads the ui file dynamically and initializes the objects + and can be eventually shown. + Note: this class is growing fast and seems like needs to be multiple classes + """ + mdiArea: QtWidgets.QMdiArea + menuView: QtWidgets.QMenu + lblStatusCANBus: QtWidgets.QLabel + lblStatusMessages: QtWidgets.QLabel + + plugins = [] + + def __init__(self): + super().__init__(os.path.dirname(__file__)) + self.saline_requested_state = txStates.SALINE_BOLUS_STATE_IDLE + self.__initialize() + if self.__check_can_bus(): + self.__init_plugins() + self.__init_connections() + + def __initialize(self): + """ + initializes the class by calling it's initializer methods to make objects ready + :return: none + """ + self.lblStatusCANBus = self.find_label('lblStatusCANBus') + self.lblStatusMessages = self.find_label('lblStatusMessages') + self.mdiArea = self.find_widget(QtWidgets.QMdiArea, 'mdiArea') + self.menuView = self.find_widget(QtWidgets.QMenu, 'menuView') + self.action_show_all = self.find_action('actionShowAll') + + def __init_plugins(self): + """ + initializes the widgets' properties + :return: none + """ + # loading/registering plugins + self.__register_plugin('TreatmentStates', TreatmentStates()) + self.__register_plugin('TreatmentRanges', TreatmentRanges(), True) + self.__register_plugin('Ultrafiltration', Ultrafiltration()) + self.__register_plugin('InlineBloodPressures', InlineBloodPressures()) + self.__register_plugin('SalineBolus', SalineBolus()) + self.__register_plugin('Heparin', Heparin(), True) + self.__register_plugin('Alarms', Alarms(), maximize=True) + + def __init_connections(self): + """ + initializes the widgets connections + :return: none + """ + self.action_show_all.toggled.connect(self.set_all_windows_visible) + + def __create_actions(self, name: str, window: QtWidgets.QWidget): + """ + creates a menu action item with the name/title name and set to show/hide the plugin form object + :param name: the action menu title + :param window: the object to show/hide + :return: false if the object is None + """ + if window is None: + return False + + act = self.menuView.addAction(name) + act.setCheckable(True) + act.toggled.connect(window.setVisible) + self.action_show_all.toggled.connect(act.setChecked) + + def __register_plugin(self, name: str, obj: RunTimeWidget, + add_separator: bool = False, visible: bool = False, maximize: bool = False): + """ + creates the plugin object and adds it to the mdi and creates an action menu for it + :param name: action menu title + :param obj: the plugin object + :return: False if the passed obj is None + """ + self.plugins.append(obj) + wgt = obj.window + sub = self.mdiArea.addSubWindow(wgt) + sub.setWindowFlags(Qt.WindowMinimizeButtonHint | Qt.WindowTitleHint) + if maximize: + sub.setWindowFlag(Qt.WindowMaximizeButtonHint, True) + sub.setVisible(visible) + self.__create_actions(name, sub) + if add_separator: + self.menuView.addSeparator() + + def set_all_windows_visible(self, visible: bool): + """ + sets all the windows (in)visible + :param visible: if true the windows are set to visible + :return: None + """ + for sub in self.mdiArea.subWindowList(): + sub.setVisible(visible) + + def __check_can_bus(self): + """ + checks if CANBus can0 presents + :return: False if CANBus can0 is not present. + """ + ok, msg = check_can0() + print(ok, msg) + + if ok: + self.lblStatusCANBus.setStyleSheet('color: rgb(78, 154, 6);') + self.lblStatusCANBus.setText('CANBus: can0') + return ok + else: + self.lblStatusCANBus.setStyleSheet('color: rgb(239, 41, 41);') + self.lblStatusCANBus.setText('CANBus \'can0\' not found') Index: simulator/simulator/runtimewidget.py =================================================================== diff -u --- simulator/simulator/runtimewidget.py (revision 0) +++ simulator/simulator/runtimewidget.py (revision 69b2aacf31c5fdc28e078f87dbdee5c3ab672dd1) @@ -0,0 +1,145 @@ +""" + find and loads the ui objects +""" +import os +from PySide2.QtUiTools import QUiLoader +from PySide2.QtCore import QFile, QObject +from PySide2 import QtWidgets + + +class RunTimeWidget(QObject): + """ + the parent class of all the run time loadable widgets + """ + + loader: QUiLoader + window: QtWidgets.QWidget + + def __init__(self, location: str): + super().__init__(None) + self.location = location + 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.location + "/interface.ui") + 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_widget(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_action(self, name: str) -> QtWidgets.QAction: + """ + convenient method of find_widget for QAction + :param name: (str) name of the QLabel Object + :return: (QAction) reference to the QAction + """ + child = self.find_widget(QtWidgets.QAction, name) + return child + + def find_label(self, name: str) -> QtWidgets.QLabel: + """ + convenient method of find_widget for QLabel + :param name: (str) name of the QLabel Object + :return: (QLabel) reference to the QLabel + """ + child = self.find_widget(QtWidgets.QLabel, name) + return child + + def find_button(self, name: str) -> QtWidgets.QPushButton: + """ + convenient method of find_widget for QPushButton + :param name: (str) name of the QPushButton Object + :return: (QPushButton) reference to the QPushButton + """ + child = self.find_widget(QtWidgets.QPushButton, name) + return child + + def find_combobox(self, name: str) -> QtWidgets.QComboBox: + """ + convenient method of find_widget for QComboBox + :param name: (str) name of the QComboBox Object + :return: (QComboBox) reference to the QComboBox + """ + child = self.find_widget(QtWidgets.QComboBox, name) + return child + + def find_checkbox(self, name: str) -> QtWidgets.QCheckBox: + """ + convenient method of find_widget for QCheckBox + :param name: (str) name of the QCheckBox Object + :return: (QCheckBox) reference to the QComboBox + """ + child = self.find_widget(QtWidgets.QCheckBox, name) + return child + + def find_spinbox(self, name: str) -> QtWidgets.QSpinBox: + """ + convenient method of find_widget for QSpinBox + :param name: (str) name of the QSpinBox Object + :return: (QSpinBox) reference to the QSpinBox + """ + child = self.find_widget(QtWidgets.QSpinBox, name) + return child + + def find_slider(self, name: str) -> QtWidgets.QSlider: + """ + convenient method of find_widget for QSlider + :param name: (str) name of the QSlider Object + :return: (QSlider) reference to the QSlider + """ + child = self.find_widget(QtWidgets.QSlider, name) + return child + + def find_table_widget(self, name: str) -> QtWidgets.QTableWidget: + """ + convenient method of find_widget for QTableWidget + :param name: (str) name of the QTableWidget Object + :return: (QTableWidget) reference to the QTableWidget + """ + child: QtWidgets.QTableWidget = self.find_widget(QtWidgets.QTableWidget, name) + return child + + def find_list_widget(self, name: str) -> QtWidgets.QListWidget: + """ + convenient method of find_widget for QListWidget + :param name: (str) name of the QListWidget Object + :return: (QListWidget) reference to the QListWidget + """ + child: QtWidgets.QListWidget = self.find_widget(QtWidgets.QListWidget, name) + return child + + def find_tool_button(self, name: str) -> QtWidgets.QToolButton: + """ + convenient method of find_widget for QToolButton + :param name: (str) name of the QToolButton Object + :return: (QToolButton) reference to the QToolButton + """ + child: QtWidgets.QToolButton = self.find_widget(QtWidgets.QToolButton, name) + return child +