From 77ac3ea8c1f365cf7d4691c7580d64d0e7c7c720 Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Tue, 20 Oct 2026 12:35:36 +0200 Subject: Packages: fix segfault on Clear / Select visible behind a filter Both emitted layoutChanged without layoutAboutToBeChanged; with a filter on and a current row, the proxy kept stale persistent indexes and Qt crashed (Ctrl+Shift+A with orphaned + cat:games closed the app). Only check states change, so the model now emits dataChanged on the box column. The new test segfaults on the old code. Co-Authored-By: Claude Opus 5.5 --- sb_builder/packages.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'sb_builder') diff --git a/sb_builder/packages.py b/sb_builder/packages.py index ab6f3ce..68de7c2 100644 --- a/sb_builder/packages.py +++ b/sb_builder/packages.py @@ -112,6 +112,16 @@ class Model(QAbstractTableModel): self.checked &= names self.endResetModel() + def boxes_changed(self): + """Only check states changed: dataChanged on the box column (count follows). + + Not layoutChanged: emitted without layoutAboutToBeChanged it leaves the + filtering proxy with stale persistent indexes, and Qt segfaults. + """ + if self.rows: + self.dataChanged.emit(self.index(0, 0), self.index(len(self.rows) - 1, 0), + [Qt.ItemDataRole.CheckStateRole]) + def rowCount(self, parent=QModelIndex()): return 0 if parent.isValid() else len(self.rows) @@ -337,13 +347,11 @@ class PackagesTab(QWidget): def select_visible(self): for i in range(self.proxy.rowCount()): self.model.checked.add(self.proxy.index(i, 0).data(Qt.ItemDataRole.UserRole)["name"]) - self.model.layoutChanged.emit() - self.update_count() + self.model.boxes_changed() def clear(self): self.model.checked.clear() - self.model.layoutChanged.emit() - self.update_count() + self.model.boxes_changed() def targets(self): """Ticked packages, sorted; the highlighted row alone is not a target.""" -- cgit v1.2.3