diff --git a/CHANGELOG.md b/CHANGELOG.md
index cf457c700..5a01fee99 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -46,6 +46,7 @@ Many parts of the Spine data structure have been redesigned.
- You can now select a different Julia executable & project or Julia kernel for each Tool spec.
This overrides the global setting from Toolbox Settings.
- Headless mode now supports remote execution (see 'python -m spinetoolbox --help')
+- Commit Viewer's UI has undergone some redesigning and can now handle large databases.
### Deprecated
diff --git a/benchmarks/db_mngr_get_value.py b/benchmarks/db_mngr_get_value.py
index c3d020c29..15e23bc57 100644
--- a/benchmarks/db_mngr_get_value.py
+++ b/benchmarks/db_mngr_get_value.py
@@ -4,6 +4,8 @@
import os
import sys
+from spinedb_api.db_mapping_base import PublicItem
+
if sys.platform == "win32" and "HOMEPATH" not in os.environ:
import pathlib
os.environ["HOMEPATH"] = str(pathlib.Path(sys.executable).parent)
@@ -15,18 +17,17 @@
from PySide6.QtWidgets import QApplication
from spinetoolbox.spine_db_manager import SpineDBManager
from spinedb_api import DatabaseMapping, to_database
-from spinedb_api.temp_id import TempId
from benchmarks.utils import StdOutLogger
def db_mngr_get_value(
- loops: int, db_mngr: SpineDBManager, db_map: DatabaseMapping, ids: Sequence[TempId], role: Qt.ItemDataRole
+ loops: int, db_mngr: SpineDBManager, db_map: DatabaseMapping, items: Sequence[PublicItem], role: Qt.ItemDataRole
) -> float:
duration = 0.0
for _ in range(loops):
- for id_ in ids:
+ for item in items:
start = time.perf_counter()
- db_mngr.get_value(db_map, "parameter_value", id_, role)
+ db_mngr.get_value(db_map, item, role)
duration += time.perf_counter() - start
return duration
@@ -40,7 +41,7 @@ def run_benchmark(output_file: Optional[str]):
db_map.add_entity_class_item(name="Object")
db_map.add_parameter_definition_item(name="x", entity_class_name="Object")
db_map.add_entity_item(name="object", entity_class_name="Object")
- value_ids = []
+ value_items = []
for i in range(100):
alternative_name = str(i)
db_map.add_alternative_item(name=str(i))
@@ -54,16 +55,16 @@ def run_benchmark(output_file: Optional[str]):
type=value_type,
)
assert error is None
- value_ids.append(item["id"])
+ value_items.append(item)
runner = pyperf.Runner()
benchmark = runner.bench_time_func(
"SpineDatabaseManager.get_value[parameter_value, DisplayRole]",
db_mngr_get_value,
db_mngr,
db_map,
- value_ids,
+ value_items,
Qt.ItemDataRole.DisplayRole,
- inner_loops=len(value_ids),
+ inner_loops=len(value_items),
)
if output_file:
pyperf.add_runs(output_file, benchmark)
diff --git a/spinetoolbox/spine_db_editor/mvcmodels/parameter_value_list_item.py b/spinetoolbox/spine_db_editor/mvcmodels/parameter_value_list_item.py
index d6fa065a2..03ae1dbfc 100644
--- a/spinetoolbox/spine_db_editor/mvcmodels/parameter_value_list_item.py
+++ b/spinetoolbox/spine_db_editor/mvcmodels/parameter_value_list_item.py
@@ -104,7 +104,8 @@ def data(self, column, role=Qt.ItemDataRole.DisplayRole):
if role == Qt.ItemDataRole.DisplayRole and not self.id:
return "Enter new list value here..."
if role in (Qt.ItemDataRole.DisplayRole, Qt.ItemDataRole.EditRole, Qt.ItemDataRole.ToolTipRole, PARSED_ROLE):
- return self.db_mngr.get_value(self.db_map, self.item_type, self.id, role=role)
+ item = self.db_mngr.get_item(self.db_map, self.item_type, self.id)
+ return self.db_mngr.get_value(self.db_map, item, role=role)
return super().data(column, role)
def list_index(self):
diff --git a/spinetoolbox/spine_db_editor/mvcmodels/pivot_table_models.py b/spinetoolbox/spine_db_editor/mvcmodels/pivot_table_models.py
index eeb0915a8..37e191e03 100644
--- a/spinetoolbox/spine_db_editor/mvcmodels/pivot_table_models.py
+++ b/spinetoolbox/spine_db_editor/mvcmodels/pivot_table_models.py
@@ -1270,7 +1270,8 @@ def _data(self, index, role):
if data[0][0] is None:
return None
db_map, id_ = data[0][0]
- return self.db_mngr.get_value(db_map, "parameter_value", id_, role)
+ item = self.db_mngr.get_item(db_map, "parameter_value", id_)
+ return self.db_mngr.get_value(db_map, item, role)
def _do_batch_set_inner_data(self, row_map, column_map, data, values):
return self._batch_set_parameter_value_data(row_map, column_map, data, values)
diff --git a/spinetoolbox/spine_db_editor/mvcmodels/single_models.py b/spinetoolbox/spine_db_editor/mvcmodels/single_models.py
index e009fe6ad..241527bd8 100644
--- a/spinetoolbox/spine_db_editor/mvcmodels/single_models.py
+++ b/spinetoolbox/spine_db_editor/mvcmodels/single_models.py
@@ -329,7 +329,8 @@ def data(self, index, role=Qt.ItemDataRole.DisplayRole):
PARSED_ROLE,
):
id_ = self._main_data[index.row()]
- return self.db_mngr.get_value(self.db_map, self.item_type, id_, role)
+ item = self.db_mngr.get_item(self.db_map, self.item_type, id_)
+ return self.db_mngr.get_value(self.db_map, item, role)
return super().data(index, role)
diff --git a/spinetoolbox/spine_db_editor/ui/commit_viewer_affected_item_info.py b/spinetoolbox/spine_db_editor/ui/commit_viewer_affected_item_info.py
new file mode 100644
index 000000000..cd6b79a97
--- /dev/null
+++ b/spinetoolbox/spine_db_editor/ui/commit_viewer_affected_item_info.py
@@ -0,0 +1,60 @@
+# -*- coding: utf-8 -*-
+######################################################################################################################
+# 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 .
+######################################################################################################################
+
+################################################################################
+## Form generated from reading UI file 'commit_viewer_affected_item_info.ui'
+##
+## Created by: Qt User Interface Compiler version 6.5.2
+##
+## WARNING! All changes made in this file will be lost when recompiling UI file!
+################################################################################
+
+from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
+ QMetaObject, QObject, QPoint, QRect,
+ QSize, QTime, QUrl, Qt)
+from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
+ QFont, QFontDatabase, QGradient, QIcon,
+ QImage, QKeySequence, QLinearGradient, QPainter,
+ QPalette, QPixmap, QRadialGradient, QTransform)
+from PySide6.QtWidgets import (QApplication, QHeaderView, QLabel, QSizePolicy,
+ QTableWidget, QTableWidgetItem, QVBoxLayout, QWidget)
+
+class Ui_Form(object):
+ def setupUi(self, Form):
+ if not Form.objectName():
+ Form.setObjectName(u"Form")
+ Form.resize(400, 300)
+ self.verticalLayout = QVBoxLayout(Form)
+ self.verticalLayout.setObjectName(u"verticalLayout")
+ self.verticalLayout.setContentsMargins(0, 0, 0, 0)
+ self.affected_items_table = QTableWidget(Form)
+ self.affected_items_table.setObjectName(u"affected_items_table")
+
+ self.verticalLayout.addWidget(self.affected_items_table)
+
+ self.fetch_status_label = QLabel(Form)
+ self.fetch_status_label.setObjectName(u"fetch_status_label")
+
+ self.verticalLayout.addWidget(self.fetch_status_label)
+
+
+ self.retranslateUi(Form)
+
+ QMetaObject.connectSlotsByName(Form)
+ # setupUi
+
+ def retranslateUi(self, Form):
+ Form.setWindowTitle(QCoreApplication.translate("Form", u"Form", None))
+ self.fetch_status_label.setText(QCoreApplication.translate("Form", u"TextLabel", None))
+ # retranslateUi
+
diff --git a/spinetoolbox/spine_db_editor/ui/commit_viewer_affected_item_info.ui b/spinetoolbox/spine_db_editor/ui/commit_viewer_affected_item_info.ui
new file mode 100644
index 000000000..fe6cbacdc
--- /dev/null
+++ b/spinetoolbox/spine_db_editor/ui/commit_viewer_affected_item_info.ui
@@ -0,0 +1,56 @@
+
+
+
+ Form
+
+
+
+ 0
+ 0
+ 400
+ 300
+
+
+
+ Form
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
+
+
+ -
+
+
+ TextLabel
+
+
+
+
+
+
+
+
diff --git a/spinetoolbox/spine_db_editor/ui/db_commit_viewer.py b/spinetoolbox/spine_db_editor/ui/db_commit_viewer.py
index b9d750e60..e3bdbbe7d 100644
--- a/spinetoolbox/spine_db_editor/ui/db_commit_viewer.py
+++ b/spinetoolbox/spine_db_editor/ui/db_commit_viewer.py
@@ -26,9 +26,10 @@
QFont, QFontDatabase, QGradient, QIcon,
QImage, QKeySequence, QLinearGradient, QPainter,
QPalette, QPixmap, QRadialGradient, QTransform)
-from PySide6.QtWidgets import (QApplication, QHBoxLayout, QHeaderView, QSizePolicy,
- QSplitter, QStackedWidget, QTextBrowser, QTreeWidget,
- QTreeWidgetItem, QWidget)
+from PySide6.QtWidgets import (QApplication, QFrame, QHBoxLayout, QHeaderView,
+ QLabel, QSizePolicy, QSplitter, QStackedWidget,
+ QTabWidget, QTextBrowser, QTreeWidget, QTreeWidgetItem,
+ QVBoxLayout, QWidget)
class Ui_DBCommitViewer(object):
def setupUi(self, DBCommitViewer):
@@ -36,55 +37,107 @@ def setupUi(self, DBCommitViewer):
DBCommitViewer.setObjectName(u"DBCommitViewer")
DBCommitViewer.resize(716, 218)
self.horizontalLayout_2 = QHBoxLayout(DBCommitViewer)
- self.horizontalLayout_2.setSpacing(0)
self.horizontalLayout_2.setObjectName(u"horizontalLayout_2")
- self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0)
self.splitter = QSplitter(DBCommitViewer)
self.splitter.setObjectName(u"splitter")
self.splitter.setOrientation(Qt.Horizontal)
self.commit_list = QTreeWidget(self.splitter)
+ __qtreewidgetitem = QTreeWidgetItem()
+ __qtreewidgetitem.setText(0, u"1");
+ self.commit_list.setHeaderItem(__qtreewidgetitem)
self.commit_list.setObjectName(u"commit_list")
self.splitter.addWidget(self.commit_list)
- self.affected_items_widget_stack = QStackedWidget(self.splitter)
+ self.verticalFrame = QFrame(self.splitter)
+ self.verticalFrame.setObjectName(u"verticalFrame")
+ self.verticalFrame.setStyleSheet(u"QFrame {\n"
+" background-color: white;\n"
+"}")
+ self.verticalFrame.setFrameShape(QFrame.Box)
+ self.verticalLayout = QVBoxLayout(self.verticalFrame)
+ self.verticalLayout.setSpacing(3)
+ self.verticalLayout.setObjectName(u"verticalLayout")
+ self.verticalLayout.setContentsMargins(5, 5, 5, 0)
+ self.label = QLabel(self.verticalFrame)
+ self.label.setObjectName(u"label")
+
+ self.verticalLayout.addWidget(self.label)
+
+ self.affected_items_widget_stack = QStackedWidget(self.verticalFrame)
self.affected_items_widget_stack.setObjectName(u"affected_items_widget_stack")
- self.page = QWidget()
- self.page.setObjectName(u"page")
- self.horizontalLayout_3 = QHBoxLayout(self.page)
+ self.items_page = QWidget()
+ self.items_page.setObjectName(u"items_page")
+ self.horizontalLayout_3 = QHBoxLayout(self.items_page)
self.horizontalLayout_3.setSpacing(0)
self.horizontalLayout_3.setObjectName(u"horizontalLayout_3")
self.horizontalLayout_3.setContentsMargins(0, 0, 0, 0)
- self.affected_items = QTreeWidget(self.page)
- self.affected_items.setObjectName(u"affected_items")
+ self.affected_item_tab_widget = QTabWidget(self.items_page)
+ self.affected_item_tab_widget.setObjectName(u"affected_item_tab_widget")
+ self.affected_item_tab_widget.setDocumentMode(True)
- self.horizontalLayout_3.addWidget(self.affected_items)
+ self.horizontalLayout_3.addWidget(self.affected_item_tab_widget)
- self.affected_items_widget_stack.addWidget(self.page)
- self.page_2 = QWidget()
- self.page_2.setObjectName(u"page_2")
- self.horizontalLayout = QHBoxLayout(self.page_2)
+ self.affected_items_widget_stack.addWidget(self.items_page)
+ self.no_items_page = QWidget()
+ self.no_items_page.setObjectName(u"no_items_page")
+ self.horizontalLayout = QHBoxLayout(self.no_items_page)
self.horizontalLayout.setSpacing(0)
self.horizontalLayout.setObjectName(u"horizontalLayout")
self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
- self.no_affected_items_notice = QTextBrowser(self.page_2)
+ self.no_affected_items_notice = QTextBrowser(self.no_items_page)
self.no_affected_items_notice.setObjectName(u"no_affected_items_notice")
+ self.no_affected_items_notice.setFocusPolicy(Qt.NoFocus)
self.no_affected_items_notice.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.no_affected_items_notice.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.no_affected_items_notice.setOpenLinks(False)
self.horizontalLayout.addWidget(self.no_affected_items_notice)
- self.affected_items_widget_stack.addWidget(self.page_2)
- self.splitter.addWidget(self.affected_items_widget_stack)
+ self.affected_items_widget_stack.addWidget(self.no_items_page)
+ self.loading_page = QWidget()
+ self.loading_page.setObjectName(u"loading_page")
+ self.horizontalLayout_4 = QHBoxLayout(self.loading_page)
+ self.horizontalLayout_4.setSpacing(0)
+ self.horizontalLayout_4.setObjectName(u"horizontalLayout_4")
+ self.horizontalLayout_4.setContentsMargins(0, 0, 0, 0)
+ self.loading_label = QLabel(self.loading_page)
+ self.loading_label.setObjectName(u"loading_label")
+ self.loading_label.setAlignment(Qt.AlignLeading|Qt.AlignLeft|Qt.AlignTop)
+
+ self.horizontalLayout_4.addWidget(self.loading_label)
+
+ self.affected_items_widget_stack.addWidget(self.loading_page)
+ self.no_commit_selected_page = QWidget()
+ self.no_commit_selected_page.setObjectName(u"no_commit_selected_page")
+ self.verticalLayout_2 = QVBoxLayout(self.no_commit_selected_page)
+ self.verticalLayout_2.setSpacing(0)
+ self.verticalLayout_2.setObjectName(u"verticalLayout_2")
+ self.verticalLayout_2.setContentsMargins(0, 0, 0, 0)
+ self.label_2 = QLabel(self.no_commit_selected_page)
+ self.label_2.setObjectName(u"label_2")
+ self.label_2.setAlignment(Qt.AlignLeading|Qt.AlignLeft|Qt.AlignTop)
+
+ self.verticalLayout_2.addWidget(self.label_2)
+
+ self.affected_items_widget_stack.addWidget(self.no_commit_selected_page)
+
+ self.verticalLayout.addWidget(self.affected_items_widget_stack)
+
+ self.splitter.addWidget(self.verticalFrame)
self.horizontalLayout_2.addWidget(self.splitter)
self.retranslateUi(DBCommitViewer)
+ self.affected_items_widget_stack.setCurrentIndex(3)
+ self.affected_item_tab_widget.setCurrentIndex(-1)
+
+
QMetaObject.connectSlotsByName(DBCommitViewer)
# setupUi
def retranslateUi(self, DBCommitViewer):
+ self.label.setText(QCoreApplication.translate("DBCommitViewer", u"Affected items", None))
self.no_affected_items_notice.setHtml(QCoreApplication.translate("DBCommitViewer", u"\n"
"
\n"
"No affected items found for selected commit.
\n"
-"Note that we cannot show items that have been removed by this or a later commit.
", None))
+"Note, that it is not possible to show items that have been removed by this or a later commit.