From 5aa424e155aa502746060585d73bacc1f31ac93d Mon Sep 17 00:00:00 2001 From: Antti Soininen Date: Tue, 12 Nov 2024 16:28:23 +0200 Subject: [PATCH] Remove the Filter action from DB editor This removes the Filter icon, the associated QAction and all related code from DB editor. The action was redundant and didn't work very well. --- CHANGELOG.md | 3 + .../spine_db_editor/widgets/toolbar.py | 175 +----------------- tests/spine_db_editor/widgets/test_toolbar.py | 4 +- 3 files changed, 7 insertions(+), 175 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 878967878..72f81f097 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.1.0/) ### Removed +- The Filter button has been removed from Spine Database Editor's toolbar. + The functionality was broken anyhow and has been superseded by filtering from the Scenario tree. + ### Fixed ### Security diff --git a/spinetoolbox/spine_db_editor/widgets/toolbar.py b/spinetoolbox/spine_db_editor/widgets/toolbar.py index 4341f451e..087973275 100644 --- a/spinetoolbox/spine_db_editor/widgets/toolbar.py +++ b/spinetoolbox/spine_db_editor/widgets/toolbar.py @@ -11,30 +11,9 @@ ###################################################################################################################### """Contains the DBEditorToolBar class and helpers.""" -from PySide6.QtCore import QSize, Qt, Signal, Slot +from PySide6.QtCore import QSize, Qt from PySide6.QtGui import QAction, QIcon, QKeySequence, QTextCursor -from PySide6.QtWidgets import ( - QDialog, - QDialogButtonBox, - QHBoxLayout, - QLabel, - QSizePolicy, - QTextEdit, - QToolBar, - QToolButton, - QTreeWidget, - QTreeWidgetItem, - QVBoxLayout, - QWidget, -) -from spinedb_api.filters.tools import ( - SCENARIO_FILTER_TYPE, - append_filter_config, - clear_filter_configs, - filter_config, - filter_configs, - name_from_dict, -) +from PySide6.QtWidgets import QDialog, QSizePolicy, QTextEdit, QToolBar, QToolButton, QVBoxLayout, QWidget from spinetoolbox.helpers import CharIconEngine, add_keyboard_shortcut_to_tool_tip, plain_to_rich @@ -54,8 +33,6 @@ def __init__(self, db_editor): self.show_toolbox_action.setShortcut(QKeySequence(Qt.Modifier.CTRL | Qt.Key.Key_Escape)) self.show_toolbox_action.setToolTip(plain_to_rich("Show Spine Toolbox window")) add_keyboard_shortcut_to_tool_tip(self.show_toolbox_action) - self._filter_action = QAction(QIcon(CharIconEngine("\uf0b0")), "Filter") - self._filter_action.setToolTip(plain_to_rich("Set DB API level scenario filters")) self.show_url_action = QAction(QIcon(CharIconEngine("\uf550")), "Show URLs") self.show_url_action.setToolTip(plain_to_rich("Show URLs of currently databases in the session")) self._add_actions() @@ -91,7 +68,6 @@ def _add_actions(self): self.addWidget(spacer) self.addSeparator() self.create_button_for_action(self.show_url_action) - self.create_button_for_action(self._filter_action) self.addSeparator() self.create_button_for_action(self.show_toolbox_action) @@ -100,7 +76,6 @@ def _connect_signals(self): self.reload_action.triggered.connect(self._db_editor.refresh_session) self.reset_docks_action.triggered.connect(self._db_editor.reset_docks) self.show_url_action.triggered.connect(self._show_url_codename_widget) - self._filter_action.triggered.connect(self._show_filter_menu) def create_button_for_action(self, action): """Creates a button for the given action and adds it to the widget""" @@ -115,152 +90,6 @@ def _show_url_codename_widget(self): dialog = _URLDialog(self._db_editor.db_urls, self._db_editor.db_mngr.name_registry, self) dialog.show() - @Slot(bool) - def _show_filter_menu(self, _checked=False): - """Shows the filter menu""" - dialog = _UrlFilterDialog(self._db_editor.db_mngr, self._db_editor.db_maps, parent=self) - dialog.show() - dialog.filter_accepted.connect(self._db_editor.load_db_urls) - dialog.filter_accepted.connect(self.set_filter_action_icon_color) - - def set_filter_action_icon_color(self, codenames): - filtered = any(filter_configs(url) for url in codenames.keys()) - color = Qt.magenta if filtered else None - self._filter_action.setIcon(QIcon(CharIconEngine("\uf0b0", color=color))) - - -class _FilterWidget(QTreeWidget): - def __init__(self, db_mngr, db_map, item_type, filter_type, active_item, parent=None): - super().__init__(parent=parent) - self._filter_type = filter_type - self.setIndentation(0) - self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) - self.setHeaderLabel(filter_type) - items = db_mngr.get_items(db_map, item_type) - top_level_items = [QTreeWidgetItem([x["name"]]) for x in items] - self.addTopLevelItems(top_level_items) - self.resizeColumnToContents(0) - current = next(iter(item for item in top_level_items if item.text(0) == active_item), None) - if current is not None: - self.setCurrentItem(current) - - def sizeHint(self): - size = super().sizeHint() - size.setWidth(self.header().sectionSize(0) + self.frameWidth() * 2 + 2) - return size - - def filter_config(self): - selected = self.selectedItems() - if not selected: - return {} - return filter_config(self._filter_type, selected[0].text(0)) - - -class _FilterArrayWidget(QWidget): - filter_selection_changed = Signal() - - def __init__(self, db_mngr, db_map, parent=None): - super().__init__(parent=parent) - layout = QHBoxLayout(self) - self._offset = 0 - self._db_mngr = db_mngr - self._db_map = db_map - self._filter_widgets = [] - active_filter_configs = {cfg["type"]: cfg for cfg in filter_configs(db_map.db_url)} - for item_type, filter_type in (("scenario", SCENARIO_FILTER_TYPE),): - active_cfg = active_filter_configs.get(filter_type, {}) - active_item = name_from_dict(active_cfg) if active_cfg else None - filter_widget = _FilterWidget(db_mngr, db_map, item_type, filter_type, active_item, parent=self) - layout.addWidget(filter_widget) - self._filter_widgets.append(filter_widget) - filter_widget.itemSelectionChanged.connect(self.filter_selection_changed) - - def filtered_url_codename(self): - url = clear_filter_configs(self._db_map.db_url) - for filter_widget in self._filter_widgets: - filter_config_ = filter_widget.filter_config() - if not filter_config_: - continue - url = append_filter_config(url, filter_config_) - return url, self._db_mngr.name_registry.display_name(self._db_map.sa_url) - - def sizeHint(self): - size = super().sizeHint() - size.setWidth(size.width() - self._offset) - return size - - def moveEvent(self, ev): - if ev.pos().x() > 0: - margin = 2 - self._offset = ev.pos().x() - margin - self.move(margin, ev.pos().y()) - self.adjustSize() - return - super().moveEvent(ev) - - -class _DBListWidget(QTreeWidget): - db_filter_selection_changed = Signal() - - def __init__(self, db_mngr, db_maps, parent=None): - super().__init__(parent=parent) - self.header().hide() - self._filter_arrays = [] - for db_map in db_maps: - top_level_item = QTreeWidgetItem([db_mngr.name_registry.display_name(db_map.sa_url)]) - self.addTopLevelItem(top_level_item) - child = QTreeWidgetItem() - top_level_item.addChild(child) - filter_array = _FilterArrayWidget(db_mngr, db_map, parent=self) - self.setItemWidget(child, 0, filter_array) - self._filter_arrays.append(filter_array) - top_level_item.setExpanded(True) - filter_array.filter_selection_changed.connect(self.db_filter_selection_changed) - self.resizeColumnToContents(0) - self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) - - def sizeHint(self): - size = super().sizeHint() - last = self.topLevelItem(self.topLevelItemCount() - 1) - last_child = self.itemBelow(last) - rect = self.visualItemRect(last_child) - size.setWidth(rect.right() + 2 * self.frameWidth() + 2) - size.setHeight(rect.bottom() + 2 * self.frameWidth() + 2) - return size - - def filtered_url_codenames(self): - return dict(filter_array.filtered_url_codename() for filter_array in self._filter_arrays) - - -class _UrlFilterDialog(QDialog): - filter_accepted = Signal(dict) - - def __init__(self, db_mngr, db_maps, parent=None): - super().__init__(parent=parent, f=Qt.Popup) - outer_layout = QVBoxLayout(self) - button_box = QDialogButtonBox(self) - self._filter_button = button_box.addButton("Update filters", QDialogButtonBox.ButtonRole.AcceptRole) - self._db_list = _DBListWidget(db_mngr, db_maps, parent=self) - self._orig_filtered_url_codenames = self._db_list.filtered_url_codenames() - self._update_filter_enabled() - outer_layout.addWidget(QLabel("Select URL filters")) - outer_layout.addWidget(self._db_list) - outer_layout.addWidget(button_box) - button_box.accepted.connect(self.accept) - self._db_list.db_filter_selection_changed.connect(self._update_filter_enabled) - self.adjustSize() - - def sizeHint(self): - size = super().sizeHint() - return size - - def _update_filter_enabled(self): - self._filter_button.setEnabled(self._orig_filtered_url_codenames != self._db_list.filtered_url_codenames()) - - def accept(self): - super().accept() - self.filter_accepted.emit(self._db_list.filtered_url_codenames()) - class _URLDialog(QDialog): """Class for showing URLs and database names in the editor""" diff --git a/tests/spine_db_editor/widgets/test_toolbar.py b/tests/spine_db_editor/widgets/test_toolbar.py index 1fb920468..b76ab0ba0 100644 --- a/tests/spine_db_editor/widgets/test_toolbar.py +++ b/tests/spine_db_editor/widgets/test_toolbar.py @@ -33,7 +33,7 @@ def test_toolbar(self): self.db_mngr.setParent(self._toolbox) tb = DBEditorToolBar(self.spine_db_editor) self.assertEqual([{"database": "sqlite://"}], self.spine_db_editor._history) - with mock.patch("spinetoolbox.spine_db_editor.widgets.toolbar._UrlFilterDialog.show") as mock_show_dialog: + with mock.patch("spinetoolbox.spine_db_editor.widgets.toolbar._URLDialog.show") as mock_show_dialog: mock_show_dialog.show.return_value = True - tb._show_filter_menu() + tb._show_url_codename_widget() mock_show_dialog.assert_called()