コード例 #1
0
ファイル: pickchannelsdialog.py プロジェクト: ECGKit/mnelab
class PickChannelsDialog(QDialog):
    def __init__(self, parent, channels, selected=None, title="Pick channels"):
        super().__init__(parent)
        self.setWindowTitle(title)
        if selected is None:
            selected = []
        self.initial_selection = selected
        vbox = QVBoxLayout(self)
        self.channels = QListWidget()
        self.channels.insertItems(0, channels)
        self.channels.setSelectionMode(QListWidget.ExtendedSelection)
        for i in range(self.channels.count()):
            if self.channels.item(i).data(0) in selected:
                self.channels.item(i).setSelected(True)
        vbox.addWidget(self.channels)
        self.buttonbox = QDialogButtonBox(QDialogButtonBox.Ok |
                                          QDialogButtonBox.Cancel)
        vbox.addWidget(self.buttonbox)
        self.buttonbox.accepted.connect(self.accept)
        self.buttonbox.rejected.connect(self.reject)
        self.channels.itemSelectionChanged.connect(self.toggle_buttons)
        self.toggle_buttons()  # initialize OK button state

    @Slot()
    def toggle_buttons(self):
        """Toggle OK button.
        """
        selected = [item.data(0) for item in self.channels.selectedItems()]
        if selected != self.initial_selection:
            self.buttonbox.button(QDialogButtonBox.Ok).setEnabled(True)
        else:
            self.buttonbox.button(QDialogButtonBox.Ok).setEnabled(False)
コード例 #2
0
class AcceptFiles(QDialog):
    def __init__(self, files):
        super().__init__()
        self.ok = QPushButton("Add", self)
        self.ok.clicked.connect(self.accept)
        discard = QPushButton("Discard", self)
        discard.clicked.connect(self.close)
        self.files = QListWidget(self)
        self.files.setSelectionMode(QAbstractItemView.ExtendedSelection)
        for file_name in files:
            self.files.addItem(file_name)
        for i in range(self.files.count()):
            self.files.item(i).setSelected(True)
        self.ok.setDefault(True)
        self.ok.setAutoDefault(True)

        layout = QVBoxLayout()
        layout.addWidget(QLabel("Found {} files".format(len(files))))
        layout.addWidget(self.files)
        butt_layout = QHBoxLayout()
        butt_layout.addWidget(discard)
        butt_layout.addStretch()
        butt_layout.addWidget(self.ok)
        layout.addLayout(butt_layout)
        self.setLayout(layout)

    def selection_changed(self):
        if self.files.selectedItems().count() == 0:
            self.ok.setDisabled(True)
        else:
            self.ok.setEnabled(True)

    def get_files(self):
        return [str(item.text()) for item in self.files.selectedItems()]
コード例 #3
0
ファイル: caselist.py プロジェクト: oyvindeide/ert
class CaseList(QWidget):
    def __init__(self, facade: LibresFacade, notifier: ErtNotifier):
        self.facade = facade
        self.notifier = notifier
        QWidget.__init__(self)

        addHelpToWidget(self, "init/case_list")

        layout = QVBoxLayout()

        self._list = QListWidget(self)
        self._list.setMinimumHeight(100)
        self._list.setMaximumHeight(250)
        self._default_selection_mode = self._list.selectionMode()
        self.setSelectable(False)

        layout.addWidget(QLabel("Available cases:"))
        layout.addWidget(self._list)

        self._addRemoveWidget = AddRemoveWidget(self.addItem,
                                                self.removeItem,
                                                horizontal=True)
        self._addRemoveWidget.enableRemoveButton(False)
        layout.addWidget(self._addRemoveWidget)

        self._title = "New keyword"
        self._description = "Enter name of keyword:"

        self.setLayout(layout)

        notifier.ertChanged.connect(self.updateList)
        self.updateList()

    def setSelectable(self, selectable):
        if selectable:
            self._list.setSelectionMode(self._default_selection_mode)
        else:
            self._list.setSelectionMode(QAbstractItemView.NoSelection)

    def addItem(self):
        dialog = ValidatedDialog("New case", "Enter name of new case:",
                                 getAllCases(self.facade))
        new_case_name = dialog.showAndTell()
        if not new_case_name == "":
            self.facade.select_or_create_new_case(new_case_name)
            self.notifier.ertChanged.emit()

    def removeItem(self):
        message = "Support for removal of items has not been implemented!"
        QMessageBox.information(self, "Not implemented!", message)

    def updateList(self):
        """Retrieves data from the model and inserts it into the list"""
        case_list = getAllCases(self.facade)

        self._list.clear()

        for case in case_list:
            self._list.addItem(case)
コード例 #4
0
class AppendDialog(QDialog):
    def __init__(self, parent, compatibles, title="Append data"):
        super().__init__(parent)
        self.setWindowTitle(title)

        vbox = QVBoxLayout(self)
        grid = QGridLayout()

        grid.addWidget(QLabel("Source"), 0, 0, Qt.AlignCenter)
        grid.addWidget(QLabel("Destination"), 0, 2, Qt.AlignCenter)

        source = QListWidget(self)
        source.setAcceptDrops(True)
        source.setDragEnabled(True)
        source.setSelectionMode(QAbstractItemView.ExtendedSelection)
        source.setDefaultDropAction(Qt.DropAction.MoveAction)
        source.insertItems(0, [d["name"] for d in compatibles])
        grid.addWidget(source, 1, 0)

        grid.addWidget(QLabel("->"), 1, 1, Qt.AlignHCenter)

        self.destination = QListWidget(self)
        self.destination.setAcceptDrops(True)
        self.destination.setDragEnabled(True)
        self.destination.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.destination.setDefaultDropAction(Qt.DropAction.MoveAction)
        grid.addWidget(self.destination, 1, 2)
        vbox.addLayout(grid)

        self.buttonbox = QDialogButtonBox(QDialogButtonBox.Ok
                                          | QDialogButtonBox.Cancel)
        self.buttonbox.accepted.connect(self.accept)
        self.buttonbox.rejected.connect(self.reject)

        vbox.addWidget(self.buttonbox)
        vbox.setSizeConstraint(QVBoxLayout.SetFixedSize)
        self.destination.model().rowsInserted.connect(self.toggle_buttons)
        self.destination.model().rowsRemoved.connect(self.toggle_buttons)
        self.toggle_buttons()

    @property
    def names(self):
        names = []
        for it in range(self.destination.count()):
            names.append(self.destination.item(it).text())
        return names

    @Slot()
    def toggle_buttons(self):
        """Toggle OK button.
        """
        if self.destination.count() > 0:
            self.buttonbox.button(QDialogButtonBox.Ok).setEnabled(True)
        else:
            self.buttonbox.button(QDialogButtonBox.Ok).setEnabled(False)
コード例 #5
0
ファイル: montagedialog.py プロジェクト: stralu/mnelab
class MontageDialog(QDialog):
    def __init__(self, parent, montages, selected=None):
        super().__init__(parent)
        self.setWindowTitle("Set montage")
        vbox = QVBoxLayout(self)
        self.montages = QListWidget()
        self.montages.insertItems(0, montages)
        self.montages.setSelectionMode(QListWidget.SingleSelection)
        if selected is not None:
            for i in range(self.montages.count()):
                if self.montages.item(i).data(0) == selected:
                    self.montages.item(i).setSelected(True)
        vbox.addWidget(self.montages)
        hbox = QHBoxLayout()
        self.view_button = QPushButton("View")
        self.view_button.clicked.connect(self.view_montage)
        hbox.addWidget(self.view_button)
        hbox.addStretch()
        self.buttonbox = QDialogButtonBox(QDialogButtonBox.Ok
                                          | QDialogButtonBox.Cancel)
        hbox.addWidget(self.buttonbox)
        vbox.addLayout(hbox)
        self.buttonbox.accepted.connect(self.accept)
        self.buttonbox.rejected.connect(self.reject)
        self.montages.itemSelectionChanged.connect(self.toggle_buttons)
        self.toggle_buttons()  # initialize OK and View buttons state

    @Slot()
    def toggle_buttons(self):
        """Toggle OK and View buttons.
        """
        if self.montages.selectedItems():
            self.buttonbox.button(QDialogButtonBox.Ok).setEnabled(True)
            self.view_button.setEnabled(True)
        else:
            self.buttonbox.button(QDialogButtonBox.Ok).setEnabled(False)
            self.view_button.setEnabled(False)

    def view_montage(self):
        name = self.montages.selectedItems()[0].data(0)
        montage = make_standard_montage(name)
        fig = montage.plot(show_names=True, show=False)
        win = fig.canvas.manager.window
        win.setWindowModality(Qt.WindowModal)
        win.setWindowTitle("Montage")
        win.findChild(QStatusBar).hide()
        win.findChild(QToolBar).hide()
        fig.show()
コード例 #6
0
class PopInDialog(QDialog):

    pop_in_tabs = Signal(list)

    def __init__(self, parent, loggers):
        super().__init__(parent)
        self.loggers = loggers
        self.setupUi()

    def setupUi(self):
        self.resize(200, 320)
        self.vbox = QVBoxLayout(self)
        self.listWidget = QListWidget(self)
        self.listWidget.setSelectionMode(self.listWidget.MultiSelection)
        self.listWidget.selectionModel().reset()
        self.vbox.addWidget(self.listWidget)
        self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel, self)
        self.vbox.addWidget(self.buttonBox)

        self.buttonBox.accepted.connect(self.accept)
        self.listWidget.doubleClicked.connect(self.accept)
        self.buttonBox.rejected.connect(self.reject)

        self.fill_logger_list()

    def fill_logger_list(self):
        for logger in self.loggers:
            if logger.popped_out:
                self.listWidget.addItem(logger.name)
        self.listWidget.setCurrentRow(0)

    def accept(self, index=None):
        names = []
        if index is not None:
            item = self.listWidget.itemFromIndex(index)
            names.append(item.text())
        else:
            for item in self.listWidget.selectedItems():
                names.append(item.text())
        if len(names) > 0:
            self.pop_in_tabs.emit(names)
        self.done(0)

    def reject(self):
        self.done(0)
コード例 #7
0
class LoadRecentFiles(QDialog):
    def __init__(self, settings: BaseSettings, parent=None):
        super().__init__(parent)
        self.settings = settings
        self.file_list = QListWidget()
        self.file_list.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.cancel_btn = QPushButton("Cancel", clicked=self.reject)
        self.load_btn = QPushButton("Load", clicked=self.accept)

        for name_list, method in settings.get_last_files_multiple():
            entry = f"{name_list[0]} {method}"
            item = QListWidgetItem(entry, self.file_list)
            item.setData(Qt.UserRole, (name_list, method))

        last_set = {(tuple(x), y)
                    for x, y in settings.get_last_files_multiple()}
        for name_list, method in settings.get_last_files():
            if (tuple(name_list), method) in last_set:
                continue
            entry = f"{name_list[0]} {method}"
            item = QListWidgetItem(entry, self.file_list)
            item.setData(Qt.UserRole, (name_list, method))

        layout = QGridLayout()
        layout.addWidget(QLabel("Select files"))
        layout.addWidget(self.file_list, 1, 0, 1, 2)
        layout.addWidget(self.cancel_btn, 2, 0)
        layout.addWidget(self.load_btn, 2, 1)

        self.setLayout(layout)
        self.resize(
            *self.settings.get_from_profile("multiple_files_dialog_size", (
                self.size().width(), self.size().height())))

    def get_files(self) -> List[Tuple[List[str], str]]:
        return [
            item.data(Qt.UserRole) for item in self.file_list.selectedItems()
        ]

    def accept(self) -> None:
        self.settings.set_in_profile(
            "multiple_files_dialog_size",
            (self.size().width(), self.size().height()))
        super().accept()
コード例 #8
0
ファイル: main.py プロジェクト: danruttley/relocker
class RemoveLasersWindow(QWidget):
    def __init__(self, main_window):
        super().__init__()

        self.main_window = main_window
        lasers = self.main_window.lasers
        self.setWindowTitle("Remove laser")

        layout = QVBoxLayout()
        self.setLayout(layout)

        self.laser_list = QListWidget()
        self.laser_list.setSelectionMode(QAbstractItemView.ExtendedSelection)
        layout.addWidget(self.laser_list)

        names = []
        for laser in lasers:
            settings = laser.get_settings()
            names.append(settings['name'])
        print(names)
        self.laser_list.addItems(names)

        self.removeButton = QPushButton("Remove")
        layout.addWidget(self.removeButton)

        self._createActions()
        self._connectActions()

    def _createActions(self):
        self.removeAction = QAction(self)
        self.removeAction.setText("Remove")

    def _connectActions(self):
        self.removeButton.clicked.connect(self.removeAction.trigger)
        self.removeAction.triggered.connect(self.remove_lasers)

    def remove_lasers(self):
        selected_rows = [x.row() for x in self.laser_list.selectedIndexes()]
        print(selected_rows)
        self.main_window.remove_lasers(selected_rows)
コード例 #9
0
ファイル: appenddialog.py プロジェクト: rob-luke/mnelab
    def __init__(self, parent, compatibles, title="Append data"):
        super().__init__(parent)
        self.setWindowTitle(title)

        vbox = QVBoxLayout(self)
        grid = QGridLayout()

        grid.addWidget(QLabel("Source"), 0, 0, Qt.AlignCenter)
        grid.addWidget(QLabel("Destination"), 0, 2, Qt.AlignCenter)

        source = QListWidget(self)
        source.setAcceptDrops(True)
        source.setDragEnabled(True)
        source.setSelectionMode(QAbstractItemView.ExtendedSelection)
        source.setDefaultDropAction(Qt.DropAction.MoveAction)
        source.insertItems(0, [d["name"] for d in compatibles])
        grid.addWidget(source, 1, 0)

        grid.addWidget(QLabel("->"), 1, 1, Qt.AlignHCenter)

        self.destination = QListWidget(self)
        self.destination.setAcceptDrops(True)
        self.destination.setDragEnabled(True)
        self.destination.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.destination.setDefaultDropAction(Qt.DropAction.MoveAction)
        grid.addWidget(self.destination, 1, 2)
        vbox.addLayout(grid)

        self.buttonbox = QDialogButtonBox(QDialogButtonBox.Ok
                                          | QDialogButtonBox.Cancel)
        self.buttonbox.accepted.connect(self.accept)
        self.buttonbox.rejected.connect(self.reject)

        vbox.addWidget(self.buttonbox)
        vbox.setSizeConstraint(QVBoxLayout.SetFixedSize)
        self.destination.model().rowsInserted.connect(self.toggle_buttons)
        self.destination.model().rowsRemoved.connect(self.toggle_buttons)
        self.toggle_buttons()
コード例 #10
0
ファイル: main.py プロジェクト: danruttley/relocker
class RemoveRPWindow(QWidget):
    def __init__(self, main_window):
        super().__init__()

        self.main_window = main_window
        rps = self.main_window.rps
        self.setWindowTitle("Remove RedPitaya")

        layout = QVBoxLayout()
        self.setLayout(layout)

        self.laser_list = QListWidget()
        self.laser_list.setSelectionMode(QAbstractItemView.ExtendedSelection)
        layout.addWidget(self.laser_list)

        names = []
        self.laser_list.addItems(rps)

        self.removeButton = QPushButton("Remove")
        layout.addWidget(self.removeButton)

        self._createActions()
        self._connectActions()

    def _createActions(self):
        self.removeAction = QAction(self)
        self.removeAction.setText("Remove")

    def _connectActions(self):
        self.removeButton.clicked.connect(self.removeAction.trigger)
        self.removeAction.triggered.connect(self.remove_lasers)

    def remove_lasers(self):
        selected_rows = [x.row() for x in self.laser_list.selectedIndexes()]
        print(selected_rows)
        self.main_window.remove_rps(selected_rows)
コード例 #11
0
ファイル: epochdialog.py プロジェクト: ECGKit/mnelab
class EpochDialog(QDialog):
    def __init__(self, parent, events):
        super().__init__(parent)
        self.setWindowTitle("Create Epochs")

        grid = QGridLayout(self)
        label = QLabel("Events:")
        label.setAlignment(Qt.AlignTop)
        grid.addWidget(label, 0, 0, 1, 1)

        self.events = QListWidget()
        self.events.insertItems(0, unique(events[:, 2]).astype(str))
        self.events.setSelectionMode(QListWidget.ExtendedSelection)
        grid.addWidget(self.events, 0, 1, 1, 2)

        grid.addWidget(QLabel("Interval around events:"), 1, 0, 1, 1)
        self.tmin = QDoubleSpinBox()
        self.tmin.setMinimum(-10000)
        self.tmin.setValue(-0.2)
        self.tmin.setSingleStep(0.1)
        self.tmin.setAlignment(Qt.AlignRight)
        self.tmax = QDoubleSpinBox()
        self.tmax.setMinimum(-10000)
        self.tmax.setValue(0.5)
        self.tmax.setSingleStep(0.1)
        self.tmax.setAlignment(Qt.AlignRight)
        grid.addWidget(self.tmin, 1, 1, 1, 1)
        grid.addWidget(self.tmax, 1, 2, 1, 1)

        self.baseline = QCheckBox("Baseline Correction:")
        self.baseline.setChecked(True)
        self.baseline.stateChanged.connect(self.toggle_baseline)
        grid.addWidget(self.baseline, 2, 0, 1, 1)
        self.a = QDoubleSpinBox()
        self.a.setMinimum(-10000)
        self.a.setValue(-0.2)
        self.a.setSingleStep(0.1)
        self.a.setAlignment(Qt.AlignRight)
        self.b = QDoubleSpinBox()
        self.b.setMinimum(-10000)
        self.b.setValue(0)
        self.b.setSingleStep(0.1)
        self.b.setAlignment(Qt.AlignRight)
        grid.addWidget(self.a, 2, 1, 1, 1)
        grid.addWidget(self.b, 2, 2, 1, 1)
        self.buttonbox = QDialogButtonBox(QDialogButtonBox.Ok
                                          | QDialogButtonBox.Cancel)
        self.buttonbox.accepted.connect(self.accept)
        self.buttonbox.rejected.connect(self.reject)
        grid.addWidget(self.buttonbox, 3, 0, 1, -1)
        self.events.itemSelectionChanged.connect(self.toggle_ok)
        self.toggle_ok()
        grid.setSizeConstraint(QGridLayout.SetFixedSize)

    @Slot()
    def toggle_ok(self):
        if self.events.selectedItems():
            self.buttonbox.button(QDialogButtonBox.Ok).setEnabled(True)
        else:
            self.buttonbox.button(QDialogButtonBox.Ok).setEnabled(False)

    @Slot()
    def toggle_baseline(self):
        if self.baseline.isChecked():
            self.a.setEnabled(True)
            self.b.setEnabled(True)
        else:
            self.a.setEnabled(False)
            self.b.setEnabled(False)
コード例 #12
0
ファイル: checklist.py プロジェクト: oyvindeide/ert
class CheckList(QWidget):
    def __init__(self, model, label="", help_link="", custom_filter_button=None):
        """
        :param custom_filter_button:  if needed, add a button that opens a
        custom filter menu. Useful when search alone isn't enough to filter the
        list.
        :type custom_filter_button: QToolButton
        """
        QWidget.__init__(self)

        self._model = model

        if help_link != "":
            addHelpToWidget(self, help_link)

        layout = QVBoxLayout()

        self._createCheckButtons()

        self._list = QListWidget()
        self._list.setContextMenuPolicy(Qt.CustomContextMenu)
        self._list.setSelectionMode(QAbstractItemView.ExtendedSelection)

        self._search_box = SearchBox()

        check_button_layout = QHBoxLayout()

        check_button_layout.setContentsMargins(0, 0, 0, 0)
        check_button_layout.setSpacing(0)
        check_button_layout.addWidget(QLabel(label))
        check_button_layout.addStretch(1)
        check_button_layout.addWidget(self._checkAllButton)
        check_button_layout.addWidget(self._uncheckAllButton)

        layout.addLayout(check_button_layout)
        layout.addWidget(self._list)

        """
        Inserts the custom filter button, if provided. The caller is responsible
        for all related actions.
        """
        if custom_filter_button is not None:
            search_bar_layout = QHBoxLayout()
            search_bar_layout.addWidget(self._search_box)
            search_bar_layout.addWidget(custom_filter_button)
            layout.addLayout(search_bar_layout)
        else:
            layout.addWidget(self._search_box)

        self.setLayout(layout)

        self._checkAllButton.clicked.connect(self.checkAll)
        self._uncheckAllButton.clicked.connect(self.uncheckAll)
        self._list.itemChanged.connect(self.itemChanged)
        self._search_box.filterChanged.connect(self.filterList)
        self._list.customContextMenuRequested.connect(self.showContextMenu)

        self._model.selectionChanged.connect(self.modelChanged)
        self._model.modelChanged.connect(self.modelChanged)

        self.modelChanged()

    def _createCheckButtons(self):
        self._checkAllButton = QToolButton()
        self._checkAllButton.setIcon(resourceIcon("check.svg"))
        self._checkAllButton.setIconSize(QSize(16, 16))
        self._checkAllButton.setToolButtonStyle(Qt.ToolButtonIconOnly)
        self._checkAllButton.setAutoRaise(True)
        self._checkAllButton.setToolTip("Select all")
        self._uncheckAllButton = QToolButton()
        self._uncheckAllButton.setIcon(resourceIcon("checkbox_outline.svg"))
        self._uncheckAllButton.setIconSize(QSize(16, 16))
        self._uncheckAllButton.setToolButtonStyle(Qt.ToolButtonIconOnly)
        self._uncheckAllButton.setAutoRaise(True)
        self._uncheckAllButton.setToolTip("Unselect all")

    def itemChanged(self, item):
        """@type item: QListWidgetItem"""
        if item.checkState() == Qt.Checked:
            self._model.selectValue(str(item.text()))
        elif item.checkState() == Qt.Unchecked:
            self._model.unselectValue(str(item.text()))
        else:
            raise AssertionError("Unhandled checkstate!")

    def modelChanged(self):
        self._list.clear()

        items = self._model.getList()

        for item in items:
            list_item = QListWidgetItem(item)
            list_item.setFlags(list_item.flags() | Qt.ItemIsUserCheckable)

            if self._model.isValueSelected(item):
                list_item.setCheckState(Qt.Checked)
            else:
                list_item.setCheckState(Qt.Unchecked)

            self._list.addItem(list_item)

        self.filterList(self._search_box.filter())

    def setSelectionEnabled(self, enabled):
        self.setEnabled(enabled)
        self._checkAllButton.setEnabled(enabled)
        self._uncheckAllButton.setEnabled(enabled)

    def filterList(self, filter):
        filter = filter.lower()

        for index in range(0, self._list.count()):
            item = self._list.item(index)
            text = str(item.text()).lower()

            if filter == "":
                item.setHidden(False)
            elif filter in text:
                item.setHidden(False)
            else:
                item.setHidden(True)

    def checkAll(self):
        """
        Checks all visible items in the list.
        """
        for index in range(0, self._list.count()):
            item = self._list.item(index)
            if not item.isHidden():
                self._model.selectValue(str(item.text()))

    def uncheckAll(self):
        """
        Unchecks all items in the list, visible or not
        """
        self._model.unselectAll()

    def checkSelected(self):
        items = []
        for item in self._list.selectedItems():
            items.append(str(item.text()))

        for item in items:
            self._model.selectValue(item)

    def uncheckSelected(self):
        items = []
        for item in self._list.selectedItems():
            items.append(str(item.text()))

        for item in items:
            self._model.unselectValue(item)

    def showContextMenu(self, point):
        p = self._list.mapToGlobal(point)
        menu = QMenu()
        check_selected = menu.addAction("Check selected")
        uncheck_selected = menu.addAction("Uncheck selected")
        menu.addSeparator()
        clear_selection = menu.addAction("Clear selection")

        selected_item = menu.exec_(p)

        if selected_item == check_selected:
            self.checkSelected()
        elif selected_item == uncheck_selected:
            self.uncheckSelected()
        elif selected_item == clear_selection:
            self._list.clearSelection()
コード例 #13
0
class MainWindow(QMainWindow):
    def selectFileToOpen(self):
        def getPreProcessingChoice(self, filename, filestructure):
            items = ("Choose the longest", "Merge all")
            item, okPressed = QInputDialog.getItem(
                self, "Multiple tracks/segments", "File '" + filename +
                "' contains more than one track/segment\n\n" + infos +
                "\nWhat to do?", items, 0, False)
            if okPressed and item:
                return items.index(item)
            else:
                return 0

        # Try to recover the last used directory
        old_directory = self.settings.value("lastdirectory", str)

        # Check if the setting exists
        if old_directory is not None:
            # Check if it's not empty
            if old_directory:
                old_directory = old_directory
            else:
                old_directory = bombo.TRACKS_FOLDER
        else:
            old_directory = bombo.TRACKS_FOLDER

        # Open the dialog box
        fullfilename_list = QFileDialog.getOpenFileNames(
            self, 'Open .gpx', old_directory, "GPX files (*.gpx)")
        if os.environ['QT_API'] == 'pyqt':
            pass
        elif os.environ['QT_API'] == 'pyqt5':
            fullfilename_list = fullfilename_list[0]

        # Process every selected file
        for i, fullfilename in enumerate(fullfilename_list):
            # Process filename
            directory, filename = os.path.split(str(fullfilename))
            filename, fileextension = os.path.splitext(filename)

            # Save the new directory in the application settings (it only
            # needs to be done once)
            if i == 0:
                # print "New directory to be saved: {}\n".format(directory)
                if os.environ['QT_API'] == 'pyqt':
                    self.settings.setValue("lastdirectory", str(directory))
                elif os.environ['QT_API'] == 'pyqt5':
                    self.settings.setValue("lastdirectory",
                                           QtCore.QVariant(str(directory)))

            # Open file and inspect what's inside
            gpxraw, longest_traseg, Ntracks, Nsegments, infos = bombo.LoadGPX(
                fullfilename)

            # If there's more than one track or segment, ask how to proceed
            if (Ntracks > 1) or (Nsegments > 1):
                preprocessingchoice = getPreProcessingChoice(
                    self, filename, infos)
                if preprocessingchoice == 0:
                    preprocessedgpx = bombo.SelectOneTrackAndSegmentFromGPX(
                        gpxraw, longest_traseg[0], longest_traseg[1])
                    listname = filename + " (longest)"
                elif preprocessingchoice == 1:
                    preprocessedgpx = bombo.MergeAllTracksAndSegmentsFromGPX(
                        gpxraw)
                    listname = filename + " (merged)"
            else:
                preprocessedgpx = gpxraw
                listname = filename

            # Append the list of open GPX files using the next available color (that's the size of the list -1)
            self.gpxlist.append(preprocessedgpx)
            self.gpxnamelist.append(listname)
            newitem = QListWidgetItem(listname)
            newitem.setBackground(
                QtGui.QColor(self.palette[len(self.gpxlist) - 1]))
            self.tracklist.addItem(newitem)

        return

    def Go(self):
        if len(self.gpxselectedlist) > 0:
            # Temporarily change cursor
            QApplication.setOverrideCursor(QtCore.Qt.WaitCursor)

            # Clear up global variables
            self.proc_coords = []
            self.proc_measurements = []
            self.proc_state_means = []
            self.proc_state_vars = []
            self.proc_new_coords = []
            self.proc_new_gpx = []
            self.proc_coords_to_plot = []
            self.proc_coords_to_plot2 = []
            self.proc_balloondata = []

            # For every GPX file that is selected
            self.textWarningConsole.clear()
            for i, currentgpx in enumerate(self.gpxselectedlist):
                # Parse the GPX file
                gpx, coords, dinfos_before, warnings = bombo.ParseGPX(
                    currentgpx,
                    track_nr=0,
                    segment_nr=0,
                    use_srtm_elevation=bool(self.checkUseSRTM.isChecked()))
                self.textWarningConsole.append(warnings)

                # Kalman processing
                coords, measurements, state_means, state_vars, dinfos_during = bombo.ApplyKalmanFilter(
                    coords,
                    gpx,
                    method=self.comboBoxProcessingMethod.currentIndex(),
                    use_acceleration=self.checkUseAcceleration.isChecked(),
                    extra_smooth=self.checkExtraSmooth.isChecked(),
                    debug_plot=False)

                # Save data in GPX structure to compute speed and elevations
                new_coords, new_gpx, dinfos_after = bombo.SaveDataToCoordsAndGPX(
                    coords, state_means)

                # Update GUI with the computed stats
                parent = QtGui.QStandardItem(self.gpxselectednamelist[i])

                parent_beforeprocessing = QtGui.QStandardItem("Raw GPX stats")
                parent_beforeprocessing.appendRow([
                    QtGui.QStandardItem("Total distance"),
                    QtGui.QStandardItem(dinfos_before['total_distance'])
                ])
                parent_beforeprocessing_moving = QtGui.QStandardItem("Moving")
                parent_beforeprocessing_moving.appendRow([
                    QtGui.QStandardItem("Time"),
                    QtGui.QStandardItem(dinfos_before['moving_time'])
                ])
                parent_beforeprocessing_moving.appendRow([
                    QtGui.QStandardItem("Distance"),
                    QtGui.QStandardItem(dinfos_before['moving_distance'])
                ])
                parent_beforeprocessing.appendRow(
                    parent_beforeprocessing_moving)
                parent_beforeprocessing_idle = QtGui.QStandardItem("Idle")
                parent_beforeprocessing_idle.appendRow([
                    QtGui.QStandardItem("Time"),
                    QtGui.QStandardItem(dinfos_before['idle_time'])
                ])
                parent_beforeprocessing_idle.appendRow([
                    QtGui.QStandardItem("Distance"),
                    QtGui.QStandardItem(dinfos_before['idle_distance'])
                ])
                parent_beforeprocessing.appendRow(parent_beforeprocessing_idle)
                parent_beforeprocessing.appendRow([
                    QtGui.QStandardItem("Elevation"),
                    QtGui.QStandardItem(dinfos_before['elevation'])
                ])
                parent_beforeprocessing.appendRow([
                    QtGui.QStandardItem("Climb"),
                    QtGui.QStandardItem(dinfos_before['climb'])
                ])
                parent.appendRow(parent_beforeprocessing)

                parent.appendRow([
                    QtGui.QStandardItem("Samples"),
                    QtGui.QStandardItem(dinfos_during['nsamples'])
                ])
                parent.appendRow([
                    QtGui.QStandardItem("Total distance"),
                    QtGui.QStandardItem(dinfos_after['total_distance'])
                ])
                parent_moving = QtGui.QStandardItem("Moving")
                parent_moving.appendRow([
                    QtGui.QStandardItem("Time"),
                    QtGui.QStandardItem(dinfos_after['moving_time'])
                ])
                parent_moving.appendRow([
                    QtGui.QStandardItem("Distance"),
                    QtGui.QStandardItem(dinfos_after['moving_distance'])
                ])
                parent.appendRow(parent_moving)
                parent_idle = QtGui.QStandardItem("Idle")
                parent_idle.appendRow([
                    QtGui.QStandardItem("Time"),
                    QtGui.QStandardItem(dinfos_after['idle_time'])
                ])
                parent_idle.appendRow([
                    QtGui.QStandardItem("Distance"),
                    QtGui.QStandardItem(dinfos_after['idle_distance'])
                ])
                parent.appendRow(parent_idle)
                parent.appendRow([
                    QtGui.QStandardItem("Elevation"),
                    QtGui.QStandardItem(dinfos_after['elevation'])
                ])
                parent.appendRow([
                    QtGui.QStandardItem("Climb"),
                    QtGui.QStandardItem(dinfos_after['climb'])
                ])
                self.treemodel.appendRow(parent)

                # Create balloondata for the html plot
                balloondata = {
                    'distance':
                    np.cumsum(
                        bombo.HaversineDistance(np.asarray(new_coords['lat']),
                                                np.asarray(
                                                    new_coords['lon']))),
                    'elevation':
                    np.asarray(new_coords['ele']),
                    'speed':
                    None
                }

                # Create extra data for the html plot (fully implemented in bombo, not here)
                """
                data = np.ones((len(lat_cleaned),2))
                data[:,0] = h_filtered / np.max(h_filtered) * 0.0004
                data[:,1] = np.hstack((np.asarray([0]), speed_h)) / np.max(np.hstack((np.asarray([0]), speed_h))) * 0.0004
                tangentdata = {'data': data,
                               'sides': (0, 1),
                               'palette': ('blue','red')}
                """

                # Save relevant output in global variables
                self.proc_coords.append(coords)
                self.proc_measurements.append(measurements)
                self.proc_state_means.append(state_means)
                self.proc_state_vars.append(state_vars)
                self.proc_new_coords.append(new_coords)
                self.proc_new_gpx.append(new_gpx)
                self.proc_coords_to_plot.append(
                    np.vstack((new_coords['lat'], new_coords['lon'])).T)
                self.proc_coords_to_plot2.append(
                    np.vstack((coords['lat'], coords['lon'])).T)
                self.proc_balloondata.append(balloondata)

            # Restore original cursor
            QApplication.restoreOverrideCursor()

            # Generate embedded plots
            if len(self.gpxselectedlist) == 1:
                self.plotEmbeddedElevationAndSpeed.update_figure(
                    measurements, state_means, new_gpx.tracks[0].segments[0])
                self.plotEmbeddedDetails.update_figure(
                    measurements, state_means, state_vars,
                    new_gpx.tracks[0].segments[0])
            else:
                # Commentato per adesso
                # self.plotEmbeddedElevationAndSpeed.update_figure_multiple_tracks(self.proc_measurements, self.proc_state_means, self.proc_new_gpx)
                self.plotEmbeddedElevationAndSpeed.clear_figure()
                self.plotEmbeddedDetails.clear_figure()

            # Generate html plot, if only one track is selected, proceed with the complete output, otherwise just plot the traces
            if len(self.gpxselectedlist) is 1:
                bombo.PlotOnMap(
                    coords_array_list=self.proc_coords_to_plot,
                    coords_array2_list=self.proc_coords_to_plot2,
                    coords_palette=self.selectedpalette,
                    tangentdata=None,
                    balloondata_list=self.proc_balloondata,
                    rdp_reduction=self.checkUseRDP.isChecked(),
                    showmap=bool(self.check2DMapInExternalBrowser.isChecked()))
            else:
                bombo.PlotOnMap(
                    coords_array_list=self.proc_coords_to_plot,
                    coords_array2_list=None,
                    coords_palette=self.selectedpalette,
                    tangentdata=None,
                    balloondata_list=self.proc_balloondata,
                    rdp_reduction=self.checkUseRDP.isChecked(),
                    showmap=bool(self.check2DMapInExternalBrowser.isChecked()))

            self.map2d.load(QtCore.QUrl(bombo.MAP_2D_FILENAME))
            self.map2d.show()

            # Generate 3D plot, only with one track for the moment
            if len(self.gpxselectedlist) == 1:
                if self.check3DMapSelection.isChecked():
                    tile_selection = 'auto'
                else:
                    tile_selection = self.text3DMapName.text()
                terrain, track, warnings = bombo.Generate3DMap(
                    new_coords['lat'],
                    new_coords['lon'],
                    tile_selection=tile_selection,
                    margin=self.spinbox3DMargin.value(),
                    elevation_scale=self.spinbox3DElevationScale.value(),
                    mapping='coords',
                    use_osm_texture=True,
                    texture_type='osm',
                    texture_zoom=self.spinbox3DOSMZoom.value(),
                    texture_invert=self.check3DOSMInvert.isChecked(),
                    use_proxy=self.use_proxy,
                    proxy_data=self.proxy_config,
                    verbose=False)

                self.textWarningConsole.append(warnings)

                if terrain is not None:
                    self.map3d.update_plot(terrain, track)

        else:
            self.textWarningConsole.setText(
                "You need to open a .gpx file before!")
        return

    def PlotSpecificAreaDialog(self):
        def PlotSpecificArea():
            # Save coordinates for the next time
            if os.environ['QT_API'] == 'pyqt':
                self.settings.setValue("last_point_coord_lat",
                                       self.spinboxLatDec.value())
                self.settings.setValue("last_point_coord_lon",
                                       self.spinboxLonDec.value())
            elif os.environ['QT_API'] == 'pyqt5':
                self.settings.setValue(
                    "last_point_coord_lat",
                    QtCore.QVariant(self.spinboxLatDec.value()))
                self.settings.setValue(
                    "last_point_coord_lon",
                    QtCore.QVariant(self.spinboxLonDec.value()))

            # Select the 3D Map tab
            self.tab.setCurrentIndex(2)

            # Plot
            if self.check3DMapSelection.isChecked():
                tile_selection = 'auto'
            else:
                tile_selection = self.text3DMapName.text()

            terrain, track, warnings = bombo.Generate3DMap(
                [self.spinboxLatDec.value()], [self.spinboxLonDec.value()],
                tile_selection=tile_selection,
                margin=self.spinbox3DMargin.value(),
                elevation_scale=self.spinbox3DElevationScale.value(),
                mapping='coords',
                use_osm_texture=True,
                texture_type='osm',
                texture_zoom=self.spinbox3DOSMZoom.value(),
                texture_invert=self.check3DOSMInvert.isChecked(),
                use_proxy=self.use_proxy,
                proxy_data=self.proxy_config,
                verbose=False)

            self.textWarningConsole.append(warnings)

            if terrain is not None:
                self.map3d.update_plot(terrain, track)
            d.done(0)

        def Convert():
            try:
                dd = bombo.parse_dms(self.textLatLonGMS.text())
                self.spinboxLatDec.setValue(dd[0])
                self.spinboxLonDec.setValue(dd[1])
            except:
                pass

        d = QDialog()
        grid = QGridLayout()

        hBox_coordsGMS = QHBoxLayout()
        hBox_coordsGMS.setSpacing(5)
        label = QLabel('Coordinates (gms)')
        grid.addWidget(label, 0, 0)
        self.textLatLonGMS = QLineEdit()
        self.textLatLonGMS.setText("")
        grid.addWidget(self.textLatLonGMS, 0, 1, 1, 2)

        button1 = QPushButton("Convert to decimal")
        button1.clicked.connect(Convert)
        grid.addWidget(button1, 0, 3)

        label = QLabel('Coordinates (decimal)')
        grid.addWidget(label, 1, 0)
        self.spinboxLatDec = QDoubleSpinBox()
        self.spinboxLatDec.setRange(-90, +90)
        self.spinboxLatDec.setSingleStep(0.0000001)
        self.spinboxLatDec.setDecimals(7)
        grid.addWidget(self.spinboxLatDec, 1, 1)
        self.spinboxLonDec = QDoubleSpinBox()
        self.spinboxLonDec.setRange(-180, +180)
        self.spinboxLonDec.setSingleStep(0.0000001)
        self.spinboxLonDec.setDecimals(7)
        grid.addWidget(self.spinboxLonDec, 1, 2)

        # Try to recover the last used points
        try:
            old_lat = self.settings.value("last_point_coord_lat", type=float)
            old_lon = self.settings.value("last_point_coord_lon", type=float)
            self.spinboxLatDec.setValue(old_lat)
            self.spinboxLonDec.setValue(old_lon)
        except:
            # Coordinates of Mt. Rinjani in Indonesia
            self.spinboxLatDec.setValue(-8.4166000)
            self.spinboxLonDec.setValue(116.4666000)

        button2 = QPushButton("Show 3D map")
        button2.clicked.connect(PlotSpecificArea)
        grid.addWidget(button2, 1, 3)

        d.setWindowTitle("Show point on 3D map")
        d.setLayout(grid)
        d.setWindowModality(QtCore.Qt.ApplicationModal)
        d.exec_()

    def ProxyDialog(self):
        def SetProxy():
            self.use_proxy = bool(self.checkUseProxy.isChecked())
            self.proxy_config = self.textProxyConfig.text()

            if os.environ['QT_API'] == 'pyqt':
                self.settings.setValue("use_proxy", self.use_proxy)
                self.settings.setValue("proxy_config", str(self.proxy_config))
            elif os.environ['QT_API'] == 'pyqt5':
                self.settings.setValue("use_proxy",
                                       QtCore.QVariant(self.use_proxy))
                self.settings.setValue("proxy_config",
                                       QtCore.QVariant(str(self.proxy_config)))

            d.done(0)

        d = QDialog()

        box = QVBoxLayout()

        hBox_proxy = QHBoxLayout()
        hBox_proxy.setSpacing(5)
        label = QLabel('Proxy')
        hBox_proxy.addWidget(label)
        self.textProxyConfig = QLineEdit()
        try:
            self.textProxyConfig.setText(
                self.settings.value('proxy_config', str))
        except:
            self.textProxyConfig.setText(bombo.PROXY_DATA)
        self.textProxyConfig.setMinimumWidth(200)
        hBox_proxy.addWidget(self.textProxyConfig)
        box.addLayout(hBox_proxy)

        self.checkUseProxy = QCheckBox("Use proxy")
        try:
            self.checkUseProxy.setChecked(
                self.settings.value('use_proxy', bool))
        except:
            self.checkUseProxy.setChecked(bool(bombo.USE_PROXY))
        box.addWidget(self.checkUseProxy)

        button = QPushButton("Save configuration")
        button.clicked.connect(SetProxy)
        box.addWidget(button)

        d.setWindowTitle("Proxy configuration")
        d.setLayout(box)
        d.setWindowModality(QtCore.Qt.ApplicationModal)
        d.exec_()

    def __init__(self, parent=None):
        super(MainWindow, self).__init__()
        self.initVariables()
        self.initUI()

    def initVariables(self):
        self.gpxlist = list()
        self.gpxnamelist = list()
        self.gpxselectedlist = list()
        self.gpxselectednamelist = list()
        self.palette = bombo.GeneratePalette(N=10) * 5  # replicated 5 times
        #self.palette = ["#0000FF", "#00FF00", "#00FFFF", "#FF0000", "#FF00FF", "#FFFF00", "#FFFFFF"] # test palette
        self.selectedpalette = list()

        self.proc_coords = list()
        self.proc_measurements = list()
        self.proc_state_means = list()
        self.proc_state_vars = list()
        self.proc_new_coords = list()
        self.proc_new_gpx = list()
        self.proc_coords_to_plot = list()
        self.proc_coords_to_plot2 = list()
        self.proc_balloondata = list()

    def initUI(self):
        def selection_changed():
            # Retrieve selected items
            # selecteditems = self.tracklist.selectedItems()
            selectedindexes = self.tracklist.selectedIndexes()

            # Adding the selected items to the processing list
            self.gpxselectedlist[:] = []
            self.gpxselectednamelist[:] = []
            self.selectedpalette[:] = []
            for i in selectedindexes:
                # print str(i.text())
                self.gpxselectedlist.append(self.gpxlist[i.row()])
                self.gpxselectednamelist.append(self.gpxnamelist[i.row()])
                self.selectedpalette.append(self.palette[i.row()])

        def ClearStats():
            """
            # Some other code that could be used in the future
            index = self.treemodel.indexFromItem(parent1)
            self.tree.expand(index)
            selmod = self.tree.selectionModel()
            index2 = self.treemodel.indexFromItem(child2)
            selmod.select(index2, QtCore.QItemSelectionModel.Select|QtCore.QItemSelectionModel.Rows)
            
            root = self.treemodel.invisibleRootItem()
            (item.parent() or root).removeChild(item)
            """
            # Returns a list of indexes. In our case, for each row there are 2 indexes, cos there are 2 columns.
            for index in self.tree.selectedIndexes():
                # Consider only the first columns
                if index.column() == 0:
                    # Need to check if it's a top item (i.e. track), otherwise if a subitem (i.e. distance or time) is selected, the result might be buggy
                    parent = index.parent()
                    parent_item = self.treemodel.itemFromIndex(parent)
                    if parent_item is None:
                        self.treemodel.removeRow(index.row())

        # Application Settings
        QtCore.QCoreApplication.setOrganizationName("Ste")
        QtCore.QCoreApplication.setOrganizationDomain(
            "https://github.com/stesalati/sport/")
        QtCore.QCoreApplication.setApplicationName("TrackAnalyser")

        # Config settings
        self.settings = QtCore.QSettings(self)

        # Proxy settings
        try:
            self.use_proxy = self.settings.value('use_proxy', bool)
            self.proxy_config = self.settings.value('proxy_config', str)
        except:
            self.use_proxy = bombo.USE_PROXY
            self.proxy_config = bombo.PROXY_DATA

        # Actions
        openfile = QAction(QtGui.QIcon("icons/openfile.png"), "Open .gpx",
                           self)
        openfile.setShortcut("Ctrl+O")
        openfile.setStatusTip("Open file")
        openfile.triggered.connect(self.selectFileToOpen)

        go = QAction(QtGui.QIcon("icons/go.png"), "Go!", self)
        go.setShortcut("Ctrl+R")
        go.setStatusTip("Run analysis")
        go.triggered.connect(self.Go)

        clearstats = QAction(QtGui.QIcon("icons/clear.png"), "Clear stats",
                             self)
        clearstats.setShortcut("Ctrl+C")
        clearstats.setStatusTip("Clear stats")
        clearstats.triggered.connect(ClearStats)

        sep1 = QAction(self)
        sep1.setSeparator(True)

        showpoint = QAction(QtGui.QIcon("icons/point.png"), "Show point", self)
        showpoint.setShortcut("Ctrl+P")
        showpoint.setStatusTip("Show point")
        showpoint.triggered.connect(self.PlotSpecificAreaDialog)

        sep2 = QAction(self)
        sep2.setSeparator(True)

        quitapp = QAction(QtGui.QIcon("icons/quit.png"), "Quit", self)
        quitapp.setShortcut("Ctrl+Q")
        quitapp.setStatusTip("Quit application")
        quitapp.triggered.connect(qApp.quit)

        configs = QAction(QtGui.QIcon("icons/configs.png"), "Configs", self)
        configs.setStatusTip("Configs")
        configs.triggered.connect(self.ProxyDialog)

        # Menubar
        mainMenu = self.menuBar()
        configMenu = mainMenu.addMenu('&Config')
        configMenu.addAction(configs)

        # Toolbar
        toolbar = self.addToolBar('My tools')
        toolbar.addAction(openfile)
        toolbar.addAction(go)
        toolbar.addAction(clearstats)
        toolbar.addAction(sep1)
        toolbar.addAction(showpoint)
        toolbar.addAction(sep2)
        toolbar.addAction(quitapp)
        toolbar.setToolButtonStyle(QtCore.Qt.ToolButtonTextUnderIcon)
        toolbar.setIconSize(QtCore.QSize(30, 30))

        # Status bar
        self.statusBar().show()

        # Main widget (everything that's not toolbar, statusbar or menubar must be in this widget)
        self.scatola = QWidget()

        # Main horizontal impagination
        hBox = QHBoxLayout()
        hBox.setSpacing(5)

        # Vertical left column
        vBox_left = QVBoxLayout()
        vBox_left.setSpacing(5)

        # 1st vertical box, a list
        self.tracklist = QListWidget()
        vBox_left.addWidget(self.tracklist)
        self.tracklist.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.tracklist.itemSelectionChanged.connect(selection_changed)
        self.tracklist.setMaximumHeight(120)

        # 2nd vertical box, containing several horizontal boxes, one for each setting
        vBox2 = QVBoxLayout()
        vBox2.setSpacing(5)

        # Just the group label
        labelSettings = QLabel('Settings')
        vBox2.addWidget(labelSettings)

        # Use/don't use corrected altitude
        self.checkUseSRTM = QCheckBox(
            "Use SRTM corrected elevation (needs Internet)")
        self.checkUseSRTM.setChecked(False)
        vBox2.addWidget(self.checkUseSRTM)

        # Choose processing method + use/don't use acceleration
        hBoxProcessingMethod = QHBoxLayout()
        labelProcessingMethod = QLabel('Processing method')
        hBoxProcessingMethod.addWidget(labelProcessingMethod)
        self.comboBoxProcessingMethod = QComboBox()
        self.comboBoxProcessingMethod.addItem("Just use available data")
        self.comboBoxProcessingMethod.addItem(
            "Fill all gaps at T=1s (resample)")
        self.comboBoxProcessingMethod.addItem("Fill only smaller gaps at T=1s")
        hBoxProcessingMethod.addWidget(self.comboBoxProcessingMethod)
        self.checkUseAcceleration = QCheckBox("Use acceleration")
        self.checkUseAcceleration.setChecked(False)
        hBoxProcessingMethod.addWidget(self.checkUseAcceleration)
        vBox2.addLayout(hBoxProcessingMethod)

        # Use/don't use variance smooth
        self.checkExtraSmooth = QCheckBox("Extra smooth")
        self.checkExtraSmooth.setChecked(False)
        vBox2.addWidget(self.checkExtraSmooth)

        # 2D interactive map settings
        hBox2DMap = QHBoxLayout()
        self.checkUseRDP = QCheckBox("Use RDP to reduce points")
        self.checkUseRDP.setChecked(False)
        hBox2DMap.addWidget(self.checkUseRDP)
        self.check2DMapInExternalBrowser = QCheckBox(
            "Show in external browser")
        self.check2DMapInExternalBrowser.setChecked(False)
        hBox2DMap.addWidget(self.check2DMapInExternalBrowser)
        vBox2.addLayout(hBox2DMap)

        # Settings for the 3D map
        line3DViewSettings = QFrame()
        #line3DViewSettings.setGeometry(QtCore.QRect(320, 150, 118, 3))
        line3DViewSettings.setFrameShape(QFrame.HLine)
        line3DViewSettings.setFrameShadow(QFrame.Sunken)
        vBox2.addWidget(line3DViewSettings)

        label3DViewSettings = QLabel('3D view settings')
        vBox2.addWidget(label3DViewSettings)

        hBox3DMapSelection = QHBoxLayout()
        self.check3DMapSelection = QCheckBox(
            "Select elevation tiles automatically, otherwise")
        self.check3DMapSelection.setChecked(True)
        hBox3DMapSelection.addWidget(self.check3DMapSelection)
        self.text3DMapName = QLineEdit()
        self.text3DMapName.setText("Iceland.tif")
        hBox3DMapSelection.addWidget(self.text3DMapName)
        vBox2.addLayout(hBox3DMapSelection)

        hBox3D = QHBoxLayout()
        label3DMargin = QLabel('Margin')
        hBox3D.addWidget(label3DMargin)
        self.spinbox3DMargin = QSpinBox()
        self.spinbox3DMargin.setRange(50, 1000)
        self.spinbox3DMargin.setValue(100)
        self.spinbox3DMargin.setSingleStep(10)
        hBox3D.addWidget(self.spinbox3DMargin)

        labelSpace = QLabel('  ')
        hBox3D.addWidget(labelSpace)

        label3DElevationScale = QLabel('Elev. scale')
        hBox3D.addWidget(label3DElevationScale)
        self.spinbox3DElevationScale = QDoubleSpinBox()
        self.spinbox3DElevationScale.setRange(1, 50)
        self.spinbox3DElevationScale.setSingleStep(0.1)
        hBox3D.addWidget(self.spinbox3DElevationScale)

        hBox3D.addWidget(labelSpace)

        label3DOSMZoom = QLabel('Zoom')
        hBox3D.addWidget(label3DOSMZoom)
        self.spinbox3DOSMZoom = QSpinBox()
        self.spinbox3DOSMZoom.setRange(8, 15)
        self.spinbox3DOSMZoom.setValue(13)
        self.spinbox3DOSMZoom.setSingleStep(1)
        hBox3D.addWidget(self.spinbox3DOSMZoom)

        hBox3D.addWidget(labelSpace)

        self.check3DOSMInvert = QCheckBox("Invert")
        self.check3DOSMInvert.setChecked(False)
        hBox3D.addWidget(self.check3DOSMInvert)
        vBox2.addLayout(hBox3D)

        vBox_left.addLayout(vBox2)

        # 3rd stats tree
        lineTree = QFrame()
        lineTree.setFrameShape(QFrame.HLine)
        lineTree.setFrameShadow(QFrame.Sunken)
        vBox2.addWidget(lineTree)
        labelTree = QLabel('Track stats')
        vBox2.addWidget(labelTree)

        self.tree = QTreeView()
        self.tree.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.treemodel = QtGui.QStandardItemModel()
        self.treemodel.setHorizontalHeaderLabels(['Name', 'Value'])
        self.tree.setModel(self.treemodel)
        self.tree.setUniformRowHeights(True)
        self.tree.setColumnWidth(0, 200)
        vBox_left.addWidget(self.tree)

        # 4th text, containing text messages/errors
        self.textWarningConsole = QTextEdit()
        self.textWarningConsole.setReadOnly(True)
        self.textWarningConsole.setFont(QtGui.QFont("Courier New", FONTSIZE))
        self.textWarningConsole.clear()
        self.textWarningConsole.setMaximumHeight(50)
        vBox_left.addWidget(self.textWarningConsole)

        # I put "vBox_left" inside a widget and then the widget inside "hBox"
        # instead of just doing "hBox.addLayout(vBox_left) so I can set its
        # maximum width.
        vBox_left_widget = QWidget()
        vBox_left_widget.setLayout(vBox_left)
        vBox_left_widget.setMinimumWidth(400)
        vBox_left_widget.setMaximumWidth(500)
        hBox.addWidget(vBox_left_widget)

        # Vertical right column
        self.tab = QTabWidget()

        # Tab 1: Summary: elevation and speed
        tab1 = QWidget()
        # The tab layout
        vBox_tab = QVBoxLayout()
        vBox_tab.setSpacing(5)
        # Plot area
        self.plotEmbeddedElevationAndSpeed = EmbeddedPlot_ElevationSpeed(
            width=5, height=4, dpi=100)
        self.plotEmbeddedElevationAndSpeed.setMinimumWidth(800)
        # Add toolbar to the plot
        self.mpl_toolbar1 = NavigationToolbar(
            self.plotEmbeddedElevationAndSpeed, self.scatola)
        # Add widgets to the layout
        vBox_tab.addWidget(self.plotEmbeddedElevationAndSpeed)
        vBox_tab.addWidget(self.mpl_toolbar1)
        # Associate the layout to the tab
        tab1.setLayout(vBox_tab)

        # Tab 2: html 2D map
        tab2 = QWidget()
        # The tab layout
        vBox_tab = QVBoxLayout()
        vBox_tab.setSpacing(5)
        # Area
        self.map2d = QtWebEngineWidgets.QWebEngineView()
        # Add widgets to the layout
        vBox_tab.addWidget(self.map2d)
        # Associate the layout to the tab
        tab2.setLayout(vBox_tab)

        # Tab 3: 3D plot
        tab3 = QWidget()
        # The tab layout
        vBox_tab = QVBoxLayout()
        vBox_tab.setSpacing(5)
        # Area
        self.map3d = MayaviQWidget()
        # Add widgets to the layout
        vBox_tab.addWidget(self.map3d)
        # Associate the layout to the tab
        tab3.setLayout(vBox_tab)

        # Tab 4: Details
        tab4 = QWidget()
        # The tab layout
        vBox_tab = QVBoxLayout()
        vBox_tab.setSpacing(5)
        # Plot area
        self.plotEmbeddedDetails = EmbeddedPlot_Details(width=5,
                                                        height=4,
                                                        dpi=100)
        self.plotEmbeddedDetails.setMinimumWidth(800)
        # Add toolbar to the plot
        self.mpl_toolbar2 = NavigationToolbar(self.plotEmbeddedDetails,
                                              self.scatola)
        # Add widgets to the layout
        vBox_tab.addWidget(self.plotEmbeddedDetails)
        vBox_tab.addWidget(self.mpl_toolbar2)
        # Associate the layout to the tab
        tab4.setLayout(vBox_tab)

        # Associate tabs
        self.tab.addTab(tab1, "Summary")
        self.tab.addTab(tab2, "2D Map")
        self.tab.addTab(tab3, "3D Map")
        self.tab.addTab(tab4, "Details")

        hBox.addWidget(self.tab)

        # Setting hBox as main box
        self.scatola.setLayout(hBox)
        self.setCentralWidget(self.scatola)

        # Application settings
        self.setWindowTitle('TrackAnalyser')
        self.setWindowIcon((QtGui.QIcon('icons/app.png')))
        self.setGeometry(100, 100, 1200, 700)
        self.show()
コード例 #14
0
ファイル: merge_dialog.py プロジェクト: yangrq1018/cutelog
class MergeDialog(QDialog):

    # name of src tab, names of dst tabs, whether to keep connections alive or not
    merge_tabs_signal = Signal(str, list, bool)

    def __init__(self, parent, loggers):
        super().__init__(parent)

        self.loggers = loggers
        self.merge_list = []   # all tabs to be merged
        self.merge_dst = None  # tab to merge the rest of merge_list into

        self.setupUi()

    def setupUi(self):
        self.resize(340, 320)
        self.gridLayout = QGridLayout(self)
        self.dstComboBox = QComboBox(self)
        self.gridLayout.addWidget(self.dstComboBox, 1, 2, 1, 2)
        self.buttonBox = QDialogButtonBox(QDialogButtonBox.Cancel | QDialogButtonBox.Ok, self)
        self.gridLayout.addWidget(self.buttonBox, 5, 0, 1, 4)
        self.loggerList = QListWidget(self)
        self.loggerList.setDefaultDropAction(Qt.IgnoreAction)
        self.loggerList.setSelectionMode(QAbstractItemView.MultiSelection)
        self.gridLayout.addWidget(self.loggerList, 1, 0, 4, 2)
        self.keepAliveCheckBox = QCheckBox("Keep connections alive", self)
        self.keepAliveCheckBox.setChecked(True)
        self.gridLayout.addWidget(self.keepAliveCheckBox, 2, 2, 1, 2)
        self.srcsLabel = QLabel("All loggers:", self)
        self.gridLayout.addWidget(self.srcsLabel, 0, 0, 1, 2)
        self.dstLabel = QLabel("Merge all into:", self)
        self.gridLayout.addWidget(self.dstLabel, 0, 2, 1, 2)
        spacerItem = QSpacerItem(20, 169, QSizePolicy.Minimum, QSizePolicy.Expanding)
        self.gridLayout.addItem(spacerItem, 4, 2, 1, 2)

        self.buttonBox.accepted.connect(self.accept)
        self.buttonBox.rejected.connect(self.reject)

        self.loggerList.selectionModel().selectionChanged.connect(self.merge_list_changed)
        self.dstComboBox.currentTextChanged.connect(self.merge_dst_changed)
        self.ok_button = self.buttonBox.button(QDialogButtonBox.Ok)
        self.ok_button.setEnabled(False)
        self.keepAliveCheckBox.setToolTip("If disabled then only the destination connection "
                                          "will still be alive after merging.")

        self.fill_logger_list()

    def fill_logger_list(self):
        for logger_name in self.loggers.keys():
            LoggerListItem(self.loggerList, logger_name)

    def merge_list_changed(self, sel, desel):
        sel = sel.indexes()
        desel = desel.indexes()
        for index in sel:
            sel_item = self.loggerList.itemFromIndex(index)
            self.merge_list.append(sel_item)
            self.dstComboBox.addItem(sel_item.name)
            self.ok_button.setEnabled(True)

        for index in desel:
            desel_item = self.loggerList.itemFromIndex(index)
            self.merge_list.remove(desel_item)
            row = self.dstComboBox.findText(desel_item.name)
            self.dstComboBox.removeItem(row)
            if self.dstComboBox.count() == 0:
                self.ok_button.setEnabled(False)

    def merge_dst_changed(self, text):
        self.merge_dst = text

    def accept(self):
        name_list = [item.name for item in self.merge_list]
        name_list.remove(self.merge_dst)
        self.merge_tabs_signal.emit(self.merge_dst, name_list, self.keepAliveCheckBox.isChecked())
        self.done(0)

    def reject(self):
        self.done(0)
コード例 #15
0
class HeaderEditDialog(QDialog):

    # name of the current preset; whether to set this preset as default; list of Columns
    header_changed = Signal(str, bool, list)

    def __init__(self, parent, table_header):
        super().__init__(parent)

        self.table_header = table_header
        self.default_preset_name = None
        self.preset_name = table_header.preset_name
        self.columns = deepcopy(table_header.columns)
        self.setupUi()
        self.update_output()

    def setupUi(self):
        self.resize(240, 400)
        self.vbox = QVBoxLayout(self)
        self.presetLabel = QLabel(self)
        self.columnList = QListWidget(self)
        self.setAsDefaultCheckbox = QCheckBox("Set as default preset", self)
        self.vbox.addWidget(self.presetLabel)
        self.vbox.addWidget(self.columnList)
        self.vbox.addWidget(self.setAsDefaultCheckbox)

        self.columnList.setDragDropMode(QListWidget.InternalMove)
        self.columnList.setDefaultDropAction(Qt.MoveAction)
        self.columnList.setSelectionMode(QListWidget.ExtendedSelection)
        self.columnList.setAlternatingRowColors(True)
        self.columnList.installEventFilter(self)
        self.columnList.setContextMenuPolicy(Qt.CustomContextMenu)
        self.columnList.customContextMenuRequested.connect(self.open_menu)
        self.columnList.model().rowsMoved.connect(self.read_columns_from_list)

        # for a dumb qss hack to make selected checkboxes not white on a light theme
        self.columnList.setObjectName("ColumnList")

        buttons = QDialogButtonBox.Reset | QDialogButtonBox.Save | QDialogButtonBox.Cancel
        self.buttonBox = QDialogButtonBox(buttons, self)
        self.vbox.addWidget(self.buttonBox)
        self.buttonBox.accepted.connect(self.accept)
        self.buttonBox.rejected.connect(self.reject)
        self.resetButton = self.buttonBox.button(QDialogButtonBox.Reset)
        self.resetButton.clicked.connect(self.reset_to_stock)

    def eventFilter(self, object, event):
        if event.type() == QEvent.KeyPress:
            if event.key() == Qt.Key_Space or event.key() == Qt.Key_Return:
                self.toggle_selected_columns()
                return True
            if event.key() == Qt.Key_Delete:
                self.delete_selected()
                return True
        return False

    def update_output(self):
        self.presetLabel.setText("Preset: {}".format(self.preset_name))
        self.setAsDefaultCheckbox.setChecked(
            CONFIG['default_header_preset'] == self.preset_name)
        self.columnList.clear()
        for column in self.columns:
            ColumnListItem(self.columnList, column)

    def accept(self):
        self.read_columns_from_list()
        self.header_changed.emit(self.preset_name,
                                 self.setAsDefaultCheckbox.isChecked(),
                                 self.columns)
        self.done(0)

    def reject(self):
        self.done(0)

    def reset_to_stock(self):
        self.columns = deepcopy(DEFAULT_COLUMNS)
        self.update_output()

    def read_columns_from_list(self):
        new_columns = []
        for i in range(self.columnList.count()):
            item = self.columnList.item(i)
            new_columns.append(item.column)
        self.columns = new_columns

    def toggle_selected_columns(self):
        selected = self.columnList.selectedItems()
        for item in selected:
            value_now = item.data(Qt.CheckStateRole)
            item.setData(Qt.CheckStateRole, not value_now)
        self.columnList.reset(
        )  # @Improvement: is there a better way to update QListWidget?

    def open_menu(self, position):
        menu = QMenu(self)

        preset_menu = menu.addMenu('Presets')
        preset_menu.addAction('New preset', self.new_preset_dialog)
        preset_menu.addSeparator()

        preset_names = CONFIG.get_header_presets()

        if len(preset_names) == 0:
            action = preset_menu.addAction('No presets')
            action.setEnabled(False)
        else:
            delete_menu = menu.addMenu('Delete preset')
            for name in preset_names:
                preset_menu.addAction(name, partial(self.load_preset, name))
                delete_menu.addAction(name, partial(self.delete_preset, name))

        menu.addSeparator()
        menu.addAction('New column...', self.create_new_column_dialog)

        if len(self.columnList.selectedIndexes()) > 0:
            menu.addAction('Delete selected', self.delete_selected)

        menu.popup(self.columnList.viewport().mapToGlobal(position))

    def load_preset(self, name):
        new_columns = CONFIG.load_header_preset(name)
        if not new_columns:
            return

        self.columns = new_columns
        self.preset_name = name
        self.update_output()

    def new_preset_dialog(self):
        d = QInputDialog(self)
        d.setLabelText('Enter the new name for the new preset:')
        d.setWindowTitle('Create new preset')
        d.textValueSelected.connect(self.create_new_preset)
        d.open()

    def create_new_preset(self, name):
        if name in CONFIG.get_header_presets():
            show_warning_dialog(
                self, "Preset creation error",
                'Preset named "{}" already exists.'.format(name))
            return
        if len(name.strip()) == 0:
            show_warning_dialog(
                self, "Preset creation error",
                'This preset name is not allowed.'.format(name))
            return

        self.preset_name = name
        self.update_output()
        CONFIG.save_header_preset(name, self.columns)

    def delete_preset(self, name):
        CONFIG.delete_header_preset(name)
        if name == self.preset_name:
            self.columns = deepcopy(DEFAULT_COLUMNS)
            self.update_output()

    def create_new_column_dialog(self):
        d = CreateNewColumnDialog(self)
        d.add_new_column.connect(self.add_new_column)
        d.setWindowTitle('Create new column')
        d.open()

    def add_new_column(self, name, title):
        new_column = Column(name, title)
        # if the last column is message, insert this column before it (I think that makes sense?)
        if len(self.columns) == 0:
            self.columns.append(new_column)
        elif self.columns[-1].name in ('message', 'msg'):
            self.columns.insert(-1, new_column)
        else:
            self.columns.append(new_column)
        self.update_output()

    def delete_selected(self):
        selected = self.columnList.selectedItems()
        for item in selected:
            self.columnList.takeItem(self.columnList.row(item))
        self.read_columns_from_list()
        self.update_output()
コード例 #16
0
class CycleWindow(SiriusMainWindow):
    """Power supplies cycle window."""
    def __init__(self, parent=None, checked_accs=(), adv_mode=False):
        """Constructor."""
        super().__init__(parent)
        self.setObjectName('ASApp')
        cor = get_appropriate_color(section='AS')
        self.setWindowIcon(qta.icon('mdi.recycle', color=cor))
        self._is_adv_mode = adv_mode
        # Data structs
        self._psnames = get_psnames(isadv=self._is_adv_mode)
        self._timing = Timing()
        self._ps2cycle = list()
        self._ps_ready = list()
        self._ps_failed = list()
        self._checked_accs = checked_accs
        # Flags
        self._is_preparing = ''
        self._prepared_init_vals = {
            'timing': False,
            'ps_sofbmode': False,
            'ps_om_slowref': False,
            'ps_current': False,
            'ps_params': False,
            'ps_om_cycle': False,
            'trims': True
        }
        self._prepared = self._prepared_init_vals.copy()
        self._icon_check = qta.icon('fa5s.check')
        self._pixmap_check = self._icon_check.pixmap(
            self._icon_check.actualSize(QSize(16, 16)))
        self._icon_not = qta.icon('fa5s.times')
        self._pixmap_not = self._icon_not.pixmap(
            self._icon_not.actualSize(QSize(16, 16)))
        # Tasks
        self._step_2_task = {
            'save_timing': SaveTiming,
            'timing': PrepareTiming,
            'ps_sofbmode': PreparePSSOFBMode,
            'ps_om_slowref': PreparePSOpModeSlowRef,
            'ps_current': PreparePSCurrentZero,
            'ps_params': PreparePSParams,
            'ps_om_cycle': PreparePSOpModeCycle,
            'trims': CycleTrims,
            'cycle': Cycle,
            'restore_timing': RestoreTiming,
        }
        # Setup UI
        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()
        self.setWindowTitle('PS Cycle')

    def _setup_ui(self):
        # central widget
        self.central_widget = QWidget()
        self.setCentralWidget(self.central_widget)

        # tree
        gb_tree = QGroupBox('Select power supplies:')
        self.pwrsupplies_tree = PVNameTree(self._psnames, ('sec', 'mag_group'),
                                           tuple(), self)
        self.pwrsupplies_tree.tree.setHeaderHidden(True)
        self.pwrsupplies_tree.tree.setColumnCount(1)
        glay_tree = QVBoxLayout(gb_tree)
        glay_tree.addWidget(self.pwrsupplies_tree)

        # commands
        lb_prep_ti = QLabel('<h4>Prepare Timing</h4>',
                            self,
                            alignment=Qt.AlignCenter)
        ti_ch = [
            PVName(name).substitute(prefix=VACA_PREFIX)
            for name in self._timing.get_pvnames_by_psnames()
        ]
        self.ticonn_led = PyDMLedMultiConn(self, channels=ti_ch)

        self.save_timing_bt = QPushButton('1. Save Timing Initial State', self)
        self.save_timing_bt.setToolTip(
            'Save timing current state as initial state.')
        self.save_timing_bt.clicked.connect(
            _part(self._run_task, 'save_timing'))
        self.save_timing_bt.clicked.connect(self._set_lastcomm)

        self.prepare_timing_bt = QPushButton('2. Prepare Timing', self)
        self.prepare_timing_bt.setToolTip('Prepare EVG, triggers and events')
        self.prepare_timing_bt.clicked.connect(_part(self._run_task, 'timing'))
        self.prepare_timing_bt.clicked.connect(self._set_lastcomm)

        self.prepare_timing_lb = QLabel(self)
        self.prepare_timing_lb.setPixmap(self._pixmap_not)

        lb_prep_ps = QLabel('<h4>Prepare PS</h4>',
                            self,
                            alignment=Qt.AlignCenter)
        self.psconn_led = PyDMLedMultiConn(self)

        self.set_ps_sofbmode_off_bt = QPushButton('3. Turn off PS SOFBMode',
                                                  self)
        self.set_ps_sofbmode_off_bt.setToolTip(
            'Turn off power supplies SOFBMode.')
        self.set_ps_sofbmode_off_bt.clicked.connect(
            _part(self._run_task, 'ps_sofbmode'))
        self.set_ps_sofbmode_off_bt.clicked.connect(self._set_lastcomm)

        self.set_ps_sofbmode_off_lb = QLabel(self)
        self.set_ps_sofbmode_off_lb.setPixmap(self._pixmap_not)

        self.set_ps_opmode_slowref_bt = QPushButton(
            '4. Set PS OpMode to SlowRef', self)
        self.set_ps_opmode_slowref_bt.setToolTip(
            'Set power supplies OpMode to SlowRef.')
        self.set_ps_opmode_slowref_bt.clicked.connect(
            _part(self._run_task, 'ps_om_slowref'))
        self.set_ps_opmode_slowref_bt.clicked.connect(self._set_lastcomm)

        self.set_ps_opmode_slowref_lb = QLabel(self)
        self.set_ps_opmode_slowref_lb.setPixmap(self._pixmap_not)

        self.set_ps_current_zero_bt = QPushButton('5. Set PS current to zero',
                                                  self)
        self.set_ps_current_zero_bt.setToolTip(
            'Set power supplies current to zero.')
        self.set_ps_current_zero_bt.clicked.connect(
            _part(self._run_task, 'ps_current'))
        self.set_ps_current_zero_bt.clicked.connect(self._set_lastcomm)

        self.set_ps_current_zero_lb = QLabel(self)
        self.set_ps_current_zero_lb.setPixmap(self._pixmap_not)

        self.prepare_ps_params_bt = QPushButton('6. Prepare PS Parameters',
                                                self)
        self.prepare_ps_params_bt.setToolTip(
            'Check power supplies OpMode in SlowRef, check\n'
            'current is zero and configure cycle parameters.')
        self.prepare_ps_params_bt.clicked.connect(
            _part(self._run_task, 'ps_params'))
        self.prepare_ps_params_bt.clicked.connect(self._set_lastcomm)

        self.prepare_ps_params_lb = QLabel(self)
        self.prepare_ps_params_lb.setPixmap(self._pixmap_not)

        self.prepare_ps_opmode_bt = QPushButton('7. Prepare PS OpMode', self)
        self.prepare_ps_opmode_bt.setToolTip(
            'Set power supplies OpMode to Cycle.')
        self.prepare_ps_opmode_bt.clicked.connect(
            _part(self._run_task, 'ps_om_cycle'))
        self.prepare_ps_opmode_bt.clicked.connect(self._set_lastcomm)

        self.prepare_ps_opmode_lb = QLabel(self)
        self.prepare_ps_opmode_lb.setPixmap(self._pixmap_not)

        lb_cycle = QLabel('<h4>Cycle</h4>', self, alignment=Qt.AlignCenter)

        self.cycle_trims_bt = QPushButton('8. Cycle Trims', self)
        self.cycle_trims_bt.setToolTip(
            'Cycle trims:\nStep 1) CH, QS and QTrims\nStep 2) CV')
        self.cycle_trims_bt.clicked.connect(_part(self._run_task, 'trims'))
        self.cycle_trims_bt.clicked.connect(self._set_lastcomm)
        self.cycle_trims_bt.setVisible(False)

        self.cycle_trims_lb = QLabel(self)
        self.cycle_trims_lb.setPixmap(self._pixmap_check)
        self.cycle_trims_lb.setVisible(False)

        self.cycle_bt = QPushButton('8. Cycle', self)
        self.cycle_bt.setToolTip(
            'Check all configurations,\nenable triggers and run cycle.')
        self.cycle_bt.clicked.connect(_part(self._run_task, 'cycle'))
        self.cycle_bt.clicked.connect(self._set_lastcomm)
        self.cycle_bt.setEnabled(False)

        lb_rest_ti = QLabel('<h4>Restore Timing</h4>',
                            self,
                            alignment=Qt.AlignCenter)
        self.restore_timing_bt = QPushButton('9. Restore Timing Initial State',
                                             self)
        self.restore_timing_bt.setToolTip('Restore timing initial state.')
        self.restore_timing_bt.clicked.connect(
            _part(self._run_task, 'restore_timing'))
        self.restore_timing_bt.clicked.connect(self._set_lastcomm)

        self._prepared_labels = {
            'timing': self.prepare_timing_lb,
            'ps_sofbmode': self.set_ps_sofbmode_off_lb,
            'ps_om_slowref': self.set_ps_opmode_slowref_lb,
            'ps_current': self.set_ps_current_zero_lb,
            'ps_params': self.prepare_ps_params_lb,
            'ps_om_cycle': self.prepare_ps_opmode_lb,
            'trims': self.cycle_trims_lb
        }

        gb_commsts = QGroupBox()
        gb_commsts.setStyleSheet("""
            QPushButton{min-height:1.5em;}
            QLabel{qproperty-alignment: AlignCenter;}""")
        lay_commsts = QGridLayout(gb_commsts)
        lay_commsts.addItem(
            QSpacerItem(1, 1, QSzPlcy.Ignored, QSzPlcy.Expanding), 0, 0, 1, 2)
        lay_commsts.addWidget(lb_prep_ti, 1, 0)
        lay_commsts.addWidget(self.ticonn_led, 1, 1)
        lay_commsts.addWidget(self.save_timing_bt, 2, 0)
        lay_commsts.addWidget(self.prepare_timing_bt, 3, 0)
        lay_commsts.addWidget(self.prepare_timing_lb, 3, 1)
        lay_commsts.addItem(
            QSpacerItem(1, 1, QSzPlcy.Ignored, QSzPlcy.Expanding), 4, 0)
        lay_commsts.addWidget(lb_prep_ps, 5, 0)
        lay_commsts.addWidget(self.psconn_led, 5, 1)
        lay_commsts.addWidget(self.set_ps_sofbmode_off_bt, 6, 0)
        lay_commsts.addWidget(self.set_ps_sofbmode_off_lb, 6, 1)
        lay_commsts.addWidget(self.set_ps_opmode_slowref_bt, 7, 0)
        lay_commsts.addWidget(self.set_ps_opmode_slowref_lb, 7, 1)
        lay_commsts.addWidget(self.set_ps_current_zero_bt, 8, 0)
        lay_commsts.addWidget(self.set_ps_current_zero_lb, 8, 1)
        lay_commsts.addWidget(self.prepare_ps_params_bt, 9, 0)
        lay_commsts.addWidget(self.prepare_ps_params_lb, 9, 1)
        lay_commsts.addWidget(self.prepare_ps_opmode_bt, 10, 0)
        lay_commsts.addWidget(self.prepare_ps_opmode_lb, 10, 1)
        lay_commsts.addItem(
            QSpacerItem(1, 1, QSzPlcy.Ignored, QSzPlcy.Expanding), 11, 0)
        lay_commsts.addWidget(lb_cycle, 12, 0)
        lay_commsts.addWidget(self.cycle_trims_bt, 13, 0)
        lay_commsts.addWidget(self.cycle_trims_lb, 13, 1)
        lay_commsts.addWidget(self.cycle_bt, 14, 0)
        lay_commsts.addItem(
            QSpacerItem(1, 1, QSzPlcy.Ignored, QSzPlcy.Expanding), 15, 0)
        lay_commsts.addWidget(lb_rest_ti, 16, 0)
        lay_commsts.addWidget(self.restore_timing_bt, 17, 0)
        lay_commsts.addItem(
            QSpacerItem(1, 1, QSzPlcy.Ignored, QSzPlcy.Expanding), 18, 0)
        lay_commsts.setColumnStretch(0, 10)
        lay_commsts.setColumnStretch(1, 1)
        lay_commsts.setVerticalSpacing(12)
        lay_commsts.setHorizontalSpacing(6)

        self.label_lastcomm = QLabel('Last Command: ', self)
        self.clearhist_bt = QPushButton('Clear', self)
        self.clearhist_bt.clicked.connect(self._clear_lastcomm)
        lay_lc = QHBoxLayout()
        lay_lc.setContentsMargins(0, 0, 0, 0)
        lay_lc.addWidget(self.label_lastcomm, alignment=Qt.AlignLeft)
        lay_lc.addWidget(self.clearhist_bt, alignment=Qt.AlignRight)
        lay_lc.setStretch(0, 10)
        lay_lc.setStretch(1, 1)

        self.progress_list = QListWidget(self)
        self.progress_list.setObjectName('progresslist')
        self.progress_list.setStyleSheet('#progresslist{min-width:20em;}')
        self.progress_list.itemDoubleClicked.connect(self._open_ps_detail)
        self.progress_list.setSelectionMode(QAbstractItemView.MultiSelection)
        self.progress_list.setToolTip(
            'Select rows and press Ctrl+C to copy and Esc to deselect.')

        self.progress_bar = MyProgressBar(self)

        lay_log = QVBoxLayout()
        lay_log.addLayout(lay_lc)
        lay_log.addWidget(self.progress_list)
        lay_log.addWidget(self.progress_bar)

        # connect tree signals
        self.pwrsupplies_tree.tree.doubleClicked.connect(self._open_ps_detail)
        self.pwrsupplies_tree.tree.itemChanged.connect(
            self._handle_checked_items_changed)
        self.pwrsupplies_tree.check_requested_levels(self._checked_accs)

        # layout
        layout = QGridLayout()
        layout.setVerticalSpacing(10)
        layout.setHorizontalSpacing(10)
        layout.addWidget(
            QLabel('<h3>PS Cycle</h3>', self, alignment=Qt.AlignCenter), 0, 0,
            1, 3)
        layout.addWidget(gb_tree, 1, 0)
        layout.addWidget(gb_commsts, 1, 1)
        layout.addLayout(lay_log, 1, 2)
        layout.setRowStretch(0, 1)
        layout.setRowStretch(1, 15)
        layout.setColumnStretch(0, 5)
        layout.setColumnStretch(1, 4)
        layout.setColumnStretch(2, 8)
        self.central_widget.setLayout(layout)

    # --- handle tasks ---

    def _run_task(self, control=''):
        if not self._check_connected(control):
            return
        pwrsupplies = self._get_ps_list()
        if not pwrsupplies:
            return

        if 'ps' in control and not self._verify_ps(pwrsupplies):
            return

        if control in self._step_2_task:
            task_class = self._step_2_task[control]
        else:
            raise NotImplementedError(
                "Task not defined for control '{}'".format(control))
        self._is_preparing = control

        self._handle_buttons_enabled(False)
        self.progress_list.clear()

        task = task_class(parent=self,
                          psnames=pwrsupplies,
                          timing=self._timing,
                          isadv=self._is_adv_mode)
        task.updated.connect(self._update_progress)
        duration = task.duration()

        self.progress_bar.setMinimum(0)
        self.progress_bar.setMaximum(duration)
        self.progress_bar.setValue(0)
        pal = self.progress_bar.palette()
        pal.setColor(QPalette.Highlight, self.progress_bar.default_color)
        self.progress_bar.setPalette(pal)

        self.update_bar = UpdateProgressBar(duration, self)
        self.update_bar.increment.connect(self.progress_bar.increment)

        task.start()
        self.update_bar.start()

    def _update_progress(self, text, done, warning=False, error=False):
        """Update automated cycle progress list and bar."""
        if done:
            last_item = self.progress_list.item(self.progress_list.count() - 1)
            curr_text = last_item.text()
            last_item.setText(curr_text + ' done.')
        elif 'Remaining time' in text:
            last_item = self.progress_list.item(self.progress_list.count() - 1)
            if 'Remaining time' in last_item.text():
                last_item.setText(text)
            else:
                self.progress_list.addItem(text)
                self.progress_list.scrollToBottom()
        elif 'Sent ' in text:
            last_item = self.progress_list.item(self.progress_list.count() - 1)
            if 'Sent ' in last_item.text():
                last_item.setText(text)
            else:
                self.progress_list.addItem(text)
                self.progress_list.scrollToBottom()
        elif 'Successfully checked ' in text:
            last_item = self.progress_list.item(self.progress_list.count() - 1)
            if 'Successfully checked ' in last_item.text():
                last_item.setText(text)
            else:
                self.progress_list.addItem(text)
                self.progress_list.scrollToBottom()
        elif 'Created connections ' in text:
            last_item = self.progress_list.item(self.progress_list.count() - 1)
            if 'Created connections ' in last_item.text():
                last_item.setText(text)
            else:
                self.progress_list.addItem(text)
                self.progress_list.scrollToBottom()
        else:
            item = QListWidgetItem(text)
            if error:
                item.setForeground(errorcolor)
                self.update_bar.exit_task()
                pal = self.progress_bar.palette()
                pal.setColor(QPalette.Highlight,
                             self.progress_bar.warning_color)
                self.progress_bar.setPalette(pal)
                if self._is_preparing in self._prepared.keys():
                    self._prepared[self._is_preparing] = False
                cycle = all(self._prepared.values())
                self._handle_buttons_enabled(True, cycle=cycle)
            elif warning:
                item.setForeground(warncolor)
            elif 'finished' in text:
                self.update_bar.exit_task()
                self.progress_bar.setValue(self.progress_bar.maximum())
                if self._is_preparing == 'cycle':
                    self._prepared = {k: False for k in self._prepared.keys()}
                    if not self.cycle_trims_bt.isVisible():
                        self._prepared['trims'] = True
                    cycle = False
                else:
                    if self._is_preparing in self._prepared.keys():
                        self._prepared[self._is_preparing] = True
                    cycle = all(self._prepared.values())
                self._handle_buttons_enabled(True, cycle=cycle)

            self._handle_stslabels_content()

            self.progress_list.addItem(item)
            self.progress_list.scrollToBottom()

    def _handle_buttons_enabled(self, enable, cycle=False):
        self.save_timing_bt.setEnabled(enable)
        self.prepare_timing_bt.setEnabled(enable)
        self.set_ps_sofbmode_off_bt.setEnabled(enable)
        self.set_ps_opmode_slowref_bt.setEnabled(enable)
        self.set_ps_current_zero_bt.setEnabled(enable)
        self.prepare_ps_params_bt.setEnabled(enable)
        self.prepare_ps_opmode_bt.setEnabled(enable)
        self.cycle_trims_bt.setEnabled(enable)
        self.cycle_bt.setEnabled(cycle)
        self.restore_timing_bt.setEnabled(enable)
        self.clearhist_bt.setEnabled(enable)
        self.pwrsupplies_tree.setEnabled(enable)

    def _handle_stslabels_content(self):
        for prep, value in self._prepared.items():
            pixmap = self._pixmap_check if value else self._pixmap_not
            self._prepared_labels[prep].setPixmap(pixmap)

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

    def _clear_lastcomm(self):
        self.progress_bar.setValue(0)
        self.progress_list.clear()
        self.label_lastcomm.setText('Last Command: ')

    # --- handle ps selection ---

    def _get_ps_list(self):
        """Return list of power supplies to cycle."""
        # Get power supplies list
        pwrsupplies = self.pwrsupplies_tree.checked_items()
        if not pwrsupplies:
            QMessageBox.critical(self, 'Message', 'No power supply selected!')
            return False

        sections = get_sections(pwrsupplies)
        if 'BO' in sections and len(sections) > 1:
            QMessageBox.critical(self, 'Error',
                                 'Can not cycle Booster with other sectors!')
            return False

        create_task = CreateCyclers(parent=self, psnames=pwrsupplies)
        dlg = ProgressDialog('Creating cycles...', create_task, self)
        ret = dlg.exec_()
        if ret == dlg.Rejected:
            return False

        return pwrsupplies

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

        if not self._is_adv_mode and psname.sec == 'SI' and \
                not psname.dev.startswith('FC'):
            psname2check = Filter.process_filters(self._psnames,
                                                  filters={
                                                      'sec': 'SI',
                                                      'dev': '(?!FC)'
                                                  })
            psname2check.remove(psname)
            state2set = item.checkState(0)
            self.pwrsupplies_tree.tree.blockSignals(True)
            for psn in psname2check:
                item2check = self.pwrsupplies_tree._item_map[psn]
                if item2check.checkState(0) != state2set:
                    item2check.setData(0, Qt.CheckStateRole, state2set)
            self.pwrsupplies_tree.tree.blockSignals(False)
        else:
            if (psname.sec in ['BO', 'SI'] and psname.dev in ['B', 'B1B2']):
                psname2check = PSSearch.get_psnames({
                    'sec': psname.sec,
                    'dev': 'B.*'
                })
                psname2check.remove(psname)
                item2check = self.pwrsupplies_tree._item_map[psname2check[0]]

                state2set = item.checkState(0)
                state2change = item2check.checkState(0)
                if state2change != state2set:
                    self.pwrsupplies_tree.tree.blockSignals(True)
                    item2check.setData(0, Qt.CheckStateRole, state2set)
                    self.pwrsupplies_tree.tree.blockSignals(False)

        self._prepared.update(self._prepared_init_vals)
        self._needs_update_setup = True

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

        # update leds
        psnames = self.pwrsupplies_tree.checked_items()
        ti_ch = [
            PVName(name).substitute(prefix=VACA_PREFIX)
            for name in self._timing.get_pvnames_by_psnames(psnames)
        ]
        self.ticonn_led.set_channels(ti_ch)

        ps_ch = list()
        for name in psnames:
            ps_ch.append(
                PVName(name).substitute(prefix=VACA_PREFIX,
                                        propty='PwrState-Sts'))
        self.psconn_led.set_channels(ps_ch)

        # update buttons and self._prepared dict if not in advanced mode
        if not self._is_adv_mode:
            has_si = False
            for psn in PSSearch.get_psnames({'sec': 'SI', 'dis': 'PS'}):
                if psn not in self.pwrsupplies_tree._item_map:
                    continue
                item = self.pwrsupplies_tree._item_map[psn]
                has_si |= item.checkState(0) != 0

            if not has_si:
                self.cycle_bt.setText('8. Cycle')
                self.restore_timing_bt.setText(
                    '9. Restore Timing Initial State')
                self.cycle_trims_bt.setVisible(False)
                self.cycle_trims_lb.setVisible(False)
                self._prepared['trims'] = True
            else:
                self.cycle_bt.setText('9. Cycle')
                self.restore_timing_bt.setText(
                    '10. Restore Timing Initial State')
                self.cycle_trims_bt.setVisible(True)
                self.cycle_trims_lb.setVisible(True)
                self._prepared['trims'] = False

        self._handle_stslabels_content()
        self._handle_buttons_enabled(True)

    # --- auxiliary checks ---

    def _check_connected(self, control):
        if control in ['trims', 'cycle']:
            leds = [self.ticonn_led, self.psconn_led]
        elif 'timing' in control:
            leds = [
                self.ticonn_led,
            ]
        else:
            leds = [
                self.psconn_led,
            ]

        for led in leds:
            pvs_disconnected = set()
            for ch, v in led.channels2conn.items():
                if not v:
                    pvs_disconnected.add(ch)
            if pvs_disconnected:
                sttr = ''
                for item in pvs_disconnected:
                    sttr += item + '\n'
                QMessageBox.information(
                    self, 'Message',
                    'The following PVs are not connected:\n' + sttr)
                return False
        return True

    def _verify_ps(self, pwrsupplies):
        self._ps_failed = set()

        task = VerifyPS(parent=self, psnames=pwrsupplies)
        task.itemDone.connect(self._get_ps_not_ready_2_cycle)

        dlg = ProgressDialog('Verifying power supplies initial state...', task,
                             self)
        ret = dlg.exec_()
        if ret == dlg.Rejected:
            self._handle_buttons_enabled(True)
            return False

        if self._ps_failed:
            text = 'Verify power state and interlocks' \
                ' of the following power supplies'
            dlg = PSStatusDialog(self._ps_failed, text, self)
            dlg.exec_()
            self._handle_buttons_enabled(True)
            return False

        return True

    def _get_ps_not_ready_2_cycle(self, psname, status):
        if not status:
            self._ps_failed.add(psname)

    def _open_ps_detail(self, item):
        if self.sender() == self.progress_list:
            text_split = item.data(Qt.DisplayRole).split(' ')
            psname = ''
            for text in text_split:
                if _re.match('.*-.*:.*-.*', text):
                    psname = text
            if not psname:
                return
        else:
            psname = item.data()
        if not _re.match('.*-.*:.*-.*', psname):
            if item.model().rowCount(item) == 1:
                psname = item.child(0, 0).data()
            else:
                return
        run_newprocess(['sirius-hla-as-ps-detail.py', psname])

    # --- events ---

    def keyPressEvent(self, evt):
        """Implement keyPressEvent."""
        if evt.matches(QKeySequence.Copy) and self.progress_list.underMouse():
            items = self.progress_list.selectedItems()
            items = '\n'.join([i.text() for i in items])
            QApplication.clipboard().setText(items)
        if evt.key() == Qt.Key_Escape and self.progress_list.underMouse():
            items = self.progress_list.clearSelection()
        super().keyPressEvent(evt)

    def closeEvent(self, ev):
        self._update_setup_timer.stop()
        super().closeEvent(ev)
コード例 #17
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)
コード例 #18
0
class SelectedLinesWidget(QWidget):
    """ Widget to show and enable lines to be selected
    inp : LineList
      Input LineList
    init_select : str or list of indices
      str -- 'All'

    """
    def __init__(self, inp, parent=None, init_select=None, plot_widget=None):
        """
        """
        super(SelectedLinesWidget, self).__init__(parent)

        self.parent = parent

        # Line list Table
        if isinstance(inp, LineList):
            self.lines = inp._data
            self.llst = inp
        elif isinstance(inp, Table):
            raise ValueError('SelectedLineWidget: DEPRECATED')
        else:
            raise ValueError('SelectedLineWidget: Wrong type of input')

        self.plot_widget = plot_widget

        # Create the line list
        line_label = QLabel('Lines:')
        self.lines_widget = QListWidget(self)
        self.lines_widget.setSelectionMode(QAbstractItemView.MultiSelection)

        # Initialize list
        self.item_flg = 0
        self.init_list()

        # Initial selection
        if init_select is None:
            self.selected = [0]
        elif init_select == 'All':
            self.selected = []
            for ii in range(self.lines_widget.count()):
                self.lines_widget.item(ii).setSelected(True)
                self.selected.append(ii)
        else:
            self.selected = init_select
            if len(self.selected) == 0:
                self.selected = [0]

        for iselect in self.selected:
            self.lines_widget.item(iselect).setSelected(True)

        self.lines_widget.scrollToItem(self.lines_widget.item(
            self.selected[0]))

        # Events
        self.lines_widget.itemSelectionChanged.connect(self.on_item_change)

        # Layout
        vbox = QVBoxLayout()
        vbox.addWidget(line_label)
        vbox.addWidget(self.lines_widget)

        self.setLayout(vbox)

    def init_list(self):
        nlin = len(self.lines['wrest'])
        for ii in range(nlin):
            self.lines_widget.addItem('{:s} :: {:.3f} :: {}'.format(
                self.lines['name'][ii], self.lines['wrest'][ii],
                self.lines['f'][ii]))

    def on_item_change(self):  #,item):
        # For big changes
        if self.item_flg == 1:
            return
        all_items = [
            self.lines_widget.item(ii)
            for ii in range(self.lines_widget.count())
        ]
        sel_items = self.lines_widget.selectedItems()
        self.selected = [all_items.index(isel) for isel in sel_items]
        self.selected.sort()

        #QtCore.pyqtRemoveInputHook()
        #xdb.set_trace()
        #QtCore.pyqtRestoreInputHook()

        # Update llist
        try:
            self.plot_widget.llist['show_line'] = self.selected
        except AttributeError:
            if self.parent is not None:
                self.parent.updated_slines(self.selected)
            return
        else:
            self.plot_widget.on_draw()

    def on_list_change(self, llist):
        # Clear
        if not isinstance(llist, LineList):
            raise ValueError('Expecting LineList!!')
        self.item_flg = 1
        self.lines = llist._data
        self.llst = llist
        self.lines_widget.clear()
        # Initialize
        self.init_list()
        # Set selected
        for iselect in self.selected:
            self.lines_widget.item(iselect).setSelected(True)
        self.lines_widget.scrollToItem(self.lines_widget.item(
            self.selected[0]))
        self.item_flg = 0