From e1c2645cc8fdfb3110b2087d4ec971f90a1416d8 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 23 Aug 2021 12:30:45 +0200 Subject: [PATCH] added basic log viewer for publishing --- .../publish_log_viewer/window.py | 272 +++++++++++++++--- 1 file changed, 232 insertions(+), 40 deletions(-) diff --git a/openpype/tools/new_publisher/publish_log_viewer/window.py b/openpype/tools/new_publisher/publish_log_viewer/window.py index 01d8b853a8..96de03b299 100644 --- a/openpype/tools/new_publisher/publish_log_viewer/window.py +++ b/openpype/tools/new_publisher/publish_log_viewer/window.py @@ -1,6 +1,8 @@ import os import sys import json +import copy +import uuid import collections openpype_dir = r"C:\Users\jakub.trllo\Desktop\pype\pype3" @@ -19,62 +21,175 @@ for path in [ ]: sys.path.append(path) -from Qt import QtWidgets, QtGui +from Qt import QtWidgets, QtCore, QtGui + +from openpype import style + +ITEM_ID_ROLE = QtCore.Qt.UserRole + 1 + + +class PluginItem: + def __init__(self, plugin_data): + self._id = uuid.uuid4() + + self.name = plugin_data["name"] + self.label = plugin_data["label"] + self.order = plugin_data["order"] + self.skipped = plugin_data["skipped"] + + logs = [] + for instance_data in plugin_data["instances_data"]: + logs.extend(copy.deepcopy(instance_data["logs"])) + + self.logs = logs + + @property + def id(self): + return self._id + + +class InstanceItem: + def __init__(self, instance_id, instance_data, report_data): + self._id = instance_id + self.label = instance_data.get("label") or instance_data.get("name") + self.family = instance_data.get("family") + + logs = [] + for plugin_data in report_data["plugins_data"]: + for instance_data_item in plugin_data["instances_data"]: + if instance_data_item["id"] == self._id: + logs.extend(copy.deepcopy(instance_data_item["logs"])) + + self.logs = logs + + @property + def id(self): + return self._id + + +class PublishReport: + def __init__(self, report_data): + data = copy.deepcopy(report_data) + + context_data = data["context"] + context_data["name"] = "context" + context_data["label"] = context_data["label"] or "Context" + + instance_items_by_id = {} + instance_items_by_family = {} + context_item = InstanceItem(None, context_data, data) + instance_items_by_id[context_item.id] = context_item + instance_items_by_family[context_item.family] = [context_item] + + for instance_id, instance_data in data["instances"].items(): + item = InstanceItem(instance_id, instance_data, data) + instance_items_by_id[item.id] = item + if item.family not in instance_items_by_family: + instance_items_by_family[item.family] = [] + instance_items_by_family[item.family].append(item) + + all_logs = [] + plugins_items_by_id = {} + plugins_id_order = [] + for plugin_data in data["plugins_data"]: + item = PluginItem(plugin_data) + plugins_id_order.append(item.id) + plugins_items_by_id[item.id] = item + all_logs.extend(copy.deepcopy(item.logs)) + + self.instance_items_by_id = instance_items_by_id + self.instance_items_by_family = instance_items_by_family + + self.plugins_id_order = plugins_id_order + self.plugins_items_by_id = plugins_items_by_id + + self.logs = all_logs class InstancesModel(QtGui.QStandardItemModel): - def set_report(self, report_data): + def set_report(self, report_item): self.clear() root_item = self.invisibleRootItem() - context_data = report_data["context"] - context_label = context_data["label"] or "Context" + families = set(report_item.instance_items_by_family.keys()) + families.remove(None) + all_families = list(sorted(families)) + all_families.insert(0, None) - context_item = QtGui.QStandardItem(context_label) + family_items = [] + for family in all_families: + items = [] + instance_items = report_item.instance_items_by_family[family] + for instance_item in instance_items: + item = QtGui.QStandardItem(instance_item.label) + item.setData(instance_item.id, ITEM_ID_ROLE) + items.append(item) - items = [context_item] - families = [] - instances_by_family = collections.defaultdict(list) - instances_by_id = {} - for instance_id, instance_detail in report_data["instances"].items(): - family = instance_detail["family"] - if family not in families: - families.append(family) + if family is None: + family_items.extend(items) + continue - label = instance_detail["label"] or instance_detail["name"] - - instance_item = QtGui.QStandardItem(label) - instances_by_id[instance_id] = instance_item - instances_by_family[family].append(instance_item) - - for family in families: - instance_items = instances_by_family[family] family_item = QtGui.QStandardItem(family) - family_item.appendRows(instance_items) - items.append(family_item) + family_item.appendRows(items) + family_items.append(family_item) - root_item.appendRows(items) + root_item.appendRows(family_items) class PluginsModel(QtGui.QStandardItemModel): - def set_report(self, report_data): + def set_report(self, report_item): self.clear() - plugins_data = report_data["plugins_data"] - root_item = self.invisibleRootItem() items = [] - for plugin_detail in plugins_data: - item = QtGui.QStandardItem(plugin_detail["label"]) + for plugin_id in report_item.plugins_id_order: + plugin_item = report_item.plugins_items_by_id[plugin_id] + item = QtGui.QStandardItem(plugin_item.label) + item.setData(plugin_item.id, ITEM_ID_ROLE) items.append(item) root_item.appendRows(items) +class DetailsWidget(QtWidgets.QWidget): + def __init__(self, parent): + super(DetailsWidget, self).__init__(parent) + + output_widget = QtWidgets.QPlainTextEdit(self) + output_widget.setTextInteractionFlags(QtCore.Qt.TextBrowserInteraction) + output_widget.setObjectName("PublishLogConsole") + + layout = QtWidgets.QVBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.addWidget(output_widget) + + self._output_widget = output_widget + + def clear(self): + self._output_widget.setPlainText("") + + def set_logs(self, logs): + lines = [] + for log in logs: + if log["type"] == "record": + message = "{}: {}".format(log["levelname"], log["msg"]) + + lines.append(message) + exc_info = log["exc_info"] + if exc_info: + lines.append(exc_info) + + else: + print(log["type"]) + + text = "\n".join(lines) + self._output_widget.setPlainText(text) + + class PublishLogViewerWindow(QtWidgets.QWidget): - default_width = 1000 + default_width = 1200 default_height = 600 def __init__(self, parent=None): @@ -85,18 +200,33 @@ class PublishLogViewerWindow(QtWidgets.QWidget): instances_view = QtWidgets.QTreeView(self) instances_view.setModel(instances_model) + # instances_view.setIndentation(0) + instances_view.setHeaderHidden(True) + instances_view.setEditTriggers(QtWidgets.QTreeView.NoEditTriggers) plugins_view = QtWidgets.QTreeView(self) plugins_view.setModel(plugins_model) + # plugins_view.setIndentation(0) + plugins_view.setHeaderHidden(True) + plugins_view.setEditTriggers(QtWidgets.QTreeView.NoEditTriggers) - views_layout = QtWidgets.QHBoxLayout() - views_layout.addWidget(instances_view) - views_layout.addWidget(plugins_view) + details_widget = DetailsWidget(self) layout = QtWidgets.QHBoxLayout(self) - layout.addLayout(views_layout) + layout.addWidget(instances_view) + layout.addWidget(plugins_view) + layout.addWidget(details_widget, 1) - self.resize(self.default_width, self.default_height) + instances_view.selectionModel().selectionChanged.connect( + self._on_instance_change + ) + plugins_view.selectionModel().selectionChanged.connect( + self._on_plugin_change + ) + + self._ignore_selection_changes = False + self._report_item = None + self._details_widget = details_widget self._instances_view = instances_view self._plugins_view = plugins_view @@ -104,18 +234,80 @@ class PublishLogViewerWindow(QtWidgets.QWidget): self._instances_model = instances_model self._plugins_model = plugins_model - log_path = os.path.join(os.path.dirname(__file__), "logs.json") - with open(log_path, "r") as file_stream: - report_data = json.load(file_stream) + self.resize(self.default_width, self.default_height) + self.setStyleSheet(style.load_stylesheet()) - plugins_model.set_report(report_data) - instances_model.set_report(report_data) + def _on_instance_change(self, *_args): + if self._ignore_selection_changes: + return + + valid_index = None + for index in self._instances_view.selectedIndexes(): + if index.isValid(): + valid_index = index + break + + if valid_index is None: + print("NOT INSTANCE") + return + + if self._plugins_view.selectedIndexes(): + self._ignore_selection_changes = True + self._plugins_view.selectionModel().clearSelection() + self._ignore_selection_changes = False + + plugin_id = valid_index.data(ITEM_ID_ROLE) + instance_item = self._report_item.instance_items_by_id[plugin_id] + self._details_widget.set_logs(instance_item.logs) + + def _on_plugin_change(self, *_args): + if self._ignore_selection_changes: + return + + valid_index = None + for index in self._plugins_view.selectedIndexes(): + if index.isValid(): + valid_index = index + break + + if valid_index is None: + self._details_widget.set_logs(self._report_item.logs) + return + + if self._instances_view.selectedIndexes(): + self._ignore_selection_changes = True + self._instances_view.selectionModel().clearSelection() + self._ignore_selection_changes = False + + plugin_id = valid_index.data(ITEM_ID_ROLE) + plugin_item = self._report_item.plugins_items_by_id[plugin_id] + self._details_widget.set_logs(plugin_item.logs) + + def set_report(self, report_data): + self._ignore_selection_changes = True + + report_item = PublishReport(report_data) + self._report_item = report_item + + self._instances_model.set_report(report_item) + self._plugins_model.set_report(report_item) + + self._details_widget.set_logs(report_item.logs) + + self._ignore_selection_changes = False def main(): """Main function for testing purposes.""" app = QtWidgets.QApplication([]) window = PublishLogViewerWindow() + + log_path = os.path.join(os.path.dirname(__file__), "logs.json") + with open(log_path, "r") as file_stream: + report_data = json.load(file_stream) + + window.set_report(report_data) + window.show() app.exec_()