Source code for widgets.parameter_value_editor

######################################################################################################################
# Copyright (C) 2017-2019 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/>.
######################################################################################################################

"""
An editor dialog for editing database (relationship) parameter values.

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

from enum import Enum
from PySide2.QtCore import Qt, Slot
from PySide2.QtWidgets import QDialog, QMessageBox
from spinedb_api import (
    DateTime,
    Duration,
    duration_to_relativedelta,
    from_database,
    ParameterValueFormatError,
    TimePattern,
    TimeSeriesFixedResolution,
    TimeSeriesVariableResolution,
    to_database,
)
from ui.parameter_value_editor import Ui_ParameterValueEditor
from widgets.duration_editor import DurationEditor
from widgets.datetime_editor import DatetimeEditor
from widgets.plain_parameter_value_editor import PlainParameterValueEditor
from widgets.time_pattern_editor import TimePatternEditor
from widgets.time_series_fixed_resolution_editor import TimeSeriesFixedResolutionEditor
from widgets.time_series_variable_resolution_editor import TimeSeriesVariableResolutionEditor


[docs]class _Editor(Enum): """Indexes for the specialized editors corresponding to the selector combo box and editor stack."""
[docs] PLAIN_VALUE = 0
[docs] TIME_SERIES_FIXED_RESOLUTION = 1
[docs] TIME_SERIES_VARIABLE_RESOLUTION = 2
[docs] TIME_PATTERN = 3
[docs] DATETIME = 4
[docs] DURATION = 5
[docs]class ParameterValueEditor(QDialog): """ Dialog for editing (relationship) parameter values. The dialog takes the editable value from a parent model and shows a specialized editor corresponding to the value type in a stack widget. The user can change the value type by changing the specialized editor using a combo box. When the dialog is closed the value from the currently shown specialized editor is written back to the parent model. Attributes: parent_index (QModelIndex): an index to a parameter value in parent_model value_name (str): name of the value value: parameter value or None if it should be loaded from parent_index parent_widget (QWidget): a parent widget """ def __init__(self, parent_index, value_name="", value=None, parent_widget=None): super().__init__(parent_widget) self._parent_model = parent_index.model() self._parent_index = parent_index self._ui = Ui_ParameterValueEditor() self._ui.setupUi(self) self.setWindowTitle(value_name + " - Edit value") self.setWindowFlag(Qt.WindowMinMaxButtonsHint) self._ui.ok_button.clicked.connect(self.accept) self._ui.cancel_button.clicked.connect(self.reject) self._time_pattern_editor = TimePatternEditor() self._plain_value_editor = PlainParameterValueEditor() self._time_series_fixed_resolution_editor = TimeSeriesFixedResolutionEditor() self._time_series_variable_resolution_editor = TimeSeriesVariableResolutionEditor() self._datetime_editor = DatetimeEditor() self._duration_editor = DurationEditor() self._ui.editor_stack.addWidget(self._plain_value_editor) self._ui.editor_stack.addWidget(self._time_series_fixed_resolution_editor) self._ui.editor_stack.addWidget(self._time_series_variable_resolution_editor) self._ui.editor_stack.addWidget(self._time_pattern_editor) self._ui.editor_stack.addWidget(self._datetime_editor) self._ui.editor_stack.addWidget(self._duration_editor) self._ui.parameter_type_selector.activated.connect(self._change_parameter_type) if value is None: try: value = from_database(self._parent_model.data(parent_index, Qt.EditRole)) except ParameterValueFormatError as error: self._warn_and_select_default_view("Failed to load value: {}".format(error)) return self._select_editor(value) @Slot(name="accept")
[docs] def accept(self): """Saves the parameter value shown in the currently selected editor widget back to the parent model.""" editor = self._ui.editor_stack.currentWidget() try: self._parent_model.setData(self._parent_index, to_database(editor.value())) except ParameterValueFormatError as error: message_box = QMessageBox() message_box.setWindowTitle("Parameter value error") message_box.setText("Cannot set value: {}".format(error)) message_box.exec() return self.close()
@Slot(int, name="_change_parameter_type")
[docs] def _change_parameter_type(self, selector_index): """ Handles switching between value types. Does a rude conversion between fixed and variable resolution time series. In other cases, a default 'empty' value is used. Args: selector_index (int): an index to the selector combo box """ old_index = self._ui.editor_stack.currentIndex() if ( selector_index == _Editor.TIME_SERIES_VARIABLE_RESOLUTION.value and old_index == _Editor.TIME_SERIES_FIXED_RESOLUTION.value ): fixed_resolution_value = self._time_series_fixed_resolution_editor.value() stamps = fixed_resolution_value.indexes values = fixed_resolution_value.values variable_resolution_value = TimeSeriesVariableResolution( stamps, values, fixed_resolution_value.ignore_year, fixed_resolution_value.repeat ) self._time_series_variable_resolution_editor.set_value(variable_resolution_value) elif ( selector_index == _Editor.TIME_SERIES_FIXED_RESOLUTION and old_index == _Editor.TIME_SERIES_VARIABLE_RESOLUTION ): variable_resolution_value = self._time_series_variable_resolution_editor.value() stamps = variable_resolution_value.indexes start = stamps[0] difference = stamps[1] - start resolution = [duration_to_relativedelta(difference)] fixed_resolution_value = TimeSeriesFixedResolution( start, resolution, variable_resolution_value.values, variable_resolution_value.ignore_year, variable_resolution_value.repeat, ) self._time_series_fixed_resolution_editor.set_value(fixed_resolution_value) self._ui.editor_stack.setCurrentIndex(selector_index)
[docs] def _select_editor(self, value): """Shows the editor widget corresponding to the given value type on the editor stack.""" if isinstance(value, (int, float, bool)): self._ui.parameter_type_selector.setCurrentIndex(_Editor.PLAIN_VALUE.value) self._ui.editor_stack.setCurrentIndex(_Editor.PLAIN_VALUE.value) self._plain_value_editor.set_value(value) elif isinstance(value, TimeSeriesFixedResolution): self._ui.parameter_type_selector.setCurrentIndex(_Editor.TIME_SERIES_FIXED_RESOLUTION.value) self._ui.editor_stack.setCurrentIndex(_Editor.TIME_SERIES_FIXED_RESOLUTION.value) self._time_series_fixed_resolution_editor.set_value(value) elif isinstance(value, TimeSeriesVariableResolution): self._ui.parameter_type_selector.setCurrentIndex(_Editor.TIME_SERIES_VARIABLE_RESOLUTION.value) self._ui.editor_stack.setCurrentIndex(_Editor.TIME_SERIES_VARIABLE_RESOLUTION.value) self._time_series_variable_resolution_editor.set_value(value) elif isinstance(value, TimePattern): self._ui.parameter_type_selector.setCurrentIndex(_Editor.TIME_PATTERN.value) self._ui.editor_stack.setCurrentIndex(_Editor.TIME_PATTERN.value) self._time_pattern_editor.set_value(value) elif isinstance(value, DateTime): self._ui.parameter_type_selector.setCurrentIndex(_Editor.DATETIME.value) self._ui.editor_stack.setCurrentIndex(_Editor.DATETIME.value) self._datetime_editor.set_value(value) elif isinstance(value, Duration): self._ui.parameter_type_selector.setCurrentIndex(_Editor.DURATION.value) self._ui.editor_stack.setCurrentIndex(_Editor.DURATION.value) self._duration_editor.set_value(value) else: self._warn_and_select_default_view("Unknown parameter type. Opening an empty editor.")
[docs] def _warn_and_select_default_view(self, message): """Displays a warning dialog and opens the default editor widget after user clicks OK.""" message_box = QMessageBox() message_box.setWindowTitle("Warning") message_box.setText(message) message_box.exec() self._ui.parameter_type_selector.setCurrentIndex(_Editor.PLAIN_VALUE.value) self._ui.editor_stack.setCurrentIndex(_Editor.PLAIN_VALUE.value)