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()