Source code for spinetoolbox.mvcmodels.time_pattern_model

######################################################################################################################
# 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)
# 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/>.
######################################################################################################################

"""A model for time patterns, used by the parameter_value editors."""
import numpy as np
from PySide6.QtCore import QModelIndex, Qt
from PySide6.QtWidgets import QMessageBox
from spinedb_api import TimePattern, ParameterValueFormatError
from .indexed_value_table_model import IndexedValueTableModel


[docs]class TimePatternModel(IndexedValueTableModel): """A model for time pattern type parameter values."""
[docs] def flags(self, index): """Returns flags at index.""" if not index.isValid(): return Qt.NoItemFlags return Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsEditable
[docs] def insertRows(self, row, count, parent=QModelIndex()): """ Inserts new time period - value pairs into the pattern. New time periods are initialized to empty strings and the corresponding values to zeros. Args: row (int): an index where to insert the new data count (int): number of time period - value pairs to insert parent (QModelIndex): an index to a parent model Returns: bool: True if the operation was successful """ self.beginInsertRows(parent, row, row + count - 1) old_indexes = self._value.indexes old_values = self._value.values new_indexes = list(old_indexes) for _ in range(count): new_indexes.insert(row, "") if row == len(old_values): new_values = np.append(old_values, np.zeros(count)) else: new_values = np.insert(old_values, row, np.zeros(count)) self._value = TimePattern(new_indexes, new_values) self.endInsertRows() return True
[docs] def removeRows(self, row, count, parent=QModelIndex()): """ Removes time period - value pairs from the pattern. Args: row (int): an index where to remove the data count (int): number of time period - value pairs to remove parent (QModelIndex): an index to a parent model Returns: bool: True if the operation was successful """ if len(self._value) == 1: return False if count == len(self._value): count = len(self._value) - 1 row = 1 self.beginRemoveRows(parent, row, row + count - 1) old_indexes = self._value.indexes old_values = self._value.values new_indexes = list(old_indexes) del new_indexes[row : row + count] remove_indexes = range(row, row + count) if count > 1 else row new_values = np.delete(old_values, remove_indexes) self._value = TimePattern(new_indexes, new_values) self.endRemoveRows() return True
[docs] def setData(self, index, value, role=Qt.ItemDataRole.EditRole): """ Sets a time period or a value in the pattern. Column index 0 corresponds to the time periods while 1 corresponds to the values. Args: index (QModelIndex): an index to the model value (str, float): a new time period or value role (int): a role Returns: bool: True if the operation was successful """ if not index.isValid() or role != Qt.ItemDataRole.EditRole: return False row = index.row() if row == len(self._value): self.insertRow(row) if index.column() == 0: try: self._value.indexes[row] = value except ParameterValueFormatError as error: QMessageBox.warning(self.parent(), "Error", str(error)) return False else: self._value.values[row] = value self.dataChanged.emit(index, index, [Qt.ItemDataRole.EditRole]) return True
[docs] def batch_set_data(self, indexes, values): """ Sets data for several indexes at once. Args: indexes (Sequence): a sequence of model indexes values (Sequence): a sequence of time periods/floats corresponding to the indexes """ modified_rows = list() modified_columns = list() for index, value in zip(indexes, values): row = index.row() modified_rows.append(row) column = index.column() modified_columns.append(column) if column == 0: self._value.indexes[row] = value else: self._value.values[row] = value left_top = self.index(min(modified_rows), min(modified_columns)) right_bottom = self.index(max(modified_rows), max(modified_columns)) self.dataChanged.emit(left_top, right_bottom, [Qt.ItemDataRole.EditRole])