Skip to content

Commit

Permalink
Remove the Filter action from DB editor (#3007)
Browse files Browse the repository at this point in the history
  • Loading branch information
soininen authored Nov 12, 2024
2 parents 9a5c21b + 5aa424e commit aa5c7bb
Show file tree
Hide file tree
Showing 3 changed files with 7 additions and 175 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
175 changes: 2 additions & 173 deletions spinetoolbox/spine_db_editor/widgets/toolbar.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand All @@ -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()
Expand Down Expand Up @@ -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)

Expand All @@ -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"""
Expand All @@ -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"""
Expand Down
4 changes: 2 additions & 2 deletions tests/spine_db_editor/widgets/test_toolbar.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()

0 comments on commit aa5c7bb

Please sign in to comment.