From b3d2d41267c313a822c186af9b0232f29baad85e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 8 Dec 2021 12:58:37 +0100 Subject: [PATCH 1/9] added working state context to category widget --- openpype/tools/settings/settings/categories.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/openpype/tools/settings/settings/categories.py b/openpype/tools/settings/settings/categories.py index a6e4154b2b7..79b5de952bf 100644 --- a/openpype/tools/settings/settings/categories.py +++ b/openpype/tools/settings/settings/categories.py @@ -1,6 +1,7 @@ import os import sys import traceback +import contextlib from enum import Enum from Qt import QtWidgets, QtCore, QtGui @@ -309,6 +310,12 @@ def add_widget_to_layout(self, widget, label_widget=None): ) self.content_layout.addWidget(widget, 0) + @contextlib.contextmanager + def working_state_context(self): + self.set_state(CategoryState.Working) + yield + self.set_state(CategoryState.Idle) + def save(self): if not self.items_are_valid(): return From 347b8da8a7a9a1a6c25d113fa6a2588b55acac04 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 8 Dec 2021 12:59:01 +0100 Subject: [PATCH 2/9] use working_state_context for current actions --- openpype/tools/settings/settings/base.py | 39 ++++++++++++++++-------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/openpype/tools/settings/settings/base.py b/openpype/tools/settings/settings/base.py index f8378ed18cb..1df7b2c75aa 100644 --- a/openpype/tools/settings/settings/base.py +++ b/openpype/tools/settings/settings/base.py @@ -110,9 +110,10 @@ def _discard_changes_action(self, menu, actions_mapping): return def discard_changes(): - self.ignore_input_changes.set_ignore(True) - self.entity.discard_changes() - self.ignore_input_changes.set_ignore(False) + with self.category_widget.working_state_context(): + self.ignore_input_changes.set_ignore(True) + self.entity.discard_changes() + self.ignore_input_changes.set_ignore(False) action = QtWidgets.QAction("Discard changes") actions_mapping[action] = discard_changes @@ -124,8 +125,11 @@ def _add_to_studio_default(self, menu, actions_mapping): if not self.entity.can_trigger_add_to_studio_default: return + def add_to_studio_default(): + with self.category_widget.working_state_context(): + self.entity.add_to_studio_default() action = QtWidgets.QAction("Add to studio default") - actions_mapping[action] = self.entity.add_to_studio_default + actions_mapping[action] = add_to_studio_default menu.addAction(action) def _remove_from_studio_default_action(self, menu, actions_mapping): @@ -133,9 +137,10 @@ def _remove_from_studio_default_action(self, menu, actions_mapping): return def remove_from_studio_default(): - self.ignore_input_changes.set_ignore(True) - self.entity.remove_from_studio_default() - self.ignore_input_changes.set_ignore(False) + with self.category_widget.working_state_context(): + self.ignore_input_changes.set_ignore(True) + self.entity.remove_from_studio_default() + self.ignore_input_changes.set_ignore(False) action = QtWidgets.QAction("Remove from studio default") actions_mapping[action] = remove_from_studio_default menu.addAction(action) @@ -144,8 +149,12 @@ def _add_to_project_override_action(self, menu, actions_mapping): if not self.entity.can_trigger_add_to_project_override: return + def add_to_project_override(): + with self.category_widget.working_state_context(): + self.entity.add_to_project_override + action = QtWidgets.QAction("Add to project project override") - actions_mapping[action] = self.entity.add_to_project_override + actions_mapping[action] = add_to_project_override menu.addAction(action) def _remove_from_project_override_action(self, menu, actions_mapping): @@ -153,9 +162,11 @@ def _remove_from_project_override_action(self, menu, actions_mapping): return def remove_from_project_override(): - self.ignore_input_changes.set_ignore(True) - self.entity.remove_from_project_override() - self.ignore_input_changes.set_ignore(False) + with self.category_widget.working_state_context(): + self.ignore_input_changes.set_ignore(True) + self.entity.remove_from_project_override() + self.ignore_input_changes.set_ignore(False) + action = QtWidgets.QAction("Remove from project override") actions_mapping[action] = remove_from_project_override menu.addAction(action) @@ -257,14 +268,16 @@ def _set_entity_value(_entity, _value): # Simple paste value method def paste_value(): - _set_entity_value(self.entity, value) + with self.category_widget.working_state_context(): + _set_entity_value(self.entity, value) action = QtWidgets.QAction("Paste", menu) output.append((action, paste_value)) # Paste value to matchin entity def paste_value_to_path(): - _set_entity_value(matching_entity, value) + with self.category_widget.working_state_context(): + _set_entity_value(matching_entity, value) if matching_entity is not None: action = QtWidgets.QAction("Paste to same place", menu) From 74b6da96aca81a54e32f8984d865d6f5674c4061 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 8 Dec 2021 12:59:21 +0100 Subject: [PATCH 3/9] added method to return project names from project list --- openpype/tools/settings/settings/widgets.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/openpype/tools/settings/settings/widgets.py b/openpype/tools/settings/settings/widgets.py index ac9870287b6..4c7bf87ce89 100644 --- a/openpype/tools/settings/settings/widgets.py +++ b/openpype/tools/settings/settings/widgets.py @@ -747,6 +747,13 @@ def select_project(self, project_name): index, QtCore.QItemSelectionModel.SelectionFlag.SelectCurrent ) + def get_project_names(self): + output = [] + for row in range(self.project_proxy.rowCount()): + index = self.project_proxy.index(row, 0) + output.append(index.data(PROJECT_NAME_ROLE)) + return output + def refresh(self): selected_project = None for index in self.project_list.selectedIndexes(): From e2f24fb87b3b732740649cf7f70fb32784530dcd Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 8 Dec 2021 12:59:42 +0100 Subject: [PATCH 4/9] project category widget has ability to retrieve project names --- openpype/tools/settings/settings/categories.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/openpype/tools/settings/settings/categories.py b/openpype/tools/settings/settings/categories.py index 79b5de952bf..029619849ed 100644 --- a/openpype/tools/settings/settings/categories.py +++ b/openpype/tools/settings/settings/categories.py @@ -606,6 +606,14 @@ def ui_tweaks(self): self.project_list_widget = project_list_widget + def get_project_names(self): + if ( + self.modify_defaults_checkbox + and self.modify_defaults_checkbox.isChecked() + ): + return [] + return self.project_list_widget.get_project_names() + def on_saved(self, saved_tab_widget): """Callback on any tab widget save. From 2fdac8639a00e58cb5544a6cdf9822d2bfa3d2c9 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 8 Dec 2021 13:00:07 +0100 Subject: [PATCH 5/9] initial version of applying settings from different project --- openpype/tools/settings/settings/base.py | 43 ++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/openpype/tools/settings/settings/base.py b/openpype/tools/settings/settings/base.py index 1df7b2c75aa..f03d0c61865 100644 --- a/openpype/tools/settings/settings/base.py +++ b/openpype/tools/settings/settings/base.py @@ -1,7 +1,10 @@ import json from Qt import QtWidgets, QtGui, QtCore + +from openpype.settings.entities import ProjectSettings from openpype.tools.settings import CHILD_OFFSET + from .widgets import ExpandingWidget from .lib import create_deffered_value_change_timer @@ -285,6 +288,45 @@ def paste_value_to_path(): return output + def _apply_values_from_project_action(self, menu, actions_mapping): + for attr_name in ("project_name", "get_project_names"): + if not hasattr(self.category_widget, attr_name): + return + + if self.entity.is_dynamic_item or self.entity.is_in_dynamic_item: + return + + submenu = QtWidgets.QMenu("Apply values from", menu) + + current_project_name = self.category_widget.project_name + for project_name in self.category_widget.get_project_names(): + if current_project_name == project_name: + continue + + if project_name is None: + project_name = "< Default >" + + action = QtWidgets.QAction(project_name) + submenu.addAction(action) + actions_mapping[action] = lambda: self._apply_values_from_project( + project_name + ) + menu.addMenu(submenu) + + def _apply_values_from_project(self, project_name): + with self.category_widget.working_state_context(): + path_keys = [ + item + for item in self.entity.path.split("/") + if item + ] + + settings = ProjectSettings(project_name) + entity = settings + for key in path_keys: + entity = entity[key] + self.entity.set(entity.value) + def show_actions_menu(self, event=None): if event and event.button() != QtCore.Qt.RightButton: return @@ -303,6 +345,7 @@ def show_actions_menu(self, event=None): self._remove_from_studio_default_action(menu, actions_mapping) self._add_to_project_override_action(menu, actions_mapping) self._remove_from_project_override_action(menu, actions_mapping) + self._apply_values_from_project_action(menu, actions_mapping) ui_actions = [] ui_actions.extend(self._copy_value_actions(menu)) From c08b4673fd5fd935f41b5277c8977e80aaeb595b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 8 Dec 2021 13:07:38 +0100 Subject: [PATCH 6/9] use defined constant for default project label --- openpype/tools/settings/settings/base.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openpype/tools/settings/settings/base.py b/openpype/tools/settings/settings/base.py index f03d0c61865..94687f4f350 100644 --- a/openpype/tools/settings/settings/base.py +++ b/openpype/tools/settings/settings/base.py @@ -7,6 +7,7 @@ from .widgets import ExpandingWidget from .lib import create_deffered_value_change_timer +from .constants import DEFAULT_PROJECT_LABEL class BaseWidget(QtWidgets.QWidget): @@ -304,7 +305,7 @@ def _apply_values_from_project_action(self, menu, actions_mapping): continue if project_name is None: - project_name = "< Default >" + project_name = DEFAULT_PROJECT_LABEL action = QtWidgets.QAction(project_name) submenu.addAction(action) From 8270f2fc402a7cb119fdc71ead0bd474f0d7c9d6 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 8 Dec 2021 13:07:57 +0100 Subject: [PATCH 7/9] catch exceptions happened during applying values from different project --- openpype/tools/settings/settings/base.py | 42 +++++++++++++++++------- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/openpype/tools/settings/settings/base.py b/openpype/tools/settings/settings/base.py index 94687f4f350..6776845125b 100644 --- a/openpype/tools/settings/settings/base.py +++ b/openpype/tools/settings/settings/base.py @@ -1,4 +1,6 @@ +import sys import json +import traceback from Qt import QtWidgets, QtGui, QtCore @@ -316,17 +318,35 @@ def _apply_values_from_project_action(self, menu, actions_mapping): def _apply_values_from_project(self, project_name): with self.category_widget.working_state_context(): - path_keys = [ - item - for item in self.entity.path.split("/") - if item - ] - - settings = ProjectSettings(project_name) - entity = settings - for key in path_keys: - entity = entity[key] - self.entity.set(entity.value) + try: + path_keys = [ + item + for item in self.entity.path.split("/") + if item + ] + entity = ProjectSettings(project_name) + for key in path_keys: + entity = entity[key] + self.entity.set(entity.value) + + except Exception: + if project_name is None: + project_name = DEFAULT_PROJECT_LABEL + + # TODO better message + title = "Applying values failed" + msg = "Using values from project \"{}\" failed.".format( + project_name + ) + detail_msg = "".join( + traceback.format_exception(*sys.exc_info()) + ) + dialog = QtWidgets.QMessageBox(self) + dialog.setWindowTitle(title) + dialog.setIcon(QtWidgets.QMessageBox.Warning) + dialog.setText(msg) + dialog.setDetailedText(detail_msg) + dialog.exec_() def show_actions_menu(self, event=None): if event and event.button() != QtCore.Qt.RightButton: From 8e71919145a1ad491511697486238e8ebc82221e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 8 Dec 2021 13:25:22 +0100 Subject: [PATCH 8/9] skip action if does not have any projects which can be used as source for values --- openpype/tools/settings/settings/base.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/openpype/tools/settings/settings/base.py b/openpype/tools/settings/settings/base.py index 6776845125b..9016e639706 100644 --- a/openpype/tools/settings/settings/base.py +++ b/openpype/tools/settings/settings/base.py @@ -299,13 +299,18 @@ def _apply_values_from_project_action(self, menu, actions_mapping): if self.entity.is_dynamic_item or self.entity.is_in_dynamic_item: return - submenu = QtWidgets.QMenu("Apply values from", menu) - current_project_name = self.category_widget.project_name + project_names = [] for project_name in self.category_widget.get_project_names(): - if current_project_name == project_name: - continue + if project_name != current_project_name: + project_names.append(project_name) + + if not project_names: + return + + submenu = QtWidgets.QMenu("Apply values from", menu) + for project_name in project_names: if project_name is None: project_name = DEFAULT_PROJECT_LABEL From 68b99391acecec1a208468df98026506db7ac95a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 14 Dec 2021 15:35:39 +0100 Subject: [PATCH 9/9] modified message --- openpype/tools/settings/settings/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/tools/settings/settings/base.py b/openpype/tools/settings/settings/base.py index 9016e639706..b10c9588809 100644 --- a/openpype/tools/settings/settings/base.py +++ b/openpype/tools/settings/settings/base.py @@ -340,7 +340,7 @@ def _apply_values_from_project(self, project_name): # TODO better message title = "Applying values failed" - msg = "Using values from project \"{}\" failed.".format( + msg = "Applying values from project \"{}\" failed.".format( project_name ) detail_msg = "".join(