diff options
Diffstat (limited to 'sb_builder')
| -rw-r--r-- | sb_builder/hints_tab.py | 117 |
1 files changed, 112 insertions, 5 deletions
diff --git a/sb_builder/hints_tab.py b/sb_builder/hints_tab.py index fbf8a70..ca16354 100644 --- a/sb_builder/hints_tab.py +++ b/sb_builder/hints_tab.py @@ -21,9 +21,9 @@ import os from PyQt6.QtCore import Qt, pyqtSignal from PyQt6.QtGui import QColor, QFontDatabase, QKeySequence, QShortcut, QSyntaxHighlighter -from PyQt6.QtWidgets import (QDialog, QHBoxLayout, QLabel, QListWidget, QListWidgetItem, - QMessageBox, QPlainTextEdit, QPushButton, QSplitter, QTableWidget, - QTableWidgetItem, QVBoxLayout, QWidget) +from PyQt6.QtWidgets import (QAbstractItemView, QDialog, QHBoxLayout, QLabel, QLineEdit, + QListWidget, QListWidgetItem, QMessageBox, QPlainTextEdit, QPushButton, + QSplitter, QTableWidget, QTableWidgetItem, QVBoxLayout, QWidget) from . import upstream from .dashboard import STATUS @@ -34,7 +34,7 @@ STATES = ("outdated", "current", "no stanza", "not checked", "nvchecker error") STATE_COLOR = {"outdated": STATUS["aborted"], "current": STATUS["ok"], "nvchecker error": STATUS["failed"]} COLUMNS = ("", "package", "hint", ".info", "upstream", "state") -HINT_JOBS = ("hint-update", "hint-new") +HINT_JOBS = ("hint-update", "hint-new", "fix-current") class HintsTab(QWidget): @@ -78,7 +78,10 @@ class HintsTab(QWidget): self.act_update = action(self, "Update selected", "document-save", SP.SP_DialogSaveButton, self.update_selected) self.act_delete = action(self, "Delete hint", "edit-delete", SP.SP_TrashIcon, self.delete) - self.actions = [self.act_check, self.act_update, self.act_delete] + self.actions = [self.act_check, self.act_update, self.act_delete, + action(self, "Phantom deps…", "view-list-details", SP.SP_FileDialogListView, + self.phantom)] + self.phantom_dialog = None self.no_dl = action(self, "No download", "network-offline", SP.SP_DriveNetIcon, checkable=True) self.no_dl.setToolTip('Update selected writes DOWNLOAD="no": slackrepo uses the source ' "already in its cache") @@ -212,6 +215,14 @@ class HintsTab(QWidget): self.start_requested.emit(["hint-update", *self.pairs()] + (["--no-dl"] if self.no_dl.isChecked() else [])) + def phantom(self): + if self.phantom_dialog is None: + self.phantom_dialog = d = PhantomDialog(self.remote, self) + d.apply_requested.connect(lambda: self.start_requested.emit(["fix-current"])) + d.finished.connect(lambda _r: setattr(self, "phantom_dialog", None)) + d.show() + self.phantom_dialog.raise_() + def confirm(self, title, text): return QMessageBox.question(self, title, text) == QMessageBox.StandardButton.Yes @@ -332,3 +343,99 @@ class HintResultDialog(QDialog): if pkgs: self.build_requested.emit(pkgs) self.accept() + + +class PhantomDialog(QDialog): + """The -current phantom deps: the list, suggestions from the tree, Apply = fix-current.""" + + apply_requested = pyqtSignal() + + def __init__(self, remote, parent=None): + super().__init__(parent) + self.remote = remote + self.setWindowTitle("Phantom deps: shipped by -current, DELREQUIREd from SBo packages") + self.resize(900, 600) + self.deps = QListWidget(selectionMode=QAbstractItemView.SelectionMode.ExtendedSelection) + self.name = QLineEdit(placeholderText="package name") + self.name.returnPressed.connect(self.add_name) + add = QPushButton("Add") + add.clicked.connect(self.add_name) + remove = QPushButton("Remove") + remove.clicked.connect(self.remove_selected) + self.suggestions = QListWidget() + self.suggestions.itemClicked.connect(lambda item: item.setCheckState( + Qt.CheckState.Unchecked if item.checkState() == Qt.CheckState.Checked else Qt.CheckState.Checked)) + add_ticked = QPushButton("Add ticked") + add_ticked.clicked.connect(self.add_ticked) + apply = QPushButton("Apply to hints", default=True) + apply.setToolTip("Start fix-current: the listed deps go into DELREQUIRES of the " + "packages that require them") + apply.clicked.connect(self.apply) + close = QPushButton("Close") + close.clicked.connect(self.accept) + + left = QVBoxLayout() + left.addWidget(QLabel("<b>Listed</b>")) + left.addWidget(self.deps) + left.addWidget(self.name) + row = QHBoxLayout() + row.addWidget(add) + row.addWidget(remove) + left.addLayout(row) + right = QVBoxLayout() + right.addWidget(QLabel("<b>Suggested</b>: required, but no package of the tree has them")) + right.addWidget(self.suggestions) + right.addWidget(add_ticked) + lists = QHBoxLayout() + lists.addLayout(left, 1) + lists.addLayout(right, 2) + bar = QHBoxLayout() + bar.addStretch() + bar.addWidget(close) + bar.addWidget(apply) + layout = QVBoxLayout(self) + layout.addLayout(lists, 1) + layout.addLayout(bar) + self.reload() + + def reload(self): + self.remote.call(self._loaded, "phantom-list") + + def _loaded(self, data, err): + if err: + QMessageBox.warning(self, "Phantom deps", err) + return + self.deps.clear() + self.deps.addItems(data["deps"]) + self.suggestions.clear() + for s in data["suggestions"]: + needed = s["needed_by"] + more = f" (+{len(needed) - 5})" if len(needed) > 5 else "" + item = QListWidgetItem(f"{s['name']} needed by {', '.join(needed[:5])}{more}") + item.setData(Qt.ItemDataRole.UserRole, s["name"]) + item.setToolTip(", ".join(needed)) + item.setFlags(Qt.ItemFlag.ItemIsEnabled) # the click handler toggles: no double toggle + item.setCheckState(Qt.CheckState.Unchecked) + self.suggestions.addItem(item) + + def _change(self, cmd, names): + if names: + self.remote.call(lambda _d, err: self._loaded(None, err) if err else self.reload(), + cmd, *names) + + def add_name(self): + name = self.name.text().strip() + self.name.clear() + self._change("phantom-add", [name] if name else []) + + def add_ticked(self): + self._change("phantom-add", [ + self.suggestions.item(i).data(Qt.ItemDataRole.UserRole) for i in range(self.suggestions.count()) + if self.suggestions.item(i).checkState() == Qt.CheckState.Checked]) + + def remove_selected(self): + self._change("phantom-remove", [i.text() for i in self.deps.selectedItems()]) + + def apply(self): + self.apply_requested.emit() + self.accept() |
