From d864674a1f67ff8aba476d3a82be5c07b9c39e57 Mon Sep 17 00:00:00 2001 From: Vesna Tanko Date: Tue, 14 May 2024 19:31:00 +0200 Subject: [PATCH] ListViewFilter: Retain selection when filtering (#270) ListViewFilter: Retain selection when filtering --- orangewidget/utils/listview.py | 25 ++++++++++++++++++++++- orangewidget/utils/tests/test_listview.py | 15 ++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/orangewidget/utils/listview.py b/orangewidget/utils/listview.py index dda8e0836..3d9f43306 100644 --- a/orangewidget/utils/listview.py +++ b/orangewidget/utils/listview.py @@ -10,8 +10,11 @@ QSortFilterProxyModel, QItemSelection, QSize, + QItemSelectionModel, ) +from orangewidget.utils.itemmodels import signal_blocking + class ListViewFilter(QListView): """ @@ -27,6 +30,7 @@ def __init__( **kwargs ): super().__init__(*args, **kwargs) + self.__selection = QItemSelection() self.__search = QLineEdit(self, placeholderText="Filter...") self.__search.textEdited.connect(self.__on_text_edited) self.__preferred_size = preferred_size @@ -40,9 +44,28 @@ def __init__( assert isinstance(proxy, QSortFilterProxyModel) super().setModel(proxy) self.set_source_model(model) + self.selectionModel().selectionChanged.connect(self.__on_sel_changed) + + def __on_sel_changed( + self, + selected: QItemSelection, + deselected: QItemSelection + ): + selected = self.model().mapSelectionToSource(selected) + deselected = self.model().mapSelectionToSource(deselected) + self.__selection.merge(selected, QItemSelectionModel.Select) + self.__selection.merge(deselected, QItemSelectionModel.Deselect) + self.__select() def __on_text_edited(self, string: str): - self.model().setFilterFixedString(string) + with signal_blocking(self.selectionModel()): + self.model().setFilterFixedString(string) + self.__select() + + def __select(self): + selection = self.model().mapSelectionFromSource(self.__selection) + self.selectionModel().select(selection, + QItemSelectionModel.ClearAndSelect) def setModel(self, _): raise TypeError("The model cannot be changed. " diff --git a/orangewidget/utils/tests/test_listview.py b/orangewidget/utils/tests/test_listview.py index b43ef8340..aeb91730b 100644 --- a/orangewidget/utils/tests/test_listview.py +++ b/orangewidget/utils/tests/test_listview.py @@ -134,6 +134,21 @@ def test_set_proxy(self): def test_set_proxy_raises(self): self.assertRaises(Exception, ListViewFilter, proxy=PyListModel()) + def test_selection(self): + view = ListViewFilter() + view.model().setSourceModel(PyListModel(["one", "two", "three"])) + sel_model = view.selectionModel() + selected_row = 0 + index = view.model().index(selected_row, 0) + sel_model.select(index, sel_model.ClearAndSelect) + self.assertEqual(sel_model.selectedRows(0)[0].row(), selected_row) + + view._ListViewFilter__search.textEdited.emit("two") + self.assertEqual(len(sel_model.selectedRows(0)), 0) + + view._ListViewFilter__search.textEdited.emit("") + self.assertEqual(sel_model.selectedRows(0)[0].row(), selected_row) + if __name__ == "__main__": unittest.main()