Пример #1
0
    def display_graph(self):
        '''Display the graph tabs and all their contents'''
        gp_vlay = QVBoxLayout()
        tab = QTabWidget()
        tab.setObjectName("LITab")

        for graph_name in self.graph_all_data:
            tablay = QVBoxLayout()
            tab_content = QWidget()

            graph_item = self.graph_all_data.get(graph_name)

            if len(graph_item.items()) != 2:
                tablay.addWidget(self.createGraph(graph_item), 10)
                tab_content.setLayout(tablay)
            else:
                for data in graph_item:
                    tablay.addWidget(self.createGraph(graph_item.get(data)),
                                     10)

                tab_content.setLayout(tablay)
            tab.addTab(tab_content, graph_name)

        gp_vlay.addWidget(tab)

        return gp_vlay
Пример #2
0
    def updateEditors(self, *, payloadsView: QWidget, blocksView: QWidget,
                      panelsView: QWidget, imagesView: QWidget) -> None:
        descriptionTextEdit = QPlainTextEdit()
        self.descriptionTextEdit = descriptionTextEdit

        descriptionLayout = QVBoxLayout()
        descriptionLayout.addWidget(descriptionTextEdit)

        descriptionBox = QGroupBox()
        descriptionBox.setTitle("Description")
        descriptionBox.setLayout(descriptionLayout)
        descriptionBox.setMaximumHeight(130)

        tabWidget = QTabWidget()
        tabWidget.setObjectName("settingsWidget")
        tabWidget.setTabPosition(QTabWidget.North)
        tabWidget.addTab(payloadsView, "Payloads")
        tabWidget.addTab(blocksView, "Blocks")
        tabWidget.addTab(panelsView, "Panels")
        tabWidget.addTab(imagesView, "Images")
        self.tabWidget = tabWidget

        layout = QVBoxLayout()
        layout.addWidget(descriptionBox, stretch=0)
        layout.addWidget(tabWidget, stretch=1)

        # replace no_project_selected_label with the settings layout
        parentLayout: QHBoxLayout = self.layout()
        item: QLayoutItem = parentLayout.takeAt(
            2)  # after statusWidget and spacer
        if item.widget() is not None:
            item.widget().deleteLater()
        parentLayout.addLayout(layout, stretch=1)
Пример #3
0
 def displayTabs(self):
     ''' Display all the tabs '''
     tab = QTabWidget()
     tab.setObjectName("LITab")
     tab.addTab(self.displayControlMPS(0), "MPS Controls")
     tab.addTab(self.displayControlMPS(1), "Temperature")
     tab.currentChanged.connect(self.adjustSize)
     return tab
Пример #4
0
    def _setup_ui(self):
        cwid = QTabWidget()

        for section in ('tb', 'bo', 'ts', 'si'):
            widget = EnergyButton(section, parent=cwid)
            cwid.addTab(widget, section.upper())
        self.setCentralWidget(cwid)
        cwid.setObjectName('cwid')
        cwid.setStyleSheet('#cwid{width: 20em; height: 25em;}')
Пример #5
0
    def _setupUi(self):
        lay = QGridLayout(self)
        lay.setAlignment(Qt.AlignTop)
        lay.setHorizontalSpacing(25)
        lay.setVerticalSpacing(15)

        self.title = QLabel(
            '<h3>RF Temperature Monitor</h3>', self,
            alignment=Qt.AlignCenter)
        lay.addWidget(self.title, 0, 0)

        if len(self.chs['TempMon']) == 1:
            dettab = QTabWidget(self)
        else:
            dettab = DetachableTabWidget(self)
        dettab.setObjectName(self.section+'Tab')
        for dettabtitle, dtcontent in self.chs['TempMon'].items():
            if dettabtitle == 'Power':
                labels = list(dtcontent.keys())
                channels = [self.prefix+ch for ch in dtcontent.values()]
                wid = BarGraph(
                    channels=channels, xLabels=labels, yLabel='Power [kW]',
                    title=dettabtitle)
            else:
                wid = QTabWidget()
                for tabtitle, content in dtcontent.items():
                    labels = list(content.keys())
                    channels = [self.prefix+ch for ch in content.values()]
                    ylabel = 'Temperature [°C]' \
                        if 'temp' in dettabtitle.lower() \
                        else 'Diss. Power [kW]'
                    tabwid = BarGraph(
                        channels=channels, xLabels=labels,
                        yLabel=ylabel, title=dettabtitle)
                    wid.addTab(tabwid, tabtitle)
            dettab.addTab(wid, dettabtitle)
        lay.addWidget(dettab, 1, 0)
Пример #6
0
class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName(_fromUtf8("MainWindow"))
        MainWindow.resize(1155, 853)
        self.centralwidget = QWidget(MainWindow)
        self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
        self.verticalLayout = QVBoxLayout(self.centralwidget)
        self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
        self.tabWidget = QTabWidget(self.centralwidget)
        self.tabWidget.setObjectName(_fromUtf8("tabWidget"))
        self.tab = QWidget()
        self.tab.setObjectName(_fromUtf8("tab"))
        self.tabWidget.addTab(self.tab, _fromUtf8(""))
        self.tab_2 = QWidget()
        self.tab_2.setObjectName(_fromUtf8("tab_2"))
        self.tabWidget.addTab(self.tab_2, _fromUtf8(""))
        self.verticalLayout.addWidget(self.tabWidget)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QMenuBar(MainWindow)
        self.menubar.setGeometry(QRect(0, 0, 1155, 20))
        self.menubar.setObjectName(_fromUtf8("menubar"))
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QStatusBar(MainWindow)
        self.statusbar.setObjectName(_fromUtf8("statusbar"))
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        self.tabWidget.setCurrentIndex(0)
        QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow", None))
        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab),
                                  _translate("MainWindow", "Tab 1", None))
        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2),
                                  _translate("MainWindow", "Tab 2", None))
Пример #7
0
class UiLinelistsWindow(object):

    # this code was taken as-is from the Designer.
    # Cleaning it up sounds like a lower priority
    # task for now.
    def setupUi(self, MainWindow, title):
        MainWindow.setWindowTitle(title)
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(600, 850)
        MainWindow.setMinimumSize(QSize(300, 350))
        self.centralWidget = QWidget(MainWindow)
        self.centralWidget.setObjectName("centralWidget")
        self.gridLayout = QGridLayout(self.centralWidget)
        self.gridLayout.setContentsMargins(11, 11, 11, 11)
        self.gridLayout.setSpacing(6)
        self.gridLayout.setObjectName("gridLayout")
        self.horizontalLayout_5 = QHBoxLayout()
        self.horizontalLayout_5.setContentsMargins(11, 11, 11, 11)
        self.horizontalLayout_5.setSpacing(6)
        self.horizontalLayout_5.setObjectName("horizontalLayout_5")
        self.lines_selected_label = QLabel(self.centralWidget)
        self.lines_selected_label.setObjectName("lines_selected_label")
        self.horizontalLayout_5.addWidget(self.lines_selected_label)
        self.label = QLabel(self.centralWidget)
        self.label.setObjectName("label")
        self.horizontalLayout_5.addWidget(self.label)
        spacerItem = QSpacerItem(40, 20, QSizePolicy.Expanding,
                                 QSizePolicy.Minimum)
        self.horizontalLayout_5.addItem(spacerItem)
        self.draw_button = QPushButton(self.centralWidget)
        self.draw_button.setObjectName("draw_button")
        self.horizontalLayout_5.addWidget(self.draw_button)
        self.erase_button = QPushButton(self.centralWidget)
        self.erase_button.setObjectName("erase_button")
        self.horizontalLayout_5.addWidget(self.erase_button)
        self.dismiss_button = QPushButton(self.centralWidget)
        self.dismiss_button.setObjectName("dismiss_button")
        self.horizontalLayout_5.addWidget(self.dismiss_button)
        self.gridLayout.addLayout(self.horizontalLayout_5, 4, 0, 1, 1)
        self.verticalLayout_11 = QVBoxLayout()
        self.verticalLayout_11.setContentsMargins(11, 11, 11, 11)
        self.verticalLayout_11.setSpacing(6)
        self.verticalLayout_11.setObjectName("verticalLayout_11")
        self.tabWidget = QTabWidget(self.centralWidget)
        self.tabWidget.setObjectName("tabWidget")
        self.tabWidget.setTabsClosable(True)
        self.verticalLayout_11.addWidget(self.tabWidget)
        self.gridLayout.addLayout(self.verticalLayout_11, 0, 0, 1, 1)
        self.horizontalLayout_7 = QHBoxLayout()
        self.horizontalLayout_7.setContentsMargins(11, 11, 11, 11)
        self.horizontalLayout_7.setSpacing(6)
        spacerItem = QSpacerItem(40, 20, QSizePolicy.Expanding,
                                 QSizePolicy.Minimum)
        self.horizontalLayout_7.addItem(spacerItem)
        self.horizontalLayout_7.setObjectName("horizontalLayout_7")
        self.gridLayout.addLayout(self.horizontalLayout_7, 2, 0, 2, 1)
        MainWindow.setCentralWidget(self.centralWidget)

        # self.menuBar = QMenuBar(MainWindow)
        # self.menuBar.setGeometry(QRect(0, 0, 767, 22))
        # self.menuBar.setObjectName("menuBar")
        #
        # self.menuFile = QMenu(self.menuBar)
        # self.menuFile.setObjectName("menuFile")
        #
        # MainWindow.setMenuBar(self.menuBar)

        self.mainToolBar = QToolBar(MainWindow)
        self.mainToolBar.setMovable(False)
        self.mainToolBar.setFloatable(False)
        self.mainToolBar.setObjectName("mainToolBar")
        MainWindow.addToolBar(Qt.TopToolBarArea, self.mainToolBar)

        # self.statusBar = QStatusBar(MainWindow)
        # self.statusBar.setObjectName("statusBar")
        # MainWindow.setStatusBar(self.statusBar)

        self.actionOpen = QAction(MainWindow)
        icon = QIcon(os.path.join(ICON_PATH, "Open Folder-48.png"))
        self.actionOpen.setIcon(icon)
        self.actionOpen.setObjectName("actionOpen")

        self.actionExport = QAction(MainWindow)
        icon = QIcon(os.path.join(ICON_PATH, "Export-48.png"))
        self.actionExport.setIcon(icon)
        self.actionExport.setObjectName("actionExport")

        self.line_list_selector = QComboBox()
        self.line_list_selector.setToolTip(
            "Select line list from internal library")

        self.actionExit = QAction(MainWindow)
        self.actionExit.setObjectName("actionExit")
        self.actionRemove = QAction(MainWindow)
        self.actionRemove.setObjectName("actionRemove")
        self.actionChange_Color = QAction(MainWindow)
        self.actionChange_Color.setObjectName("actionChange_Color")
        # self.menuFile.addAction(self.actionOpen)
        # self.menuFile.addSeparator()
        # self.menuFile.addAction(self.actionExit)
        # self.menuBar.addAction(self.menuFile.menuAction())
        self.mainToolBar.addAction(self.actionOpen)
        self.mainToolBar.addAction(self.actionExport)
        self.mainToolBar.addSeparator()
        self.mainToolBar.addWidget(self.line_list_selector)
        self.retranslateUi(MainWindow)
        QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QCoreApplication.translate
        self.lines_selected_label.setText(_translate("MainWindow", "0"))
        self.lines_selected_label.setToolTip(
            "Total number of lines selected in all sets.")
        self.label.setText(_translate("MainWindow", "lines selected"))
        self.label.setToolTip("Total number of lines selected in all sets.")
        self.draw_button.setText(_translate("MainWindow", "Draw"))
        self.draw_button.setToolTip(
            "Plot markers for all selected lines in all sets.")
        self.erase_button.setText(_translate("MainWindow", "Erase"))
        self.erase_button.setToolTip("Erase all markers")
        self.dismiss_button.setText(_translate("MainWindow", "Dismiss"))
        self.dismiss_button.setToolTip("Dismiss this window")
        # self.menuFile.setTitle(_translate("MainWindow", "File"))
        self.actionOpen.setText(_translate("MainWindow", "Open"))
        self.actionExport.setText(
            _translate("MainWindow", "Export plotted lines"))
        self.actionExit.setText(_translate("MainWindow", "Exit"))
        self.actionRemove.setText(_translate("MainWindow", "Remove"))
        self.actionRemove.setToolTip(
            _translate("MainWindow", "Removes the selected layer"))
        self.actionChange_Color.setText(
            _translate("MainWindow", "Change Color"))
        self.actionChange_Color.setToolTip(
            _translate("MainWindow", "Change the line color selected layer"))
Пример #8
0
    def _setup_ll_list_wid(self):
        ll_list_layout = QGridLayout(self.ll_list_wid)
        ll_list_layout.setHorizontalSpacing(20)
        ll_list_layout.setVerticalSpacing(20)

        but = QPushButton('Open LL Triggers', self)
        but.setAutoDefault(False)
        but.setDefault(False)
        obj_names = HLTimeSearch.get_ll_trigger_names(self.device.device_name)
        icon = qta.icon('mdi.timer',
                        color=get_appropriate_color(self.device.sec))
        Window = create_window_from_widget(LLTriggers,
                                           title=self.device.device_name +
                                           ': LL Triggers',
                                           icon=icon)
        connect_window(but,
                       Window,
                       self,
                       prefix=self.prefix,
                       hltrigger=self.device.device_name,
                       obj_names=obj_names)
        ll_list_layout.addWidget(but, 0, 0, 1, 2)

        init_channel = self.get_pvname('LowLvlLock-Sel')
        sp = PyDMStateButton(self, init_channel=init_channel)
        init_channel = self.get_pvname('LowLvlLock-Sts')
        rb = PyDMLed(self, init_channel=init_channel)
        gb = self._create_small_group('Lock Low Level', self.ll_list_wid,
                                      (sp, rb))
        ll_list_layout.addWidget(gb, 1, 0)

        init_channel = self.get_pvname('State-Sel')
        sp = PyDMStateButton(self, init_channel=init_channel)
        init_channel = self.get_pvname('State-Sts')
        rb = PyDMLed(self, init_channel=init_channel)
        gb = self._create_small_group('Enabled', self.ll_list_wid, (sp, rb))
        ll_list_layout.addWidget(gb, 1, 1)

        init_channel = self.get_pvname('Polarity-Sel')
        sp = SiriusEnumComboBox(self, init_channel=init_channel)
        init_channel = self.get_pvname('Polarity-Sts')
        rb = PyDMLabel(self, init_channel=init_channel)
        gb = self._create_small_group('Polarity', self.ll_list_wid, (sp, rb))
        ll_list_layout.addWidget(gb, 2, 0)

        init_channel = self.get_pvname('Src-Sel')
        sp = SiriusEnumComboBox(self, init_channel=init_channel)
        init_channel = self.get_pvname('Src-Sts')
        rb = PyDMLabel(self, init_channel=init_channel)
        gb = self._create_small_group('Source', self.ll_list_wid, (sp, rb))
        ll_list_layout.addWidget(gb, 2, 1)

        init_channel = self.get_pvname('NrPulses-SP')
        sp = SiriusSpinbox(self, init_channel=init_channel)
        sp.showStepExponent = False
        init_channel = self.get_pvname('NrPulses-RB')
        rb = PyDMLabel(self, init_channel=init_channel)
        gb = self._create_small_group('Nr Pulses', self.ll_list_wid, (sp, rb))
        ll_list_layout.addWidget(gb, 3, 0)

        init_channel = self.get_pvname('Duration-SP')
        sp = SiriusSpinbox(self, init_channel=init_channel)
        sp.showStepExponent = False
        init_channel = self.get_pvname('Duration-RB')
        rb = PyDMLabel(self, init_channel=init_channel)
        gb = self._create_small_group('Duration [us]', self.ll_list_wid,
                                      (sp, rb))
        ll_list_layout.addWidget(gb, 3, 1)

        init_channel = self.get_pvname('Delay-SP')
        sp = SiriusSpinbox(self, init_channel=init_channel)
        sp.showStepExponent = False
        init_channel = self.get_pvname('Delay-RB')
        rb = PyDMLabel(self, init_channel=init_channel)
        gbdel = self._create_small_group('[us]', self.ll_list_wid, (sp, rb))

        init_channel = self.get_pvname('DelayRaw-SP')
        sp = SiriusSpinbox(self, init_channel=init_channel)
        sp.showStepExponent = False
        init_channel = self.get_pvname('DelayRaw-RB')
        rb = PyDMLabel(self, init_channel=init_channel)
        gbdelr = self._create_small_group('Raw', self.ll_list_wid, (sp, rb))

        init_channel = self.get_pvname('TotalDelay-Mon')
        rb = PyDMLabel(self, init_channel=init_channel)
        gbtdel = self._create_small_group('[us]', self.ll_list_wid, (rb, ))

        init_channel = self.get_pvname('TotalDelayRaw-Mon')
        rb = PyDMLabel(self, init_channel=init_channel)
        gbtdelr = self._create_small_group('Raw', self.ll_list_wid, (rb, ))

        widd = QWidget(self.ll_list_wid)
        widd.setLayout(QHBoxLayout())
        widd.layout().addWidget(gbdel)
        widd.layout().addWidget(gbdelr)

        widt = QWidget(self.ll_list_wid)
        widt.setLayout(QHBoxLayout())
        widt.layout().addWidget(gbtdel)
        widt.layout().addWidget(gbtdelr)

        tabdel = QTabWidget(self)
        tabdel.setObjectName(self.device.sec + 'Tab')
        tabdel.addTab(widd, 'Delay')
        tabdel.addTab(widt, 'Total Delay')

        if HLTimeSearch.has_delay_type(self.device.device_name):
            init_channel = self.get_pvname('RFDelayType-Sel')
            sp = SiriusEnumComboBox(self, init_channel=init_channel)
            init_channel = self.get_pvname('RFDelayType-Sts')
            rb = PyDMLabel(self, init_channel=init_channel)
            gb = self._create_small_group('Delay Type', self.ll_list_wid,
                                          (sp, rb))
            ll_list_layout.addWidget(gb, 4, 0)
            ll_list_layout.addWidget(tabdel, 4, 1)
        else:
            ll_list_layout.addWidget(tabdel, 4, 0, 1, 2)

        gbdelta = self._create_deltadelay()
        ll_list_layout.addWidget(gbdelta, 0, 2, 5, 1)
Пример #9
0
class PSTabControlWindow(PSControlWindow):
    """Base window to show devices of a section in tabs."""

    Devices = {
        "LI": ["lens", "corrector-slow", "solenoid", "quadrupole",
               "spectrometer"],
        "TB": ["dipole", "quadrupole", "corrector-slow"],
        "BO": ["dipole", "quadrupole", "sextupole", "corrector-slow",
               "skew-quadrupole"],
        "TS": ["dipole", "quadrupole", "corrector-slow"],
        "SI": ["dipole", "quadrupole", "sextupole"],
        "IT": ["lens", ]}

    TabName = {"dipole": "Dipoles",
               "spectrometer": "Spectrometer",
               "quadrupole": "Quadrupoles",
               "sextupole": "Sextupoles",
               "solenoid": "Solenoids",
               "corrector-slow": "Slow Correctors",
               "corrector-fast": "Fast Correctors",
               "skew-quadrupole": "Quadrupoles Skew",
               "trim-quadrupole": "Trims",
               "lens": "Lens",
               }

    tabFilled = Signal()

    def __init__(self, section, parent=None):
        """Class constructor."""
        super().__init__(section=section,
                         device=None,
                         parent=parent)

    def _setup_ui(self):
        self.setWindowTitle(self._section+' PS Control')
        # Create Tabs
        self.tabs = QTabWidget()
        self.tabs.setObjectName(self._section + "Tab")
        self.TabIndex = dict()
        self._addTabs()
        self.tabs.currentChanged.connect(self._fillTabTask)
        # Set widget layout
        self.setCentralWidget(self.tabs)

    def _addTabs(self):
        for device in self.Devices[self._section]:
            widget = QWidget(self)
            index = self.tabs.addTab(widget, self.TabName[device])
            self.TabIndex[index] = {
                'device': device, 'widget': widget, 'filled': False}
            if index in range(3):
                self._fillTab(index)

    def _fillTabTask(self, index):
        if self.TabIndex[index]['filled']:
            return
        th = _WaitThread(parent=self, index=index)
        dlg = _WaitDialog(self)
        th.opendiag.connect(dlg.show)
        th.closediag.connect(dlg.close)
        th.tabIndex.connect(self._fillTab)
        self.tabFilled.connect(th.exit_thread)
        th.start()

    def _fillTab(self, index):
        self.TabIndex[index]['filled'] = True
        device = self.TabIndex[index]['device']
        widget = self.TabIndex[index]['widget']
        widget.setLayout(QGridLayout())
        widget.layout().setContentsMargins(0, 0, 0, 0)
        tabwid = ControlWidgetFactory.factory(
            self, self._section, device)
        self._connect_buttons(tabwid)
        widget.layout().addWidget(tabwid)
        self.tabFilled.emit()

    def _dipoleWidgetWrapper(self, widget):
        wrapper = QWidget(self)
        wrapper.layout = QGridLayout()
        wrapper.setLayout(wrapper.layout)

        wrapper.layout.addWidget(widget, 0, 0)
        wrapper.layout.setRowStretch(1, 1)
        wrapper.layout.setColumnStretch(1, 1)

        return wrapper
Пример #10
0
class PSTestWindow(SiriusMainWindow):
    """PS test window."""
    def __init__(self, parent=None, adv_mode=False):
        """Constructor."""
        super().__init__(parent)
        self.setWindowTitle('PS/PU Test')
        self.setObjectName('ASApp')
        cor = get_appropriate_color(section='AS')
        self.setWindowIcon(qta.icon('mdi.test-tube', color=cor))

        # auxiliar data for initializing SI Fam PS
        self._is_adv_mode = adv_mode
        self._si_fam_psnames = PSSearch.get_psnames(filters={
            'sec': 'SI',
            'sub': 'Fam',
            'dis': 'PS'
        })

        # auxiliary data for SI fast correctors
        self._si_fastcorrs = PSSearch.get_psnames(filters={
            'sec': 'SI',
            'dis': 'PS',
            'dev': 'FC.*'
        })

        self._needs_update_setup = False
        self._setup_ui()
        self._update_setup_timer = QTimer(self)
        self._update_setup_timer.timeout.connect(self._update_setup)
        self._update_setup_timer.setInterval(250)
        self._update_setup_timer.start()

    def _setup_ui(self):
        # setup central widget
        self.central_widget = QFrame()
        self.central_widget.setStyleSheet("""
            #OkList {
                background-color: #eafaea;
            }
            #NokList {
                background-color: #ffebe6;
            }
            QLabel{
                max-height: 1.29em;
            }
            QTabWidget::pane {
                border-left: 2px solid gray;
                border-bottom: 2px solid gray;
                border-right: 2px solid gray;
            }""")
        self.setCentralWidget(self.central_widget)

        self.tab = QTabWidget(self)
        self.tab.setObjectName('ASTab')

        # # PS
        self.ps_wid = QWidget(self)
        lay_ps = QGridLayout(self.ps_wid)
        lay_ps.setContentsMargins(0, 9, 0, 0)
        lay_ps.setHorizontalSpacing(0)

        # PS selection
        self.ps_tree = PVNameTree(items=self._get_ps_tree_names(),
                                  tree_levels=('sec', 'mag_group'),
                                  parent=self)
        self.ps_tree.tree.setHeaderHidden(True)
        self.ps_tree.setSizePolicy(QSizePolicy.Preferred,
                                   QSizePolicy.Preferred)
        self.ps_tree.tree.setColumnCount(1)
        self.ps_tree.tree.doubleClicked.connect(self._open_detail)
        self.ps_tree.tree.itemChanged.connect(
            self._handle_checked_items_changed)

        gbox_ps_select = QGroupBox('Select PS: ', self)
        gbox_ps_select.setObjectName('select')
        gbox_ps_select.setStyleSheet("""
            #select{
                border-top: 0px solid transparent;
                border-left: 0px solid transparent;
                border-bottom: 0px solid transparent;
            }""")
        lay_ps_select = QVBoxLayout(gbox_ps_select)
        lay_ps_select.addWidget(self.ps_tree)
        lay_ps.addWidget(gbox_ps_select, 0, 0)
        lay_ps.setColumnStretch(0, 1)

        # PS commands
        self.checkcomm_ps_bt = QPushButton('Check Communication', self)
        self.checkcomm_ps_bt.clicked.connect(_part(self._set_lastcomm, 'PS'))
        self.checkcomm_ps_bt.clicked.connect(self._check_comm)
        self.checkcomm_ps_bt.setToolTip(
            'Check PS and DCLinks communication status (verify invalid alarms '
            'and, if LI, the value of Connected-Mon PV)')

        self.checkstatus_ps_bt = QPushButton('Show Status Summary', self)
        self.checkstatus_ps_bt.clicked.connect(_part(self._set_lastcomm, 'PS'))
        self.checkstatus_ps_bt.clicked.connect(_part(self._check_status, 'PS'))
        self.checkstatus_ps_bt.setToolTip(
            'Check PS and DCLinks interlock status and, if powered on, '
            'check if it is following reference')

        self.dsbltrigger_ps_bt = QPushButton('Disable PS triggers', self)
        self.dsbltrigger_ps_bt.clicked.connect(_part(self._set_lastcomm, 'PS'))
        self.dsbltrigger_ps_bt.clicked.connect(
            _part(self._set_check_trigger_state, 'PS', 'dsbl'))

        self.setsofbmode_ps_bt = QPushButton('Turn Off SOFBMode', self)
        self.setsofbmode_ps_bt.clicked.connect(_part(self._set_lastcomm, 'PS'))
        self.setsofbmode_ps_bt.clicked.connect(
            _part(self._set_check_fbp_sofbmode, 'off'))

        self.setslowref_ps_bt = QPushButton('Set PS and DCLinks to SlowRef',
                                            self)
        self.setslowref_ps_bt.clicked.connect(_part(self._set_lastcomm, 'PS'))
        self.setslowref_ps_bt.clicked.connect(self._set_check_opmode_slowref)

        self.currzero_ps_bt1 = QPushButton('Set PS Current to zero', self)
        self.currzero_ps_bt1.clicked.connect(_part(self._set_lastcomm, 'PS'))
        self.currzero_ps_bt1.clicked.connect(self._set_zero_ps)

        self.reset_ps_bt = QPushButton('Reset PS and DCLinks', self)
        self.reset_ps_bt.clicked.connect(_part(self._set_lastcomm, 'PS'))
        self.reset_ps_bt.clicked.connect(_part(self._reset_intlk, 'PS'))

        self.prep_sidclink_bt = QPushButton('Prepare SI Fam DCLinks', self)
        self.prep_sidclink_bt.clicked.connect(_part(self._set_lastcomm, 'PS'))
        self.prep_sidclink_bt.clicked.connect(self._prepare_sidclinks)
        self.prep_sidclink_bt.setVisible(False)

        self.init_sips_bt = QPushButton('Initialize SI Fam PS', self)
        self.init_sips_bt.clicked.connect(_part(self._set_lastcomm, 'PS'))
        self.init_sips_bt.clicked.connect(self._set_check_pwrstateinit)
        self.init_sips_bt.setVisible(False)

        self.aux_label = QLabel('')
        self.aux_label.setVisible(False)

        self.turnon_dcl_bt = QPushButton('Turn DCLinks On', self)
        self.turnon_dcl_bt.clicked.connect(_part(self._set_lastcomm, 'PS'))
        self.turnon_dcl_bt.clicked.connect(
            _part(self._set_check_pwrstate_dclinks, 'on'))

        self.checkctrlloop_dcl_bt = QPushButton('Check DCLinks CtrlLoop', self)
        self.checkctrlloop_dcl_bt.clicked.connect(
            _part(self._set_lastcomm, 'PS'))
        self.checkctrlloop_dcl_bt.clicked.connect(
            _part(self._set_check_ctrlloop, 'dclink'))

        self.setvolt_dcl_bt = QPushButton('Set DCLinks Voltage', self)
        self.setvolt_dcl_bt.clicked.connect(_part(self._set_lastcomm, 'PS'))
        self.setvolt_dcl_bt.clicked.connect(self._set_check_dclinks_capvolt)

        self.turnon_ps_bt = QPushButton('Turn PS On', self)
        self.turnon_ps_bt.clicked.connect(_part(self._set_lastcomm, 'PS'))
        self.turnon_ps_bt.clicked.connect(
            _part(self._set_check_pwrstate, 'PS', 'on', True))

        self.setcheckctrlloop_ps_bt = QPushButton('Check PS CtrlLoop', self)
        self.setcheckctrlloop_ps_bt.clicked.connect(
            _part(self._set_lastcomm, 'PS'))
        self.setcheckctrlloop_ps_bt.clicked.connect(
            _part(self._set_check_ctrlloop, 'pwrsupply'))

        self.test_ps_bt = QPushButton('Set PS Current to test value', self)
        self.test_ps_bt.clicked.connect(_part(self._set_lastcomm, 'PS'))
        self.test_ps_bt.clicked.connect(self._set_test_ps)

        self.currzero_ps_bt2 = QPushButton('Set PS Current to zero', self)
        self.currzero_ps_bt2.clicked.connect(_part(self._set_lastcomm, 'PS'))
        self.currzero_ps_bt2.clicked.connect(self._set_zero_ps)

        self.restoretrigger_ps_bt = QPushButton('Restore PS triggers', self)
        self.restoretrigger_ps_bt.clicked.connect(
            _part(self._set_lastcomm, 'PS'))
        self.restoretrigger_ps_bt.clicked.connect(
            _part(self._restore_triggers_state, 'PS'))

        gbox_ps_comm = QGroupBox('Commands', self)
        gbox_ps_comm.setObjectName('comm')
        gbox_ps_comm.setStyleSheet('#comm{border: 0px solid transparent;}')
        lay_ps_comm = QVBoxLayout(gbox_ps_comm)
        lay_ps_comm.setContentsMargins(20, 9, 20, 9)
        lay_ps_comm.addWidget(QLabel(''))
        lay_ps_comm.addWidget(
            QLabel('<h4>Check</h4>', self, alignment=Qt.AlignCenter))
        lay_ps_comm.addWidget(self.checkcomm_ps_bt)
        lay_ps_comm.addWidget(self.checkstatus_ps_bt)
        lay_ps_comm.addWidget(QLabel(''))
        lay_ps_comm.addWidget(
            QLabel('<h4>Prepare</h4>', self, alignment=Qt.AlignCenter))
        lay_ps_comm.addWidget(self.dsbltrigger_ps_bt)
        lay_ps_comm.addWidget(self.setsofbmode_ps_bt)
        lay_ps_comm.addWidget(self.setslowref_ps_bt)
        lay_ps_comm.addWidget(self.currzero_ps_bt1)
        lay_ps_comm.addWidget(self.reset_ps_bt)
        lay_ps_comm.addWidget(QLabel(''))
        lay_ps_comm.addWidget(self.prep_sidclink_bt)
        lay_ps_comm.addWidget(self.init_sips_bt)
        lay_ps_comm.addWidget(self.aux_label)
        lay_ps_comm.addWidget(
            QLabel('<h4>Config DCLinks</h4>', self, alignment=Qt.AlignCenter))
        lay_ps_comm.addWidget(self.turnon_dcl_bt)
        lay_ps_comm.addWidget(self.checkctrlloop_dcl_bt)
        lay_ps_comm.addWidget(self.setvolt_dcl_bt)
        lay_ps_comm.addWidget(QLabel(''))
        lay_ps_comm.addWidget(
            QLabel('<h4>Test</h4>', self, alignment=Qt.AlignCenter))
        lay_ps_comm.addWidget(self.turnon_ps_bt)
        lay_ps_comm.addWidget(self.setcheckctrlloop_ps_bt)
        lay_ps_comm.addWidget(self.test_ps_bt)
        lay_ps_comm.addWidget(self.currzero_ps_bt2)
        lay_ps_comm.addWidget(QLabel(''))
        lay_ps_comm.addWidget(
            QLabel('<h4>Restore</h4>', self, alignment=Qt.AlignCenter))
        lay_ps_comm.addWidget(self.restoretrigger_ps_bt)
        lay_ps_comm.addWidget(QLabel(''))
        lay_ps.addWidget(gbox_ps_comm, 0, 1)
        lay_ps.setColumnStretch(1, 1)

        self.tab.addTab(self.ps_wid, 'PS')

        # # PU
        self.pu_wid = QWidget(self)
        lay_pu = QGridLayout(self.pu_wid)
        lay_pu.setContentsMargins(0, 9, 0, 0)
        lay_pu.setHorizontalSpacing(0)

        # PU selection
        self.pu_tree = PVNameTree(items=self._get_pu_tree_names(),
                                  tree_levels=('sec', ),
                                  parent=self)
        self.pu_tree.tree.setHeaderHidden(True)
        self.pu_tree.setSizePolicy(QSizePolicy.Preferred,
                                   QSizePolicy.Preferred)
        self.pu_tree.tree.setColumnCount(1)
        self.pu_tree.tree.doubleClicked.connect(self._open_detail)

        gbox_pu_select = QGroupBox('Select PU: ', self)
        gbox_pu_select.setObjectName('select')
        gbox_pu_select.setStyleSheet("""
            #select{
                border-top: 0px solid transparent;
                border-left: 0px solid transparent;
                border-bottom: 0px solid transparent;
            }""")
        lay_pu_select = QVBoxLayout(gbox_pu_select)
        lay_pu_select.addWidget(self.pu_tree)
        lay_pu.addWidget(gbox_pu_select, 0, 0)
        lay_pu.setColumnStretch(0, 1)

        # PU commands
        self.checkstatus_pu_bt = QPushButton('Show Status Summary', self)
        self.checkstatus_pu_bt.clicked.connect(_part(self._set_lastcomm, 'PU'))
        self.checkstatus_pu_bt.clicked.connect(_part(self._check_status, 'PU'))
        self.checkstatus_pu_bt.setToolTip(
            'Check PU interlock status and, if powered on, '
            'check if it is following voltage setpoint')

        self.voltzero_pu_bt1 = QPushButton('Set PU Voltage to zero', self)
        self.voltzero_pu_bt1.clicked.connect(_part(self._set_lastcomm, 'PU'))
        self.voltzero_pu_bt1.clicked.connect(_part(self._set_zero_pu, False))

        self.reset_pu_bt = QPushButton('Reset PU', self)
        self.reset_pu_bt.clicked.connect(_part(self._set_lastcomm, 'PU'))
        self.reset_pu_bt.clicked.connect(_part(self._reset_intlk, 'PU'))

        self.turnon_pu_bt = QPushButton('Turn PU On', self)
        self.turnon_pu_bt.clicked.connect(_part(self._set_lastcomm, 'PU'))
        self.turnon_pu_bt.clicked.connect(
            _part(self._set_check_pwrstate, 'PU', 'on', True))

        self.enblpulse_pu_bt = QPushButton('Enable PU Pulse', self)
        self.enblpulse_pu_bt.clicked.connect(_part(self._set_lastcomm, 'PU'))
        self.enblpulse_pu_bt.clicked.connect(_part(self._set_check_pulse,
                                                   'on'))

        self.enbltrigger_pu_bt = QPushButton('Enable PU triggers', self)
        self.enbltrigger_pu_bt.clicked.connect(_part(self._set_lastcomm, 'PU'))
        self.enbltrigger_pu_bt.clicked.connect(
            _part(self._set_check_trigger_state, 'PU', 'on'))

        self.test_pu_bt = QPushButton('Set PU Voltage to test value', self)
        self.test_pu_bt.clicked.connect(_part(self._set_lastcomm, 'PU'))
        self.test_pu_bt.clicked.connect(self._set_test_pu)

        self.voltzero_pu_bt2 = QPushButton('Set PU Voltage to zero', self)
        self.voltzero_pu_bt2.clicked.connect(_part(self._set_lastcomm, 'PU'))
        self.voltzero_pu_bt2.clicked.connect(_part(self._set_zero_pu, True))

        self.restoretrigger_pu_bt = QPushButton('Restore PU triggers', self)
        self.restoretrigger_pu_bt.clicked.connect(
            _part(self._set_lastcomm, 'PU'))
        self.restoretrigger_pu_bt.clicked.connect(
            _part(self._restore_triggers_state, 'PU'))

        gbox_pu_comm = QGroupBox('Commands', self)
        gbox_pu_comm.setObjectName('comm')
        gbox_pu_comm.setStyleSheet('#comm{border: 0px solid transparent;}')
        lay_pu_comm = QVBoxLayout(gbox_pu_comm)
        lay_pu_comm.setContentsMargins(20, 9, 20, 9)
        lay_pu_comm.addWidget(QLabel(''))
        lay_pu_comm.addWidget(
            QLabel('<h4>Check</h4>', self, alignment=Qt.AlignCenter))
        lay_pu_comm.addWidget(self.checkstatus_pu_bt)
        lay_pu_comm.addWidget(QLabel(''))
        lay_pu_comm.addWidget(
            QLabel('<h4>Prepare</h4>', self, alignment=Qt.AlignCenter))
        lay_pu_comm.addWidget(self.voltzero_pu_bt1)
        lay_pu_comm.addWidget(self.reset_pu_bt)
        lay_pu_comm.addWidget(QLabel(''))
        lay_pu_comm.addWidget(
            QLabel('<h4>Test</h4>', self, alignment=Qt.AlignCenter))
        lay_pu_comm.addWidget(self.turnon_pu_bt)
        lay_pu_comm.addWidget(self.enblpulse_pu_bt)
        lay_pu_comm.addWidget(self.enbltrigger_pu_bt)
        lay_pu_comm.addWidget(self.test_pu_bt)
        lay_pu_comm.addWidget(self.voltzero_pu_bt2)
        lay_pu_comm.addWidget(QLabel(''))
        lay_pu_comm.addWidget(
            QLabel('<h4>Restore</h4>', self, alignment=Qt.AlignCenter))
        lay_pu_comm.addWidget(self.restoretrigger_pu_bt)
        lay_pu_comm.addWidget(QLabel(''))
        lay_pu.addWidget(gbox_pu_comm, 0, 1)
        lay_pu.setColumnStretch(1, 1)

        self.tab.addTab(self.pu_wid, 'PU')

        # lists
        self.label_lastcomm = QLabel('Last Command: ', self)
        self.ok_ps = QListWidget(self)
        self.ok_ps.setObjectName('OkList')
        self.ok_ps.doubleClicked.connect(self._open_detail)
        self.ok_ps.setSelectionMode(QAbstractItemView.MultiSelection)
        self.ok_ps.setToolTip(
            'Select rows and press Ctrl+C to copy and Esc to deselect.')
        self.nok_ps = QListWidget(self)
        self.nok_ps.setObjectName('NokList')
        self.nok_ps.doubleClicked.connect(self._open_detail)
        self.nok_ps.setSelectionMode(QAbstractItemView.MultiSelection)
        self.nok_ps.setToolTip(
            'Select rows and press Ctrl+C to copy and Esc to deselect.')
        self.clearlists_bt = QPushButton('Clear', self)
        self.clearlists_bt.clicked.connect(self._clear_lastcomm)
        self.ok_ps_aux_list = list()
        self.nok_ps_aux_list = list()
        hbox = QHBoxLayout()
        hbox.addWidget(self.label_lastcomm)
        hbox.addWidget(self.clearlists_bt, alignment=Qt.AlignRight)
        list_layout = QGridLayout()
        list_layout.setContentsMargins(0, 0, 0, 0)
        list_layout.setVerticalSpacing(6)
        list_layout.setHorizontalSpacing(9)
        list_layout.addLayout(hbox, 0, 0, 1, 2)
        list_layout.addWidget(
            QLabel('<h4>Ok</h4>', self, alignment=Qt.AlignCenter), 1, 0)
        list_layout.addWidget(self.ok_ps, 2, 0)
        list_layout.addWidget(
            QLabel('<h4>Failed</h4>', self, alignment=Qt.AlignCenter), 1, 1)
        list_layout.addWidget(self.nok_ps, 2, 1)

        # menu
        self.menu = self.menuBar()

        self.act_cycle = self.menu.addAction('Open Cycle Window')
        connect_newprocess(self.act_cycle,
                           'sirius-hla-as-ps-cycle.py',
                           parent=self)

        self.aux_comm = self.menu.addMenu('Auxiliary commands')

        # # auxiliary PS
        self.ps_menu = self.aux_comm.addMenu('PS')

        self.act_turnoff_ps = self.ps_menu.addAction('Turn PS Off')
        self.act_turnoff_ps.triggered.connect(_part(self._set_lastcomm, 'PS'))
        self.act_turnoff_ps.triggered.connect(
            _part(self._set_check_pwrstate, 'PS', 'off', True))

        self.act_turnoff_dclink = self.ps_menu.addAction('Turn DCLinks Off')
        self.act_turnoff_dclink.triggered.connect(
            _part(self._set_lastcomm, 'PS'))
        self.act_turnoff_dclink.triggered.connect(
            _part(self._set_check_pwrstate_dclinks, 'off'))

        self.act_setcurrent_ps = self.ps_menu.addAction('Set PS Current')
        self.act_setcurrent_ps.triggered.connect(
            _part(self._set_lastcomm, 'PS'))
        self.act_setcurrent_ps.triggered.connect(self._set_check_current)

        self.act_opmode_ps = self.ps_menu.addAction('Set PS OpMode')
        self.act_opmode_ps.triggered.connect(_part(self._set_lastcomm, 'PS'))
        self.act_opmode_ps.triggered.connect(self._set_check_opmode)

        # # auxiliary PU
        self.pu_menu = self.aux_comm.addMenu('PU')

        self.act_turnoff_pu = self.pu_menu.addAction('Turn PU Off')
        self.act_turnoff_pu.triggered.connect(_part(self._set_lastcomm, 'PU'))
        self.act_turnoff_pu.triggered.connect(
            _part(self._set_check_pwrstate, 'PU', 'off', True))

        self.act_dsblpulse_pu = self.pu_menu.addAction('Disable PU Pulse')
        self.act_dsblpulse_pu.triggered.connect(_part(self._set_lastcomm,
                                                      'PU'))
        self.act_dsblpulse_pu.triggered.connect(
            _part(self._set_check_pulse, 'off'))

        # layout
        lay = QGridLayout()
        lay.setHorizontalSpacing(15)
        lay.setVerticalSpacing(5)
        lay.addWidget(
            QLabel('<h3>Power Supplies Test</h3>',
                   self,
                   alignment=Qt.AlignCenter), 0, 0, 1, 3)
        lay.addWidget(self.tab, 1, 0)
        lay.addLayout(list_layout, 1, 1)
        lay.setColumnStretch(0, 2)
        lay.setColumnStretch(1, 2)
        lay.setRowStretch(0, 2)
        lay.setRowStretch(1, 18)
        self.central_widget.setLayout(lay)

    # ---------- commands ------------

    def _check_comm(self):
        self.ok_ps.clear()
        self.nok_ps.clear()
        devices = self._get_selected_ps()
        if not devices:
            return
        dclinks = self._get_related_dclinks(devices, include_regatrons=True)
        devices.extend(dclinks)

        task0 = CreateTesters(devices, parent=self)
        task1 = CheckComm(devices, parent=self)
        task1.itemDone.connect(self._log)

        labels = [
            'Connecting to devices...',
            'Checking PS and DCLinks Comm. Status...'
        ]
        tasks = [task0, task1]
        dlg = ProgressDialog(labels, tasks, self)
        dlg.exec_()

    def _check_status(self, dev_type):
        self.ok_ps.clear()
        self.nok_ps.clear()
        if dev_type == 'PS':
            devices = self._get_selected_ps()
            if not devices:
                return
            dclinks = self._get_related_dclinks(devices,
                                                include_regatrons=True)
            devices.extend(dclinks)
            label1 = 'Reading PS and DCLinks Status...'
        elif dev_type == 'PU':
            devices = self._get_selected_pu()
            if not devices:
                return
            label1 = 'Reading PU Status...'

        task0 = CreateTesters(devices, parent=self)
        task1 = CheckStatus(devices, parent=self)
        task1.itemDone.connect(self._log)

        labels = ['Connecting to devices...', label1]
        tasks = [task0, task1]
        dlg = ProgressDialog(labels, tasks, self)
        dlg.exec_()

    def _set_check_trigger_state(self, dev_type, state):
        self.ok_ps.clear()
        self.nok_ps.clear()
        if dev_type == 'PS':
            devices = self._get_selected_ps()
        elif dev_type == 'PU':
            devices = self._get_selected_pu()
        if not devices:
            return

        task1 = SetTriggerState(parent=self,
                                dis=dev_type,
                                state=state,
                                devices=devices)
        task2 = CheckTriggerState(parent=self,
                                  dis=dev_type,
                                  state=state,
                                  devices=devices)
        task2.itemDone.connect(self._log)
        tasks = [task1, task2]

        labels = [
            'Disabling ' + dev_type + ' triggers...',
            'Checking ' + dev_type + ' trigger states...'
        ]

        dlg = ProgressDialog(labels, tasks, self)
        dlg.exec_()

    def _set_check_opmode_slowref(self):
        self.ok_ps.clear()
        self.nok_ps.clear()
        devices = self._get_selected_ps()
        if not devices:
            return
        dclinks = self._get_related_dclinks(devices)
        devices.extend(dclinks)
        devices = [dev for dev in devices if 'LI-' not in dev]

        task0 = CreateTesters(devices, parent=self)
        task1 = SetOpMode(devices, state=_PSC.OpMode.SlowRef, parent=self)
        task2 = CheckOpMode(devices,
                            state=[
                                _PSC.States.SlowRef, _PSC.States.Off,
                                _PSC.States.Interlock
                            ],
                            parent=self)
        task2.itemDone.connect(self._log)

        labels = [
            'Connecting to devices...', 'Setting PS OpMode to SlowRef...',
            'Checking PS OpMode...'
        ]
        tasks = [task0, task1, task2]
        dlg = ProgressDialog(labels, tasks, self)
        dlg.exec_()

    def _reset_intlk(self, dev_type):
        self.ok_ps.clear()
        self.nok_ps.clear()
        if dev_type == 'PS':
            devices = self._get_selected_ps()
            if not devices:
                return
            dclinks = self._get_related_dclinks(devices,
                                                include_regatrons=True)
            devices.extend(dclinks)
            dev_label = 'PS and DCLinks'
        elif dev_type == 'PU':
            devices = self._get_selected_pu()
            if not devices:
                return
            dev_label = 'PU'
        devices_not_rst = {
            dev
            for dev in devices
            if dev.sec != 'LI' and dev.dev not in ('FCH', 'FCV')
        }

        task0 = CreateTesters(devices, parent=self)
        task1 = ResetIntlk(devices_not_rst, parent=self)
        task2 = CheckIntlk(devices, parent=self)
        task2.itemDone.connect(self._log)
        tasks = [task0, task1, task2]

        labels = [
            'Connecting to devices...', 'Reseting ' + dev_label + '...',
            'Checking ' + dev_label + ' Interlocks...'
        ]

        dlg = ProgressDialog(labels, tasks, self)
        dlg.exec_()

    def _set_check_pwrstate(self, dev_type, state, show=True):
        self.ok_ps.clear()
        self.nok_ps.clear()
        if isinstance(dev_type, list):
            devices = list(dev_type)
            dev_type = devices[0].dis
        else:
            if dev_type == 'PS':
                devices = self._get_selected_ps()
            elif dev_type == 'PU':
                devices = self._get_selected_pu()
        if not devices:
            return

        if state == 'on' and dev_type == 'PS':
            dev2ctrl = list(set(devices) - set(self._si_fam_psnames))
        else:
            dev2ctrl = devices

        task0 = CreateTesters(devices, parent=self)
        task1 = SetPwrState(dev2ctrl, state=state, parent=self)
        task2 = CheckPwrState(devices, state=state, is_test=True, parent=self)
        task2.itemDone.connect(_part(self._log, show=show))
        tasks = [task0, task1, task2]

        labels = [
            'Connecting to devices...',
            'Turning ' + dev_type + ' ' + state + '...',
            'Checking ' + dev_type + ' powered ' + state + '...'
        ]

        dlg = ProgressDialog(labels, tasks, self)
        dlg.exec_()

    def _prepare_sidclinks(self):
        self.ok_ps.clear()
        self.nok_ps.clear()
        selected = self._get_selected_ps()
        ps2check = [ps for ps in selected if ps in self._si_fam_psnames]
        dclinks = self._get_related_dclinks(ps2check, include_regatrons=True)
        if not ps2check:
            return

        # if power state is on, do nothing
        self.ok_ps_aux_list.clear()
        self.nok_ps_aux_list.clear()
        self._check_pwrstate(ps2check, state='on', is_test=False, show=False)
        if set(self.ok_ps_aux_list) == set(ps2check):
            for dev in dclinks:
                self._log(dev, True)
            return

        ps2act = list(self.nok_ps_aux_list)  # act in PS off
        dcl2act = self._get_related_dclinks(ps2act, include_regatrons=True)
        # print('act', ps2act, dcl2act)

        # if need initializing, check if DCLinks are turned off
        self.ok_ps_aux_list.clear()
        self.nok_ps_aux_list.clear()
        self._check_pwrstate(dcl2act, state='off', is_test=False, show=False)
        if not self.nok_ps_aux_list:
            for dev in dclinks:
                self._log(dev, True)
            return

        dcl2ctrl = list(self.nok_ps_aux_list)  # control DCLink on
        dcl_ok = set(dclinks) - set(dcl2ctrl)
        ps2ctrl = set()  # get related psnames
        for dcl in dcl2ctrl:
            pss = PSSearch.conv_dclink_2_psname(dcl)
            ps2ctrl.update(pss)
        # print('ctrl', ps2ctrl, dcl2ctrl)

        # if some DCLink is on, make sure related PS are turned off
        self.ok_ps_aux_list.clear()
        self.nok_ps_aux_list.clear()
        self._check_pwrstate(ps2ctrl, state='off', is_test=False, show=False)
        if self.nok_ps_aux_list:
            ps2ctrl = list(self.nok_ps_aux_list)

            self.ok_ps_aux_list.clear()
            self.nok_ps_aux_list.clear()
            self._set_zero_ps(ps2ctrl, show=False)

            self.ok_ps_aux_list.clear()
            self.nok_ps_aux_list.clear()
            self._set_check_pwrstate(dev_type=ps2ctrl, state='off', show=False)

            if self.nok_ps_aux_list:
                for dev in self.ok_ps_aux_list:
                    self._log(dev, True)
                for dev in self.nok_ps_aux_list:
                    self._log(dev, False)
                text = 'The listed PS seems to be taking too\n'\
                    'long to turn off.\n'\
                    'Try to execute this step once again.'
                QMessageBox.warning(self, 'Message', text)
                return

        # finally, turn DCLinks off
        self._set_check_pwrstate_dclinks(state='off',
                                         devices=dcl2ctrl,
                                         ps2check=ps2ctrl)
        # log DCLinks Ok
        for dev in dcl_ok:
            self._log(dev, True)

    def _set_check_pwrstateinit(self):
        self.ok_ps.clear()
        self.nok_ps.clear()
        selected = self._get_selected_ps()
        devices = [ps for ps in selected if ps in self._si_fam_psnames]
        if not devices:
            return

        # if power state is on, do nothing
        self.ok_ps_aux_list.clear()
        self.nok_ps_aux_list.clear()
        self._check_pwrstate(devices, state='on', is_test=False, show=False)
        if len(self.ok_ps_aux_list) == len(devices):
            for dev in self.ok_ps_aux_list:
                self._log(dev, True)
            return

        # if need initializing, check if DCLinks are turned off before continue
        ps_ok = list(self.ok_ps_aux_list)
        ps2ctrl = list(self.nok_ps_aux_list)  # check PS off
        dcl2check = self._get_related_dclinks(ps2ctrl, include_regatrons=True)
        # print('set_check_pwrstateinit', ps2ctrl)

        self.ok_ps_aux_list.clear()
        self.nok_ps_aux_list.clear()
        self._check_pwrstate(dcl2check, state='off', is_test=False, show=False)
        if len(self.nok_ps_aux_list) > 0:
            for dev in self.ok_ps_aux_list:
                self._log(dev, True)
            for dev in self.nok_ps_aux_list:
                self._log(dev, False)
            QMessageBox.critical(
                self, 'Message', 'Make sure related DCLinks are turned\n'
                'off before initialize SI Fam PS!')
            return

        # list in Ok PS already on
        for dev in ps_ok:
            self._log(dev, True)

        # then, initialize SI Fam PS
        task0 = CreateTesters(ps2ctrl, parent=self)
        task1 = SetPwrState(ps2ctrl, state='on', parent=self)
        task2 = CheckOpMode(ps2ctrl,
                            state=_PSC.States.Initializing,
                            parent=self)
        task2.itemDone.connect(self._log)
        tasks = [task0, task1, task2]

        labels = [
            'Connecting to devices...', 'Initializing SI Fam PS...',
            'Checking SI Fam PS initialized...'
        ]

        dlg = ProgressDialog(labels, tasks, self)
        dlg.exec_()

    def _set_check_pulse(self, state):
        self.ok_ps.clear()
        self.nok_ps.clear()
        devices = self._get_selected_pu()
        if not devices:
            return

        task0 = CreateTesters(devices, parent=self)
        task1 = SetPulse(devices, state=state, parent=self)
        task2 = CheckPulse(devices, state=state, parent=self)
        task2.itemDone.connect(self._log)
        tasks = [task0, task1, task2]

        labels = [
            'Connecting to devices...', 'Turning PU Pulse ' + state + '...',
            'Checking PU Pulse ' + state + '...'
        ]

        dlg = ProgressDialog(labels, tasks, self)
        dlg.exec_()

    def _set_check_pwrstate_dclinks(self,
                                    state,
                                    devices=list(),
                                    ps2check=list()):
        self.ok_ps.clear()
        self.nok_ps.clear()
        if not devices:
            pwrsupplies = self._get_selected_ps()
            if not pwrsupplies:
                return
            devices = self._get_related_dclinks(pwrsupplies,
                                                include_regatrons=True)
            ps2check = set()
            for dev in devices:
                ps2check.update(PSSearch.conv_dclink_2_psname(dev))
        if not devices:
            return

        if state == 'off':
            self.ok_ps_aux_list.clear()
            self.nok_ps_aux_list.clear()
            self._check_pwrstate(ps2check, state='offintlk', show=False)
            if len(self.nok_ps_aux_list) > 0:
                for dev in self.ok_ps_aux_list:
                    self._log(dev, True)
                for dev in self.nok_ps_aux_list:
                    self._log(dev, False)
                QMessageBox.critical(
                    self, 'Message', 'Make sure all related power supplies\n'
                    'are turned off before turning DCLinks off!')
                return

        task0 = CreateTesters(devices, parent=self)
        task1 = SetPwrState(devices, state=state, parent=self)
        task2 = CheckPwrState(devices, state=state, is_test=True, parent=self)
        tasks = [task0, task1, task2]

        labels = [
            'Connecting to DCLinks...', 'Turning DCLinks ' + state + '...',
            'Checking DCLinks powered ' + state + '...'
        ]

        if state == 'on':
            task3 = CheckInitOk(devices, parent=self)
            task3.itemDone.connect(self._log)
            tasks.append(task3)
            labels.append('Wait DCLinks initialize...')
        else:
            task2.itemDone.connect(self._log)

        dlg = ProgressDialog(labels, tasks, self)
        dlg.exec_()

    def _check_pwrstate(self, devices, state, is_test=True, show=True):
        self.ok_ps.clear()
        self.nok_ps.clear()

        task0 = CreateTesters(devices, parent=self)

        if state == 'offintlk':
            text = 'off or interlock'
            task1 = CheckOpMode(devices,
                                state=[_PSC.States.Off, _PSC.States.Interlock],
                                parent=self)
        else:
            text = state
            task1 = CheckPwrState(devices,
                                  state=state,
                                  is_test=is_test,
                                  parent=self)
        task1.itemDone.connect(_part(self._log, show=show))
        tasks = [task0, task1]

        labels = [
            'Connecting to devices...',
            'Checking devices powered ' + text + '...'
        ]

        dlg = ProgressDialog(labels, tasks, self)
        dlg.exec_()

    def _set_check_ctrlloop(self, dev_type='pwrsupply'):
        self.ok_ps.clear()
        self.nok_ps.clear()
        pwrsupplies = self._get_selected_ps()
        if not pwrsupplies:
            return
        devices_set = {}
        if dev_type == 'pwrsupply':
            devices = {dev for dev in pwrsupplies if 'LI' not in dev}
            devices_set = {dev for dev in devices if dev.dev in ('FCH', 'FCV')}
        else:
            devices = self._get_related_dclinks(pwrsupplies)
        if not devices:
            return

        tasks = [
            CreateTesters(devices, parent=self),
        ]
        labels = [
            'Connecting to devices...',
        ]
        if devices_set:
            task1 = SetCtrlLoop(devices_set, parent=self)
            task2 = CheckCtrlLoop(devices, parent=self)
            task2.itemDone.connect(self._log)
            tasks.extend([task1, task2])
            labels.extend(
                ['Setting CtrlLoop...', 'Checking CtrlLoop state...'])
        else:
            task1 = CheckCtrlLoop(devices, parent=self)
            task1.itemDone.connect(self._log)
            tasks.append(task1)
            labels.append('Checking CtrlLoop state...')
        dlg = ProgressDialog(labels, tasks, self)
        dlg.exec_()

    def _set_check_dclinks_capvolt(self):
        self.ok_ps.clear()
        self.nok_ps.clear()
        pwrsupplies = self._get_selected_ps()
        if not pwrsupplies:
            return
        devices = self._get_related_dclinks(pwrsupplies,
                                            include_regatrons=True)
        dev_exc_regatrons = {
            dev
            for dev in devices
            if PSSearch.conv_psname_2_psmodel(dev) != 'REGATRON_DCLink'
        }
        if not devices:
            return

        task0 = CreateTesters(devices, parent=self)
        task1 = SetCapBankVolt(dev_exc_regatrons, parent=self)
        task2 = CheckCapBankVolt(devices, parent=self)
        task2.itemDone.connect(self._log)
        labels = [
            'Connecting to devices...', 'Setting capacitor bank voltage...',
            'Checking capacitor bank voltage...'
        ]
        tasks = [task0, task1, task2]
        dlg = ProgressDialog(labels, tasks, self)
        dlg.exec_()

    def _set_check_fbp_sofbmode(self, state):
        self.ok_ps.clear()
        self.nok_ps.clear()
        devices = self._get_selected_ps()
        devices = [
            dev for dev in devices
            if PSSearch.conv_psname_2_psmodel(dev) == 'FBP'
        ]
        if not devices:
            return

        task0 = CreateTesters(devices, parent=self)
        task1 = SetSOFBMode(devices, state=state, parent=self)
        task2 = CheckSOFBMode(devices, state=state, parent=self)
        task2.itemDone.connect(self._log)
        tasks = [task0, task1, task2]

        labels = [
            'Connecting to devices...', 'Turning PS SOFBMode ' + state + '...',
            'Checking PS SOFBMode ' + state + '...'
        ]

        dlg = ProgressDialog(labels, tasks, self)
        dlg.exec_()

    def _set_test_ps(self):
        self.ok_ps.clear()
        self.nok_ps.clear()
        devices = self._get_selected_ps()
        if not devices:
            return

        task0 = CreateTesters(devices, parent=self)
        task1 = SetCurrent(devices, is_test=True, parent=self)
        task2 = CheckCurrent(devices, is_test=True, parent=self)
        task2.itemDone.connect(self._log)
        tasks = [task0, task1, task2]

        labels = [
            'Connecting to devices...', 'Testing PS... Setting current...',
            'Testing PS... Checking current value...'
        ]

        dlg = ProgressDialog(labels, tasks, self)
        dlg.exec_()

    def _set_zero_ps(self, devices=list(), show=True):
        self.ok_ps.clear()
        self.nok_ps.clear()
        if not devices:
            devices = self._get_selected_ps()
        if not devices:
            return

        task0 = CreateTesters(devices, parent=self)
        task1 = SetCurrent(devices, parent=self)
        task2 = CheckCurrent(devices, parent=self)
        task2.itemDone.connect(_part(self._log, show=show))
        tasks = [task0, task1, task2]

        labels = [
            'Connecting to devices...', 'Setting current to zero...',
            'Checking current value...'
        ]

        dlg = ProgressDialog(labels, tasks, self)
        dlg.exec_()

    def _set_check_current(self):
        self.ok_ps.clear()
        self.nok_ps.clear()
        devices = self._get_selected_ps()
        if not devices:
            return

        value, ok = QInputDialog.getDouble(self, "Setpoint Input",
                                           "Insert current setpoint: ")
        if not ok:
            return

        task0 = CreateTesters(devices, parent=self)
        task1 = SetCurrent(devices, value=value, parent=self)
        task2 = CheckCurrent(devices, value=value, parent=self)
        task2.itemDone.connect(self._log)
        tasks = [task0, task1, task2]

        labels = [
            'Connecting to devices...', 'Setting current...',
            'Checking current value...'
        ]

        dlg = ProgressDialog(labels, tasks, self)
        dlg.exec_()

    def _set_check_opmode(self):
        self.ok_ps.clear()
        self.nok_ps.clear()
        devices = self._get_selected_ps()
        devices = [
            dev for dev in devices
            if dev.sec != 'LI' and dev.dev not in ('FCH', 'FCV')
        ]
        if not devices:
            return

        state, ok = QInputDialog.getItem(self,
                                         "OpMode Input",
                                         "Select OpMode: ",
                                         _PSE.OPMODES,
                                         editable=False)
        if not ok:
            return
        state2set = getattr(_PSC.OpMode, state)
        state2check = getattr(_PSC.States, state)

        task0 = CreateTesters(devices, parent=self)
        task1 = SetOpMode(devices, state=state2set, parent=self)
        task2 = CheckOpMode(devices, state=state2check, parent=self)
        task2.itemDone.connect(self._log)

        labels = [
            'Connecting to devices...',
            'Setting PS OpMode to ' + state + '...',
            'Checking PS OpMode in ' + state + '...'
        ]
        tasks = [task0, task1, task2]
        dlg = ProgressDialog(labels, tasks, self)
        dlg.exec_()

    def _set_test_pu(self):
        self.ok_ps.clear()
        self.nok_ps.clear()
        devices = self._get_selected_pu()
        if not devices:
            return

        task0 = CreateTesters(devices, parent=self)
        task1 = SetVoltage(devices, is_test=True, parent=self)
        task2 = CheckVoltage(devices, is_test=True, parent=self)
        task2.itemDone.connect(self._log)
        tasks = [task0, task1, task2]

        labels = [
            'Connecting to devices...', 'Testing PU... Setting voltage...',
            'Testing PU... Checking voltage value...'
        ]

        dlg = ProgressDialog(labels, tasks, self)
        dlg.exec_()

    def _set_zero_pu(self, check=True):
        self.ok_ps.clear()
        self.nok_ps.clear()
        devices = self._get_selected_pu()
        if not devices:
            return

        task0 = CreateTesters(devices, parent=self)
        task1 = SetVoltage(devices, parent=self)
        tasks = [task0, task1]

        labels = ['Connecting to devices...', 'Setting voltage to zero...']

        if check:
            task2 = CheckVoltage(devices, parent=self)
            task2.itemDone.connect(self._log)
            tasks.append(task2)
            labels.append('Checking voltage value...')
        else:
            task1.itemDone.connect(self._log)

        dlg = ProgressDialog(labels, tasks, self)
        dlg.exec_()

    def _restore_triggers_state(self, dev_type):
        self.ok_ps.clear()
        self.nok_ps.clear()
        if dev_type == 'PS':
            devices = self._get_selected_ps()
        elif dev_type == 'PU':
            devices = self._get_selected_pu()
        if not devices:
            return

        task1 = SetTriggerState(parent=self,
                                restore_initial_value=True,
                                dis=dev_type,
                                devices=devices)
        task2 = CheckTriggerState(parent=self,
                                  restore_initial_value=True,
                                  dis=dev_type,
                                  devices=devices)
        task2.itemDone.connect(self._log)
        tasks = [task1, task2]

        labels = [
            'Restoring ' + dev_type + ' trigger states...',
            'Checking ' + dev_type + ' trigger states...'
        ]

        dlg = ProgressDialog(labels, tasks, self)
        dlg.exec_()

    # ---------- log updates -----------

    def _set_lastcomm(self, dev_type):
        sender_text = self.sender().text()
        self.label_lastcomm.setText('Last Command: ' + dev_type + ' - ' +
                                    sender_text)

    def _clear_lastcomm(self):
        self.ok_ps.clear()
        self.nok_ps.clear()
        self.label_lastcomm.setText('Last Command: ')

    def _log(self, name, status, show=True):
        if show:
            if status:
                self.ok_ps.addItem(name)
            else:
                self.nok_ps.addItem(name)
        else:
            if status:
                self.ok_ps_aux_list.append(name)
            else:
                self.nok_ps_aux_list.append(name)

    # ---------- devices control ----------

    def _get_ps_tree_names(self):
        # add LI, TB, BO, TS
        psnames = PSSearch.get_psnames({'sec': '(LI|TB|BO|TS)', 'dis': 'PS'})
        # add SI Fams
        psnames.extend(
            PSSearch.get_psnames({
                'sec': 'SI',
                'sub': 'Fam',
                'dis': 'PS',
                'dev': '(B.*|Q.*|S.*)'
            }))
        # add SI Corrs
        psnames.extend(
            PSSearch.get_psnames({
                'sec': 'SI',
                'sub': '[0-2][0-9].*',
                'dis': 'PS',
                'dev': '(CH|CV)'
            }))
        # add SI QTrims
        psnames.extend(
            PSSearch.get_psnames({
                'sec': 'SI',
                'sub': '[0-2][0-9].*',
                'dis': 'PS',
                'dev': '(QD.*|QF.*|Q[1-4])'
            }))
        # add SI QSkews
        psnames.extend(
            PSSearch.get_psnames({
                'sec': 'SI',
                'dis': 'PS',
                'dev': 'QS'
            }))
        # add SI Fast Corrs
        psnames.extend(
            PSSearch.get_psnames({
                'sec': 'SI',
                'dis': 'PS',
                'dev': 'FC.*'
            }))
        return psnames

    def _get_pu_tree_names(self):
        punames = PSSearch.get_psnames({
            'sec': '(TB|BO|TS|SI)',
            'dis': 'PU',
            'dev': '.*(Kckr|Sept).*'
        })
        return punames

    def _get_selected_ps(self):
        devices = self.ps_tree.checked_items()
        if not devices:
            QMessageBox.critical(self, 'Message', 'No power supply selected!')
            return False
        devices = [PVName(dev) for dev in devices]
        return devices

    def _get_selected_pu(self):
        devices = self.pu_tree.checked_items()
        if not devices:
            QMessageBox.critical(self, 'Message',
                                 'No pulsed power supply selected!')
            return False
        devices = [PVName(dev) for dev in devices]
        return devices

    def _get_related_dclinks(self, psnames, include_regatrons=False):
        if isinstance(psnames, str):
            psnames = [
                psnames,
            ]
        alldclinks = set()
        for name in psnames:
            if 'LI' in name:
                continue
            dclinks = PSSearch.conv_psname_2_dclink(name)
            if dclinks:
                dclink_model = PSSearch.conv_psname_2_psmodel(dclinks[0])
                if dclink_model != 'REGATRON_DCLink':
                    alldclinks.update(dclinks)
                elif include_regatrons:
                    for dcl in dclinks:
                        dcl_typ = PSSearch.conv_psname_2_pstype(dcl)
                        if dcl_typ == 'as-dclink-regatron-master':
                            alldclinks.add(dcl)
        alldclinks = [PVName(dev) for dev in alldclinks]
        return alldclinks

    def _open_detail(self, index):
        name = PVName(index.data())
        if name.dis == 'TI':
            app = QApplication.instance()
            wind = create_window_from_widget(HLTriggerDetailed,
                                             title=name,
                                             is_main=True)
            app.open_window(wind, parent=self, **{'device': name})
            return
        elif not _re.match('.*-.*:.*-.*', name):
            if index.model().rowCount(index) == 1:
                name = PVName(index.child(0, 0).data())
            else:
                return
        if name.dis == 'PS':
            run_newprocess(['sirius-hla-as-ps-detail.py', name])
        elif name.dis == 'PU':
            run_newprocess(['sirius-hla-as-pu-detail.py', name])

    # ---------- update setup ----------

    def _handle_checked_items_changed(self, item):
        devname = PVName(item.data(0, Qt.DisplayRole))
        if not _re.match('.*-.*:.*-.*', devname):
            return
        state2set = item.checkState(0)

        # ensure power supplies that share dclinks are checked together
        if devname in self._si_fam_psnames and not self._is_adv_mode:
            dclinks = PSSearch.conv_psname_2_dclink(devname)
            if dclinks:
                psname2check = set()
                for dcl in dclinks:
                    relps = PSSearch.conv_dclink_2_psname(dcl)
                    relps.remove(devname)
                    psname2check.update(relps)
                self.ps_tree.tree.blockSignals(True)
                for psn in psname2check:
                    item2check = self.ps_tree._item_map[psn]
                    if item2check.checkState(0) != state2set:
                        item2check.setData(0, Qt.CheckStateRole, state2set)
                self.ps_tree.tree.blockSignals(False)

        self._needs_update_setup = True

    def _update_setup(self):
        if not self._needs_update_setup:
            return
        self._needs_update_setup = False

        # show/hide buttons to initialize SI Fam PS
        has_sifam = False
        for psn in self._si_fam_psnames:
            item = self.ps_tree._item_map[psn]
            has_sifam |= item.checkState(0) != 0

        self.prep_sidclink_bt.setVisible(has_sifam)
        self.init_sips_bt.setVisible(has_sifam)
        self.aux_label.setVisible(has_sifam)

        # set CtrlLoop button label
        has_fast = False
        for psn in self._si_fastcorrs:
            item = self.ps_tree._item_map[psn]
            has_fast |= item.checkState(0) != 0

        text = 'Set(FC) and Check PS CtrlLoop' \
            if has_fast else 'Check PS CtrlLoop'
        self.setcheckctrlloop_ps_bt.setText(text)

    # ---------- events ----------

    def keyPressEvent(self, evt):
        """Implement keyPressEvent."""
        if evt.matches(QKeySequence.Copy):
            if self.ok_ps.underMouse():
                items = self.ok_ps.selectedItems()
            elif self.nok_ps.underMouse():
                items = self.nok_ps.selectedItems()
            items = '\n'.join([i.text() for i in items])
            QApplication.clipboard().setText(items)
        if evt.key() == Qt.Key_Escape:
            if self.ok_ps.underMouse():
                items = self.ok_ps.clearSelection()
            elif self.nok_ps.underMouse():
                items = self.nok_ps.clearSelection()
        super().keyPressEvent(evt)
Пример #11
0
class MacReportWindow(SiriusMainWindow):
    """Machine Report Window."""
    def __init__(self, parent=None):
        """Init."""
        super().__init__(parent)
        self._macreport = MacReport()
        self._macreport.connector.timeout = 5 * 60

        self.setWindowIcon(qta.icon('fa.book', color='gray'))
        self.setWindowTitle('Machine Reports')

        self._fsi = '{:8d}'
        self._fs1 = '{:8.3f}'
        self._fs2 = '{:8.3f} ± {:8.3f}'
        self._fst1 = '{:02d}h{:02d}'
        self._fst2 = '{:02d}h{:02d} ± {:02d}h{:02d}'

        self._update_task = None

        self._setupUi()
        self.setFocusPolicy(Qt.StrongFocus)
        self.setFocus(True)

    def _setupUi(self):
        cwid = QWidget(self)
        self.setCentralWidget(cwid)

        title = QLabel('<h3>Machine Reports</h3>',
                       self,
                       alignment=Qt.AlignCenter)

        self._timesel_gbox = self._setupTimePeriodSelWidget()
        self._timesel_gbox.setObjectName('timesel_gbox')
        self._timesel_gbox.setStyleSheet(
            "#timesel_gbox{min-height: 8em; max-height: 8em;}")

        self._progress_list = QListWidget(self)
        self._progress_list.setObjectName('progress_list')
        self._progress_list.setStyleSheet(
            "#progress_list{min-height: 8em; max-height: 8em;}")

        self._reports_wid = QTabWidget(cwid)
        self._reports_wid.setObjectName('ASTab')
        self._reports_wid.addTab(self._setupUserShiftStatsWidget(),
                                 'User Shift Stats')
        self._reports_wid.addTab(self._setupLightSourceUsageStats(),
                                 'Light Source Usage Stats')
        self._reports_wid.addTab(self._setupStoredCurrentStats(),
                                 'Stored Current Stats')

        self._pb_showraw = QPushButton(qta.icon('mdi.chart-line'),
                                       'Show Raw Data', self)
        self._pb_showraw.setEnabled(False)
        self._pb_showraw.clicked.connect(self._show_raw_data)

        self._pb_showpvsd = QPushButton(qta.icon('mdi.chart-line'),
                                        'Show Progrmd.vs.Delivered Hours',
                                        self)
        self._pb_showpvsd.setEnabled(False)
        self._pb_showpvsd.clicked.connect(self._show_progmd_vs_delivd)

        lay = QGridLayout(cwid)
        lay.setVerticalSpacing(10)
        lay.setHorizontalSpacing(10)
        lay.setContentsMargins(18, 9, 18, 9)
        lay.addWidget(title, 0, 0, 1, 3)
        lay.addWidget(self._timesel_gbox, 1, 0)
        lay.addWidget(self._progress_list,
                      1,
                      1,
                      1,
                      2,
                      alignment=Qt.AlignBottom)
        lay.addWidget(self._reports_wid, 2, 0, 1, 3)
        lay.addWidget(self._pb_showpvsd, 4, 0, alignment=Qt.AlignLeft)
        lay.addWidget(self._pb_showraw, 4, 2, alignment=Qt.AlignRight)

        self._updateUserShiftStats(setup=True)
        self._updateStoredCurrentStats(setup=True)
        self._updateLightSourceUsageStats(setup=True)

    def _setupTimePeriodSelWidget(self):
        tnow = Time.now()

        ld_tstart = QLabel('Time start: ')
        self.dt_start = QDateTimeEdit(tnow - 10 * 60, self)
        self.dt_start.setCalendarPopup(True)
        self.dt_start.setMinimumDate(Time(2020, 1, 1))
        self.dt_start.setDisplayFormat('dd/MM/yyyy hh:mm')

        ld_tstop = QLabel('Time stop: ')
        self.dt_stop = QDateTimeEdit(tnow, self)
        self.dt_stop.setCalendarPopup(True)
        self.dt_stop.setMinimumDate(Time(2020, 1, 1))
        self.dt_stop.setDisplayFormat('dd/MM/yyyy hh:mm')

        self.pb_search = QPushButton(qta.icon('fa5s.search'), 'Search', self)
        self.pb_search.clicked.connect(self._do_update)
        self.pb_search.setObjectName('pb_search')
        self.pb_search.setStyleSheet("""
            #pb_search{
                min-width:100px; max-width:100px;
                min-height:25px; max-height:25px;
                icon-size:20px;}
        """)

        wid = QGroupBox('Select interval: ', self)
        lay = QGridLayout(wid)
        lay.addWidget(ld_tstart, 0, 0)
        lay.addWidget(self.dt_start, 0, 1)
        lay.addWidget(ld_tstop, 1, 0)
        lay.addWidget(self.dt_stop, 1, 1)
        lay.addWidget(self.pb_search, 2, 1, alignment=Qt.AlignRight)
        return wid

    def _setupUserShiftStatsWidget(self):
        self.lb_uspt = LbData('')
        self.lb_usdt = LbData('')
        self.lb_ustt = LbData('')
        self.lb_uset = LbData('')
        self.lb_uspc = LbData('')
        self.lb_cav = LbData('')
        self.lb_cbav = LbData('')
        self.lb_ceav = LbData('')
        self.lb_tft = LbData('')
        self.lb_bdc = LbData('')
        self.lb_mttr = LbData('')
        self.lb_mtbf = LbData('')
        self.lb_reli = LbData('')
        self.lb_tsbt = LbData('')
        self.lb_tubt = LbData('')
        self.lb_mtbu = LbData('')
        self.lb_rsbt = LbData('')
        self.lb_itav = LbData('')

        wid = QWidget(self)
        lay = QGridLayout(wid)
        lay.setVerticalSpacing(0)
        lay.setHorizontalSpacing(0)
        lay.setAlignment(Qt.AlignTop)
        lay.addItem(QSpacerItem(120, 1, QSzPlcy.Fixed, QSzPlcy.Ignored), 0, 0)
        lay.addWidget(LbHHeader('Programmed Time (h)'), 0, 1)
        lay.addWidget(self.lb_uspt, 0, 2)
        lay.addWidget(LbHHeader('Delivered Time (h)'), 1, 1)
        lay.addWidget(self.lb_usdt, 1, 2)
        lay.addWidget(LbHHeader('Total Time (h)'), 2, 1)
        lay.addWidget(self.lb_ustt, 2, 2)
        lay.addWidget(LbHHeader('Extra Time (h)'), 3, 1)
        lay.addWidget(self.lb_uset, 3, 2)
        lay.addWidget(LbHHeader('# Programmed Shifts'), 4, 1)
        lay.addWidget(self.lb_uspc, 4, 2)
        lay.addWidget(LbHHeader('Current (avg ± std) (mA)'), 5, 1)
        lay.addWidget(self.lb_cav, 5, 2)
        lay.addWidget(
            LbHHeader('Current at the Beg. of the Shift (avg ± std) (mA)'), 6,
            1)
        lay.addWidget(self.lb_cbav, 6, 2)
        lay.addWidget(
            LbHHeader('Current at the End of the Shift (avg ± std) (mA)'), 7,
            1)
        lay.addWidget(self.lb_ceav, 7, 2)
        lay.addWidget(LbHHeader('Total Failures Time (h)'), 8, 1)
        lay.addWidget(self.lb_tft, 8, 2)
        lay.addWidget(LbHHeader('# Beam Dumps'), 9, 1)
        lay.addWidget(self.lb_bdc, 9, 2)
        lay.addWidget(LbHHeader('Time To Recover (avg ± std) (h)'), 10, 1)
        lay.addWidget(self.lb_mttr, 10, 2)
        lay.addWidget(LbHHeader('Time Between Failures (avg) (h)'), 11, 1)
        lay.addWidget(self.lb_mtbf, 11, 2)
        lay.addWidget(LbHHeader('Beam Reliability (%)'), 12, 1)
        lay.addWidget(self.lb_reli, 12, 2)
        lay.addWidget(LbHHeader('Total stable beam time (h)'), 13, 1)
        lay.addWidget(self.lb_tsbt, 13, 2)
        lay.addWidget(LbHHeader('Total unstable beam time (h)'), 14, 1)
        lay.addWidget(self.lb_tubt, 14, 2)
        lay.addWidget(LbHHeader('Time between unstable beams (avg) (h)'), 15,
                      1)
        lay.addWidget(self.lb_mtbu, 15, 2)
        lay.addWidget(LbHHeader('Relative stable beam time (%)'), 16, 1)
        lay.addWidget(self.lb_rsbt, 16, 2)
        lay.addWidget(LbHHeader('Injection time (avg ± std) (h)'), 17, 1)
        lay.addWidget(self.lb_itav, 17, 2)
        lay.addItem(QSpacerItem(120, 1, QSzPlcy.Fixed, QSzPlcy.Ignored), 0, 3)
        return wid

    def _updateUserShiftStats(self, setup=False):
        w2r = {
            'uspt': [
                'usershift_progmd_time',
            ],
            'usdt': [
                'usershift_delivd_time',
            ],
            'ustt': [
                'usershift_total_time',
            ],
            'uset': [
                'usershift_extra_time',
            ],
            'uspc': [
                'usershift_progmd_count',
            ],
            'cav': ['usershift_current_average', 'usershift_current_stddev'],
            'cbav':
            ['usershift_current_beg_average', 'usershift_current_beg_stddev'],
            'ceav':
            ['usershift_current_end_average', 'usershift_current_end_stddev'],
            'tft': [
                'usershift_total_failures_time',
            ],
            'bdc': [
                'usershift_beam_dump_count',
            ],
            'mttr': [
                'usershift_time_to_recover_average',
                'usershift_time_to_recover_stddev'
            ],
            'mtbf': [
                'usershift_time_between_failures_average',
            ],
            'reli': [
                'usershift_beam_reliability',
            ],
            'tsbt': [
                'usershift_total_stable_beam_time',
            ],
            'tubt': [
                'usershift_total_unstable_beam_time',
            ],
            'mtbu': ['usershift_time_between_unstable_beams_average'],
            'rsbt': ['usershift_relative_stable_beam_time'],
            'itav': [
                'usershift_injection_time_average',
                'usershift_injection_time_stddev'
            ]
        }

        for wname, rname in w2r.items():
            wid = getattr(self, 'lb_' + wname)
            items = [getattr(self._macreport, n) for n in rname]
            if 'time' in rname[0] and 'relative' not in rname[0]:
                if len(items) == 2:
                    if items[0] not in [None, _np.inf]:
                        hour1 = int(items[0])
                        minu1 = int((items[0] - hour1) * 60)
                        hour2 = int(items[1])
                        minu2 = int((items[1] - hour2) * 60)
                        items = [hour1, minu1, hour2, minu2]
                        str2fmt = self._fst2
                    else:
                        str2fmt = self._fs1
                elif items[0] not in [None, _np.inf]:
                    hour = int(items[0])
                    minu = int((items[0] - hour) * 60)
                    items = [hour, minu]
                    str2fmt = self._fst1
                else:
                    str2fmt = self._fs1
            else:
                str2fmt = getattr(
                    self,
                    '_fsi' if 'count' in rname[0] else '_fs' + str(len(rname)))
            text = '' if any([i is None for i in items]) \
                else str2fmt.format(*items)
            wid.setText(text)
            if setup:
                wid.setToolTip(getattr(MacReport, rname[0]).__doc__)

    def _setupStoredCurrentStats(self):
        self.lb_user_mb_avg = LbData('')
        self.lb_user_mb_intvl = LbData('')
        self.lb_user_sb_avg = LbData('')
        self.lb_user_sb_intvl = LbData('')
        self.lb_user_tt_avg = LbData('')
        self.lb_user_tt_intvl = LbData('')
        self.lb_commi_mb_avg = LbData('')
        self.lb_commi_mb_intvl = LbData('')
        self.lb_commi_sb_avg = LbData('')
        self.lb_commi_sb_intvl = LbData('')
        self.lb_commi_tt_avg = LbData('')
        self.lb_commi_tt_intvl = LbData('')
        self.lb_condi_mb_avg = LbData('')
        self.lb_condi_mb_intvl = LbData('')
        self.lb_condi_sb_avg = LbData('')
        self.lb_condi_sb_intvl = LbData('')
        self.lb_condi_tt_avg = LbData('')
        self.lb_condi_tt_intvl = LbData('')
        self.lb_mstdy_mb_avg = LbData('')
        self.lb_mstdy_mb_intvl = LbData('')
        self.lb_mstdy_sb_avg = LbData('')
        self.lb_mstdy_sb_intvl = LbData('')
        self.lb_mstdy_tt_avg = LbData('')
        self.lb_mstdy_tt_intvl = LbData('')
        self.lb_stord_mb_avg = LbData('')
        self.lb_stord_mb_intvl = LbData('')
        self.lb_stord_sb_avg = LbData('')
        self.lb_stord_sb_intvl = LbData('')
        self.lb_stord_tt_avg = LbData('')
        self.lb_stord_tt_intvl = LbData('')

        wid = QWidget(self)
        lay = QGridLayout(wid)
        lay.setVerticalSpacing(0)
        lay.setHorizontalSpacing(0)
        lay.setAlignment(Qt.AlignTop)
        lay.addWidget(LbHHeader('Current (avg ± std) (mA) (MB)'), 1, 0)
        lay.addWidget(LbHHeader('Time in MB mode (h)'), 2, 0)
        lay.addWidget(LbHHeader('Current (avg ± std) (mA) (SB)'), 3, 0)
        lay.addWidget(LbHHeader('Time in SB mode (h)'), 4, 0)
        lay.addWidget(LbHHeader('Current (avg ± std) (mA) (SB+MB)'), 5, 0)
        lay.addWidget(LbHHeader('Total Time (h) (SB+MB)'), 6, 0)
        lay.addWidget(LbVHeader('Users'), 0, 1)
        lay.addWidget(self.lb_user_mb_avg, 1, 1)
        lay.addWidget(self.lb_user_mb_intvl, 2, 1)
        lay.addWidget(self.lb_user_sb_avg, 3, 1)
        lay.addWidget(self.lb_user_sb_intvl, 4, 1)
        lay.addWidget(self.lb_user_tt_avg, 5, 1)
        lay.addWidget(self.lb_user_tt_intvl, 6, 1)
        lay.addWidget(LbVHeader('Commissioning'), 0, 2)
        lay.addWidget(self.lb_commi_mb_avg, 1, 2)
        lay.addWidget(self.lb_commi_mb_intvl, 2, 2)
        lay.addWidget(self.lb_commi_sb_avg, 3, 2)
        lay.addWidget(self.lb_commi_sb_intvl, 4, 2)
        lay.addWidget(self.lb_commi_tt_avg, 5, 2)
        lay.addWidget(self.lb_commi_tt_intvl, 6, 2)
        lay.addWidget(LbVHeader('Conditioning'), 0, 3)
        lay.addWidget(self.lb_condi_mb_avg, 1, 3)
        lay.addWidget(self.lb_condi_mb_intvl, 2, 3)
        lay.addWidget(self.lb_condi_sb_avg, 3, 3)
        lay.addWidget(self.lb_condi_sb_intvl, 4, 3)
        lay.addWidget(self.lb_condi_tt_avg, 5, 3)
        lay.addWidget(self.lb_condi_tt_intvl, 6, 3)
        lay.addWidget(LbVHeader('Machine Study'), 0, 4)
        lay.addWidget(self.lb_mstdy_mb_avg, 1, 4)
        lay.addWidget(self.lb_mstdy_mb_intvl, 2, 4)
        lay.addWidget(self.lb_mstdy_sb_avg, 3, 4)
        lay.addWidget(self.lb_mstdy_sb_intvl, 4, 4)
        lay.addWidget(self.lb_mstdy_tt_avg, 5, 4)
        lay.addWidget(self.lb_mstdy_tt_intvl, 6, 4)
        lay.addWidget(LbVHeader('All Stored Beam'), 0, 5)
        lay.addWidget(self.lb_stord_mb_avg, 1, 5)
        lay.addWidget(self.lb_stord_mb_intvl, 2, 5)
        lay.addWidget(self.lb_stord_sb_avg, 3, 5)
        lay.addWidget(self.lb_stord_sb_intvl, 4, 5)
        lay.addWidget(self.lb_stord_tt_avg, 5, 5)
        lay.addWidget(self.lb_stord_tt_intvl, 6, 5)
        return wid

    def _updateStoredCurrentStats(self, setup=False):
        shifttype = {
            'mstdy': 'machinestudy',
            'commi': 'commissioning',
            'condi': 'conditioning',
            'stord': 'ebeam',
            'user': '******'
        }
        fillmode = {'mb': 'multibunch', 'sb': 'singlebunch', 'tt': 'total'}
        stats = {
            'avg': ['average', 'stddev'],
            'intvl': [
                'time',
            ]
        }

        for wsht, rsht in shifttype.items():
            for wfm, rfm in fillmode.items():
                for wstt, rstt in stats.items():
                    wid = getattr(self, 'lb_' + wsht + '_' + wfm + '_' + wstt)
                    pname = 'current_' + rsht + '_' + rfm + '_'
                    items = [getattr(self._macreport, pname + i) for i in rstt]
                    if 'time' in rstt[0] and items[0] is not None:
                        hour = int(items[0])
                        minu = int((items[0] - hour) * 60)
                        items = [hour, minu]
                    str2fmt = getattr(
                        self, '_fst1' if
                        ('time' in rstt[0]) else '_fs' + str(len(rstt)))
                    text = '' if any([i is None for i in items]) \
                        else str2fmt.format(*items)
                    wid.setText(text)
                    if setup:
                        wid.setToolTip(
                            getattr(MacReport, pname + rstt[0]).__doc__)

    def _setupLightSourceUsageStats(self):
        self.lb_mstdy_fail_intvl = LbData('')
        self.lb_mstdy_fail_pcntl = LbData('')
        self.lb_mstdy_oper_intvl = LbData('')
        self.lb_mstdy_oper_pcntl = LbData('')
        self.lb_mstdy_total_intvl = LbData('')
        self.lb_mstdy_total_pcntl = LbData('')
        self.lb_commi_fail_intvl = LbData('')
        self.lb_commi_fail_pcntl = LbData('')
        self.lb_commi_oper_intvl = LbData('')
        self.lb_commi_oper_pcntl = LbData('')
        self.lb_commi_total_intvl = LbData('')
        self.lb_commi_total_pcntl = LbData('')
        self.lb_condi_fail_intvl = LbData('')
        self.lb_condi_fail_pcntl = LbData('')
        self.lb_condi_oper_intvl = LbData('')
        self.lb_condi_oper_pcntl = LbData('')
        self.lb_condi_total_intvl = LbData('')
        self.lb_condi_total_pcntl = LbData('')
        self.lb_maint_fail_intvl = LbData('')
        self.lb_maint_fail_pcntl = LbData('')
        self.lb_maint_oper_intvl = LbData('')
        self.lb_maint_oper_pcntl = LbData('')
        self.lb_maint_total_intvl = LbData('')
        self.lb_maint_total_pcntl = LbData('')
        self.lb_user_fail_intvl = LbData('')
        self.lb_user_fail_pcntl = LbData('')
        self.lb_user_oper_intvl = LbData('')
        self.lb_user_oper_pcntl = LbData('')
        self.lb_user_total_intvl = LbData('')
        self.lb_user_total_pcntl = LbData('')
        self.lb_total_intvl = LbHHeader('Total Usage Time (h): - ')

        wid = QWidget(self)
        lay = QGridLayout(wid)
        lay.setVerticalSpacing(0)
        lay.setHorizontalSpacing(0)
        lay.setAlignment(Qt.AlignTop)
        lay.addWidget(LbHHeader('Operational Time (h)'), 1, 0)
        lay.addWidget(LbHHeader('Operational Percentage (%)'), 2, 0)
        lay.addWidget(LbHHeader('Failures Time (h)'), 3, 0)
        lay.addWidget(LbHHeader('Failures Percentage (%)'), 4, 0)
        lay.addWidget(LbHHeader('Shift Time (h)'), 5, 0)
        lay.addWidget(LbHHeader('Shift Percentage (%)'), 6, 0)
        lay.addWidget(self.lb_total_intvl, 7, 0, 1, 6)
        lay.addWidget(LbVHeader('Users'), 0, 1)
        lay.addWidget(self.lb_user_oper_intvl, 1, 1)
        lay.addWidget(self.lb_user_oper_pcntl, 2, 1)
        lay.addWidget(self.lb_user_fail_intvl, 3, 1)
        lay.addWidget(self.lb_user_fail_pcntl, 4, 1)
        lay.addWidget(self.lb_user_total_intvl, 5, 1)
        lay.addWidget(self.lb_user_total_pcntl, 6, 1)
        lay.addWidget(LbVHeader('Commissioning'), 0, 2)
        lay.addWidget(self.lb_commi_oper_intvl, 1, 2)
        lay.addWidget(self.lb_commi_oper_pcntl, 2, 2)
        lay.addWidget(self.lb_commi_fail_intvl, 3, 2)
        lay.addWidget(self.lb_commi_fail_pcntl, 4, 2)
        lay.addWidget(self.lb_commi_total_intvl, 5, 2)
        lay.addWidget(self.lb_commi_total_pcntl, 6, 2)
        lay.addWidget(LbVHeader('Conditioning'), 0, 3)
        lay.addWidget(self.lb_condi_oper_intvl, 1, 3)
        lay.addWidget(self.lb_condi_oper_pcntl, 2, 3)
        lay.addWidget(self.lb_condi_fail_intvl, 3, 3)
        lay.addWidget(self.lb_condi_fail_pcntl, 4, 3)
        lay.addWidget(self.lb_condi_total_intvl, 5, 3)
        lay.addWidget(self.lb_condi_total_pcntl, 6, 3)
        lay.addWidget(LbVHeader('Machine Study'), 0, 4)
        lay.addWidget(self.lb_mstdy_oper_intvl, 1, 4)
        lay.addWidget(self.lb_mstdy_oper_pcntl, 2, 4)
        lay.addWidget(self.lb_mstdy_fail_intvl, 3, 4)
        lay.addWidget(self.lb_mstdy_fail_pcntl, 4, 4)
        lay.addWidget(self.lb_mstdy_total_intvl, 5, 4)
        lay.addWidget(self.lb_mstdy_total_pcntl, 6, 4)
        lay.addWidget(LbVHeader('Maintenance'), 0, 5)
        lay.addWidget(self.lb_maint_oper_intvl, 1, 5)
        lay.addWidget(self.lb_maint_oper_pcntl, 2, 5)
        lay.addWidget(self.lb_maint_fail_intvl, 3, 5)
        lay.addWidget(self.lb_maint_fail_pcntl, 4, 5)
        lay.addWidget(self.lb_maint_total_intvl, 5, 5)
        lay.addWidget(self.lb_maint_total_pcntl, 6, 5)
        return wid

    def _updateLightSourceUsageStats(self, setup=False):
        shifttype = {
            'mstdy': 'machinestudy',
            'commi': 'commissioning',
            'condi': 'conditioning',
            'maint': 'maintenance',
            'user': '******'
        }
        intervaltype = {
            'fail': '_failures',
            'oper': '_operational',
            'total': ''
        }
        for wst, rst in shifttype.items():
            for wit, rit in intervaltype.items():
                widt = getattr(self, 'lb_' + wst + '_' + wit + '_intvl')
                tname = 'lsusage_' + rst + rit + '_time'
                tval = getattr(self._macreport, tname)
                if tval is None:
                    text = ''
                else:
                    hour = int(tval)
                    minu = int((tval - hour) * 60)
                    text = self._fst1.format(hour, minu)
                widt.setText(text)
                if setup:
                    widt.setToolTip(getattr(MacReport, tname).__doc__)

                widp = getattr(self, 'lb_' + wst + '_' + wit + '_pcntl')
                pname = 'lsusage_' + rst + rit
                pval = getattr(self._macreport, pname)
                text = '' if pval is None else self._fs1.format(pval)
                widp.setText(text)
                if setup:
                    widp.setToolTip(getattr(MacReport, pname).__doc__)

        text = 'Total Usage Time (h): '
        if self._macreport.lsusage_total_time is not None:
            val = self._macreport.lsusage_total_time
            hour = int(val)
            minu = int((val - hour) * 60)
            text += self._fst1.format(hour, minu)
        self.lb_total_intvl.setText(text)

    def _do_update(self):
        if self.sender().text() == 'Abort':
            self._update_task.terminate()
            now = Time.now().strftime('%Y/%m/%d-%H:%M:%S')
            item = QListWidgetItem(now + '  Aborted.')
            self._progress_list.addItem(item)
            self._progress_list.scrollToBottom()
            self._setup_search_button()
        else:
            if self.dt_start.dateTime() >= self.dt_stop.dateTime() or \
                    self.dt_start.dateTime() > Time.now() or \
                    self.dt_stop.dateTime() > Time.now():
                QMessageBox.warning(self, 'Ops...',
                                    'Insert a valid time interval.')
                return

            self._macreport.timestamp_start = \
                self.dt_start.dateTime().toSecsSinceEpoch()
            self._macreport.timestamp_stop = \
                self.dt_stop.dateTime().toSecsSinceEpoch()

            self._progress_list.clear()
            self._pb_showraw.setEnabled(False)
            self._pb_showpvsd.setEnabled(False)
            self._setup_search_button()

            self._update_task = UpdateTask(self._macreport)
            self._update_task.updated.connect(self._update_progress)
            self._update_task.start()

    def _update_progress(self, message):
        item = QListWidgetItem(message)
        self._progress_list.addItem(item)
        self._progress_list.scrollToBottom()

        if 'Collected' in message:
            self._setup_search_button()
            self._updateUserShiftStats()
            self._updateStoredCurrentStats()
            self._updateLightSourceUsageStats()
            self._pb_showraw.setEnabled(True)
            self._pb_showpvsd.setEnabled(True)

    def _setup_search_button(self):
        if self.pb_search.text() == 'Abort':
            self.pb_search.setIcon(qta.icon('fa5s.search'))
            self.pb_search.setText('Search')
        else:
            self.pb_search.setIcon(
                qta.icon('fa5s.spinner', animation=qta.Spin(self.pb_search)))
            self.pb_search.setText('Abort')

    def _show_raw_data(self):
        fig = self._macreport.plot_raw_data()
        wid = MatplotlibWidget(fig)
        wid.setWindowTitle('Machine Reports - Raw Data (' +
                           str(self._macreport.time_start) + ' -> ' +
                           str(self._macreport.time_stop) + ')')
        wid.show()

    def _show_progmd_vs_delivd(self):
        fig = self._macreport.plot_progmd_vs_delivd_hours()
        wid = MatplotlibWidget(fig)
        wid.setWindowTitle(
            'Machine Reports - Programmed vs. Delivered Hours (' +
            str(self._macreport.time_start) + ' -> ' +
            str(self._macreport.time_stop) + ')')
        wid.show()