コード例 #1
0
ファイル: conflicts_solver.py プロジェクト: neutrons/FastGR
    def _add_tab(self, json=None):
        """will look at the json and will display the values in conflicts in a new tab to allow the user
        to fix the conflicts"""

        number_of_tabs = self.ui.tabWidget.count()

        _table = QTableWidget()

        # initialize each table
        columns_width = self._calculate_columns_width(json=json)
        for _col in np.arange(len(json[0])):
            _table.insertColumn(_col)
            _table.setColumnWidth(_col, columns_width[_col])
        for _row in np.arange(len(json)):
            _table.insertRow(_row)
        self.list_table.append(_table)

        _table.setHorizontalHeaderLabels(self.columns_label)

        for _row in np.arange(len(json)):

            # run number
            _col = 0
            list_runs = json[_row]["Run Number"]
            o_parser = ListRunsParser()
            checkbox = QRadioButton(o_parser.new_runs(list_runs=list_runs))
            if _row == 0:
                checkbox.setChecked(True)
            # QtCore.QObject.connect(checkbox, QtCore.SIGNAL("clicked(bool)"),
            #                        lambda bool, row=_row, table_id=_table:
            #                        self._changed_conflict_checkbox(bool, row, table_id))
            _table.setCellWidget(_row, _col, checkbox)

            _col += 1
            # chemical formula
            item = QTableWidgetItem(json[_row]["chemical_formula"])
            _table.setItem(_row, _col, item)

            _col += 1
            # geometry
            item = QTableWidgetItem(json[_row]["geometry"])
            _table.setItem(_row, _col, item)

            _col += 1
            # mass_density
            item = QTableWidgetItem(json[_row]["mass_density"])
            _table.setItem(_row, _col, item)

            _col += 1
            # sample_env_device
            item = QTableWidgetItem(json[_row]["sample_env_device"])
            _table.setItem(_row, _col, item)

        self.ui.tabWidget.insertTab(number_of_tabs, _table, "Conflict #{}".format(number_of_tabs))
コード例 #2
0
ファイル: view.py プロジェクト: robertapplin/mantid
    def _setup_table_widget(self):
        """
        Make a table showing
        :return: A QTableWidget object which will contain plot widgets
        """
        table_widget = QTableWidget(3, 7, self)
        table_widget.setVerticalHeaderLabels(['u1', 'u2', 'u3'])
        col_headers = [
            'a*', 'b*', 'c*'
        ] if self.frame == SpecialCoordinateSystem.HKL else ['Qx', 'Qy', 'Qz']
        col_headers.extend(['start', 'stop', 'nbins', 'step'])
        table_widget.setHorizontalHeaderLabels(col_headers)
        table_widget.setFixedHeight(
            table_widget.verticalHeader().defaultSectionSize() *
            (table_widget.rowCount() + 1))  # +1 to include headers
        for icol in range(table_widget.columnCount()):
            table_widget.setColumnWidth(icol, 50)
        table_widget.horizontalHeader().setSectionResizeMode(
            QHeaderView.Stretch)
        table_widget.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

        self.table = table_widget
        self.layout.addWidget(self.table)
コード例 #3
0
ファイル: tableshow.py プロジェクト: hzyrc6011/pmgwidgets
class PMGTableShow(BaseExtendedWidget):
    default_bg = QTableWidgetItem().background()
    default_fg = QTableWidgetItem().foreground()

    def __init__(self,
                 layout_dir: str,
                 title: List[str],
                 initial_value: List[List[Union[int, float, str]]],
                 size_restricted=False,
                 header_adaption_h=False,
                 header_adaption_v=False,
                 background_color: List[List[Union[str]]] = None,
                 foreground_color: List[List[Union[str]]] = None):
        super().__init__(layout_dir=layout_dir)

        self.maximum_rows = 100
        self.size_restricted = size_restricted
        self.header_adaption_h = header_adaption_h
        self.header_adaption_v = header_adaption_v
        self.background_color = background_color if background_color is not None else ''
        self.foreground_color = foreground_color if foreground_color is not None else ''
        self.char_width = 15
        self.on_check_callback = None
        self.title_list = title
        entryLayout = QHBoxLayout()
        entryLayout.setContentsMargins(0, 0, 0, 0)

        self.ctrl = QTableWidget()
        self.ctrl.verticalHeader().setVisible(False)
        self.set_params(size_restricted, header_adaption_h, header_adaption_v)
        self.ctrl.setColumnCount(len(title))

        self.ctrl.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        for i, text in enumerate(title):
            self.ctrl.setColumnWidth(i, len(text) * self.char_width + 10)
            self.ctrl.setHorizontalHeaderItem(i, QTableWidgetItem(text))

        self.central_layout.addLayout(entryLayout)
        entryLayout.addWidget(self.ctrl)

        if initial_value is not None:
            for sublist in initial_value:
                assert len(sublist) == len(title), \
                    'title is not as long as sublist,%s,%s' % (repr(title), sublist)
                self.ctrl.setRowCount(len(initial_value))
                self.set_value(initial_value)

    def set_params(self,
                   size_restricted=False,
                   header_adaption_h=False,
                   header_adaption_v=False):
        self.size_restricted = size_restricted
        self.header_adaption_h = header_adaption_h
        self.header_adaption_v = header_adaption_v
        if header_adaption_h:
            self.ctrl.horizontalHeader().setSectionResizeMode(
                QHeaderView.Stretch)
        if header_adaption_v:
            self.ctrl.verticalHeader().setSectionResizeMode(
                QHeaderView.Stretch)

    def check_data(self, value: List[List[Union[int, float, str]]]):
        for sublist in value:
            assert len(sublist) == len(self.title_list),\
                '%s,%s' % (repr(sublist), repr(self.title_list))

    def set_value(self, value: List[List[Union[int, float, str]]]):
        self.check_data(value)
        self.ctrl.setRowCount(len(value))
        cols = len(value[0])
        if isinstance(self.foreground_color, str):
            fg = [[self.foreground_color for i in range(cols)]
                  for j in range(len(value))]

        else:
            fg = self.foreground_color
        if isinstance(self.background_color, str):
            bg = [[self.background_color for i in range(cols)]
                  for j in range(len(value))]
        else:
            bg = self.background_color
        for row, row_list in enumerate(value):
            for col, content in enumerate(row_list):
                if len(str(content)) * self.char_width > self.ctrl.columnWidth(
                        col):
                    self.ctrl.setColumnWidth(
                        col,
                        len(str(content)) * self.char_width + 10)
                table_item = QTableWidgetItem(str(content))
                table_item.setTextAlignment(Qt.AlignCenter)
                # 字体颜色(红色)
                if fg[row][col] == '':
                    table_item.setForeground(self.default_fg)
                else:
                    table_item.setForeground(
                        QBrush(QColor(*color_str2tup(fg[row][col]))))

                # 背景颜色(红色)
                if bg[row][col] == '':
                    table_item.setBackground(self.default_bg)
                else:
                    table_item.setBackground(
                        QBrush(QColor(*color_str2tup(bg[row][col]))))
                self.ctrl.setItem(row, col, table_item)

        if self.size_restricted:
            if self.header_adaption_h:
                self.ctrl.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
                scrollbar_area_width = 0
            else:
                self.ctrl.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
                scrollbar_area_width = 10
            self.ctrl.setMaximumHeight((self.ctrl.rowCount() + 1) * 30 +
                                       scrollbar_area_width)
            self.setMaximumHeight((self.ctrl.rowCount() + 1) * 30 +
                                  scrollbar_area_width)

    def alert(self, alert_level: int):
        self.ctrl.alert(alert_level)

    def add_row(self, row: List):
        assert len(row) == self.ctrl.columnCount()
        rc = self.ctrl.rowCount()
        self.ctrl.setRowCount(rc + 1)
        for i, val in enumerate(row):
            self.ctrl.setItem(rc, i, QTableWidgetItem(str(val)))
        if self.ctrl.rowCount() > self.maximum_rows:
            self.ctrl.removeRow(0)
コード例 #4
0
class Extension2ReaderTable(QWidget):
    """Table showing extension to reader mappings with removal button.

    Widget presented in preferences-plugin dialog."""

    valueChanged = Signal(int)

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

        self._table = QTableWidget()
        self._table.setShowGrid(False)
        self._populate_table()

        layout = QVBoxLayout()
        layout.addWidget(self._table)
        self.setLayout(layout)

    def _populate_table(self):
        """Add row for each extension to reader mapping in settings"""
        self._extension_col = 0
        self._reader_col = 1

        header_strs = [trans._('Extension'), trans._('Reader Plugin')]

        self._table.setColumnCount(2)
        self._table.setColumnWidth(self._extension_col, 100)
        self._table.setColumnWidth(self._reader_col, 150)
        self._table.verticalHeader().setVisible(False)
        self._table.setMinimumHeight(120)

        extension2reader = get_settings().plugins.extension2reader
        if len(extension2reader) > 0:
            self._table.setRowCount(len(extension2reader))
            self._table.horizontalHeader().setStretchLastSection(True)
            self._table.horizontalHeader().setStyleSheet(
                'border-bottom: 2px solid white;')
            self._table.setHorizontalHeaderLabels(header_strs)

            for row, (extension,
                      plugin_name) in enumerate(extension2reader.items()):
                item = QTableWidgetItem(extension)
                item.setFlags(Qt.NoItemFlags)
                self._table.setItem(row, self._extension_col, item)

                plugin_widg = QWidget()
                # need object name to easily find row
                plugin_widg.setObjectName(f'{extension}')
                plugin_widg.setLayout(QHBoxLayout())
                plugin_widg.layout().setContentsMargins(0, 0, 0, 0)

                plugin_label = QLabel(plugin_name)
                # need object name to easily work out which button was clicked
                remove_btn = QPushButton('x', objectName=f'{extension}')
                remove_btn.setFixedWidth(30)
                remove_btn.setStyleSheet('margin: 4px;')
                remove_btn.setToolTip(
                    trans._('Remove this extension to reader association'))
                remove_btn.clicked.connect(self._remove_extension_assignment)

                plugin_widg.layout().addWidget(plugin_label)
                plugin_widg.layout().addWidget(remove_btn)
                self._table.setCellWidget(row, self._reader_col, plugin_widg)
        else:
            # Display that there are no extensions with reader associations
            self._table.setRowCount(1)
            self._table.setHorizontalHeaderLabels(header_strs)

            self._table.setColumnHidden(self._reader_col, True)
            self._table.setColumnWidth(self._extension_col, 200)
            item = QTableWidgetItem(trans._('No extensions found.'))
            item.setFlags(Qt.NoItemFlags)
            self._table.setItem(0, 0, item)

    def _remove_extension_assignment(self, event):
        """Delete extension to reader mapping setting and remove table row"""
        extension_to_remove = self.sender().objectName()
        current_settings = get_settings().plugins.extension2reader
        # need explicit assignment to new object here for persistence
        get_settings().plugins.extension2reader = {
            k: v
            for k, v in current_settings.items() if k != extension_to_remove
        }

        for i in range(self._table.rowCount()):
            row_widg_name = self._table.cellWidget(
                i, self._reader_col).objectName()
            if row_widg_name == extension_to_remove:
                self._table.removeRow(i)
                return
コード例 #5
0
ファイル: packages.py プロジェクト: irfanalamt/JSnoobie
class PackagesDialog(DialogBase):
    """Package dependencies dialog."""

    sig_setup_ready = Signal()

    def __init__(
        self,
        parent=None,
        packages=None,
        pip_packages=None,
        remove_only=False,
        update_only=False,
    ):
        """About dialog."""
        super(PackagesDialog, self).__init__(parent=parent)

        # Variables
        self.api = AnacondaAPI()
        self.actions = None
        self.packages = packages or []
        self.pip_packages = pip_packages or []

        # Widgets
        self.stack = QStackedWidget()
        self.table = QTableWidget()
        self.text = QTextEdit()
        self.label_description = LabelBase()
        self.label_status = LabelBase()
        self.progress_bar = QProgressBar()
        self.button_ok = ButtonPrimary('Apply')
        self.button_cancel = ButtonNormal('Cancel')

        # Widget setup
        self.text.setReadOnly(True)
        self.stack.addWidget(self.table)
        self.stack.addWidget(self.text)
        if remove_only:
            text = 'The following packages will be removed:<br>'
        else:
            text = 'The following packages will be modified:<br>'
        self.label_description.setText(text)
        self.label_description.setWordWrap(True)
        self.label_description.setWordWrap(True)
        self.label_status.setWordWrap(True)
        self.table.horizontalScrollBar().setVisible(False)
        self.table.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.table.setAlternatingRowColors(True)
        self.table.setSelectionMode(QAbstractItemView.NoSelection)
        self.table.setSortingEnabled(True)
        self._hheader = self.table.horizontalHeader()
        self._vheader = self.table.verticalHeader()
        self._hheader.setStretchLastSection(True)
        self._hheader.setDefaultAlignment(Qt.AlignLeft)
        self._hheader.setSectionResizeMode(self._hheader.Fixed)
        self._vheader.setSectionResizeMode(self._vheader.Fixed)
        self.button_ok.setMinimumWidth(70)
        self.button_ok.setDefault(True)
        self.base_minimum_width = 300 if remove_only else 420
        if remove_only:
            self.setWindowTitle("Remove Packages")
        elif update_only:
            self.setWindowTitle("Update Packages")
        else:
            self.setWindowTitle("Install Packages")

        self.setMinimumWidth(self.base_minimum_width)

        # Layouts
        layout_progress = QHBoxLayout()
        layout_progress.addWidget(self.label_status)
        layout_progress.addWidget(SpacerHorizontal())
        layout_progress.addWidget(self.progress_bar)

        layout_buttons = QHBoxLayout()
        layout_buttons.addStretch()
        layout_buttons.addWidget(self.button_cancel)
        layout_buttons.addWidget(SpacerHorizontal())
        layout_buttons.addWidget(self.button_ok)

        layout = QVBoxLayout()
        layout.addWidget(self.label_description)
        layout.addWidget(SpacerVertical())
        layout.addWidget(self.stack)
        layout.addWidget(SpacerVertical())
        layout.addLayout(layout_progress)
        layout.addWidget(SpacerVertical())
        layout.addWidget(SpacerVertical())
        layout.addLayout(layout_buttons)
        self.setLayout(layout)

        # Signals
        self.button_ok.clicked.connect(self.accept)
        self.button_cancel.clicked.connect(self.reject)
        self.button_ok.setDisabled(True)

        # Setup
        self.table.setDisabled(True)
        self.update_status('Solving package specifications',
                           value=0,
                           max_value=0)

    def setup(self, worker, output, error):
        """Setup the widget to include the list of dependencies."""
        if not isinstance(output, dict):
            output = {}

        packages = sorted(pkg.split('==')[0] for pkg in self.packages)
        success = output.get('success')
        error = output.get('error', '')
        exception_name = output.get('exception_name', '')
        actions = output.get('actions', [])
        prefix = worker.prefix

        if exception_name:
            message = exception_name
        else:
            # All requested packages already installed
            message = output.get('message', ' ')

        navi_deps_error = self.api.check_navigator_dependencies(
            actions, prefix)
        description = self.label_description.text()

        if error:
            description = 'No packages will be modified.'
            self.stack.setCurrentIndex(1)
            self.button_ok.setDisabled(True)
            if self.api.is_offline():
                error = ("Some of the functionality of Anaconda Navigator "
                         "will be limited in <b>offline mode</b>. <br><br>"
                         "Installation and upgrade actions will be subject to "
                         "the packages currently available on your package "
                         "cache.")
            self.text.setText(error)
        elif navi_deps_error:
            description = 'No packages will be modified.'
            error = ('Downgrading/removing these packages will modify '
                     'Anaconda Navigator dependencies.')
            self.text.setText(error)
            self.stack.setCurrentIndex(1)
            message = 'NavigatorDependenciesError'
            self.button_ok.setDisabled(True)
        elif success and actions:
            self.stack.setCurrentIndex(0)
            # Conda 4.3.x
            if isinstance(actions, list):
                actions_link = actions[0].get('LINK', [])
                actions_unlink = actions[0].get('UNLINK', [])
            # Conda 4.4.x
            else:
                actions_link = actions.get('LINK', [])
                actions_unlink = actions.get('UNLINK', [])

            deps = set()
            deps = deps.union({p['name'] for p in actions_link})
            deps = deps.union({p['name'] for p in actions_unlink})
            deps = deps - set(packages)
            deps = sorted(list(deps))

            count_total_packages = len(packages) + len(deps)
            plural_total = 's' if count_total_packages != 1 else ''
            plural_selected = 's' if len(packages) != 1 else ''

            self.table.setRowCount(count_total_packages)
            self.table.setColumnCount(4)
            if actions_link:
                description = '{0} package{1} will be installed'.format(
                    count_total_packages, plural_total)
                self.table.showColumn(2)
                self.table.showColumn(3)
            elif actions_unlink and not actions_link:
                self.table.hideColumn(2)
                self.table.hideColumn(3)
                self.table.setHorizontalHeaderLabels(
                    ['Name', 'Unlink', 'Link', 'Channel'])
                description = '{0} package{1} will be removed'.format(
                    count_total_packages, plural_total)

            for row, pkg in enumerate(packages + deps):
                link_item = [p for p in actions_link if p['name'] == pkg]
                if not link_item:
                    link_item = {
                        'version': '-'.center(len('link')),
                        'channel': '-'.center(len('channel')),
                    }
                else:
                    link_item = link_item[0]

                unlink_item = [p for p in actions_unlink if p['name'] == pkg]
                if not unlink_item:
                    unlink_item = {
                        'version': '-'.center(len('link')),
                    }
                else:
                    unlink_item = unlink_item[0]

                unlink_version = str(unlink_item['version'])
                link_version = str(link_item['version'])

                item_unlink_v = QTableWidgetItem(unlink_version)
                item_link_v = QTableWidgetItem(link_version)
                item_link_c = QTableWidgetItem(link_item['channel'])
                if pkg in packages:
                    item_name = QTableWidgetItem(pkg)
                else:
                    item_name = QTableWidgetItem('*' + pkg)

                items = [item_name, item_unlink_v, item_link_v, item_link_c]
                for column, item in enumerate(items):
                    item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable)
                    self.table.setItem(row, column, item)

            if deps:
                message = (
                    '<b>*</b> indicates the package is a dependency of a '
                    'selected package{0}<br>').format(plural_selected)

            self.button_ok.setEnabled(True)
            self.table.resizeColumnsToContents()
            unlink_width = self.table.columnWidth(1)
            if unlink_width < 60:
                self.table.setColumnWidth(1, 60)
            self.table.setHorizontalHeaderLabels(
                ['Name  ', 'Unlink  ', 'Link  ', 'Channel  '])

        self.table.setEnabled(True)
        self.update_status(message=message)
        self.label_description.setText(description)

        # Adjust size after data has populated the table
        self.table.resizeColumnsToContents()
        width = sum(
            self.table.columnWidth(i) for i in range(self.table.columnCount()))
        delta = (self.width() - self.table.width() +
                 self.table.verticalHeader().width() + 10)

        new_width = width + delta

        if new_width < self.base_minimum_width:
            new_width = self.base_minimum_width

        self.setMinimumWidth(new_width)
        self.setMaximumWidth(new_width)

        self.sig_setup_ready.emit()

    def update_status(self, message='', value=None, max_value=None):
        """Update status of packages dialog."""
        self.label_status.setText(message)

        if max_value is None and value is None:
            self.progress_bar.setVisible(False)
        else:
            self.progress_bar.setVisible(True)
            self.progress_bar.setMaximum(max_value)
            self.progress_bar.setValue(value)
コード例 #6
0
class ShortcutEditor(QWidget):
    """Widget to edit keybindings for napari."""

    valueChanged = Signal(dict)
    VIEWER_KEYBINDINGS = trans._('Viewer key bindings')

    def __init__(
        self,
        parent: QWidget = None,
        description: str = "",
        value: dict = None,
    ):

        super().__init__(parent=parent)

        # Flag to not run _set_keybinding method after setting special symbols.
        # When changing line edit to special symbols, the _set_keybinding
        # method will be called again (and breaks) and is not needed.
        self._skip = False

        layers = [
            Image,
            Labels,
            Points,
            Shapes,
            Surface,
            Vectors,
        ]

        self.key_bindings_strs = OrderedDict()

        # widgets
        self.layer_combo_box = QComboBox(self)
        self._label = QLabel(self)
        self._table = QTableWidget(self)
        self._table.setSelectionBehavior(QAbstractItemView.SelectItems)
        self._table.setSelectionMode(QAbstractItemView.SingleSelection)
        self._table.setShowGrid(False)
        self._restore_button = QPushButton(trans._("Reset All Keybindings"))

        # Set up dictionary for layers and associated actions.
        all_actions = action_manager._actions.copy()
        self.key_bindings_strs[self.VIEWER_KEYBINDINGS] = []

        for layer in layers:
            if len(layer.class_keymap) == 0:
                actions = []
            else:
                actions = action_manager._get_layer_actions(layer)
                for name, action in actions.items():
                    all_actions.pop(name)
            self.key_bindings_strs[f"{layer.__name__} layer"] = actions

        # Left over actions can go here.
        self.key_bindings_strs[self.VIEWER_KEYBINDINGS] = all_actions

        # Widget set up
        self.layer_combo_box.addItems(list(self.key_bindings_strs))
        self.layer_combo_box.activated[str].connect(self._set_table)
        self.layer_combo_box.setCurrentText(self.VIEWER_KEYBINDINGS)
        self._set_table()
        self._label.setText("Group")
        self._restore_button.clicked.connect(self.restore_defaults)

        # layout
        hlayout1 = QHBoxLayout()
        hlayout1.addWidget(self._label)
        hlayout1.addWidget(self.layer_combo_box)
        hlayout1.setContentsMargins(0, 0, 0, 0)
        hlayout1.setSpacing(20)
        hlayout1.addStretch(0)

        hlayout2 = QHBoxLayout()
        hlayout2.addLayout(hlayout1)
        hlayout2.addWidget(self._restore_button)

        layout = QVBoxLayout()
        layout.addLayout(hlayout2)
        layout.addWidget(self._table)

        self.setLayout(layout)

    def restore_defaults(self):
        """Launches dialog to confirm restore choice."""

        self._reset_dialog = ConfirmDialog(
            parent=self,
            text=trans._(
                "Are you sure you want to restore default shortcuts?"
            ),
        )
        self._reset_dialog.valueChanged.connect(self._reset_shortcuts)
        self._reset_dialog.exec_()

    def _reset_shortcuts(self, event=None):
        """Reset shortcuts to default settings.

        Parameters
        ----------
        event: Bool
            Event will indicate whether user confirmed resetting shortcuts.
        """

        # event is True if the user confirmed reset shortcuts
        if event is True:
            get_settings().reset(sections=['shortcuts'])
            for (
                action,
                shortcuts,
            ) in get_settings().shortcuts.shortcuts.items():
                action_manager.unbind_shortcut(action)
                for shortcut in shortcuts:
                    action_manager.bind_shortcut(action, shortcut)

            self._set_table(layer_str=self.layer_combo_box.currentText())

    def _set_table(self, layer_str=''):
        """Builds and populates keybindings table.

        Parameters
        ----------
        layer_str = str
            If layer_str is not empty, then show the specified layers'
            keybinding shortcut table.
        """

        # Keep track of what is in each column.
        self._action_name_col = 0
        self._icon_col = 1
        self._shortcut_col = 2
        self._action_col = 3

        # Set header strings for table.
        header_strs = ['', '', '', '']
        header_strs[self._action_name_col] = trans._('Action')
        header_strs[self._shortcut_col] = trans._('Keybinding')

        # If no layer_str, then set the page to the viewer keybindings page.
        if layer_str == '':
            layer_str = self.VIEWER_KEYBINDINGS

        # If rebuilding the table, then need to disconnect the connection made
        # previously as well as clear the table contents.
        try:
            self._table.cellChanged.disconnect(self._set_keybinding)
        except TypeError:
            # if building the first time, the cells are not yet connected so this would fail.
            pass
        except RuntimeError:
            # Needed to pass some tests.
            pass

        self._table.clearContents()

        # Table styling set up.
        self._table.horizontalHeader().setStretchLastSection(True)
        self._table.horizontalHeader().setStyleSheet(
            'border-bottom: 2px solid white;'
        )

        # Get all actions for the layer.
        actions = self.key_bindings_strs[layer_str]

        if len(actions) > 0:

            # Set up table based on number of actions and needed columns.
            self._table.setRowCount(len(actions))
            self._table.setColumnCount(4)
            # Set up delegate in order to capture keybindings.
            self._table.setItemDelegateForColumn(
                self._shortcut_col, ShortcutDelegate(self._table)
            )
            self._table.setHorizontalHeaderLabels(header_strs)
            self._table.verticalHeader().setVisible(False)

            # Hide the column with action names.  These are kept here for reference when needed.
            self._table.setColumnHidden(self._action_col, True)

            # Column set up.
            self._table.setColumnWidth(self._action_name_col, 250)
            self._table.setColumnWidth(self._shortcut_col, 200)
            self._table.setColumnWidth(self._icon_col, 50)

            # Go through all the actions in the layer and add them to the table.
            for row, (action_name, action) in enumerate(actions.items()):

                shortcuts = action_manager._shortcuts.get(action_name, [])
                # Set action description.  Make sure its not selectable/editable.
                item = QTableWidgetItem(action.description)
                item.setFlags(Qt.NoItemFlags)
                self._table.setItem(row, self._action_name_col, item)

                # Create empty item in order to make sure this column is not
                # selectable/editable.
                item = QTableWidgetItem("")
                item.setFlags(Qt.NoItemFlags)
                self._table.setItem(row, self._icon_col, item)

                # Set the shortcuts in table.
                item_shortcut = QTableWidgetItem(
                    Shortcut(list(shortcuts)[0]).platform if shortcuts else ""
                )
                self._table.setItem(row, self._shortcut_col, item_shortcut)

                # action_name is stored in the table to use later, but is not shown on dialog.
                item_action = QTableWidgetItem(action_name)
                self._table.setItem(row, self._action_col, item_action)

            # If a cell is changed, run .set_keybinding.
            self._table.cellChanged.connect(self._set_keybinding)
        else:
            # Display that there are no actions for this layer.
            self._table.setRowCount(1)
            self._table.setColumnCount(4)
            self._table.setHorizontalHeaderLabels(header_strs)
            self._table.verticalHeader().setVisible(False)

            self._table.setColumnHidden(self._action_col, True)
            item = QTableWidgetItem('No key bindings')
            item.setFlags(Qt.NoItemFlags)
            self._table.setItem(0, 0, item)

    def _set_keybinding(self, row, col):
        """Checks the new keybinding to determine if it can be set.

        Parameters
        ----------
        row: int
            Row in keybindings table that is being edited.
        col: int
            Column being edited (shortcut column).
        """

        if self._skip is True:
            # Do nothing if the text is setting to a symbol.
            # Its already been handled.
            self._skip = False
            return

        if col == self._shortcut_col:
            # Get all layer actions and viewer actions in order to determine
            # the new shortcut is not already set to an action.

            current_layer_text = self.layer_combo_box.currentText()
            layer_actions = self.key_bindings_strs[current_layer_text]
            actions_all = layer_actions.copy()
            if current_layer_text is not self.VIEWER_KEYBINDINGS:
                viewer_actions = self.key_bindings_strs[
                    self.VIEWER_KEYBINDINGS
                ]

                actions_all.update(viewer_actions)

            # get the current item from shortcuts column
            current_item = self._table.currentItem()
            new_shortcut = current_item.text()
            new_shortcut = new_shortcut[0].upper() + new_shortcut[1:]

            # get the current action name
            current_action = self._table.item(row, self._action_col).text()

            # get the original shortcutS
            current_shortcuts = list(
                action_manager._shortcuts.get(current_action, {})
            )

            # Flag to indicate whether to set the new shortcut.
            replace = True
            # Go through all layer actions to determine if the new shortcut is already here.
            for row1, (action_name, action) in enumerate(actions_all.items()):
                shortcuts = action_manager._shortcuts.get(action_name, [])

                if new_shortcut in shortcuts:
                    # Shortcut is here (either same action or not), don't replace in settings.
                    replace = False
                    if action_name != current_action:
                        # the shortcut is saved to a different action

                        # show warning symbols
                        self._show_warning_icons([row, row1])

                        # show warning message
                        message = trans._(
                            "The keybinding <b>{new_shortcut}</b>  "
                            + "is already assigned to <b>{action_description}</b>; change or clear "
                            + "that shortcut before assigning <b>{new_shortcut}</b> to this one.",
                            new_shortcut=new_shortcut,
                            action_description=action.description,
                        )
                        self._show_warning(new_shortcut, action, row, message)

                        if len(current_shortcuts) > 0:
                            # If there was a shortcut set originally, then format it and reset the text.
                            format_shortcut = Shortcut(
                                current_shortcuts[0]
                            ).platform

                            if format_shortcut != current_shortcuts[0]:
                                # only skip the next round if there are special symbols
                                self._skip = True

                            current_item.setText(format_shortcut)

                        else:
                            # There wasn't a shortcut here.
                            current_item.setText("")

                        self._cleanup_warning_icons([row, row1])

                        break

                    else:
                        # This shortcut was here.  Reformat and reset text.
                        format_shortcut = Shortcut(new_shortcut).platform
                        if format_shortcut != new_shortcut:
                            # Only skip the next round if there are special symbols in shortcut.
                            self._skip = True

                        current_item.setText(format_shortcut)

            if replace is True:
                # This shortcut is not taken.

                #  Unbind current action from shortcuts in action manager.
                action_manager.unbind_shortcut(current_action)

                if new_shortcut != "":
                    # Bind the new shortcut.
                    try:
                        action_manager.bind_shortcut(
                            current_action, new_shortcut
                        )
                    except TypeError:
                        # Shortcut is not valid.
                        action_manager._shortcuts[current_action] = set()
                        # need to rebind the old shortcut
                        action_manager.unbind_shortcut(current_action)
                        action_manager.bind_shortcut(
                            current_action, current_shortcuts[0]
                        )

                        # Show warning message to let user know this shortcut is invalid.
                        self._show_warning_icons([row])

                        message = trans._(
                            "<b>{new_shortcut}</b> is not a valid keybinding.",
                            new_shortcut=new_shortcut,
                        )
                        self._show_warning(new_shortcut, action, row, message)

                        self._cleanup_warning_icons([row])

                        format_shortcut = Shortcut(
                            current_shortcuts[0]
                        ).platform
                        if format_shortcut != current_shortcuts[0]:
                            # Skip the next round if there are special symbols.
                            self._skip = True

                        # Update text to formated shortcut.
                        current_item.setText(format_shortcut)
                        return

                    # The new shortcut is valid and can be displayed in widget.

                    # Keep track of what changed.
                    new_value_dict = {current_action: [new_shortcut]}

                    # Format new shortcut.
                    format_shortcut = Shortcut(new_shortcut).platform
                    if format_shortcut != new_shortcut:
                        # Skip the next round because there are special symbols.
                        self._skip = True

                    # Update text to formated shortcut.
                    current_item.setText(format_shortcut)

                else:
                    # There is not a new shortcut to bind.  Keep track of it.
                    if action_manager._shortcuts[current_action] != "":
                        new_value_dict = {current_action: [""]}

                if new_value_dict:
                    # Emit signal when new value set for shortcut.
                    self.valueChanged.emit(new_value_dict)

    def _show_warning_icons(self, rows):
        """Creates and displays the warning icons.

        Parameters
        ----------
        rows: list[int]
            List of row numbers that should have the icon.
        """

        for row in rows:
            self.warning_indicator = QLabel(self)
            self.warning_indicator.setObjectName("error_label")

            self._table.setCellWidget(
                row, self._icon_col, self.warning_indicator
            )

    def _cleanup_warning_icons(self, rows):
        """Remove the warning icons from the shortcut table.

        Paramters
        ---------
        rows: list[int]
            List of row numbers to remove warning icon from.

        """
        for row in rows:
            self._table.setCellWidget(row, self._icon_col, QLabel(""))

    def _show_warning(self, new_shortcut='', action=None, row=0, message=''):
        """Creates and displays warning message when shortcut is already assigned.

        Parameters
        ----------
        new_shortcut: str
            The new shortcut attempting to be set.
        action: Action
            Action that is already assigned with the shortcut.
        row: int
            Row in table where the shortcut is attempting to be set.
        message: str
            Message to be displayed in warning pop up.
        """

        # Determine placement of warning message.
        delta_y = 105
        delta_x = 10
        global_point = self.mapToGlobal(
            QPoint(
                self._table.columnViewportPosition(self._shortcut_col)
                + delta_x,
                self._table.rowViewportPosition(row) + delta_y,
            )
        )

        # Create warning pop up and move it to desired position.
        self._warn_dialog = KeyBindWarnPopup(
            text=message,
        )
        self._warn_dialog.move(global_point)

        # Styling adjustments.
        self._warn_dialog.resize(250, self._warn_dialog.sizeHint().height())

        self._warn_dialog._message.resize(
            200, self._warn_dialog._message.sizeHint().height()
        )

        self._warn_dialog.exec_()

    def value(self):
        """Return the actions and shortcuts currently assigned in action manager.

        Returns
        -------
        value: dict

            Dictionary of action names and shortcuts assigned to them.
        """

        value = {}

        for row, (action_name, action) in enumerate(
            action_manager._actions.items()
        ):
            shortcuts = action_manager._shortcuts.get(action_name, [])
            value[action_name] = list(shortcuts)

        return value
コード例 #7
0
class D0(QGroupBox):
    def __init__(self, parent=None):
        self._parent = parent
        super().__init__(parent)
        self.setTitle("Define d₀")
        layout = QVBoxLayout()
        self.d0_grid_switch = QComboBox()
        self.d0_grid_switch.addItems(["Constant", "Field"])
        self.d0_grid_switch.currentTextChanged.connect(self.set_case)
        layout.addWidget(self.d0_grid_switch)
        self.d0_box = QWidget()
        d0_box_layout = QHBoxLayout()
        d0_box_layout.addWidget(QLabel("d₀"))
        validator = QDoubleValidator()
        validator.setBottom(0)
        self.d0 = QLineEdit()
        self.d0.setValidator(validator)
        self.d0.editingFinished.connect(self.update_d0)
        d0_box_layout.addWidget(self.d0)
        d0_box_layout.addWidget(QLabel("Δd₀"))
        self.d0e = QLineEdit()
        self.d0e.setValidator(validator)
        self.d0e.editingFinished.connect(self.update_d0)
        d0_box_layout.addWidget(self.d0e)
        self.d0_box.setLayout(d0_box_layout)
        layout.addWidget(self.d0_box)

        load_save = QWidget()
        load_save_layout = QHBoxLayout()
        self.load_grid = QPushButton("Load d₀ Grid")
        self.load_grid.clicked.connect(self.load_d0_field)
        load_save_layout.addWidget(self.load_grid)
        self.save_grid = QPushButton("Save d₀ Grid")
        self.save_grid.clicked.connect(self.save_d0_field)
        load_save_layout.addWidget(self.save_grid)
        load_save.setLayout(load_save_layout)
        layout.addWidget(load_save)
        self.d0_grid = QTableWidget()
        self.d0_grid.setColumnCount(5)
        self.d0_grid.setColumnWidth(0, 60)
        self.d0_grid.setColumnWidth(1, 60)
        self.d0_grid.setColumnWidth(2, 60)
        self.d0_grid.setColumnWidth(3, 60)
        self.d0_grid.verticalHeader().setVisible(False)
        self.d0_grid.horizontalHeader().setStretchLastSection(True)
        self.d0_grid.setHorizontalHeaderLabels(['vx', 'vy', 'vz', "d₀", "Δd₀"])
        spinBoxDelegate = SpinBoxDelegate()
        self.d0_grid.setItemDelegateForColumn(3, spinBoxDelegate)
        self.d0_grid.setItemDelegateForColumn(4, spinBoxDelegate)
        layout.addWidget(self.d0_grid)

        self.setLayout(layout)

        self.set_case('Constant')

    def set_case(self, case):
        if case == "Constant":
            self.d0_box.setEnabled(True)
            self.load_grid.setEnabled(False)
            self.save_grid.setEnabled(False)
            self.d0_grid.setEnabled(False)
        else:
            self.d0_box.setEnabled(False)
            self.load_grid.setEnabled(True)
            self.save_grid.setEnabled(True)
            self.d0_grid.setEnabled(True)

    def update_d0(self):
        self._parent.update_plot()

    def set_d0(self, d0, d0e):
        if d0 is None:
            self.d0.clear()
            self.d0e.clear()
        else:
            self.d0.setText(str(d0))
            self.d0e.setText(str(d0e))

    def set_d0_field(self, x, y, z, d0, d0e):
        if x is None:
            self.d0_grid.clearContents()
        else:
            self.d0_grid.setRowCount(len(x))

            for n in range(len(x)):
                x_item = QTableWidgetItem(f'{x[n]: 7.2f}')
                x_item.setFlags(x_item.flags() ^ Qt.ItemIsEditable)
                y_item = QTableWidgetItem(f'{y[n]: 7.2f}')
                y_item.setFlags(y_item.flags() ^ Qt.ItemIsEditable)
                z_item = QTableWidgetItem(f'{z[n]: 7.2f}')
                z_item.setFlags(z_item.flags() ^ Qt.ItemIsEditable)
                d0_item = QTableWidgetItem()
                d0_item.setData(Qt.EditRole, float(d0[n]))
                d0e_item = QTableWidgetItem()
                d0e_item.setData(Qt.EditRole, float(d0e[n]))
                self.d0_grid.setItem(n, 0, QTableWidgetItem(x_item))
                self.d0_grid.setItem(n, 1, QTableWidgetItem(y_item))
                self.d0_grid.setItem(n, 2, QTableWidgetItem(z_item))
                self.d0_grid.setItem(n, 3, QTableWidgetItem(d0_item))
                self.d0_grid.setItem(n, 4, QTableWidgetItem(d0e_item))

    def get_d0_field(self):
        if self.d0_grid.rowCount() == 0:
            return None
        else:
            x = [
                float(self.d0_grid.item(row, 0).text())
                for row in range(self.d0_grid.rowCount())
            ]
            y = [
                float(self.d0_grid.item(row, 1).text())
                for row in range(self.d0_grid.rowCount())
            ]
            z = [
                float(self.d0_grid.item(row, 2).text())
                for row in range(self.d0_grid.rowCount())
            ]
            d0 = [
                float(self.d0_grid.item(row, 3).text())
                for row in range(self.d0_grid.rowCount())
            ]
            d0e = [
                float(self.d0_grid.item(row, 4).text())
                for row in range(self.d0_grid.rowCount())
            ]
            return (d0, d0e, x, y, z)

    def save_d0_field(self):
        filename, _ = QFileDialog.getSaveFileName(
            self, "Save d0 Grid", "", "CSV (*.csv);;All Files (*)")
        if filename:
            d0, d0e, x, y, z = self.get_d0_field()
            np.savetxt(filename,
                       np.array([x, y, z, d0, d0e]).T,
                       fmt=['%.4g', '%.4g', '%.4g', '%.9g', '%.9g'],
                       header="vx, vy, vz, d0, d0_error",
                       delimiter=',')

    def load_d0_field(self):
        filename, _ = QFileDialog.getOpenFileName(
            self, "Load d0 Grid", "", "CSV (*.csv);;All Files (*)")
        if filename:
            x, y, z, d0, d0e = np.loadtxt(filename, delimiter=',', unpack=True)
            self.set_d0_field(x, y, z, d0, d0e)

    def get_d0(self):
        if self.d0_grid_switch.currentText() == "Constant":
            try:
                return (float(self.d0.text()), float(self.d0e.text()))
            except ValueError:
                return None
        else:
            return self.get_d0_field()
コード例 #8
0
ファイル: qt_extension2reader.py プロジェクト: kne42/napari
class Extension2ReaderTable(QWidget):
    """Table showing extension to reader mappings with removal button.

    Widget presented in preferences-plugin dialog."""

    valueChanged = Signal(int)

    def __init__(self, parent=None, npe2_readers=None, npe1_readers=None):
        super().__init__(parent=parent)

        npe2, npe1 = get_all_readers()
        if npe2_readers is None:
            npe2_readers = npe2
        if npe1_readers is None:
            npe1_readers = npe1

        self._npe2_readers = npe2_readers
        self._npe1_readers = npe1_readers

        self._table = QTableWidget()
        self._table.setShowGrid(False)
        self._set_up_table()
        self._edit_row = self._make_new_preference_row()
        self._populate_table()

        instructions = QLabel(
            trans.
            _('Enter a filename pattern to associate with a reader e.g. "*.tif" for all TIFF files.'
              ) + trans.
            _('Available readers will be filtered to those compatible with your pattern. Hover over a reader to see what patterns it accepts.'
              ) + trans.
            _('\n\nPreference saving for folder readers is not supported, so these readers are not shown.'
              ) + trans.
            _('\n\nFor documentation on valid filename patterns, see https://docs.python.org/3/library/fnmatch.html'
              ))
        instructions.setWordWrap(True)
        instructions.setOpenExternalLinks(True)

        layout = QVBoxLayout()
        instructions.setSizePolicy(QSizePolicy.MinimumExpanding,
                                   QSizePolicy.Expanding)
        layout.addWidget(instructions)
        layout.addWidget(self._edit_row)
        layout.addWidget(self._table)
        self.setLayout(layout)

    def _set_up_table(self):
        """Add table columns and headers, define styling"""
        self._fn_pattern_col = 0
        self._reader_col = 1

        header_strs = [trans._('Filename Pattern'), trans._('Reader Plugin')]

        self._table.setColumnCount(2)
        self._table.setColumnWidth(self._fn_pattern_col, 200)
        self._table.setColumnWidth(self._reader_col, 200)
        self._table.verticalHeader().setVisible(False)
        self._table.setMinimumHeight(120)
        self._table.horizontalHeader().setStyleSheet(
            'border-bottom: 2px solid white;')
        self._table.setHorizontalHeaderLabels(header_strs)
        self._table.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

    def _populate_table(self):
        """Add row for each extension to reader mapping in settings"""

        fnpattern2reader = get_settings().plugins.extension2reader
        if len(fnpattern2reader) > 0:
            for fn_pattern, plugin_name in fnpattern2reader.items():
                self._add_new_row(fn_pattern, plugin_name)
        else:
            # Display that there are no filename patterns with reader associations
            self._display_no_preferences_found()

    def _make_new_preference_row(self):
        """Make row for user to add a new filename pattern assignment"""
        edit_row_widget = QWidget()
        edit_row_widget.setLayout(QGridLayout())
        edit_row_widget.layout().setContentsMargins(0, 0, 0, 0)

        self._fn_pattern_edit = QLineEdit()
        self._fn_pattern_edit.setPlaceholderText(
            "Start typing filename pattern...")
        self._fn_pattern_edit.textChanged.connect(
            self._filter_compatible_readers)

        add_reader_widg = QWidget()
        add_reader_widg.setLayout(QHBoxLayout())
        add_reader_widg.layout().setContentsMargins(0, 0, 0, 0)

        self._new_reader_dropdown = QComboBox()
        for i, (plugin_name, display_name) in enumerate(
                sorted(dict(self._npe2_readers,
                            **self._npe1_readers).items())):
            self._add_reader_choice(i, plugin_name, display_name)

        add_btn = QPushButton('Add')
        add_btn.setToolTip(trans._('Save reader preference for pattern'))
        add_btn.clicked.connect(self._save_new_preference)

        add_reader_widg.layout().addWidget(self._new_reader_dropdown)
        add_reader_widg.layout().addWidget(add_btn)

        edit_row_widget.layout().addWidget(
            self._fn_pattern_edit,
            0,
            0,
        )
        edit_row_widget.layout().addWidget(add_reader_widg, 0, 1)

        return edit_row_widget

    def _display_no_preferences_found(self):
        self._table.setRowCount(1)
        item = QTableWidgetItem(trans._('No filename preferences found.'))
        item.setFlags(Qt.NoItemFlags)
        self._table.setItem(self._fn_pattern_col, 0, item)

    def _add_reader_choice(self, i, plugin_name, display_name):
        """Add dropdown item for plugin_name with reader pattern tooltip"""
        reader_patterns = get_filename_patterns_for_reader(plugin_name)
        # TODO: no reader_patterns means directory reader,
        # we don't support preference association yet
        if not reader_patterns:
            return

        self._new_reader_dropdown.addItem(display_name, plugin_name)
        if '*' in reader_patterns:
            tooltip_text = 'Accepts all'
        else:
            reader_patterns_formatted = ', '.join(sorted(
                list(reader_patterns)))
            tooltip_text = f'Accepts: {reader_patterns_formatted}'
        self._new_reader_dropdown.setItemData(i,
                                              tooltip_text,
                                              role=Qt.ToolTipRole)

    def _filter_compatible_readers(self, new_pattern):
        """Filter reader dropwdown items to those that accept `new_extension`"""
        self._new_reader_dropdown.clear()

        readers = self._npe2_readers.copy()
        to_delete = []

        compatible_readers = get_potential_readers(new_pattern)
        for plugin_name, display_name in readers.items():
            if plugin_name not in compatible_readers:
                to_delete.append(plugin_name)

        for reader in to_delete:
            del readers[reader]
        readers.update(self._npe1_readers)

        if not readers:
            self._new_reader_dropdown.addItem("None available")
        else:
            for i, (plugin_name,
                    display_name) in enumerate(sorted(readers.items())):
                self._add_reader_choice(i, plugin_name, display_name)

    def _save_new_preference(self, event):
        """Save current preference to settings and show in table"""
        fn_pattern = self._fn_pattern_edit.text()
        reader = self._new_reader_dropdown.currentData()

        if not fn_pattern or not reader:
            return

        # if user types pattern that starts with a . it's probably a file extension so prepend the *
        if fn_pattern.startswith('.'):
            fn_pattern = f'*{fn_pattern}'

        if fn_pattern in get_settings().plugins.extension2reader:
            self._edit_existing_preference(fn_pattern, reader)
        else:
            self._add_new_row(fn_pattern, reader)
        get_settings().plugins.extension2reader = {
            **get_settings().plugins.extension2reader,
            fn_pattern: reader,
        }

    def _edit_existing_preference(self, fn_pattern, reader):
        """Edit existing extension preference"""
        current_reader_label = self.findChild(QLabel, fn_pattern)
        if reader in self._npe2_readers:
            reader = self._npe2_readers[reader]
        current_reader_label.setText(reader)

    def _add_new_row(self, fn_pattern, reader):
        """Add new reader preference to table"""
        last_row = self._table.rowCount()

        if (last_row == 1 and 'No filename preferences found'
                in self._table.item(0, 0).text()):
            self._table.removeRow(0)
            last_row = 0

        self._table.insertRow(last_row)
        item = QTableWidgetItem(fn_pattern)
        item.setFlags(Qt.NoItemFlags)
        self._table.setItem(last_row, self._fn_pattern_col, item)

        plugin_widg = QWidget()
        # need object name to easily find row
        plugin_widg.setObjectName(f'{fn_pattern}')
        plugin_widg.setLayout(QHBoxLayout())
        plugin_widg.layout().setContentsMargins(0, 0, 0, 0)

        if reader in self._npe2_readers:
            reader = self._npe2_readers[reader]
        plugin_label = QLabel(reader, objectName=fn_pattern)
        # need object name to easily work out which button was clicked
        remove_btn = QPushButton('X', objectName=fn_pattern)
        remove_btn.setFixedWidth(30)
        remove_btn.setStyleSheet('margin: 4px;')
        remove_btn.setToolTip(
            trans._('Remove this filename pattern to reader association'))
        remove_btn.clicked.connect(self.remove_existing_preference)

        plugin_widg.layout().addWidget(plugin_label)
        plugin_widg.layout().addWidget(remove_btn)
        self._table.setCellWidget(last_row, self._reader_col, plugin_widg)

    def remove_existing_preference(self, event):
        """Delete extension to reader mapping setting and remove table row"""
        pattern_to_remove = self.sender().objectName()
        current_settings = get_settings().plugins.extension2reader
        # need explicit assignment to new object here for persistence
        get_settings().plugins.extension2reader = {
            k: v
            for k, v in current_settings.items() if k != pattern_to_remove
        }

        for i in range(self._table.rowCount()):
            row_widg_name = self._table.cellWidget(
                i, self._reader_col).objectName()
            if row_widg_name == pattern_to_remove:
                self._table.removeRow(i)
                break

        if self._table.rowCount() == 0:
            self._display_no_preferences_found()

    def value(self):
        """Return extension:reader mapping from settings.

        Returns
        -------
        Dict[str, str]
            mapping of extension to reader plugin display name
        """
        return get_settings().plugins.extension2reader