コード例 #1
0
 def _create_table(self) -> QTableWidget:
     """Create and configure a new table widget."""
     table = QTableWidget()
     table.verticalHeader().setVisible(False)
     table.horizontalHeader().setVisible(False)
     table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
     table.resizeRowsToContents()
     table.setShowGrid(False)
     return table
コード例 #2
0
ファイル: recover.py プロジェクト: sohnishi/spyder
    def add_table(self):
        """Add table with info about files to be recovered."""
        table = QTableWidget(len(self.data), 3, self)
        self.table = table

        labels = [_('Original file'), _('Autosave file'), _('Actions')]
        table.setHorizontalHeaderLabels(labels)
        table.verticalHeader().hide()

        table.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        table.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        table.setSelectionMode(QTableWidget.NoSelection)

        # Show horizontal grid lines
        table.setShowGrid(False)
        table.setStyleSheet('::item { border-bottom: 1px solid gray }')

        for idx, (original, autosave) in enumerate(self.data):
            self.add_label_to_table(idx, 0, file_data_to_str(original))
            self.add_label_to_table(idx, 1, file_data_to_str(autosave))

            widget = QWidget()
            layout = QHBoxLayout()

            tooltip = _('Recover the autosave file to its original location, '
                        'replacing the original if it exists.')
            button = QPushButton(_('Restore'))
            button.setToolTip(tooltip)
            button.clicked.connect(
                lambda checked, my_idx=idx: self.restore(my_idx))
            layout.addWidget(button)

            tooltip = _('Delete the autosave file.')
            button = QPushButton(_('Discard'))
            button.setToolTip(tooltip)
            button.clicked.connect(
                lambda checked, my_idx=idx: self.discard(my_idx))
            layout.addWidget(button)

            tooltip = _('Display the autosave file (and the original, if it '
                        'exists) in Spyder\'s Editor. You will have to move '
                        'or delete it manually.')
            button = QPushButton(_('Open'))
            button.setToolTip(tooltip)
            button.clicked.connect(
                lambda checked, my_idx=idx: self.open_files(my_idx))
            layout.addWidget(button)

            widget.setLayout(layout)
            self.table.setCellWidget(idx, 2, widget)

        table.resizeRowsToContents()
        table.resizeColumnsToContents()

        self.layout.addWidget(table)
コード例 #3
0
ファイル: logger.py プロジェクト: locolucco209/MongoScraper
class LogViewerDialog(DialogBase):
    """Logger widget."""

    def __init__(
        self,
        parent=None,
        log_folder=LOG_FOLDER,
        log_filename=LOG_FILENAME,
    ):
        """
        Logger widget.

        Parameters
        ----------
        log_folder: str
            Folder where logs are located
        log_filename: str
            Basic name for the rotating log files.
        """
        super(LogViewerDialog, self).__init__(parent=parent)

        self._data = None
        self._columns = ['level', 'time', 'module', 'method', 'message']
        self._headers = [c.capitalize() for c in self._columns]
        self._log_filename = log_filename
        self._log_folder = log_folder

        # Widgets
        self.label = QLabel('Select log file:')
        self.combobox = ComboBoxBase()
        self.table_logs = QTableWidget(self)
        self.button_copy = ButtonPrimary('Copy')
        self.text_search = LineEditSearch()

        # Widget setup
        self.table_logs.setAttribute(Qt.WA_LayoutUsesWidgetRect, True)
        horizontal_header = self.table_logs.horizontalHeader()
        vertical_header = self.table_logs.verticalHeader()
        horizontal_header.setStretchLastSection(True)
        horizontal_header.setSectionResizeMode(QHeaderView.Fixed)
        vertical_header.setSectionResizeMode(QHeaderView.Fixed)

        self.table_logs.setSelectionBehavior(QTableWidget.SelectRows)
        self.table_logs.setEditTriggers(QTableWidget.NoEditTriggers)

        self.setWindowTitle('Log Viewer')
        self.setMinimumWidth(800)
        self.setMinimumHeight(500)
        self.text_search.setPlaceholderText("Search...")

        # Layouts
        top_layout = QHBoxLayout()
        top_layout.addWidget(self.label)
        top_layout.addWidget(SpacerHorizontal())
        top_layout.addWidget(self.combobox)
        top_layout.addStretch()
        top_layout.addWidget(SpacerHorizontal())
        top_layout.addWidget(self.text_search)
        top_layout.addWidget(SpacerHorizontal())
        top_layout.addWidget(self.button_copy)
        layout = QVBoxLayout()
        layout.addLayout(top_layout)
        layout.addWidget(SpacerVertical())
        layout.addWidget(self.table_logs)
        self.setLayout(layout)

        # Signals
        self.combobox.currentIndexChanged.connect(self.update_text)
        self.button_copy.clicked.connect(self.copy_item)
        self.text_search.textChanged.connect(self.filter_text)

        # Setup()
        self.setup()
        self.update_style_sheet()

    def update_style_sheet(self, style_sheet=None):
        """Update custom CSS stylesheet."""
        if style_sheet is None:
            style_sheet = load_style_sheet()
        self.setStyleSheet(style_sheet)

    def setup(self):
        """Setup widget content."""
        self.combobox.clear()
        paths = log_files(
            log_folder=self._log_folder,
            log_filename=self._log_filename,
        )
        files = [os.path.basename(p) for p in paths]
        self.combobox.addItems(files)

    def filter_text(self):
        """Search for text in the selected log file."""
        search = self.text_search.text().lower()
        for i, data in enumerate(self._data):
            if any(search in str(d).lower() for d in data.values()):
                self.table_logs.showRow(i)
            else:
                self.table_logs.hideRow(i)

    def row_data(self, row):
        """Give the current row data concatenated with spaces."""
        data = {}
        if self._data:
            length = len(self._data)
            if 0 >= row < length:
                data = self._data[row]
        return data

    def update_text(self, index):
        """Update logs based on combobox selection."""
        path = os.path.join(self._log_folder, self.combobox.currentText())
        self._data = load_log(path)

        self.table_logs.clear()
        self.table_logs.setSortingEnabled(False)
        self.table_logs.setRowCount(len(self._data))
        self.table_logs.setColumnCount(len(self._columns))
        self.table_logs.setHorizontalHeaderLabels(self._headers)

        for row, data in enumerate(self._data):
            for col, col_key in enumerate(self._columns):
                item = QTableWidgetItem(data.get(col_key, ''))
                self.table_logs.setItem(row, col, item)

        for c in [0, 2, 3]:
            self.table_logs.resizeColumnToContents(c)

        self.table_logs.resizeRowsToContents()
        self.table_logs.setSortingEnabled(True)
        self.table_logs.scrollToBottom()
        self.table_logs.scrollToTop()
        self.table_logs.sortByColumn(1, Qt.AscendingOrder)

        # Make sure there is always a selected row
        self.table_logs.setCurrentCell(0, 0)

    def copy_item(self):
        """Copy selected item to clipboard in markdown format."""
        app = QApplication.instance()
        items = self.table_logs.selectedIndexes()
        if items:
            rows = set(sorted(i.row() for i in items))
            if self._data:
                all_data = [self._data[row] for row in rows]
                dump = json.dumps(all_data, sort_keys=True, indent=4)
                app.clipboard().setText('```json\n' + dump + '\n```')
コード例 #4
0
class RgbSelectionWidget(QWidget):

    signal_update_map_selections = Signal()

    def __init__(self):
        super().__init__()

        self._range_table = []
        self._limit_table = []
        self._rgb_keys = ["red", "green", "blue"]
        self._rgb_dict = {_: None for _ in self._rgb_keys}

        widget_layout = self._setup_rgb_widget()
        self.setLayout(widget_layout)

        sp = QSizePolicy()
        sp.setControlType(QSizePolicy.PushButton)
        sp.setHorizontalPolicy(QSizePolicy.Expanding)
        sp.setVerticalPolicy(QSizePolicy.Fixed)
        self.setSizePolicy(sp)

    def _setup_rgb_element(self, n_row, *, rb_check=0):
        """
        Parameters
        ----------
        rb_check: int
            The number of QRadioButton to check. Typically this would be the row number.
        """
        combo_elements = ComboBoxNamed(name=f"{n_row}")
        # combo_elements.setSizeAdjustPolicy(QComboBox.AdjustToContents)

        # Set text color for QComboBox widget (necessary if the program is used with Dark theme)
        pal = combo_elements.palette()
        pal.setColor(QPalette.ButtonText, Qt.black)
        combo_elements.setPalette(pal)
        # Set text color for drop-down view (necessary if the program is used with Dark theme)
        pal = combo_elements.view().palette()
        pal.setColor(QPalette.Text, Qt.black)
        combo_elements.view().setPalette(pal)

        btns = [QRadioButton(), QRadioButton(), QRadioButton()]
        if 0 <= rb_check < len(btns):
            btns[rb_check].setChecked(True)

        # Color is set for operation with Dark theme
        for btn in btns:
            pal = btn.palette()
            pal.setColor(QPalette.Text, Qt.black)
            btn.setPalette(pal)

        btn_group = QButtonGroup()
        for btn in btns:
            btn_group.addButton(btn)

        rng = RangeManager(name=f"{n_row}", add_sliders=True)
        rng.setTextColor([0, 0, 0])  # Set text color to 'black'
        # Set some text in edit boxes (just to demonstrate how the controls will look like)
        rng.le_min_value.setText("0.0")
        rng.le_max_value.setText("1.0")

        rng.setAlignment(Qt.AlignCenter)
        return combo_elements, btns, rng, btn_group

    def _enable_selection_events(self, enable):
        if enable:
            if not self.elements_btn_groups_events_enabled:
                for btn_group in self.elements_btn_groups:
                    btn_group.buttonToggled.connect(self.rb_toggled)
                for el_combo in self.elements_combo:
                    el_combo.currentIndexChanged.connect(
                        self.combo_element_current_index_changed)
                for el_range in self.elements_range:
                    el_range.selection_changed.connect(
                        self.range_selection_changed)
                self.elements_btn_groups_events_enabled = True
        else:
            if self.elements_btn_groups_events_enabled:
                for btn_group in self.elements_btn_groups:
                    btn_group.buttonToggled.disconnect(self.rb_toggled)
                for el_combo in self.elements_combo:
                    el_combo.currentIndexChanged.disconnect(
                        self.combo_element_current_index_changed)
                # Disconnecting the Range Manager signals is not necessary, but let's do it for consistency
                for el_range in self.elements_range:
                    el_range.selection_changed.disconnect(
                        self.range_selection_changed)
                self.elements_btn_groups_events_enabled = False

    def _setup_rgb_widget(self):

        self.elements_combo = []
        self.elements_rb_color = []
        self.elements_range = []
        self.elements_btn_groups = []
        self.elements_btn_groups_events_enabled = False
        self.row_colors = []

        self.table = QTableWidget()
        # Horizontal header entries
        tbl_labels = ["Element", "Red", "Green", "Blue", "Range"]
        # The list of columns that stretch with the table
        self.tbl_cols_stretch = ("Range", )

        self.table.setColumnCount(len(tbl_labels))
        self.table.setRowCount(3)
        self.table.setHorizontalHeaderLabels(tbl_labels)
        self.table.verticalHeader().hide()
        self.table.setSelectionMode(QTableWidget.NoSelection)

        header = self.table.horizontalHeader()
        for n, lbl in enumerate(tbl_labels):
            # Set stretching for the columns
            if lbl in self.tbl_cols_stretch:
                header.setSectionResizeMode(n, QHeaderView.Stretch)
            else:
                header.setSectionResizeMode(n, QHeaderView.ResizeToContents)

        vheader = self.table.verticalHeader()
        vheader.setSectionResizeMode(QHeaderView.Stretch)  # ResizeToContents)

        for n_row in range(3):
            combo_elements, btns, rng, btn_group = self._setup_rgb_element(
                n_row, rb_check=n_row)

            combo_elements.setMinimumWidth(180)
            self.table.setCellWidget(n_row, 0, combo_elements)
            for i, btn in enumerate(btns):
                item = QWidget()
                item_hbox = QHBoxLayout(item)
                item_hbox.addWidget(btn)
                item_hbox.setAlignment(Qt.AlignCenter)
                item_hbox.setContentsMargins(0, 0, 0, 0)
                item.setMinimumWidth(70)

                self.table.setCellWidget(n_row, i + 1, item)

            rng.setMinimumWidth(200)
            rng.setMaximumWidth(400)
            self.table.setCellWidget(n_row, 4, rng)

            self.elements_combo.append(combo_elements)
            self.elements_rb_color.append(btns)
            self.elements_range.append(rng)
            self.elements_btn_groups.append(btn_group)
            self.row_colors.append(self._rgb_keys[n_row])

        # Colors that are used to paint rows of the table in RGB colors
        br = 150
        self._rgb_row_colors = {
            "red": (255, br, br),
            "green": (br, 255, br),
            "blue": (br, br, 255)
        }
        self._rgb_color_keys = ["red", "green", "blue"]

        # Set initial colors
        for n_row in range(self.table.rowCount()):
            self._set_row_color(n_row)

        self._enable_selection_events(True)

        self.table.resizeRowsToContents()

        # Table height is computed based on content. It doesn't seem
        #   to account for the height of custom widgets, but the table
        #   looks good enough
        table_height = 0
        for n_row in range(self.table.rowCount()):
            table_height += self.table.rowHeight(n_row)
        self.table.setMaximumHeight(table_height)

        table_width = 650
        self.table.setMinimumWidth(table_width)
        self.table.setMaximumWidth(800)

        hbox = QHBoxLayout()
        hbox.addWidget(self.table)

        return hbox

    def combo_element_current_index_changed(self, name, index):
        if index < 0 or index >= len(self._range_table):
            return
        n_row = int(name)
        sel_eline = self._range_table[index][0]
        row_color = self.row_colors[n_row]
        self._rgb_dict[row_color] = sel_eline

        self.elements_range[n_row].set_range(self._range_table[index][1],
                                             self._range_table[index][2])
        self.elements_range[n_row].set_selection(
            value_low=self._limit_table[index][1],
            value_high=self._limit_table[index][2])
        self._update_map_selections()

    def range_selection_changed(self, v_low, v_high, name):
        n_row = int(name)
        row_color = self.row_colors[n_row]
        sel_eline = self._rgb_dict[row_color]
        ind = None
        try:
            ind = [_[0] for _ in self._limit_table].index(sel_eline)
        except ValueError:
            pass
        if ind is not None:
            self._limit_table[ind][1] = v_low
            self._limit_table[ind][2] = v_high
            self._update_map_selections()
        # We are not preventing users to select the same emission line in to rows.
        #   Update the selected limits in other rows where the same element is selected.
        for nr, el_range in enumerate(self.elements_range):
            if (nr != n_row) and (self._rgb_dict[self.row_colors[nr]]
                                  == sel_eline):
                el_range.set_selection(value_low=v_low, value_high=v_high)

    def _get_selected_row_color(self, n_row):

        color_key = None

        btns = self.elements_rb_color[n_row]

        for n, btn in enumerate(btns):
            if btn.isChecked():
                color_key = self._rgb_color_keys[n]
                break

        return color_key

    def _set_row_color(self, n_row, *, color_key=None):
        """
        Parameters
        ----------
        n_row: int
            The row number that needs background color change (0..2 if table has 3 rows)
        color_key: int
            Color key: "red", "green" or "blue"
        """

        if color_key is None:
            color_key = self._get_selected_row_color(n_row)
        if color_key is None:
            return

        self.row_colors[n_row] = color_key
        rgb = self._rgb_row_colors[color_key]

        # The following code is based on the arrangement of the widgets in the table
        #   Modify the code if widgets are arranged differently or the table structure
        #   is changed
        for n_col in range(self.table.columnCount()):
            wd = self.table.cellWidget(n_row, n_col)
            if n_col == 0:
                # Combo box: update both QComboBox and QWidget backgrounds
                #   QWidget - background of the drop-down selection list
                css1 = get_background_css(rgb,
                                          widget="QComboBox",
                                          editable=False)
                css2 = get_background_css(rgb, widget="QWidget", editable=True)
                wd.setStyleSheet(css2 + css1)
            elif n_col <= 3:
                # 3 QRadioButton's. The buttons are inserted into QWidget objects,
                #   and we need to change backgrounds of QWidgets, not only buttons.
                wd.setStyleSheet(
                    get_background_css(rgb, widget="QWidget", editable=False))
            elif n_col == 4:
                # Custom RangeManager widget, color is updated using custom method
                wd.setBackground(rgb)

        n_col = self._rgb_color_keys.index(color_key)
        for n, n_btn in enumerate(self.elements_rb_color[n_row]):
            check_status = True if n == n_col else False
            n_btn.setChecked(check_status)

    def _fill_table(self):
        self._enable_selection_events(False)

        eline_list = [_[0] for _ in self._range_table]
        for n_row in range(self.table.rowCount()):
            self.elements_combo[n_row].clear()
            self.elements_combo[n_row].addItems(eline_list)

        for n_row, color in enumerate(self._rgb_color_keys):
            # Initially set colors in order
            self._set_row_color(n_row, color_key=color)
            eline_key = self._rgb_dict[color]
            if eline_key is not None:
                try:
                    ind = eline_list.index(eline_key)
                    self.elements_combo[n_row].setCurrentIndex(ind)
                    range_low, range_high = self._range_table[ind][1:]
                    self.elements_range[n_row].set_range(range_low, range_high)
                    sel_low, sel_high = self._limit_table[ind][1:]
                    self.elements_range[n_row].set_selection(
                        value_low=sel_low, value_high=sel_high)
                except ValueError:
                    pass
            else:
                self.elements_combo[n_row].setCurrentIndex(-1)  # Deselect all
                self.elements_range[n_row].set_range(0, 1)
                self.elements_range[n_row].set_selection(value_low=0,
                                                         value_high=1)

        self._enable_selection_events(True)

    def _find_rbutton(self, button):
        for nr, btns in enumerate(self.elements_rb_color):
            for nc, btn in enumerate(btns):
                if btn == button:
                    # Return tuple (nr, nc)
                    return nr, nc
        # Return None if the button is not found (this shouldn't happen)
        return None

    def rb_toggled(self, button, state):
        if state:  # Ignore signals from unchecked buttons
            nr, nc = self._find_rbutton(button)

            color_current = self.row_colors[nr]
            color_to_set = self._rgb_color_keys[nc]
            nr_switch = self.row_colors.index(color_to_set)

            self._enable_selection_events(False)

            self._set_row_color(nr, color_key=color_to_set)
            self._set_row_color(nr_switch, color_key=color_current)
            # Swap selected maps
            tmp = self._rgb_dict[color_to_set]
            self._rgb_dict[color_to_set] = self._rgb_dict[color_current]
            self._rgb_dict[color_current] = tmp

            self._enable_selection_events(True)

            self._update_map_selections()

    def set_ranges_and_limits(self,
                              *,
                              range_table=None,
                              limit_table=None,
                              rgb_dict=None):
        if range_table is not None:
            self._range_table = copy.deepcopy(range_table)
        if limit_table is not None:
            self._limit_table = copy.deepcopy(limit_table)
        if rgb_dict is not None:
            self._rgb_dict = rgb_dict.copy()
        self._fill_table()

    def _update_map_selections(self):
        """Upload the selections (limit table) and update plot"""
        self.signal_update_map_selections.emit()
コード例 #5
0
class DialogSelectQuantStandard(QDialog):
    def __init__(self, parent=None):

        super().__init__(parent)

        self._qe_param_built_in = []
        self._qe_param_custom = []
        self._qe_standard_selected = None
        self._qe_param = []  # The list of all standards
        self._custom_label = []  # The list of booleans: True - the standard is custom, False -built-in

        self.setWindowTitle("Load Quantitative Standard")

        self.setMinimumHeight(500)
        self.setMinimumWidth(600)
        self.resize(600, 500)

        self.selected_standard_index = -1

        labels = ("C", "Serial #", "Name", "Description")
        col_stretch = (
            QHeaderView.ResizeToContents,
            QHeaderView.ResizeToContents,
            QHeaderView.ResizeToContents,
            QHeaderView.Stretch,
        )
        self.table = QTableWidget()
        set_tooltip(
            self.table,
            "To <b> load the sta"
            "ndard</b>, double-click on the table row or "
            "select the table row and then click <b>Ok</b> button.",
        )
        self.table.setMinimumHeight(200)
        self.table.setColumnCount(len(labels))
        self.table.verticalHeader().hide()
        self.table.setHorizontalHeaderLabels(labels)
        self.table.setSelectionBehavior(QTableWidget.SelectRows)
        self.table.setSelectionMode(QTableWidget.SingleSelection)
        self.table.itemSelectionChanged.connect(self.item_selection_changed)
        self.table.itemDoubleClicked.connect(self.item_double_clicked)

        self.table.setStyleSheet(
            "QTableWidget::item{color: black;}"
            "QTableWidget::item:selected{background-color: red;}"
            "QTableWidget::item:selected{color: white;}"
        )

        header = self.table.horizontalHeader()
        for n, col_stretch in enumerate(col_stretch):
            # Set stretching for the columns
            header.setSectionResizeMode(n, col_stretch)

        self.lb_info = QLabel()
        self.lb_info.setText("Column 'C': * means that the standard is user-defined.")

        button_box = QDialogButtonBox(QDialogButtonBox.Open | QDialogButtonBox.Cancel)
        button_box.button(QDialogButtonBox.Cancel).setDefault(True)
        button_box.accepted.connect(self.accept)
        button_box.rejected.connect(self.reject)

        self.pb_open = button_box.button(QDialogButtonBox.Open)
        self.pb_open.setEnabled(False)

        vbox = QVBoxLayout()
        vbox.addWidget(self.table)
        vbox.addWidget(self.lb_info)
        vbox.addWidget(button_box)
        self.setLayout(vbox)

    def _fill_table(self, table_contents):
        self.table.setRowCount(len(table_contents))

        for nr, row in enumerate(table_contents):
            for nc, entry in enumerate(row):
                s = textwrap.fill(entry, width=40)
                item = QTableWidgetItem(s)
                item.setFlags(item.flags() & ~Qt.ItemIsEditable)
                if not nc:
                    item.setTextAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
                self.table.setItem(nr, nc, item)
        self.table.resizeRowsToContents()

        brightness = 220
        for nr in range(self.table.rowCount()):
            for nc in range(self.table.columnCount()):
                self.table.item(nr, nc)
                if nr % 2:
                    color = QColor(255, brightness, brightness)
                else:
                    color = QColor(brightness, 255, brightness)
                self.table.item(nr, nc).setBackground(QBrush(color))

        try:
            index = self._qe_param.index(self._qe_standard_selected)
            self.selected_standard_index = index
            n_columns = self.table.columnCount()
            self.table.setRangeSelected(QTableWidgetSelectionRange(index, 0, index, n_columns - 1), True)
        except ValueError:
            pass

    def item_selection_changed(self):
        sel_ranges = self.table.selectedRanges()
        # The table is configured to have one or no selected ranges
        # 'Open' button should be enabled only if a range (row) is selected
        if sel_ranges:
            self.selected_standard_index = sel_ranges[0].topRow()
            self.pb_open.setEnabled(True)
        else:
            self.selected_standard_index = -1
            self.pb_open.setEnabled(False)

    def item_double_clicked(self):
        self.accept()

    def set_standards(self, qe_param_built_in, qe_param_custom, qe_standard_selected):
        self._qe_standard_selected = qe_standard_selected
        self._qe_param = qe_param_custom + qe_param_built_in
        custom_label = [True] * len(qe_param_custom) + [False] * len(qe_param_built_in)

        table_contents = []
        for n, param in enumerate(self._qe_param):
            custom = "*" if custom_label[n] else ""
            serial = param["serial"]
            name = param["name"]
            description = param["description"]
            table_contents.append([custom, serial, name, description])

        self._fill_table(table_contents)

    def get_selected_standard(self):
        if self.selected_standard_index >= 0:
            return self._qe_param[self.selected_standard_index]
        else:
            return None