Source code for spinetoolbox.project_items.exporter.widgets.parameter_merging_settings_window

######################################################################################################################
# Copyright (C) 2017-2020 Spine project consortium
# 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)
# any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
# Public License for more details. You should have received a copy of the GNU Lesser General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
######################################################################################################################

"""
Parameter merging settings window.

:author: A. Soininen (VTT)
:date:   19.2.2020
"""

from PySide2.QtCore import Qt, Signal, Slot
from PySide2.QtWidgets import QMessageBox, QWidget
from spinedb_api import DatabaseMapping
from .merging_error_flag import MergingErrorFlag
from .parameter_merging_settings import ParameterMergingSettings


[docs]class ParameterMergingSettingsWindow(QWidget): """A window which shows a list of ParameterMergingSettings widgets, one for each merged parameter."""
[docs] settings_approved = Signal()
"""Emitted when the settings have been approved."""
[docs] settings_rejected = Signal()
"""Emitted when the settings have been rejected.""" def __init__(self, merging_settings, database_path, parent): """ Args: merging_settings (dict): a map from merged parameter name to merging settings database_path (str): database URL parent (QWidget): a parent widget """ from ..ui.parameter_merging_settings_window import Ui_Form # pylint: disable=import-outside-toplevel super().__init__(parent, f=Qt.Window) self._merging_settings = merging_settings self._entity_class_infos = None self._database_url = database_path self._ui = Ui_Form() self._ui.setupUi(self) self.setWindowTitle(f"Gdx Parameter Merging Settings -- {database_path} --") self._setting_widgets = list() for parameter_name, setting in merging_settings.items(): self._add_setting(parameter_name, setting) self._ui.button_box.accepted.connect(self._collect_and_hide) self._ui.button_box.rejected.connect(self._reject_and_close) self._ui.add_button.clicked.connect(self._add_empty_setting) @property
[docs] def merging_settings(self): """a dict that maps merged parameter names to their merging settings""" return self._merging_settings
[docs] def update(self): """Updates the settings according to changes in the database.""" db_map = DatabaseMapping(self._database_url) try: self._entity_class_infos = _gather_entity_class_infos(db_map) finally: db_map.connection.close() for settings_widget in self._setting_widgets: settings_widget.update(self._entity_class_infos)
[docs] def _add_setting(self, parameter_name=None, merging_setting=None): """Inserts a new settings widget to the widget list.""" if self._entity_class_infos is None: db_map = DatabaseMapping(self._database_url) try: self._entity_class_infos = _gather_entity_class_infos(db_map) finally: db_map.connection.close() settings_widget = ParameterMergingSettings(self._entity_class_infos, self, parameter_name, merging_setting) settings_widget.removal_requested.connect(self._remove_setting) self._ui.settings_area_layout.insertWidget(0, settings_widget) self._setting_widgets.append(settings_widget)
[docs] def _ok_to_accept(self): """Returns True if it is OK to accept the settings, otherwise shows a warning dialog and returns False.""" for settings_widget in self._setting_widgets: flags = settings_widget.error_flags if flags & MergingErrorFlag.PARAMETER_NAME_MISSING: self._ui.setting_area.ensureWidgetVisible(settings_widget) message = "Parameter name is missing." QMessageBox.warning(self, "Parameter Name Missing", message) return False if flags & MergingErrorFlag.DOMAIN_NAME_MISSING: self._ui.setting_area.ensureWidgetVisible(settings_widget) message = "Domain name is missing." QMessageBox.warning(self, "Domain Name Missing", message) return False if flags & MergingErrorFlag.NO_PARAMETER_SELECTED: self._ui.setting_area.ensureWidgetVisible(settings_widget) message = "No domain selected for parameter merging." QMessageBox.warning(self, "Domain Selection Missing", message) return False return True
@Slot(bool)
[docs] def _add_empty_setting(self, _): """Adds an empty settings widget to the widget list.""" self._add_setting()
@Slot(object)
[docs] def _remove_setting(self, settings_widget): """Removes a setting widget from the widget list.""" self._setting_widgets.remove(settings_widget) self._ui.settings_area_layout.removeWidget(settings_widget) settings_widget.deleteLater()
@Slot()
[docs] def _collect_and_hide(self): """Collects settings from individual ParameterMergingSettings widgets and hides the window.""" if not self._ok_to_accept(): return self._merging_settings = {widget.parameter_name: widget.merging_setting() for widget in self._setting_widgets} self.settings_approved.emit() self.hide()
@Slot()
[docs] def _reject_and_close(self): """Emits settings_rejected and closes the window.""" self.settings_rejected.emit() self.close()
[docs]class EntityClassInfo: """ Contains information of an entity_class (object or relationship_class) for use in the parameter merging widget. Attributes: name (str): entity's name class_id (int): entity's database id domain_names (list): object classes that index the entities in this class; for object classes this list contains the entity's name only, for relationship classes the list contains the relationship's object classes parameter_names (list): entity's defined parameters is_object_class (bool): True if the entity is a object_class, False if it is a relationship_class """ def __init__(self, name, class_id, domain_names, parameter_names, is_object_class): """ Args: name (str): entity's name class_id (int): entity's database id domain_names (list): object classes that index the entities in this class; for object classes this list contains the entity's name only, for relationship classes the list contains the relationship's object classes parameter_names (list): entity's defined parameters is_object_class (bool): True if the entity is a object_class, False if it is a relationship_class """ self.name = name self.id = class_id self.is_object_class = is_object_class self.domain_names = domain_names self.parameter_names = parameter_names
[docs]def _gather_entity_class_infos(db_map): """ Collects entity_class infos from database. Args: db_map (spinedb_api.DatabaseMapping): a database map Returns: list: a list of EntityClassInfo objects """ infos = list() for object_class in db_map.object_class_list().all(): class_id = object_class.id parameter_definitions = db_map.parameter_definition_list(object_class_id=class_id).all() parameter_names = [definition.name for definition in parameter_definitions] infos.append( EntityClassInfo(object_class.name, class_id, [object_class.name], parameter_names, is_object_class=True) ) for relationship_class in db_map.wide_relationship_class_list().all(): class_id = relationship_class.id parameter_definitions = db_map.parameter_definition_list(relationship_class_id=class_id).all() parameter_names = [definition.name for definition in parameter_definitions] domain_names = relationship_class.object_class_name_list.split(",") infos.append( EntityClassInfo(relationship_class.name, class_id, domain_names, parameter_names, is_object_class=False) ) return infos