Пример #1
0
class SnapshotCompareWidget(QWidget):
    pvs_filtered = QtCore.pyqtSignal(set)
    restore_requested = QtCore.pyqtSignal(list)
    rgx_icon = None

    def __init__(self, snapshot, common_settings, parent=None, **kw):
        super().__init__(parent, **kw)
        self.snapshot = snapshot
        self.common_settings = common_settings

        # ----------- PV Table -------------
        # PV table consist of:
        #     self.model: holding the data, values, being updated by PV callbacks, etc
        #     self._proxy: a proxy model implementing the filter functionality
        #     self.view: visual representation of the PV table

        self.view = SnapshotPvTableView(self)
        self.view.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.view.restore_requested.connect(self._handle_restore_request)

        self.model = SnapshotPvTableModel(snapshot, self)
        self.model.file_parse_errors.connect(self._show_snapshot_parse_errors)
        self._proxy = SnapshotPvFilterProxyModel(self)
        self._proxy.setSourceModel(self.model)
        self._proxy.filtered.connect(self.pvs_filtered)

        # Build model and set default visualization on view (column widths, etc)
        self.model.set_pvs(snapshot.pvs.values())
        self.view.setModel(self._proxy)

        # ---------- Filter control elements ---------------
        # - text input to filter by name
        # - drop down to filter by compare status
        # - check box to select if showing pvs with incomplete data

        if SnapshotCompareWidget.rgx_icon is None:
            SnapshotCompareWidget.rgx_icon = QIcon(
                os.path.join(os.path.dirname(os.path.realpath(__file__)),
                             "images/rgx.png"))

        # #### PV name filter
        pv_filter_label = QLabel("Filter:", self)
        pv_filter_label.setAlignment(Qt.AlignCenter | Qt.AlignRight)

        self.pv_filter_sel = QComboBox(self)
        self.pv_filter_sel.setEditable(True)
        self.pv_filter_sel.setIconSize(QtCore.QSize(35, 15))
        self.pv_filter_inp = self.pv_filter_sel.lineEdit()
        self.pv_filter_inp.setPlaceholderText("Filter by PV name")

        policy = self.pv_filter_sel.sizePolicy()
        policy.setHorizontalPolicy(policy.Expanding)
        self.pv_filter_sel.setSizePolicy(policy)

        self.pv_filter_sel.currentIndexChanged.connect(
            self._predefined_filter_selected)
        self.pv_filter_inp.textChanged.connect(self._create_name_filter)

        self._populate_filter_list()

        # Prepare pallets to color the pv name filter input if rgx not valid
        self._inp_palette_ok = self.pv_filter_inp.palette()
        self._inp_palette_err = QPalette()
        self._inp_palette_err.setColor(QPalette.Base, QColor("#F39292"))

        # Create a PV name filter layout and add items
        pv_filter_layout = QHBoxLayout()
        pv_filter_layout.setSpacing(10)
        pv_filter_layout.addWidget(pv_filter_label)
        pv_filter_layout.addWidget(self.pv_filter_sel)

        # #### Regex selector
        self.regex = QCheckBox("Regex", self)
        self.regex.stateChanged.connect(self._handle_regex_change)

        # #### Selector for comparison filter
        self.compare_filter_inp = QComboBox(self)
        self.compare_filter_inp.addItems(
            ["Show all", "Different only", "Equal only"])

        self.compare_filter_inp.currentIndexChanged.connect(
            self._proxy.set_eq_filter)
        self.compare_filter_inp.setMaximumWidth(200)

        # ### Show disconnected selector
        self.show_disconn_inp = QCheckBox("Show disconnected PVs.", self)
        self.show_disconn_inp.setChecked(True)
        self.show_disconn_inp.stateChanged.connect(
            self._proxy.set_disconn_filter)
        self.show_disconn_inp.setMaximumWidth(500)

        # Tolerance setting
        tol_label = QLabel("Tolerance:")
        tol = QSpinBox()
        tol.setRange(1, 1000000)
        tol.setValue(1)
        tol.valueChanged[int].connect(self.model.change_tolerance)
        self.model.change_tolerance(tol.value())

        # ### Put all tolerance and filter selectors in one layout
        filter_layout = QHBoxLayout()
        filter_layout.addWidget(tol_label)
        filter_layout.addWidget(tol)
        filter_layout.addWidget(make_separator(self, 'vertical'))

        filter_layout.addLayout(pv_filter_layout)
        filter_layout.addWidget(self.regex)

        filter_layout.addWidget(make_separator(self, 'vertical'))

        filter_layout.addWidget(self.compare_filter_inp)

        filter_layout.addWidget(self.show_disconn_inp)
        filter_layout.setAlignment(Qt.AlignLeft)
        filter_layout.setSpacing(10)

        # ------- Build main layout ---------
        layout = QVBoxLayout(self)
        layout.setContentsMargins(10, 10, 10, 10)
        layout.addLayout(filter_layout)
        layout.addWidget(self.view)
        self.setLayout(layout)

    def _populate_filter_list(self):
        predefined_filters = self.common_settings['predefined_filters']
        self.pv_filter_sel.blockSignals(True)
        self.pv_filter_sel.clear()
        self.pv_filter_sel.addItem(None)
        for rgx in predefined_filters.get('rgx-filters', list()):
            self.pv_filter_sel.addItem(SnapshotCompareWidget.rgx_icon, rgx)
        self.pv_filter_sel.addItems(predefined_filters.get('filters', list()))
        self.pv_filter_sel.blockSignals(False)

    def _handle_regex_change(self, state):
        txt = self.pv_filter_inp.text()
        if state and txt.strip() == '':
            self.pv_filter_inp.setText('.*')
        elif not state and txt.strip() == '.*':
            self.pv_filter_inp.setText('')
        else:
            self._create_name_filter(txt)

    def _create_name_filter(self, txt):
        if self.regex.isChecked():
            try:
                srch_filter = re.compile(txt)
                self.pv_filter_inp.setPalette(self._inp_palette_ok)
            except:
                # Syntax error (happens a lot during typing an expression). In such cases make compiler which will
                # not match any pv name
                srch_filter = re.compile("")
                self.pv_filter_inp.setPalette(self._inp_palette_err)
        else:
            srch_filter = txt
            self.pv_filter_inp.setPalette(self._inp_palette_ok)

        self._proxy.set_name_filter(srch_filter)

    def _show_snapshot_parse_errors(self, errors):
        show_snapshot_parse_errors(self, errors)

    def new_selected_files(self, selected_files):
        self.model.clear_snap_files()
        self.model.add_snap_files(selected_files)
        self._proxy.apply_filter()

    def clear_snap_files(self):
        self.model.clear_snap_files()

    def handle_new_snapshot_instance(self, snapshot):
        self.snapshot = snapshot
        self.model.snapshot = snapshot
        self.model.set_pvs(snapshot.pvs.values())
        self.view.sortByColumn(0, Qt.AscendingOrder)  # default sorting
        self._populate_filter_list()

    def _handle_restore_request(self, pvs_list):
        self.restore_requested.emit(pvs_list)

    def _predefined_filter_selected(self, idx):
        txt = self.pv_filter_inp.text()
        if idx == 0:
            # First empty option; the menu is always reset to this.
            return
        if not self.pv_filter_sel.itemIcon(idx).isNull():
            # Set back to first index, to get rid of the icon. Set to regex and
            # pass text of filter to the input
            self.pv_filter_sel.setCurrentIndex(0)
            self.regex.setChecked(True)
            self.pv_filter_inp.setText(txt)
        else:
            # Imitate same behaviour
            self.pv_filter_sel.setCurrentIndex(0)
            self.regex.setChecked(False)
            self.pv_filter_inp.setText(txt)

    def filter_update(self):
        self._proxy.apply_filter()
Пример #2
0
class Window(QDialog):
    def __init__(self):
        super(Window, self).__init__()

        #self.createIconGroupBox()
        #self.createMessageGroupBox()

        self.durationLabel = QLabel("Duration:")
        self.iconLabel = QLabel("Icon:")
        self.iconComboBox = QComboBox()
        self.iconComboBox.addItem(QIcon(':/images/bad.png'), "Bad")
        self.iconComboBox.addItem(QIcon(':/images/heart.png'), "Heart")
        self.iconComboBox.addItem(QIcon(':/images/trash.png'), "Trash")

        self.iconLabel.setMinimumWidth(self.durationLabel.sizeHint().width())

        self.createActions()
        self.createTrayIcon()
        """
		self.showMessageButton.clicked.connect(self.showMessage)
		self.showIconCheckBox.toggled.connect(self.trayIcon.setVisible)
		self.iconComboBox.currentIndexChanged.connect(self.setIcon)
		"""
        self.trayIcon.messageClicked.connect(self.messageClicked)
        self.trayIcon.activated.connect(self.iconActivated)

        #mainLayout = QVBoxLayout()
        #self.setLayout(mainLayout)

        self.iconComboBox.setCurrentIndex(1)
        self.setIcon(1)
        self.trayIcon.show()

        self.setWindowTitle("Systray")
        self.resize(400, 300)

    def setIcon(self, index):
        icon = self.iconComboBox.itemIcon(index)
        self.trayIcon.setIcon(icon)
        self.setWindowIcon(icon)

        self.trayIcon.setToolTip(self.iconComboBox.itemText(index))

    def createActions(self):
        self.minimizeAction = QAction("Mi&nimize", self, triggered=self.hide)
        self.maximizeAction = QAction("Ma&ximize",
                                      self,
                                      triggered=self.showMaximized)
        self.restoreAction = QAction("&Restore",
                                     self,
                                     triggered=self.showNormal)
        self.quitAction = QAction("&Quit",
                                  self,
                                  triggered=QApplication.instance().quit)

    def createTrayIcon(self):
        self.trayIconMenu = QMenu(self)
        self.trayIconMenu.addAction(self.minimizeAction)
        self.trayIconMenu.addAction(self.maximizeAction)
        self.trayIconMenu.addAction(self.restoreAction)
        self.trayIconMenu.addSeparator()
        self.trayIconMenu.addAction(self.quitAction)

        self.trayIcon = QSystemTrayIcon(self)
        self.trayIcon.setContextMenu(self.trayIconMenu)

    def iconActivated(self, reason):
        sys.stdout.write("ouch\n")
        if reason in (QSystemTrayIcon.Trigger, QSystemTrayIcon.DoubleClick):
            self.iconComboBox.setCurrentIndex(
                (self.iconComboBox.currentIndex() + 1) %
                self.iconComboBox.count())
        elif reason == QSystemTrayIcon.MiddleClick:
            self.showMessage()

    def messageClicked(self):
        QMessageBox.information(
            None, "Systray",
            "Sorry, I already gave what help I could.\nMaybe you should "
            "try asking a human?")