Skip to content

Commit

Permalink
Fix mass select items dialog, add "Select structural items" button
Browse files Browse the repository at this point in the history
  • Loading branch information
soininen committed Aug 12, 2024
1 parent 41790c3 commit 0c1d271
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 85 deletions.
60 changes: 33 additions & 27 deletions spinetoolbox/ui/select_database_items.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
################################################################################
## Form generated from reading UI file 'select_database_items.ui'
##
## Created by: Qt User Interface Compiler version 6.5.2
## Created by: Qt User Interface Compiler version 6.6.3
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################
Expand All @@ -34,7 +34,7 @@ class Ui_Form(object):
def setupUi(self, Form):
if not Form.objectName():
Form.setObjectName(u"Form")
Form.resize(409, 300)
Form.resize(458, 300)
self.verticalLayout = QVBoxLayout(Form)
self.verticalLayout.setObjectName(u"verticalLayout")
self.groupBox = QGroupBox(Form)
Expand All @@ -46,13 +46,27 @@ def setupUi(self, Form):

self.verticalLayout_2.addLayout(self.item_grid_layout)

self.horizontalLayout = QHBoxLayout()
self.horizontalLayout.setObjectName(u"horizontalLayout")
self.horizontalLayout_2 = QHBoxLayout()
self.horizontalLayout_2.setObjectName(u"horizontalLayout_2")
self.select_all_button = QPushButton(self.groupBox)
self.select_all_button.setObjectName(u"select_all_button")

self.horizontalLayout.addWidget(self.select_all_button)
self.horizontalLayout_2.addWidget(self.select_all_button)

self.deselect_all_button = QPushButton(self.groupBox)
self.deselect_all_button.setObjectName(u"deselect_all_button")

self.horizontalLayout_2.addWidget(self.deselect_all_button)

self.horizontalSpacer_2 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)

self.horizontalLayout_2.addItem(self.horizontalSpacer_2)


self.verticalLayout_2.addLayout(self.horizontalLayout_2)

self.horizontalLayout = QHBoxLayout()
self.horizontalLayout.setObjectName(u"horizontalLayout")
self.select_data_items_button = QPushButton(self.groupBox)
self.select_data_items_button.setObjectName(u"select_data_items_button")

Expand All @@ -63,26 +77,17 @@ def setupUi(self, Form):

self.horizontalLayout.addWidget(self.select_scenario_items_button)

self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)

self.horizontalLayout.addItem(self.horizontalSpacer)


self.verticalLayout_2.addLayout(self.horizontalLayout)

self.horizontalLayout_2 = QHBoxLayout()
self.horizontalLayout_2.setObjectName(u"horizontalLayout_2")
self.deselect_all_button = QPushButton(self.groupBox)
self.deselect_all_button.setObjectName(u"deselect_all_button")
self.select_structural_items_button = QPushButton(self.groupBox)
self.select_structural_items_button.setObjectName(u"select_structural_items_button")

self.horizontalLayout_2.addWidget(self.deselect_all_button)
self.horizontalLayout.addWidget(self.select_structural_items_button)

self.horizontalSpacer_2 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)

self.horizontalLayout_2.addItem(self.horizontalSpacer_2)
self.horizontalLayout.addItem(self.horizontalSpacer)


self.verticalLayout_2.addLayout(self.horizontalLayout_2)
self.verticalLayout_2.addLayout(self.horizontalLayout)


self.verticalLayout.addWidget(self.groupBox)
Expand All @@ -99,18 +104,19 @@ def retranslateUi(self, Form):
#if QT_CONFIG(tooltip)
self.select_all_button.setToolTip(QCoreApplication.translate("Form", u"Selects all items.", None))
#endif // QT_CONFIG(tooltip)
self.select_all_button.setText(QCoreApplication.translate("Form", u"Select all", None))
self.select_all_button.setText(QCoreApplication.translate("Form", u"Select &all", None))
#if QT_CONFIG(tooltip)
self.select_data_items_button.setToolTip(QCoreApplication.translate("Form", u"Selects the entity and parameter value items.", None))
self.deselect_all_button.setToolTip(QCoreApplication.translate("Form", u"Deselects all items.", None))
#endif // QT_CONFIG(tooltip)
self.select_data_items_button.setText(QCoreApplication.translate("Form", u"Select entity and value items", None))
self.deselect_all_button.setText(QCoreApplication.translate("Form", u"&Deselect all", None))
#if QT_CONFIG(tooltip)
self.select_scenario_items_button.setToolTip(QCoreApplication.translate("Form", u"Selects the scenario and alternative items.", None))
self.select_data_items_button.setToolTip(QCoreApplication.translate("Form", u"Selects the entity and parameter value items.", None))
#endif // QT_CONFIG(tooltip)
self.select_scenario_items_button.setText(QCoreApplication.translate("Form", u"Select scenario items", None))
self.select_data_items_button.setText(QCoreApplication.translate("Form", u"Select &entity and value items", None))
#if QT_CONFIG(tooltip)
self.deselect_all_button.setToolTip(QCoreApplication.translate("Form", u"Deselects all items.", None))
self.select_scenario_items_button.setToolTip(QCoreApplication.translate("Form", u"Selects the scenario and alternative items.", None))
#endif // QT_CONFIG(tooltip)
self.deselect_all_button.setText(QCoreApplication.translate("Form", u"Deselect all", None))
self.select_scenario_items_button.setText(QCoreApplication.translate("Form", u"Select &scenario items", None))
self.select_structural_items_button.setText(QCoreApplication.translate("Form", u"Select s&tructural items", None))
# retranslateUi

52 changes: 30 additions & 22 deletions spinetoolbox/ui/select_database_items.ui
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<!--
######################################################################################################################
# Copyright (C) 2017-2022 Spine project consortium
# Copyright Spine Toolbox contributors
# This file is part of Spine Toolbox.
# Spine Toolbox is free software: you can redistribute it and\/or modify it under the terms of the GNU Lesser General
# Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option)
Expand All @@ -18,7 +19,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>409</width>
<width>458</width>
<height>300</height>
</rect>
</property>
Expand All @@ -36,39 +37,29 @@
<layout class="QGridLayout" name="item_grid_layout"/>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QPushButton" name="select_all_button">
<property name="toolTip">
<string>Selects all items.</string>
</property>
<property name="text">
<string>Select all</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="select_data_items_button">
<property name="toolTip">
<string>Selects the entity and parameter value items.</string>
</property>
<property name="text">
<string>Select entity and value items</string>
<string>Select &amp;all</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="select_scenario_items_button">
<widget class="QPushButton" name="deselect_all_button">
<property name="toolTip">
<string>Selects the scenario and alternative items.</string>
<string>Deselects all items.</string>
</property>
<property name="text">
<string>Select scenario items</string>
<string>&amp;Deselect all</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
Expand All @@ -83,19 +74,36 @@
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="deselect_all_button">
<widget class="QPushButton" name="select_data_items_button">
<property name="toolTip">
<string>Deselects all items.</string>
<string>Selects the entity and parameter value items.</string>
</property>
<property name="text">
<string>Deselect all</string>
<string>Select &amp;entity and value items</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<widget class="QPushButton" name="select_scenario_items_button">
<property name="toolTip">
<string>Selects the scenario and alternative items.</string>
</property>
<property name="text">
<string>Select &amp;scenario items</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="select_structural_items_button">
<property name="text">
<string>Select s&amp;tructural items</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
Expand Down
23 changes: 21 additions & 2 deletions spinetoolbox/widgets/select_database_items.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from PySide6.QtCore import Signal, Slot
from PySide6.QtWidgets import QCheckBox, QWidget
from spinedb_api.db_mapping import DatabaseMapping
from spinedb_api.mapped_items import item_factory


def add_check_boxes(check_boxes, checked_states, select_all_button, deselect_all_button, state_changed_slot, layout):
Expand Down Expand Up @@ -60,8 +61,19 @@ class SelectDatabaseItems(QWidget):
"parameter_value",
"entity_metadata",
"parameter_value_metadata",
"metadata",
)
_SCENARIO_ITEMS = ("alternative", "scenario", "scenario_alternative", "entity_alternative")
_STRUCTURAL_ITEMS = (
"entity_class",
"entity_class_display_mode",
"display_mode__entity_class",
"superclass_subclass",
"parameter_value_list",
"list_value",
"parameter_definition",
"parameter_type",
)
_SCENARIO_ITEMS = ("alternative", "scenario", "scenario_alternative")

def __init__(self, checked_states=None, parent=None):
"""
Expand All @@ -76,8 +88,9 @@ def __init__(self, checked_states=None, parent=None):
self._ui.setupUi(self)
self._ui.select_data_items_button.clicked.connect(self._select_data_items)
self._ui.select_scenario_items_button.clicked.connect(self._select_scenario_items)
self._ui.select_structural_items_button.clicked.connect(self._select_structural_items)
checkable_item_types = tuple(
type_ for type_ in DatabaseMapping.item_types() if type_ not in ("commit", "parameter_type")
type_ for type_ in DatabaseMapping.item_types() if not item_factory(type_).is_protected
)
checked_states = (
checked_states if checked_states is not None else {item: False for item in checkable_item_types}
Expand Down Expand Up @@ -129,3 +142,9 @@ def _select_scenario_items(self, _=False):
"""Checks all scenario items."""
for item_name in self._SCENARIO_ITEMS:
self._item_check_boxes[item_name].setChecked(True)

@Slot(bool)
def _select_structural_items(self, _=False):
"""Checks all structural items."""
for item_name in self._STRUCTURAL_ITEMS:
self._item_check_boxes[item_name].setChecked(True)
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ def test_stored_state(self):
"entity_alternative": False,
"entity_class": True,
"parameter_definition": False,
"parameter_type": False,
"parameter_value": False,
"parameter_value_list": False,
"parameter_value_metadata": False,
Expand Down
74 changes: 40 additions & 34 deletions tests/widgets/test_select_database_items.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
from contextlib import contextmanager
import unittest
from PySide6.QtWidgets import QApplication
from spinedb_api import DatabaseMapping
from spinedb_api.mapped_items import item_factory
from spinetoolbox.widgets.select_database_items import SelectDatabaseItems


Expand All @@ -22,31 +24,13 @@ def setUpClass(cls):
if not QApplication.instance():
QApplication()

ITEMS = tuple(type_ for type_ in DatabaseMapping.item_types() if not item_factory(type_).is_protected)

def test_restore_previously_checked_states(self):
stored_states = {"feature": True, "entity": True}
stored_states = {"alternative": True, "entity": True}
with _select_database_items(stored_states) as widget:
self.assertEqual(
widget.checked_states(),
{
"alternative": False,
"entity_group": False,
"entity_metadata": False,
"list_value": False,
"metadata": False,
"entity": True,
"entity_class": False,
"superclass_subclass": False,
"entity_alternative": False,
"parameter_definition": False,
"parameter_value": False,
"parameter_value_list": False,
"parameter_value_metadata": False,
"scenario": False,
"scenario_alternative": False,
"entity_class_display_mode": False,
"display_mode__entity_class": False,
},
)
expected = {**{item: False for item in self.ITEMS}, **stored_states}
self.assertEqual(widget.checked_states(), expected)

def test_any_checked(self):
with _select_database_items(None) as widget:
Expand All @@ -55,22 +39,44 @@ def test_any_checked(self):
self.assertTrue(widget.any_checked())

def test_any_structural_item_checked(self):
stored_states = {
"object": True,
"relationship": True,
"entity_group": True,
"parameter_value": True,
"entity_metadata": True,
"parameter_value_metadata": True,
"scenario": True,
"alternative": True,
"scenario_alternative": True,
}
stored_states = {item: True for item in SelectDatabaseItems._DATA_ITEMS + SelectDatabaseItems._SCENARIO_ITEMS}
with _select_database_items(stored_states) as widget:
self.assertFalse(widget.any_structural_item_checked())
widget._item_check_boxes["list_value"].click()
self.assertTrue(widget.any_structural_item_checked())

def test_select_data_items(self):
with _select_database_items({}) as widget:
widget._ui.select_data_items_button.click()
expected = {item: item in SelectDatabaseItems._DATA_ITEMS for item in self.ITEMS}
self.assertEqual(widget.checked_states(), expected)

def test_select_scenario_items(self):
with _select_database_items({}) as widget:
widget._ui.select_scenario_items_button.click()
expected = {item: item in SelectDatabaseItems._SCENARIO_ITEMS for item in self.ITEMS}
self.assertEqual(widget.checked_states(), expected)

def test_select_structural_items(self):
with _select_database_items({}) as widget:
widget._ui.select_structural_items_button.click()
expected = {item: item in SelectDatabaseItems._STRUCTURAL_ITEMS for item in self.ITEMS}
self.assertEqual(widget.checked_states(), expected)

def test_items_in_some_category(self):
self.assertEqual(
set(self.ITEMS)
- set(SelectDatabaseItems._DATA_ITEMS)
- set(SelectDatabaseItems._SCENARIO_ITEMS)
- set(SelectDatabaseItems._STRUCTURAL_ITEMS),
set(),
)

def test_no_categories_overlap(self):
self.assertEqual(set(SelectDatabaseItems._DATA_ITEMS) & set(SelectDatabaseItems._SCENARIO_ITEMS), set())
self.assertEqual(set(SelectDatabaseItems._DATA_ITEMS) & set(SelectDatabaseItems._STRUCTURAL_ITEMS), set())
self.assertEqual(set(SelectDatabaseItems._SCENARIO_ITEMS) & set(SelectDatabaseItems._STRUCTURAL_ITEMS), set())


@contextmanager
def _select_database_items(checked_states):
Expand Down

0 comments on commit 0c1d271

Please sign in to comment.