From c6382d71d7dda62dc080ef2d74141680446f3c96 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 22 Feb 2021 18:20:07 +0100 Subject: [PATCH 01/61] initial commit and rought variant of local settings widget --- .../settings/widgets/local_settings.py | 409 ++++++++++++++++++ 1 file changed, 409 insertions(+) create mode 100644 pype/tools/settings/settings/widgets/local_settings.py diff --git a/pype/tools/settings/settings/widgets/local_settings.py b/pype/tools/settings/settings/widgets/local_settings.py new file mode 100644 index 0000000000..2dda046302 --- /dev/null +++ b/pype/tools/settings/settings/widgets/local_settings.py @@ -0,0 +1,409 @@ +import platform +import logging +from Qt import QtWidgets, QtCore +from .widgets import ( + ExpandingWidget, + SpacerWidget +) +from .. import style +from .lib import CHILD_OFFSET +from pype.api import SystemSettings + +log = logging.getLogger(__name__) + + +class Separator(QtWidgets.QFrame): + def __init__(self, height=None, parent=None): + super(Separator, self).__init__(parent) + if height is None: + height = 2 + + splitter_item = QtWidgets.QWidget(self) + splitter_item.setStyleSheet("background-color: #21252B;") + splitter_item.setMinimumHeight(height) + splitter_item.setMaximumHeight(height) + + layout = QtWidgets.QHBoxLayout(self) + layout.setContentsMargins(5, 5, 5, 5) + layout.addWidget(splitter_item) + + +class LocalGeneralWidgets(QtWidgets.QWidget): + def __init__(self, parent): + super(LocalGeneralWidgets, self).__init__(parent) + + mongo_url_label = QtWidgets.QLabel("Pype Mongo URL", self) + mongo_url_input = QtWidgets.QLineEdit(self) + local_site_name_label = QtWidgets.QLabel("Local site name", self) + local_site_name_input = QtWidgets.QLineEdit(self) + + layout = QtWidgets.QGridLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + row = 0 + layout.addWidget(mongo_url_label, row, 0) + layout.addWidget(mongo_url_input, row, 1) + row += 1 + layout.addWidget(local_site_name_label, row, 0) + layout.addWidget(local_site_name_input, row, 1) + + self.mongo_url_input = mongo_url_input + self.local_site_name_input = local_site_name_input + + def set_value(self, value): + mongo_url = "" + site_name = "" + if value: + mongo_url = value.get("mongo_url", mongo_url) + site_name = value.get("site_name", site_name) + self.mongo_url_input.setText(mongo_url) + self.local_site_name_input.setText(site_name) + + def settings_value(self): + # Add changed + # If these have changed then + output = {} + mongo_url = self.mongo_url_input.text() + if mongo_url: + output["mongo_url"] = mongo_url + + local_site_name = self.local_site_name_input.text() + if local_site_name: + output["site_name"] = local_site_name + # Do not return output yet since we don't have mechanism to save or + # load these data through api calls + return None + + +class PathInput(QtWidgets.QWidget): + def __init__( + self, + parent, + executable_placeholder=None, + argument_placeholder=None + ): + super(PathInput, self).__init__(parent) + + executable_input = QtWidgets.QLineEdit(self) + if executable_placeholder: + executable_input.setPlaceholderText(executable_placeholder) + + arguments_input = QtWidgets.QLineEdit(self) + if argument_placeholder: + arguments_input.setPlaceholderText(argument_placeholder) + + layout = QtWidgets.QHBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(5) + + layout.addWidget(executable_input) + layout.addWidget(arguments_input) + + self.executable_input = executable_input + self.arguments_input = arguments_input + + def set_read_only(self, readonly=True): + self.executable_input.setReadOnly(readonly) + self.arguments_input.setReadOnly(readonly) + + def set_value(self, arguments): + executable = "" + args = "" + if arguments: + if isinstance(arguments, str): + executable = arguments + elif isinstance(arguments, list): + executable = arguments[0] + if len(arguments) > 1: + args = " ".join(arguments[1:]) + self.executable_input.setText(executable) + self.arguments_input.setText(args) + + def settings_value(self): + executable = self.executable_input.text() + if not executable: + return None + + output = [executable] + args = self.arguments_input.text() + if args: + output.append(args) + return output + + +class AppVariantWidget(QtWidgets.QWidget): + exec_placeholder = "< Specific path for this machine >" + args_placeholder = "< Launch arguments >" + + def __init__(self, group_label, variant_entity, parent): + super(AppVariantWidget, self).__init__(parent) + + self.input_widget = None + + label = " ".join([group_label, variant_entity.label]) + + expading_widget = ExpandingWidget(label, self) + content_widget = QtWidgets.QWidget(expading_widget) + content_layout = QtWidgets.QVBoxLayout(content_widget) + content_layout.setContentsMargins(CHILD_OFFSET, 5, 0, 0) + + expading_widget.set_content_widget(content_widget) + + # Add expanding widget to main layout + layout = QtWidgets.QHBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.addWidget(expading_widget) + + # TODO For celaction - not sure what is "Celaction publish" for + if not variant_entity["executables"].multiplatform: + warn_label = QtWidgets.QLabel( + "Application without multiplatform paths" + ) + content_layout.addWidget(warn_label) + return + + input_widget = PathInput( + content_widget, self.exec_placeholder, self.args_placeholder + ) + content_layout.addWidget(input_widget) + + studio_executables = ( + variant_entity["executables"][platform.system().lower()] + ) + if len(studio_executables) > 0: + content_layout.addWidget(Separator(parent=self)) + + for item in studio_executables: + path_widget = PathInput(content_widget) + path_widget.set_read_only() + path_widget.set_value(item.value) + content_layout.addWidget(path_widget) + + self.input_widget = input_widget + + def set_value(self, value): + if not self.input_widget: + return + + if not value: + value = [] + self.input_widget.set_value(value) + + def settings_value(self): + if not self.input_widget: + return None + return self.input_widget.settings_value() + + +class AppGroupWidget(QtWidgets.QWidget): + def __init__(self, group_entity, parent): + super(AppGroupWidget, self).__init__(parent) + + valid_variants = {} + for key, entity in group_entity["variants"].items(): + if entity["enabled"]: + valid_variants[key] = entity + + group_label = group_entity.label + expading_widget = ExpandingWidget(group_label, self) + content_widget = QtWidgets.QWidget(expading_widget) + content_layout = QtWidgets.QVBoxLayout(content_widget) + content_layout.setContentsMargins(CHILD_OFFSET, 5, 0, 0) + + widgets_by_variant_name = {} + for variant_name, variant_entity in valid_variants.items(): + variant_widget = AppVariantWidget( + group_label, variant_entity, content_widget + ) + widgets_by_variant_name[variant_name] = variant_widget + content_layout.addWidget(variant_widget) + + expading_widget.set_content_widget(content_widget) + + layout = QtWidgets.QHBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.addWidget(expading_widget) + + self.widgets_by_variant_name = widgets_by_variant_name + + def set_value(self, value): + if not value: + value = {} + + for variant_name, widget in self.widgets_by_variant_name.items(): + widget.set_value(value.get(variant_name)) + + def settings_value(self): + output = {} + for variant_name, widget in self.widgets_by_variant_name.items(): + value = widget.settings_value() + if value: + output[variant_name] = value + + if not output: + return None + return output + + +class LocalApplicationsWidgets(QtWidgets.QWidget): + def __init__(self, system_settings_entity, parent): + super(LocalApplicationsWidgets, self).__init__(parent) + + widgets_by_group_name = {} + + layout = QtWidgets.QVBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + + for key, entity in system_settings_entity["applications"].items(): + # Filter not enabled app groups + if not entity["enabled"]: + continue + + # Check if has enabled any variant + enabled_variant = False + for variant_entity in entity["variants"].values(): + if variant_entity["enabled"]: + enabled_variant = True + break + + if not enabled_variant: + continue + + # Create App group specific widget and store it by the key + group_widget = AppGroupWidget(entity, self) + widgets_by_group_name[key] = group_widget + layout.addWidget(group_widget) + + self.widgets_by_group_name = widgets_by_group_name + + def set_value(self, value): + if not value: + value = {} + + for group_name, widget in self.widgets_by_group_name.items(): + widget.set_value(value.get(group_name)) + + def settings_value(self): + output = {} + for group_name, widget in self.widgets_by_group_name.items(): + value = widget.settings_value() + if value: + output[group_name] = value + if not output: + return None + return output + + +class LocalSettingsWidget(QtWidgets.QWidget): + def __init__(self, parent=None): + super(LocalSettingsWidget, self).__init__(parent) + + self.system_settings = SystemSettings() + # self.project_settings = SystemSettings() + user_settings = {} + + self.main_layout = QtWidgets.QVBoxLayout(self) + + self.general_widget = None + self.apps_widget = None + + self._create_general_ui() + self._create_app_ui() + + # Add spacer to main layout + self.main_layout.addWidget(SpacerWidget(self), 1) + + self.set_value(user_settings) + + def _create_general_ui(self): + # General + general_expand_widget = ExpandingWidget( + "General (Does nothing!)", self + ) + + general_content = QtWidgets.QWidget(self) + general_layout = QtWidgets.QVBoxLayout(general_content) + general_layout.setContentsMargins(CHILD_OFFSET, 5, 0, 0) + general_expand_widget.set_content_widget(general_content) + + general_widget = LocalGeneralWidgets(general_content) + general_layout.addWidget(general_widget) + + self.main_layout.addWidget(general_expand_widget) + + self.general_widget = general_widget + + def _create_app_ui(self): + # Applications + app_expand_widget = ExpandingWidget("Applications", self) + + app_content = QtWidgets.QWidget(self) + app_layout = QtWidgets.QVBoxLayout(app_content) + app_layout.setContentsMargins(CHILD_OFFSET, 5, 0, 0) + app_expand_widget.set_content_widget(app_content) + + app_widget = LocalApplicationsWidgets( + self.system_settings, app_content + ) + app_layout.addWidget(app_widget) + + self.main_layout.addWidget(app_expand_widget) + + self.app_widget = app_widget + + def set_value(self, value): + if not value: + value = {} + + self.general_widget.set_value(value.get("general")) + self.app_widget.set_value(value.get("applications")) + + def settings_value(self): + output = {} + general_value = self.general_widget.settings_value() + if general_value: + output["general"] = general_value + + app_value = self.app_widget.settings_value() + if app_value: + output["applications"] = app_value + return output + + +class LocalSettingsWindow(QtWidgets.QWidget): + def __init__(self, parent=None): + super(LocalSettingsWindow, self).__init__(parent) + + self.resize(1000, 600) + + stylesheet = style.load_stylesheet() + self.setStyleSheet(stylesheet) + + scroll_widget = QtWidgets.QScrollArea(self) + scroll_widget.setObjectName("GroupWidget") + settings_widget = LocalSettingsWidget(scroll_widget) + + scroll_widget.setWidget(settings_widget) + scroll_widget.setWidgetResizable(True) + + footer = QtWidgets.QWidget(self) + save_btn = QtWidgets.QPushButton("Save", footer) + footer_layout = QtWidgets.QHBoxLayout(footer) + footer_layout.addWidget(SpacerWidget(footer), 1) + footer_layout.addWidget(save_btn, 0) + + main_layout = QtWidgets.QVBoxLayout(self) + main_layout.setContentsMargins(0, 0, 0, 0) + main_layout.addWidget(scroll_widget, 1) + main_layout.addWidget(footer, 0) + + save_btn.clicked.connect(self._on_save_clicked) + + self.settings_widget = settings_widget + self.save_btn = save_btn + + def _on_save_clicked(self): + try: + value = self.settings_widget.settings_value() + print(value) + except Exception: + log.warning("Failed to save", exc_info=True) From 912cf1efa1ce439dff5870a0e5f49d5d5e740da6 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 22 Feb 2021 19:22:40 +0100 Subject: [PATCH 02/61] added basics of project settings --- .../settings/widgets/local_settings.py | 86 ++++++++++++++++++- 1 file changed, 83 insertions(+), 3 deletions(-) diff --git a/pype/tools/settings/settings/widgets/local_settings.py b/pype/tools/settings/settings/widgets/local_settings.py index 2dda046302..35ec7d7714 100644 --- a/pype/tools/settings/settings/widgets/local_settings.py +++ b/pype/tools/settings/settings/widgets/local_settings.py @@ -3,11 +3,15 @@ import logging from Qt import QtWidgets, QtCore from .widgets import ( ExpandingWidget, - SpacerWidget + SpacerWidget, + ProjectListWidget ) from .. import style from .lib import CHILD_OFFSET -from pype.api import SystemSettings +from pype.api import ( + SystemSettings, + ProjectSettings +) log = logging.getLogger(__name__) @@ -293,21 +297,83 @@ class LocalApplicationsWidgets(QtWidgets.QWidget): return output +class RootsWidget(QtWidgets.QWidget): + def __init__(self, project_settings, parent): + super(RootsWidget, self).__init__(parent) + + self.project_settings = project_settings + + main_layout = QtWidgets.QVBoxLayout(self) + + self.content_layout = main_layout + + def refresh(self): + roots_entity = self.project_settings["project_anatomy"]["roots"] + for root_name, path_entity in roots_entity.items(): + platform_entity = path_entity[platform.system().lower()] + print(root_name, platform_entity.value) + + + +class _ProjectListWidget(ProjectListWidget): + def on_item_clicked(self, new_index): + new_project_name = new_index.data(QtCore.Qt.DisplayRole) + if new_project_name is None: + return + + if self.current_project == new_project_name: + return + + self.select_project(new_project_name) + self.current_project = new_project_name + self.project_changed.emit() + + +class ProjectSettingsWidget(QtWidgets.QWidget): + def __init__(self, project_settings, parent): + super(ProjectSettingsWidget, self).__init__(parent) + + projects_widget = _ProjectListWidget(self) + roots_widget = RootsWidget(project_settings, self) + + main_layout = QtWidgets.QHBoxLayout(self) + main_layout.setContentsMargins(0, 0, 0, 0) + main_layout.addWidget(projects_widget, 0) + main_layout.addWidget(roots_widget, 1) + + projects_widget.refresh() + + projects_widget.project_changed.connect(self._on_project_change) + + self.project_settings = project_settings + + self.projects_widget = projects_widget + self.roots_widget = roots_widget + + def _on_project_change(self): + self.project_settings.change_project( + self.projects_widget.project_name() + ) + self.roots_widget.refresh() + + class LocalSettingsWidget(QtWidgets.QWidget): def __init__(self, parent=None): super(LocalSettingsWidget, self).__init__(parent) self.system_settings = SystemSettings() - # self.project_settings = SystemSettings() + self.project_settings = ProjectSettings() user_settings = {} self.main_layout = QtWidgets.QVBoxLayout(self) self.general_widget = None self.apps_widget = None + self.projects_widget = None self._create_general_ui() self._create_app_ui() + self._create_project_ui() # Add spacer to main layout self.main_layout.addWidget(SpacerWidget(self), 1) @@ -350,6 +416,20 @@ class LocalSettingsWidget(QtWidgets.QWidget): self.app_widget = app_widget + def _create_project_ui(self): + project_expand_widget = ExpandingWidget("Project settings", self) + project_content = QtWidgets.QWidget(self) + project_layout = QtWidgets.QVBoxLayout(project_content) + project_layout.setContentsMargins(CHILD_OFFSET, 5, 0, 0) + project_expand_widget.set_content_widget(project_content) + + projects_widget = ProjectSettingsWidget(self.project_settings, self) + project_layout.addWidget(projects_widget) + + self.main_layout.addWidget(project_expand_widget) + + self.projects_widget = projects_widget + def set_value(self, value): if not value: value = {} From 8b7fa057e85949fb604757e1c38f5c4b32f5ee64 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 22 Feb 2021 19:23:00 +0100 Subject: [PATCH 03/61] roots widgets reflects project settings roots --- .../settings/widgets/local_settings.py | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/pype/tools/settings/settings/widgets/local_settings.py b/pype/tools/settings/settings/widgets/local_settings.py index 35ec7d7714..6b26c2ea03 100644 --- a/pype/tools/settings/settings/widgets/local_settings.py +++ b/pype/tools/settings/settings/widgets/local_settings.py @@ -302,17 +302,47 @@ class RootsWidget(QtWidgets.QWidget): super(RootsWidget, self).__init__(parent) self.project_settings = project_settings + self.widgts_by_root_name = {} main_layout = QtWidgets.QVBoxLayout(self) self.content_layout = main_layout def refresh(self): + while self.content_layout.count(): + item = self.content_layout.itemAt(0) + item.widget().hide() + self.content_layout.removeItem(item) + roots_entity = self.project_settings["project_anatomy"]["roots"] for root_name, path_entity in roots_entity.items(): platform_entity = path_entity[platform.system().lower()] - print(root_name, platform_entity.value) + root_widget = QtWidgets.QWidget(self) + key_input = QtWidgets.QLineEdit(root_widget) + key_input.setText(root_name) + key_input.setReadOnly(True) + + root_input_widget = QtWidgets.QWidget(root_widget) + root_input_layout = QtWidgets.QVBoxLayout(root_input_widget) + + value_input = QtWidgets.QLineEdit(root_input_widget) + value_input.setPlaceholderText( + "< Root overrides for this machine >" + ) + studio_input = QtWidgets.QLineEdit(root_input_widget) + studio_input.setText(platform_entity.value) + studio_input.setReadOnly(True) + + root_input_layout.addWidget(value_input) + root_input_layout.addWidget(studio_input) + + root_layout = QtWidgets.QHBoxLayout(root_widget) + root_layout.addWidget(key_input) + root_layout.addWidget(root_input_widget) + + self.content_layout.addWidget(root_widget) + self.content_layout.addWidget(SpacerWidget(self), 1) class _ProjectListWidget(ProjectListWidget): From 0841a0763f65f4aab1eae07d9be71e965b7d7b0d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 23 Feb 2021 11:24:09 +0100 Subject: [PATCH 04/61] root changes are projected as should be --- .../settings/widgets/local_settings.py | 107 ++++++++++++++++-- 1 file changed, 97 insertions(+), 10 deletions(-) diff --git a/pype/tools/settings/settings/widgets/local_settings.py b/pype/tools/settings/settings/widgets/local_settings.py index 6b26c2ea03..c73e1a7871 100644 --- a/pype/tools/settings/settings/widgets/local_settings.py +++ b/pype/tools/settings/settings/widgets/local_settings.py @@ -298,7 +298,10 @@ class LocalApplicationsWidgets(QtWidgets.QWidget): class RootsWidget(QtWidgets.QWidget): + value_changed = QtCore.Signal() + def __init__(self, project_settings, parent): + self._parent_widget = parent super(RootsWidget, self).__init__(parent) self.project_settings = project_settings @@ -314,36 +317,78 @@ class RootsWidget(QtWidgets.QWidget): item.widget().hide() self.content_layout.removeItem(item) + self.widgts_by_root_name.clear() + + default_placeholder = "< Root overrides for this machine >" + default_root_values = self.local_default_project_values() or {} + roots_entity = self.project_settings["project_anatomy"]["roots"] + is_in_default = self.project_settings.project_name is None for root_name, path_entity in roots_entity.items(): platform_entity = path_entity[platform.system().lower()] root_widget = QtWidgets.QWidget(self) - key_input = QtWidgets.QLineEdit(root_widget) - key_input.setText(root_name) - key_input.setReadOnly(True) + key_label = QtWidgets.QLabel(root_name, root_widget) root_input_widget = QtWidgets.QWidget(root_widget) root_input_layout = QtWidgets.QVBoxLayout(root_input_widget) value_input = QtWidgets.QLineEdit(root_input_widget) - value_input.setPlaceholderText( - "< Root overrides for this machine >" - ) + placeholder = None + if not is_in_default: + placeholder = default_root_values.get(root_name) + if placeholder: + placeholder = "< {} >".format(placeholder) + + if not placeholder: + placeholder = default_placeholder + value_input.setPlaceholderText(placeholder) + value_input.textChanged.connect(self._on_root_value_change) + studio_input = QtWidgets.QLineEdit(root_input_widget) studio_input.setText(platform_entity.value) studio_input.setReadOnly(True) root_input_layout.addWidget(value_input) + root_input_layout.addWidget(Separator(parent=self)) root_input_layout.addWidget(studio_input) root_layout = QtWidgets.QHBoxLayout(root_widget) - root_layout.addWidget(key_input) + root_layout.addWidget(key_label) root_layout.addWidget(root_input_widget) self.content_layout.addWidget(root_widget) + self.widgts_by_root_name[root_name] = value_input + self.content_layout.addWidget(SpacerWidget(self), 1) + def _on_root_value_change(self): + self.value_changed.emit() + + def local_default_project_values(self): + default_project = self._parent_widget.per_project_settings.get(None) + if default_project: + return default_project.get("roots") + return None + + def set_value(self, value): + if not value: + value = {} + + for root_name, widget in self.widgts_by_root_name.items(): + root_value = value.get(root_name) or "" + widget.setText(root_value) + + def settings_value(self): + output = {} + for root_name, widget in self.widgts_by_root_name.items(): + value = widget.text() + if value: + output[root_name] = value + if not output: + return None + return output + class _ProjectListWidget(ProjectListWidget): def on_item_clicked(self, new_index): @@ -363,6 +408,8 @@ class ProjectSettingsWidget(QtWidgets.QWidget): def __init__(self, project_settings, parent): super(ProjectSettingsWidget, self).__init__(parent) + self.per_project_settings = {} + projects_widget = _ProjectListWidget(self) roots_widget = RootsWidget(project_settings, self) @@ -374,18 +421,53 @@ class ProjectSettingsWidget(QtWidgets.QWidget): projects_widget.refresh() projects_widget.project_changed.connect(self._on_project_change) + roots_widget.value_changed.connect(self._on_root_value_change) + + roots_widget.refresh() self.project_settings = project_settings self.projects_widget = projects_widget self.roots_widget = roots_widget + def _current_value(self): + roots_value = self.roots_widget.settings_value() + current_value = {} + if roots_value: + current_value["roots"] = roots_value + return current_value + + def project_name(self): + return self.projects_widget.project_name() + def _on_project_change(self): - self.project_settings.change_project( - self.projects_widget.project_name() - ) + project_name = self.project_name() + + self.project_settings.change_project(project_name) self.roots_widget.refresh() + project_value = self.per_project_settings.get(project_name) or {} + self.roots_widget.set_value(project_value.get("roots")) + + def _on_root_value_change(self): + self.per_project_settings[self.project_name()] = ( + self._current_value() + ) + + def set_value(self, value): + if not value: + value = {} + self.per_project_settings = value + + def settings_value(self): + output = {} + for project_name, value in self.per_project_settings.items(): + if value: + output[project_name] = value + if not output: + return None + return output + class LocalSettingsWidget(QtWidgets.QWidget): def __init__(self, parent=None): @@ -466,6 +548,7 @@ class LocalSettingsWidget(QtWidgets.QWidget): self.general_widget.set_value(value.get("general")) self.app_widget.set_value(value.get("applications")) + self.projects_widget.set_value(value.get("projects")) def settings_value(self): output = {} @@ -476,6 +559,10 @@ class LocalSettingsWidget(QtWidgets.QWidget): app_value = self.app_widget.settings_value() if app_value: output["applications"] = app_value + + projects_value = self.projects_widget.settings_value() + if projects_value: + output["projects"] = projects_value return output From cdf6eedecc2548af58479fa6a94557121d710723 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 23 Feb 2021 15:26:27 +0100 Subject: [PATCH 05/61] added function for validation of mongo uri --- pype/lib/__init__.py | 2 ++ pype/lib/mongo.py | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/pype/lib/__init__.py b/pype/lib/__init__.py index 4b7e59ab3d..9d04c1ce31 100644 --- a/pype/lib/__init__.py +++ b/pype/lib/__init__.py @@ -23,6 +23,7 @@ from .mongo import ( decompose_url, compose_url, get_default_components, + validate_mongo_connection, PypeMongoConnection ) from .anatomy import ( @@ -191,6 +192,7 @@ __all__ = [ "decompose_url", "compose_url", "get_default_components", + "validate_mongo_connection", "PypeMongoConnection", "IniSettingRegistry", diff --git a/pype/lib/mongo.py b/pype/lib/mongo.py index f82c8b5e23..04798d88ff 100644 --- a/pype/lib/mongo.py +++ b/pype/lib/mongo.py @@ -93,6 +93,42 @@ def extract_port_from_url(url): return parsed_url.port +def validate_mongo_connection(mongo_uri): + """Check if provided mongodb URL is valid. + + Args: + mongo_uri (str): URL to validate. + + Raises: + ValueError: When port in mongo uri is not valid. + pymongo.errors.InvalidURI: If passed mongo is invalid. + pymongo.errors.ServerSelectionTimeoutError: If connection timeout + passed so probably couldn't connect to mongo server. + + """ + parsed = urlparse(mongo_uri) + # Force validation of scheme + if parsed.scheme not in ["mongodb", "mongodb+srv"]: + raise pymongo.errors.InvalidURI(( + "Invalid URI scheme:" + " URI must begin with 'mongodb://' or 'mongodb+srv://'" + )) + # we have mongo connection string. Let's try if we can connect. + components = decompose_url(mongo_uri) + mongo_args = { + "host": compose_url(**components), + "serverSelectionTimeoutMS": 1000 + } + port = components.get("port") + if port is not None: + mongo_args["port"] = int(port) + + # Create connection + client = pymongo.MongoClient(**mongo_args) + client.server_info() + client.close() + + class PypeMongoConnection: """Singleton MongoDB connection. From 958d221c449c31be01339f9f24acaf55c405cd93 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 23 Feb 2021 16:24:44 +0100 Subject: [PATCH 06/61] added functions to change pype mongo url and get local site id --- pype/api.py | 9 +++++++-- pype/lib/__init__.py | 7 ++++++- pype/lib/user_settings.py | 42 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 3 deletions(-) diff --git a/pype/api.py b/pype/api.py index 71c31efa93..44caa7632f 100644 --- a/pype/api.py +++ b/pype/api.py @@ -22,7 +22,9 @@ from .lib import ( get_app_environments_for_context, source_hash, get_latest_version, - get_global_environments + get_global_environments, + get_local_site_id, + change_pype_mongo_url ) from .lib.mongo import ( @@ -109,5 +111,8 @@ __all__ = [ "run_subprocess", "get_latest_version", - "get_global_environments" + "get_global_environments", + + "get_local_site_id", + "change_pype_mongo_url" ] diff --git a/pype/lib/__init__.py b/pype/lib/__init__.py index 9d04c1ce31..b5674a9e5d 100644 --- a/pype/lib/__init__.py +++ b/pype/lib/__init__.py @@ -95,7 +95,9 @@ from .plugin_tools import ( from .user_settings import ( IniSettingRegistry, JSONSettingRegistry, - PypeSettingsRegistry + PypeSettingsRegistry, + get_local_site_id, + change_pype_mongo_url ) from .path_tools import ( @@ -198,6 +200,9 @@ __all__ = [ "IniSettingRegistry", "JSONSettingRegistry", "PypeSettingsRegistry", + "get_local_site_id", + "change_pype_mongo_url", + "timeit", "is_overlapping_otio_ranges", diff --git a/pype/lib/user_settings.py b/pype/lib/user_settings.py index 00ce68cb0b..def126d913 100644 --- a/pype/lib/user_settings.py +++ b/pype/lib/user_settings.py @@ -28,6 +28,8 @@ import platform import appdirs import six +from .import validate_mongo_connection + @six.add_metaclass(ABCMeta) class ASettingRegistry(): @@ -464,3 +466,43 @@ class PypeSettingsRegistry(JSONSettingRegistry): self.product = "pype" path = appdirs.user_data_dir(self.product, self.vendor) super(PypeSettingsRegistry, self).__init__("pype_settings", path) + + +def _create_local_site_id(registry=None): + """Create a local site identifier.""" + from uuid import uuid4 + + if registry is None: + registry = PypeSettingsRegistry() + + new_id = str(uuid4()) + + print("Created local site id \"{}\"".format(new_id)) + + registry.set_secure_item("localId", new_id) + + return new_id + + +def get_local_site_id(): + """Get local site identifier. + + Identifier is created if does not exists yet. + """ + registry = PypeSettingsRegistry() + try: + return registry.get_secure_item("localId") + except ValueError: + return _create_local_site_id() + + +def change_pype_mongo_url(new_mongo_url): + """Change mongo url in pype registry. + + Change of Pype mongo URL require restart of running pype processes or + processes using pype. + """ + + validate_mongo_connection(new_mongo_url) + registry = PypeSettingsRegistry() + registry.set_secure_item("pypeMongo", new_mongo_url) From ebdd83d1965ac1cde7f14ca4964ea94026ff7815 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 23 Feb 2021 16:25:24 +0100 Subject: [PATCH 07/61] added abstract handler of local settings --- pype/settings/handlers.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/pype/settings/handlers.py b/pype/settings/handlers.py index 0df4c98820..f9e1ad514a 100644 --- a/pype/settings/handlers.py +++ b/pype/settings/handlers.py @@ -103,6 +103,23 @@ class SettingsHandler: pass +@six.add_metaclass(ABCMeta) +class LocalSettingsHandler: + @abstractmethod + def save_local_settings(self, data): + """Save local data of local settings. + + Args: + data(dict): Data of local data with override metadata. + """ + pass + + @abstractmethod + def get_local_settings(self): + """Studio overrides of system settings.""" + pass + + class SettingsFileHandler(SettingsHandler): def __init__(self): self.log = logging.getLogger("SettingsFileHandler") From d4f21a95b2a9e6857eb2f7c319477c908f867f5d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 23 Feb 2021 17:21:36 +0100 Subject: [PATCH 08/61] added constants for local settings --- pype/settings/constants.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pype/settings/constants.py b/pype/settings/constants.py index c68826f45b..0e346ffb7e 100644 --- a/pype/settings/constants.py +++ b/pype/settings/constants.py @@ -15,7 +15,10 @@ METADATA_KEYS = ( SYSTEM_SETTINGS_KEY = "system_settings" PROJECT_SETTINGS_KEY = "project_settings" PROJECT_ANATOMY_KEY = "project_anatomy" +LOCAL_SETTING_KEY = "local_settings" +# Key replacing `None` as key for local settings values +DEFAULT_PROJECT_KEY = "__default_project__" __all__ = ( "M_OVERRIDEN_KEY", @@ -26,5 +29,8 @@ __all__ = ( "SYSTEM_SETTINGS_KEY", "PROJECT_SETTINGS_KEY", - "PROJECT_ANATOMY_KEY" + "PROJECT_ANATOMY_KEY", + "LOCAL_SETTING_KEY", + + "DEFAULT_PROJECT_KEY" ) From 51ca593a5ee23d2b079c009cfcd8164e2ef117a5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 23 Feb 2021 17:21:54 +0100 Subject: [PATCH 09/61] implemented local settings handler using mongo --- pype/settings/handlers.py | 68 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/pype/settings/handlers.py b/pype/settings/handlers.py index f9e1ad514a..e7cf53b116 100644 --- a/pype/settings/handlers.py +++ b/pype/settings/handlers.py @@ -10,7 +10,8 @@ import pype from .constants import ( SYSTEM_SETTINGS_KEY, PROJECT_SETTINGS_KEY, - PROJECT_ANATOMY_KEY + PROJECT_ANATOMY_KEY, + LOCAL_SETTING_KEY ) from .lib import load_json_file @@ -512,3 +513,68 @@ class MongoSettingsHandler(SettingsHandler): if not project_name: return {} return self._get_project_anatomy_overrides(project_name) + + +class MongoLocalSettingshandler(LocalSettingsHandler): + """Settings handler that use mongo for store and load local settings.""" + + def __init__(self, local_site_id=None): + # Get mongo connection + from pype.lib import ( + PypeMongoConnection, + get_local_site_id + ) + + if local_site_id is None: + local_site_id = get_local_site_id() + settings_collection = PypeMongoConnection.get_mongo_client() + + # TODO prepare version of pype + # - pype version should define how are settings saved and loaded + + # TODO modify to not use hardcoded keys + database_name = "pype" + collection_name = "settings" + + self.settings_collection = settings_collection + + self.database_name = database_name + self.collection_name = collection_name + + self.collection = settings_collection[database_name][collection_name] + + self.local_site_id = local_site_id + + self.settings_cache = CacheValues() + + def save_local_settings(self, data): + """Save local settings. + + Args: + data(dict): Data of studio overrides with override metadata. + """ + self.settings_cache.update_data(data) + + self.collection.replace_one( + { + "type": LOCAL_SETTING_KEY, + "site_id": self.local_site_id + }, + { + "type": LOCAL_SETTING_KEY, + "site_id": self.local_site_id, + "value": self.settings_cache.to_json_string() + }, + upsert=True + ) + + def get_local_settings(self): + """Local settings for local site id.""" + if self.settings_cache.is_outdated: + document = self.collection.find_one({ + "type": LOCAL_SETTING_KEY, + "site_id": self.local_site_id + }) + + self.settings_cache.update_from_document(document) + return self.settings_cache.data_copy() From 4d1b825328630660e03ad74e674d2a583d08b10b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 23 Feb 2021 17:22:27 +0100 Subject: [PATCH 10/61] implemented functions to load and save local settings --- pype/settings/lib.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/pype/settings/lib.py b/pype/settings/lib.py index dfc46e1a5a..7b76346089 100644 --- a/pype/settings/lib.py +++ b/pype/settings/lib.py @@ -32,6 +32,9 @@ _DEFAULT_SETTINGS = None # Handler of studio overrides _SETTINGS_HANDLER = None +# Handler of local settings +_LOCAL_SETTINGS_HANDLER = None + def require_handler(func): @functools.wraps(func) @@ -43,6 +46,16 @@ def require_handler(func): return wrapper +def require_local_handler(func): + @functools.wraps(func) + def wrapper(*args, **kwargs): + global _LOCAL_SETTINGS_HANDLER + if _LOCAL_SETTINGS_HANDLER is None: + _LOCAL_SETTINGS_HANDLER = create_local_settings_handler() + return func(*args, **kwargs) + return wrapper + + def create_settings_handler(): from .handlers import MongoSettingsHandler # Handler can't be created in global space on initialization but only when @@ -50,6 +63,11 @@ def create_settings_handler(): return MongoSettingsHandler() +def create_local_settings_handler(): + from .handlers import MongoLocalSettingshandler + return MongoLocalSettingshandler() + + @require_handler def save_studio_settings(data): return _SETTINGS_HANDLER.save_studio_settings(data) @@ -65,6 +83,16 @@ def save_project_anatomy(project_name, anatomy_data): return _SETTINGS_HANDLER.save_project_anatomy(project_name, anatomy_data) +@require_local_handler +def save_local_settings(data): + return _LOCAL_SETTINGS_HANDLER.save_local_settings(data) + + +@require_local_handler +def get_local_settings(): + return _LOCAL_SETTINGS_HANDLER.get_local_settings() + + @require_handler def get_studio_system_settings_overrides(): return _SETTINGS_HANDLER.get_studio_system_settings_overrides() From f1190ce0534ac70a97bf520ee79c592ce7dfde97 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 23 Feb 2021 17:37:17 +0100 Subject: [PATCH 11/61] removed DEFAULT_PROJECT_KEY from constants as it is handler specific --- pype/settings/constants.py | 6 +----- pype/settings/handlers.py | 30 ++++++++++++++++++++++++------ 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/pype/settings/constants.py b/pype/settings/constants.py index 0e346ffb7e..fcc3a1d2dc 100644 --- a/pype/settings/constants.py +++ b/pype/settings/constants.py @@ -17,8 +17,6 @@ PROJECT_SETTINGS_KEY = "project_settings" PROJECT_ANATOMY_KEY = "project_anatomy" LOCAL_SETTING_KEY = "local_settings" -# Key replacing `None` as key for local settings values -DEFAULT_PROJECT_KEY = "__default_project__" __all__ = ( "M_OVERRIDEN_KEY", @@ -30,7 +28,5 @@ __all__ = ( "SYSTEM_SETTINGS_KEY", "PROJECT_SETTINGS_KEY", "PROJECT_ANATOMY_KEY", - "LOCAL_SETTING_KEY", - - "DEFAULT_PROJECT_KEY" + "LOCAL_SETTING_KEY" ) diff --git a/pype/settings/handlers.py b/pype/settings/handlers.py index e7cf53b116..c76aa6c40a 100644 --- a/pype/settings/handlers.py +++ b/pype/settings/handlers.py @@ -517,6 +517,7 @@ class MongoSettingsHandler(SettingsHandler): class MongoLocalSettingshandler(LocalSettingsHandler): """Settings handler that use mongo for store and load local settings.""" + default_project_key = "__default_project__" def __init__(self, local_site_id=None): # Get mongo connection @@ -545,7 +546,7 @@ class MongoLocalSettingshandler(LocalSettingsHandler): self.local_site_id = local_site_id - self.settings_cache = CacheValues() + self.local_settings_cache = CacheValues() def save_local_settings(self, data): """Save local settings. @@ -553,7 +554,15 @@ class MongoLocalSettingshandler(LocalSettingsHandler): Args: data(dict): Data of studio overrides with override metadata. """ - self.settings_cache.update_data(data) + data = data or {} + + # Replace key `None` (default project values) with constant string + if "projects" in data and None in data["projects"]: + data["projects"][self.default_project_key] = ( + data["projects"].pop(None) + ) + + self.local_settings_cache.update_data(data) self.collection.replace_one( { @@ -563,18 +572,27 @@ class MongoLocalSettingshandler(LocalSettingsHandler): { "type": LOCAL_SETTING_KEY, "site_id": self.local_site_id, - "value": self.settings_cache.to_json_string() + "value": self.local_settings_cache.to_json_string() }, upsert=True ) def get_local_settings(self): """Local settings for local site id.""" - if self.settings_cache.is_outdated: + if self.local_settings_cache.is_outdated: document = self.collection.find_one({ "type": LOCAL_SETTING_KEY, "site_id": self.local_site_id }) - self.settings_cache.update_from_document(document) - return self.settings_cache.data_copy() + self.local_settings_cache.update_from_document(document) + data = self.local_settings_cache.data + if ( + "projects" in data + and self.default_project_key in data["projects"] + ): + data["projects"][None] = data["projects"].pop( + self.default_project_key + ) + + return self.local_settings_cache.data_copy() From 73ad15d79382407fc79a71997d16831da887919a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 23 Feb 2021 17:38:58 +0100 Subject: [PATCH 12/61] settings are using local settings functions and have specific category for mongo url --- .../settings/widgets/local_settings.py | 177 ++++++++++++++---- 1 file changed, 137 insertions(+), 40 deletions(-) diff --git a/pype/tools/settings/settings/widgets/local_settings.py b/pype/tools/settings/settings/widgets/local_settings.py index c73e1a7871..25d8b249ec 100644 --- a/pype/tools/settings/settings/widgets/local_settings.py +++ b/pype/tools/settings/settings/widgets/local_settings.py @@ -1,3 +1,6 @@ +import os +import sys +import traceback import platform import logging from Qt import QtWidgets, QtCore @@ -8,14 +11,27 @@ from .widgets import ( ) from .. import style from .lib import CHILD_OFFSET +from pype.settings.constants import PROJECT_ANATOMY_KEY +from pype.settings.lib import ( + get_local_settings, + save_local_settings +) from pype.api import ( SystemSettings, - ProjectSettings + ProjectSettings, + change_pype_mongo_url ) +from pymongo.errors import ServerSelectionTimeoutError log = logging.getLogger(__name__) +LOCAL_GENERAL_KEY = "general" +LOCAL_PROJECTS_KEY = "projects" +LOCAL_APPS_KEY = "applications" +LOCAL_ROOTS_KEY = "roots" + + class Separator(QtWidgets.QFrame): def __init__(self, height=None, parent=None): super(Separator, self).__init__(parent) @@ -32,50 +48,107 @@ class Separator(QtWidgets.QFrame): layout.addWidget(splitter_item) +class PypeMongoWidget(QtWidgets.QWidget): + def __init__(self, parent): + super(PypeMongoWidget, self).__init__(parent) + + # Warning label + warning_label = QtWidgets.QLabel(( + "WARNING: Requires restart. Change of Pype Mongo requires to" + " restart of all running Pype processes and process using Pype" + " (Including this)." + "\n- all changes in different categories won't be saved." + ), self) + warning_label.setStyleSheet("font-weight: bold;") + + # Label + mongo_url_label = QtWidgets.QLabel("Pype Mongo URL", self) + + # Input + mongo_url_input = QtWidgets.QLineEdit(self) + mongo_url_input.setPlaceholderText("< Pype Mongo URL >") + mongo_url_input.setText(os.environ["PYPE_MONGO"]) + + # Confirm button + mongo_url_change_btn = QtWidgets.QPushButton("Confirm Change", self) + + layout = QtWidgets.QGridLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.addWidget(warning_label, 0, 0, 1, 3) + layout.addWidget(mongo_url_label, 1, 0) + layout.addWidget(mongo_url_input, 1, 1) + layout.addWidget(mongo_url_change_btn, 1, 2) + + mongo_url_change_btn.clicked.connect(self._on_confirm_click) + + self.mongo_url_input = mongo_url_input + + def _on_confirm_click(self): + value = self.mongo_url_input.text() + + dialog = QtWidgets.QMessageBox(self) + + title = "Pype mongo changed" + message = ( + "Pype mongo url was successfully changed. Restart Pype please." + ) + details = None + + try: + change_pype_mongo_url(value) + except Exception as exc: + if isinstance(exc, ServerSelectionTimeoutError): + error_message = ( + "Connection timeout passed." + " Probably can't connect to the Mongo server." + ) + else: + error_message = str(exc) + + title = "Pype mongo change failed" + # TODO catch exception message more gracefully + message = ( + "Pype mongo change was not successful." + " Full traceback can be found in details section.\n\n" + "Error message:\n{}" + ).format(error_message) + details = "\n".join(traceback.format_exception(*sys.exc_info())) + dialog.setWindowTitle(title) + dialog.setText(message) + if details: + dialog.setDetailedText(details) + dialog.exec_() + + class LocalGeneralWidgets(QtWidgets.QWidget): def __init__(self, parent): super(LocalGeneralWidgets, self).__init__(parent) - mongo_url_label = QtWidgets.QLabel("Pype Mongo URL", self) - mongo_url_input = QtWidgets.QLineEdit(self) - local_site_name_label = QtWidgets.QLabel("Local site name", self) local_site_name_input = QtWidgets.QLineEdit(self) - layout = QtWidgets.QGridLayout(self) + layout = QtWidgets.QFormLayout(self) layout.setContentsMargins(0, 0, 0, 0) - row = 0 - layout.addWidget(mongo_url_label, row, 0) - layout.addWidget(mongo_url_input, row, 1) - row += 1 - layout.addWidget(local_site_name_label, row, 0) - layout.addWidget(local_site_name_input, row, 1) - self.mongo_url_input = mongo_url_input + layout.addRow("Local site name", local_site_name_input) + self.local_site_name_input = local_site_name_input def set_value(self, value): - mongo_url = "" site_name = "" if value: - mongo_url = value.get("mongo_url", mongo_url) site_name = value.get("site_name", site_name) - self.mongo_url_input.setText(mongo_url) self.local_site_name_input.setText(site_name) def settings_value(self): # Add changed # If these have changed then output = {} - mongo_url = self.mongo_url_input.text() - if mongo_url: - output["mongo_url"] = mongo_url - local_site_name = self.local_site_name_input.text() if local_site_name: output["site_name"] = local_site_name # Do not return output yet since we don't have mechanism to save or # load these data through api calls - return None + return output class PathInput(QtWidgets.QWidget): @@ -322,7 +395,9 @@ class RootsWidget(QtWidgets.QWidget): default_placeholder = "< Root overrides for this machine >" default_root_values = self.local_default_project_values() or {} - roots_entity = self.project_settings["project_anatomy"]["roots"] + roots_entity = ( + self.project_settings[PROJECT_ANATOMY_KEY][LOCAL_ROOTS_KEY] + ) is_in_default = self.project_settings.project_name is None for root_name, path_entity in roots_entity.items(): platform_entity = path_entity[platform.system().lower()] @@ -368,7 +443,7 @@ class RootsWidget(QtWidgets.QWidget): def local_default_project_values(self): default_project = self._parent_widget.per_project_settings.get(None) if default_project: - return default_project.get("roots") + return default_project.get(LOCAL_ROOTS_KEY) return None def set_value(self, value): @@ -418,13 +493,9 @@ class ProjectSettingsWidget(QtWidgets.QWidget): main_layout.addWidget(projects_widget, 0) main_layout.addWidget(roots_widget, 1) - projects_widget.refresh() - projects_widget.project_changed.connect(self._on_project_change) roots_widget.value_changed.connect(self._on_root_value_change) - roots_widget.refresh() - self.project_settings = project_settings self.projects_widget = projects_widget @@ -434,7 +505,7 @@ class ProjectSettingsWidget(QtWidgets.QWidget): roots_value = self.roots_widget.settings_value() current_value = {} if roots_value: - current_value["roots"] = roots_value + current_value[LOCAL_ROOTS_KEY] = roots_value return current_value def project_name(self): @@ -447,7 +518,7 @@ class ProjectSettingsWidget(QtWidgets.QWidget): self.roots_widget.refresh() project_value = self.per_project_settings.get(project_name) or {} - self.roots_widget.set_value(project_value.get("roots")) + self.roots_widget.set_value(project_value.get(LOCAL_ROOTS_KEY)) def _on_root_value_change(self): self.per_project_settings[self.project_name()] = ( @@ -459,6 +530,13 @@ class ProjectSettingsWidget(QtWidgets.QWidget): value = {} self.per_project_settings = value + self.projects_widget.refresh() + self.roots_widget.refresh() + + project_name = self.project_name() + project_value = self.per_project_settings.get(project_name) or {} + self.roots_widget.set_value(project_value.get(LOCAL_ROOTS_KEY)) + def settings_value(self): output = {} for project_name, value in self.per_project_settings.items(): @@ -475,14 +553,15 @@ class LocalSettingsWidget(QtWidgets.QWidget): self.system_settings = SystemSettings() self.project_settings = ProjectSettings() - user_settings = {} self.main_layout = QtWidgets.QVBoxLayout(self) + self.pype_mongo_widget = None self.general_widget = None self.apps_widget = None self.projects_widget = None + self._create_pype_mongo_ui() self._create_general_ui() self._create_app_ui() self._create_project_ui() @@ -490,13 +569,23 @@ class LocalSettingsWidget(QtWidgets.QWidget): # Add spacer to main layout self.main_layout.addWidget(SpacerWidget(self), 1) - self.set_value(user_settings) + def _create_pype_mongo_ui(self): + pype_mongo_expand_widget = ExpandingWidget("Pype Mongo URL", self) + pype_mongo_content = QtWidgets.QWidget(self) + pype_mongo_layout = QtWidgets.QVBoxLayout(pype_mongo_content) + pype_mongo_layout.setContentsMargins(CHILD_OFFSET, 5, 0, 0) + pype_mongo_expand_widget.set_content_widget(pype_mongo_content) + + pype_mongo_widget = PypeMongoWidget(self) + pype_mongo_layout.addWidget(pype_mongo_widget) + + self.main_layout.addWidget(pype_mongo_expand_widget) + + self.pype_mongo_widget = pype_mongo_widget def _create_general_ui(self): # General - general_expand_widget = ExpandingWidget( - "General (Does nothing!)", self - ) + general_expand_widget = ExpandingWidget("General", self) general_content = QtWidgets.QWidget(self) general_layout = QtWidgets.QVBoxLayout(general_content) @@ -546,23 +635,23 @@ class LocalSettingsWidget(QtWidgets.QWidget): if not value: value = {} - self.general_widget.set_value(value.get("general")) - self.app_widget.set_value(value.get("applications")) - self.projects_widget.set_value(value.get("projects")) + self.general_widget.set_value(value.get(LOCAL_GENERAL_KEY)) + self.app_widget.set_value(value.get(LOCAL_APPS_KEY)) + self.projects_widget.set_value(value.get(LOCAL_PROJECTS_KEY)) def settings_value(self): output = {} general_value = self.general_widget.settings_value() if general_value: - output["general"] = general_value + output[LOCAL_GENERAL_KEY] = general_value app_value = self.app_widget.settings_value() if app_value: - output["applications"] = app_value + output[LOCAL_APPS_KEY] = app_value projects_value = self.projects_widget.settings_value() if projects_value: - output["projects"] = projects_value + output[LOCAL_PROJECTS_KEY] = projects_value return output @@ -598,9 +687,17 @@ class LocalSettingsWindow(QtWidgets.QWidget): self.settings_widget = settings_widget self.save_btn = save_btn + self.reset() + + def reset(self): + value = get_local_settings() + self.settings_widget.set_value(value) + def _on_save_clicked(self): try: value = self.settings_widget.settings_value() - print(value) except Exception: log.warning("Failed to save", exc_info=True) + return + + save_local_settings(value) From f8d0f6a14176d23be0b6871a3b3030a5a72b9617 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 23 Feb 2021 17:39:14 +0100 Subject: [PATCH 13/61] moved local settings functions in code --- pype/settings/lib.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/pype/settings/lib.py b/pype/settings/lib.py index 7b76346089..ecb53beaff 100644 --- a/pype/settings/lib.py +++ b/pype/settings/lib.py @@ -83,16 +83,6 @@ def save_project_anatomy(project_name, anatomy_data): return _SETTINGS_HANDLER.save_project_anatomy(project_name, anatomy_data) -@require_local_handler -def save_local_settings(data): - return _LOCAL_SETTINGS_HANDLER.save_local_settings(data) - - -@require_local_handler -def get_local_settings(): - return _LOCAL_SETTINGS_HANDLER.get_local_settings() - - @require_handler def get_studio_system_settings_overrides(): return _SETTINGS_HANDLER.get_studio_system_settings_overrides() @@ -118,6 +108,16 @@ def get_project_anatomy_overrides(project_name): return _SETTINGS_HANDLER.get_project_anatomy_overrides(project_name) +@require_local_handler +def save_local_settings(data): + return _LOCAL_SETTINGS_HANDLER.save_local_settings(data) + + +@require_local_handler +def get_local_settings(): + return _LOCAL_SETTINGS_HANDLER.get_local_settings() + + class DuplicatedEnvGroups(Exception): def __init__(self, duplicated): self.origin_duplicated = duplicated From f924afa41e52e12ca66709650a810cb0a5c2965a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 23 Feb 2021 18:03:46 +0100 Subject: [PATCH 14/61] app executable is stored under specific key --- .../settings/widgets/local_settings.py | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/pype/tools/settings/settings/widgets/local_settings.py b/pype/tools/settings/settings/widgets/local_settings.py index 25d8b249ec..4eef507839 100644 --- a/pype/tools/settings/settings/widgets/local_settings.py +++ b/pype/tools/settings/settings/widgets/local_settings.py @@ -214,7 +214,7 @@ class AppVariantWidget(QtWidgets.QWidget): def __init__(self, group_label, variant_entity, parent): super(AppVariantWidget, self).__init__(parent) - self.input_widget = None + self.executable_input_widget = None label = " ".join([group_label, variant_entity.label]) @@ -238,10 +238,10 @@ class AppVariantWidget(QtWidgets.QWidget): content_layout.addWidget(warn_label) return - input_widget = PathInput( + executable_input_widget = PathInput( content_widget, self.exec_placeholder, self.args_placeholder ) - content_layout.addWidget(input_widget) + content_layout.addWidget(executable_input_widget) studio_executables = ( variant_entity["executables"][platform.system().lower()] @@ -255,20 +255,28 @@ class AppVariantWidget(QtWidgets.QWidget): path_widget.set_value(item.value) content_layout.addWidget(path_widget) - self.input_widget = input_widget + self.executable_input_widget = executable_input_widget def set_value(self, value): - if not self.input_widget: + if not self.executable_input_widget: return if not value: - value = [] - self.input_widget.set_value(value) + value = {} + elif not isinstance(value, dict): + print("Got invalid value type {}. Expected {}".format( + type(value), dict + )) + value = {} + self.executable_input_widget.set_value(value.get("executable")) def settings_value(self): - if not self.input_widget: + if not self.executable_input_widget: return None - return self.input_widget.settings_value() + value = self.executable_input_widget.settings_value() + if not value: + return None + return {"executable": self.executable_input_widget.settings_value()} class AppGroupWidget(QtWidgets.QWidget): From 158119c2c38c1ec69fb832df8d427abc2dd6d038 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 23 Feb 2021 18:32:03 +0100 Subject: [PATCH 15/61] added functions to apply local settings --- pype/settings/lib.py | 74 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/pype/settings/lib.py b/pype/settings/lib.py index ecb53beaff..b07bd99e5d 100644 --- a/pype/settings/lib.py +++ b/pype/settings/lib.py @@ -2,6 +2,7 @@ import os import json import functools import logging +import platform import copy from .constants import ( M_OVERRIDEN_KEY, @@ -337,6 +338,69 @@ def apply_overrides(source_data, override_data): return merge_overrides(_source_data, override_data) +def apply_local_settings_on_system_settings(system_settings, local_settings): + """Apply local settings on studio system settings. + + In local settings are set application executables. + """ + if not local_settings or "applications" not in local_settings: + return + + current_platform = platform.system().lower() + for app_group_name, value in local_settings["applications"].items(): + if not value or app_group_name not in system_settings["applications"]: + continue + + variants = system_settings["applications"][app_group_name]["variants"] + for app_name, app_value in value.items(): + if not app_value or app_name not in variants: + continue + + executable = app_value.get("executable") + if not executable: + continue + platform_executables = variants[app_name]["executables"].get( + current_platform + ) + new_executables = [executable] + new_executables.extend(platform_executables) + variants[app_name]["executables"] = new_executables + + +def apply_local_settings_on_anatomy_settings( + anatomy_settings, local_settings, project_name +): + if not local_settings: + return + + local_project_settings = local_settings.get("projects") + if not local_project_settings: + return + + current_platform = platform.system().lower() + local_defaults = local_project_settings.get(None) + root_data = anatomy_settings["roots"] + if local_defaults and "roots" in local_defaults: + for root_name, path in local_defaults["roots"].items(): + if root_name not in root_data: + continue + anatomy_settings["roots"][root_name][current_platform] = ( + path + ) + if project_name is None: + return + + local_projects = local_project_settings.get(project_name) + if local_projects and "roots" in local_projects: + for root_name, path in local_projects["roots"].items(): + if root_name not in root_data: + print(root_name, "not in root data") + continue + anatomy_settings["roots"][root_name][current_platform] = ( + path + ) + + def get_system_settings(clear_metadata=True): """System settings with applied studio overrides.""" default_values = get_default_settings()[SYSTEM_SETTINGS_KEY] @@ -344,6 +408,10 @@ def get_system_settings(clear_metadata=True): result = apply_overrides(default_values, studio_values) if clear_metadata: clear_metadata_from_settings(result) + # TODO local settings may be required to apply for environments + local_settings = get_local_settings() + apply_local_settings_on_system_settings(result, local_settings) + return result @@ -371,6 +439,8 @@ def get_default_anatomy_settings(clear_metadata=True): result[key] = value if clear_metadata: clear_metadata_from_settings(result) + local_settings = get_local_settings() + apply_local_settings_on_anatomy_settings(result, local_settings, None) return result @@ -396,6 +466,10 @@ def get_anatomy_settings(project_name, clear_metadata=True): result[key] = value if clear_metadata: clear_metadata_from_settings(result) + local_settings = get_local_settings() + apply_local_settings_on_anatomy_settings( + result, local_settings, project_name + ) return result From d3801cbb4d9a86666d099fbb25b3868bfbba7dae Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 23 Feb 2021 18:33:08 +0100 Subject: [PATCH 16/61] localId is not stored as secured item because would not be accessible in python 2 hosts --- pype/lib/user_settings.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/lib/user_settings.py b/pype/lib/user_settings.py index def126d913..70313bc094 100644 --- a/pype/lib/user_settings.py +++ b/pype/lib/user_settings.py @@ -479,7 +479,7 @@ def _create_local_site_id(registry=None): print("Created local site id \"{}\"".format(new_id)) - registry.set_secure_item("localId", new_id) + registry.set_item("localId", new_id) return new_id @@ -491,7 +491,7 @@ def get_local_site_id(): """ registry = PypeSettingsRegistry() try: - return registry.get_secure_item("localId") + return registry.get_item("localId") except ValueError: return _create_local_site_id() From 29430f3b8fa19af0f71300e0cc55715fbb250f8a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 23 Feb 2021 18:40:33 +0100 Subject: [PATCH 17/61] added local settings action to tray --- pype/modules/__init__.py | 5 +- pype/modules/base.py | 1 + pype/modules/settings_action.py | 55 +++++++++++++++++++ pype/tools/settings/__init__.py | 4 +- pype/tools/settings/settings/__init__.py | 2 + .../settings/settings/widgets/__init__.py | 4 +- 6 files changed, 68 insertions(+), 3 deletions(-) diff --git a/pype/modules/__init__.py b/pype/modules/__init__.py index 93fc92f9d5..874d69c41d 100644 --- a/pype/modules/__init__.py +++ b/pype/modules/__init__.py @@ -9,7 +9,10 @@ from .base import ( ModulesManager, TrayModulesManager ) -from .settings_action import SettingsAction +from .settings_action import ( + SettingsAction, + LocalSettingsAction +) from .rest_api import ( RestApiModule, IRestApi diff --git a/pype/modules/base.py b/pype/modules/base.py index ad0fecb8f7..7efd00e39e 100644 --- a/pype/modules/base.py +++ b/pype/modules/base.py @@ -627,6 +627,7 @@ class TrayModulesManager(ModulesManager): "clockify", "standalonepublish_tool", "log_viewer", + "local_settings", "settings" ) diff --git a/pype/modules/settings_action.py b/pype/modules/settings_action.py index c1fa8a68bc..aab10e9ebf 100644 --- a/pype/modules/settings_action.py +++ b/pype/modules/settings_action.py @@ -58,3 +58,58 @@ class SettingsAction(PypeModule, ITrayAction): # Reset content if was not visible if not was_visible: self.settings_window.reset() + + +class LocalSettingsAction(PypeModule, ITrayAction): + """Action to show Setttings tool.""" + name = "local_settings" + label = "Local Settings" + + def initialize(self, _modules_settings): + # This action is always enabled + self.enabled = True + + # Tray attributes + self.settings_window = None + + def connect_with_modules(self, *_a, **_kw): + return + + def tray_init(self): + """Initialization in tray implementation of ITrayAction.""" + self.create_settings_window() + + def on_action_trigger(self): + """Implementation for action trigger of ITrayAction.""" + self.show_settings_window() + + def create_settings_window(self): + """Initializa Settings Qt window.""" + if self.settings_window: + return + from pype.tools.settings import LocalSettingsWindow + self.settings_window = LocalSettingsWindow() + + def show_settings_window(self): + """Show settings tool window. + + Raises: + AssertionError: Window must be already created. Call + `create_settings_window` before callint this method. + """ + if not self.settings_window: + raise AssertionError("Window is not initialized.") + + # Store if was visible + was_visible = self.settings_window.isVisible() + + # Show settings gui + self.settings_window.show() + + # Pull window to the front. + self.settings_window.raise_() + self.settings_window.activateWindow() + + # Reset content if was not visible + if not was_visible: + self.settings_window.reset() diff --git a/pype/tools/settings/__init__.py b/pype/tools/settings/__init__.py index 7bc54f9ab6..578c6ef82c 100644 --- a/pype/tools/settings/__init__.py +++ b/pype/tools/settings/__init__.py @@ -4,7 +4,8 @@ from Qt import QtWidgets, QtGui from .settings import ( style, MainWidget, - ProjectListWidget + ProjectListWidget, + LocalSettingsWindow ) @@ -33,5 +34,6 @@ __all__ = ( "style", "MainWidget", "ProjectListWidget", + "LocalSettingsWindow", "main" ) diff --git a/pype/tools/settings/settings/__init__.py b/pype/tools/settings/settings/__init__.py index 3c12a73639..4d930b3fda 100644 --- a/pype/tools/settings/settings/__init__.py +++ b/pype/tools/settings/settings/__init__.py @@ -1,6 +1,7 @@ from . import style from .widgets import ( MainWidget, + LocalSettingsWindow, ProjectListWidget ) @@ -8,5 +9,6 @@ from .widgets import ( __all__ = ( "style", "MainWidget", + "LocalSettingsWindow", "ProjectListWidget" ) diff --git a/pype/tools/settings/settings/widgets/__init__.py b/pype/tools/settings/settings/widgets/__init__.py index c9fec16f6e..6e31232818 100644 --- a/pype/tools/settings/settings/widgets/__init__.py +++ b/pype/tools/settings/settings/widgets/__init__.py @@ -1,8 +1,10 @@ from .window import MainWidget from .widgets import ProjectListWidget +from .local_settings import LocalSettingsWindow __all__ = [ "MainWidget", - "ProjectListWidget" + "ProjectListWidget", + "LocalSettingsWindow" ] From 2ae94e5f9f26398b0cef81b3556f48c938fbaa18 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 23 Feb 2021 18:40:46 +0100 Subject: [PATCH 18/61] added window title and icon to local settings window --- pype/tools/settings/settings/widgets/local_settings.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pype/tools/settings/settings/widgets/local_settings.py b/pype/tools/settings/settings/widgets/local_settings.py index 4eef507839..d4c5a9a5f8 100644 --- a/pype/tools/settings/settings/widgets/local_settings.py +++ b/pype/tools/settings/settings/widgets/local_settings.py @@ -3,7 +3,7 @@ import sys import traceback import platform import logging -from Qt import QtWidgets, QtCore +from Qt import QtWidgets, QtCore, QtGui from .widgets import ( ExpandingWidget, SpacerWidget, @@ -669,8 +669,11 @@ class LocalSettingsWindow(QtWidgets.QWidget): self.resize(1000, 600) + self.setWindowTitle("Pype Local settings") + stylesheet = style.load_stylesheet() self.setStyleSheet(stylesheet) + self.setWindowIcon(QtGui.QIcon(style.app_icon_path())) scroll_widget = QtWidgets.QScrollArea(self) scroll_widget.setObjectName("GroupWidget") From 0d50cc35be2dfee93e6e71b0baf3dac893cddd79 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 23 Feb 2021 18:43:48 +0100 Subject: [PATCH 19/61] renamed user_settings.py to local_settings.py --- pype/lib/__init__.py | 2 +- pype/lib/{user_settings.py => local_settings.py} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename pype/lib/{user_settings.py => local_settings.py} (99%) diff --git a/pype/lib/__init__.py b/pype/lib/__init__.py index b5674a9e5d..67a31d1737 100644 --- a/pype/lib/__init__.py +++ b/pype/lib/__init__.py @@ -92,7 +92,7 @@ from .plugin_tools import ( should_decompress ) -from .user_settings import ( +from .local_settings import ( IniSettingRegistry, JSONSettingRegistry, PypeSettingsRegistry, diff --git a/pype/lib/user_settings.py b/pype/lib/local_settings.py similarity index 99% rename from pype/lib/user_settings.py rename to pype/lib/local_settings.py index 70313bc094..aa372a52d2 100644 --- a/pype/lib/user_settings.py +++ b/pype/lib/local_settings.py @@ -120,7 +120,7 @@ class ASettingRegistry(): """Delete item from settings. Note: - see :meth:`pype.lib.user_settings.ARegistrySettings.delete_item` + see :meth:`pype.lib.local_settings.ARegistrySettings.delete_item` """ pass From 6e9c337ec5ebe4dbd41a3b6545312768552afa65 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 23 Feb 2021 18:55:38 +0100 Subject: [PATCH 20/61] added local settings module to all --- pype/modules/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pype/modules/__init__.py b/pype/modules/__init__.py index 874d69c41d..e0481d0c92 100644 --- a/pype/modules/__init__.py +++ b/pype/modules/__init__.py @@ -55,6 +55,7 @@ __all__ = ( "TrayModulesManager", "SettingsAction", + "LocalSettingsAction", "UserModule", "IUserModule", From 8112c6c9480c74485cc650a95d22df12c90e8919 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 23 Feb 2021 18:57:27 +0100 Subject: [PATCH 21/61] fix class name typo --- pype/settings/handlers.py | 2 +- pype/settings/lib.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pype/settings/handlers.py b/pype/settings/handlers.py index c76aa6c40a..f905759bc8 100644 --- a/pype/settings/handlers.py +++ b/pype/settings/handlers.py @@ -515,7 +515,7 @@ class MongoSettingsHandler(SettingsHandler): return self._get_project_anatomy_overrides(project_name) -class MongoLocalSettingshandler(LocalSettingsHandler): +class MongoLocalSettingsHandler(LocalSettingsHandler): """Settings handler that use mongo for store and load local settings.""" default_project_key = "__default_project__" diff --git a/pype/settings/lib.py b/pype/settings/lib.py index b07bd99e5d..8bf6d80bb3 100644 --- a/pype/settings/lib.py +++ b/pype/settings/lib.py @@ -65,8 +65,8 @@ def create_settings_handler(): def create_local_settings_handler(): - from .handlers import MongoLocalSettingshandler - return MongoLocalSettingshandler() + from .handlers import MongoLocalSettingsHandler + return MongoLocalSettingsHandler() @require_handler From 818a7c457e04d36c429546d36b8421e80d52ea73 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 23 Feb 2021 19:06:55 +0100 Subject: [PATCH 22/61] added some docstrings --- pype/settings/lib.py | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/pype/settings/lib.py b/pype/settings/lib.py index 8bf6d80bb3..24e16dd0ff 100644 --- a/pype/settings/lib.py +++ b/pype/settings/lib.py @@ -341,7 +341,8 @@ def apply_overrides(source_data, override_data): def apply_local_settings_on_system_settings(system_settings, local_settings): """Apply local settings on studio system settings. - In local settings are set application executables. + ATM local settings can modify only application executables. Executable + values are not overriden but prepended. """ if not local_settings or "applications" not in local_settings: return @@ -370,6 +371,26 @@ def apply_local_settings_on_system_settings(system_settings, local_settings): def apply_local_settings_on_anatomy_settings( anatomy_settings, local_settings, project_name ): + """Apply local settings on anatomy settings. + + ATM local settings can modify project roots. Project name is required as + local settings have data stored data by project's name. + + Local settings override root values in this order: + 1.) Check if local settings contain overrides for default project and + apply it's values on roots if there are any. + 2.) If passed `project_name` is not None then check project specific + overrides in local settings for the project and apply it's value on + roots if there are any. + + NOTE: Root values of default project from local settings are always applied + if are set. + + Args: + anatomy_settings (dict): Data for anatomy settings. + local_settings (dict): Data of local settings. + project_name (str): Name of project for which anatomy data are. + """ if not local_settings: return @@ -394,8 +415,8 @@ def apply_local_settings_on_anatomy_settings( if local_projects and "roots" in local_projects: for root_name, path in local_projects["roots"].items(): if root_name not in root_data: - print(root_name, "not in root data") continue + anatomy_settings["roots"][root_name][current_platform] = ( path ) From de0fdcd01281b1db29451aafd56153f34686c6ed Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 23 Feb 2021 19:12:03 +0100 Subject: [PATCH 23/61] added some docstring to handler --- pype/settings/handlers.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/pype/settings/handlers.py b/pype/settings/handlers.py index f905759bc8..64bb34e24e 100644 --- a/pype/settings/handlers.py +++ b/pype/settings/handlers.py @@ -516,7 +516,17 @@ class MongoSettingsHandler(SettingsHandler): class MongoLocalSettingsHandler(LocalSettingsHandler): - """Settings handler that use mongo for store and load local settings.""" + """Settings handler that use mongo for store and load local settings. + + Data have 2 query criteria. First is key "type" stored in constant + `LOCAL_SETTING_KEY`. Second is key "site_id" which value can be obstained + with `get_local_site_id` function. + + Because project specific values are stored by project name the default + project would have key `None` which is not allowed. Because of that is + `None` replaced with `default_project_key` value on save and the key + is replaced with `None` of load. + """ default_project_key = "__default_project__" def __init__(self, local_site_id=None): From 948f20f99b794411d3cfe732f78d071aa4acaa28 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 23 Feb 2021 19:18:00 +0100 Subject: [PATCH 24/61] added docstring to abstract local settings handler --- pype/settings/handlers.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pype/settings/handlers.py b/pype/settings/handlers.py index 64bb34e24e..135201048a 100644 --- a/pype/settings/handlers.py +++ b/pype/settings/handlers.py @@ -106,6 +106,11 @@ class SettingsHandler: @six.add_metaclass(ABCMeta) class LocalSettingsHandler: + """Handler that should handle about storing and loading of local settings. + + Local settings are "workstation" specific modifications that modify how + system and project settings look on the workstation and only there. + """ @abstractmethod def save_local_settings(self, data): """Save local data of local settings. From 58add7268ab2906925efc21dacaae0c22eaea6e5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 24 Feb 2021 14:51:18 +0100 Subject: [PATCH 25/61] fix filter of apps to display --- pype/tools/settings/settings/widgets/local_settings.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pype/tools/settings/settings/widgets/local_settings.py b/pype/tools/settings/settings/widgets/local_settings.py index d4c5a9a5f8..09c99c5063 100644 --- a/pype/tools/settings/settings/widgets/local_settings.py +++ b/pype/tools/settings/settings/widgets/local_settings.py @@ -285,7 +285,7 @@ class AppGroupWidget(QtWidgets.QWidget): valid_variants = {} for key, entity in group_entity["variants"].items(): - if entity["enabled"]: + if entity["enabled"].value: valid_variants[key] = entity group_label = group_entity.label @@ -340,13 +340,13 @@ class LocalApplicationsWidgets(QtWidgets.QWidget): for key, entity in system_settings_entity["applications"].items(): # Filter not enabled app groups - if not entity["enabled"]: + if not entity["enabled"].value: continue # Check if has enabled any variant enabled_variant = False for variant_entity in entity["variants"].values(): - if variant_entity["enabled"]: + if variant_entity["enabled"].value: enabled_variant = True break From 40923f8a05d2fa1a43eee25738390dd6471e1cb4 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 24 Feb 2021 14:54:21 +0100 Subject: [PATCH 26/61] show only executable paths from studio settings --- .../settings/widgets/local_settings.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/pype/tools/settings/settings/widgets/local_settings.py b/pype/tools/settings/settings/widgets/local_settings.py index 09c99c5063..8713cc49df 100644 --- a/pype/tools/settings/settings/widgets/local_settings.py +++ b/pype/tools/settings/settings/widgets/local_settings.py @@ -243,20 +243,25 @@ class AppVariantWidget(QtWidgets.QWidget): ) content_layout.addWidget(executable_input_widget) + self.executable_input_widget = executable_input_widget + studio_executables = ( variant_entity["executables"][platform.system().lower()] ) - if len(studio_executables) > 0: - content_layout.addWidget(Separator(parent=self)) + if len(studio_executables) < 1: + return + + content_layout.addWidget(Separator(parent=self)) + content_layout.addWidget( + QtWidgets.QLabel("Studio paths:", self) + ) for item in studio_executables: - path_widget = PathInput(content_widget) - path_widget.set_read_only() - path_widget.set_value(item.value) + path_widget = QtWidgets.QLineEdit(content_widget) + path_widget.setText(item.value[0]) + path_widget.setEnabled(False) content_layout.addWidget(path_widget) - self.executable_input_widget = executable_input_widget - def set_value(self, value): if not self.executable_input_widget: return From 1b4f57ddbcd1acf8202439bb40e93ca838d334b1 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 24 Feb 2021 14:54:56 +0100 Subject: [PATCH 27/61] dont show studio roots value but use it as placeholder --- pype/tools/settings/settings/widgets/local_settings.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/pype/tools/settings/settings/widgets/local_settings.py b/pype/tools/settings/settings/widgets/local_settings.py index 8713cc49df..1f22018be8 100644 --- a/pype/tools/settings/settings/widgets/local_settings.py +++ b/pype/tools/settings/settings/widgets/local_settings.py @@ -405,7 +405,6 @@ class RootsWidget(QtWidgets.QWidget): self.widgts_by_root_name.clear() - default_placeholder = "< Root overrides for this machine >" default_root_values = self.local_default_project_values() or {} roots_entity = ( @@ -429,17 +428,11 @@ class RootsWidget(QtWidgets.QWidget): placeholder = "< {} >".format(placeholder) if not placeholder: - placeholder = default_placeholder + placeholder = platform_entity.value value_input.setPlaceholderText(placeholder) value_input.textChanged.connect(self._on_root_value_change) - studio_input = QtWidgets.QLineEdit(root_input_widget) - studio_input.setText(platform_entity.value) - studio_input.setReadOnly(True) - root_input_layout.addWidget(value_input) - root_input_layout.addWidget(Separator(parent=self)) - root_input_layout.addWidget(studio_input) root_layout = QtWidgets.QHBoxLayout(root_widget) root_layout.addWidget(key_label) From 5fe7db24770febc5445febb3850a26bfa45eb0ec Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 24 Feb 2021 15:05:02 +0100 Subject: [PATCH 28/61] app executables are without arguments --- .../settings/widgets/local_settings.py | 82 +++++-------------- 1 file changed, 19 insertions(+), 63 deletions(-) diff --git a/pype/tools/settings/settings/widgets/local_settings.py b/pype/tools/settings/settings/widgets/local_settings.py index 1f22018be8..c9d63fa032 100644 --- a/pype/tools/settings/settings/widgets/local_settings.py +++ b/pype/tools/settings/settings/widgets/local_settings.py @@ -151,65 +151,8 @@ class LocalGeneralWidgets(QtWidgets.QWidget): return output -class PathInput(QtWidgets.QWidget): - def __init__( - self, - parent, - executable_placeholder=None, - argument_placeholder=None - ): - super(PathInput, self).__init__(parent) - - executable_input = QtWidgets.QLineEdit(self) - if executable_placeholder: - executable_input.setPlaceholderText(executable_placeholder) - - arguments_input = QtWidgets.QLineEdit(self) - if argument_placeholder: - arguments_input.setPlaceholderText(argument_placeholder) - - layout = QtWidgets.QHBoxLayout(self) - layout.setContentsMargins(0, 0, 0, 0) - layout.setSpacing(5) - - layout.addWidget(executable_input) - layout.addWidget(arguments_input) - - self.executable_input = executable_input - self.arguments_input = arguments_input - - def set_read_only(self, readonly=True): - self.executable_input.setReadOnly(readonly) - self.arguments_input.setReadOnly(readonly) - - def set_value(self, arguments): - executable = "" - args = "" - if arguments: - if isinstance(arguments, str): - executable = arguments - elif isinstance(arguments, list): - executable = arguments[0] - if len(arguments) > 1: - args = " ".join(arguments[1:]) - self.executable_input.setText(executable) - self.arguments_input.setText(args) - - def settings_value(self): - executable = self.executable_input.text() - if not executable: - return None - - output = [executable] - args = self.arguments_input.text() - if args: - output.append(args) - return output - - class AppVariantWidget(QtWidgets.QWidget): exec_placeholder = "< Specific path for this machine >" - args_placeholder = "< Launch arguments >" def __init__(self, group_label, variant_entity, parent): super(AppVariantWidget, self).__init__(parent) @@ -238,9 +181,8 @@ class AppVariantWidget(QtWidgets.QWidget): content_layout.addWidget(warn_label) return - executable_input_widget = PathInput( - content_widget, self.exec_placeholder, self.args_placeholder - ) + executable_input_widget = QtWidgets.QLineEdit(content_widget) + executable_input_widget.setPlaceholderText(self.exec_placeholder) content_layout.addWidget(executable_input_widget) self.executable_input_widget = executable_input_widget @@ -273,15 +215,29 @@ class AppVariantWidget(QtWidgets.QWidget): type(value), dict )) value = {} - self.executable_input_widget.set_value(value.get("executable")) + + executable_path = value.get("executable") + if not executable_path: + executable_path = "" + elif isinstance(executable_path, list): + print("Got list in executable path so using first item as value") + executable_path = executable_path[0] + + if not isinstance(executable_path, str): + executable_path = "" + print(( + "Got invalid value type of app executable {}. Expected {}" + ).format(type(value), str)) + + self.executable_input_widget.setText(executable_path) def settings_value(self): if not self.executable_input_widget: return None - value = self.executable_input_widget.settings_value() + value = self.executable_input_widget.text() if not value: return None - return {"executable": self.executable_input_widget.settings_value()} + return {"executable": value} class AppGroupWidget(QtWidgets.QWidget): From 0c4fb521806793fb039547ddc20e334bf2a09057 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 24 Feb 2021 16:07:41 +0100 Subject: [PATCH 29/61] added helper mardown document --- pype/settings/local_settings.md | 79 +++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 pype/settings/local_settings.md diff --git a/pype/settings/local_settings.md b/pype/settings/local_settings.md new file mode 100644 index 0000000000..66c5b753d5 --- /dev/null +++ b/pype/settings/local_settings.md @@ -0,0 +1,79 @@ +# Structure of local settings +- local settings do not have any validation schemas right now this should help to see what is stored to local settings and how it works +- they are stored by identifier site_id which should be unified identifier of workstation +- all keys may and may not available on load +- contain main categories: `general`, `applications`, `projects` + +## Categories +### General +- ATM contain only label of site +```json +{ + "general": { + "site_name": "MySite" + } +} +``` + +### Applications +- modifications of application executables +- output should match application groups and variants +```json +{ + "applications": { + "": { + "": { + "executable": "/my/path/to/nuke_12_2" + } + } + } +} +``` + +### Projects +- project specific modifications +- default project is stored under constant key defined in `pype.settings.contants` +```json +{ + "projects": { + "": { + "active_site": "", + "remote_site": "", + "roots": { + "": { + "": "" + } + } + } + } +} +``` + +## Final document +```json +{ + "_id": "", + "site_id": "", + "general": { + "site_name": "MySite" + }, + "applications": { + "": { + "": { + "executable": "" + } + } + }, + "projects": { + "": { + "active_site": "", + "remote_site": "", + "roots": { + "": { + "": "" + } + } + } + } +} +``` From 45217ed2d6d3a142104b196a8717ad5cf09e1a04 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 24 Feb 2021 16:27:36 +0100 Subject: [PATCH 30/61] moved local settings gui out of settings widgets --- pype/tools/settings/__init__.py | 8 +- .../tools/settings/local_settings/__init__.py | 1 + .../window.py} | 81 ++++++++++++++----- pype/tools/settings/settings/__init__.py | 2 - .../settings/settings/widgets/__init__.py | 4 +- 5 files changed, 68 insertions(+), 28 deletions(-) create mode 100644 pype/tools/settings/local_settings/__init__.py rename pype/tools/settings/{settings/widgets/local_settings.py => local_settings/window.py} (90%) diff --git a/pype/tools/settings/__init__.py b/pype/tools/settings/__init__.py index 578c6ef82c..0a5d6933a1 100644 --- a/pype/tools/settings/__init__.py +++ b/pype/tools/settings/__init__.py @@ -1,11 +1,10 @@ import sys from Qt import QtWidgets, QtGui - +from .local_settings import LocalSettingsWindow from .settings import ( style, MainWidget, - ProjectListWidget, - LocalSettingsWindow + ProjectListWidget ) @@ -23,7 +22,8 @@ def main(user_role=None): app = QtWidgets.QApplication(sys.argv) app.setWindowIcon(QtGui.QIcon(style.app_icon_path())) - widget = MainWidget(user_role) + # widget = MainWidget(user_role) + widget = LocalSettingsWindow() widget.show() widget.reset() diff --git a/pype/tools/settings/local_settings/__init__.py b/pype/tools/settings/local_settings/__init__.py new file mode 100644 index 0000000000..ddb9741b79 --- /dev/null +++ b/pype/tools/settings/local_settings/__init__.py @@ -0,0 +1 @@ +from .window import LocalSettingsWindow diff --git a/pype/tools/settings/settings/widgets/local_settings.py b/pype/tools/settings/local_settings/window.py similarity index 90% rename from pype/tools/settings/settings/widgets/local_settings.py rename to pype/tools/settings/local_settings/window.py index c9d63fa032..be31994425 100644 --- a/pype/tools/settings/settings/widgets/local_settings.py +++ b/pype/tools/settings/local_settings/window.py @@ -4,13 +4,13 @@ import traceback import platform import logging from Qt import QtWidgets, QtCore, QtGui -from .widgets import ( +from pype.tools.settings.settings.widgets.widgets import ( ExpandingWidget, SpacerWidget, ProjectListWidget ) -from .. import style -from .lib import CHILD_OFFSET +from ..settings import style +from pype.tools.settings.settings.widgets.lib import CHILD_OFFSET from pype.settings.constants import PROJECT_ANATOMY_KEY from pype.settings.lib import ( get_local_settings, @@ -353,6 +353,9 @@ class RootsWidget(QtWidgets.QWidget): self.content_layout = main_layout + def _on_root_value_change(self): + self.value_changed.emit() + def refresh(self): while self.content_layout.count(): item = self.content_layout.itemAt(0) @@ -399,9 +402,6 @@ class RootsWidget(QtWidgets.QWidget): self.content_layout.addWidget(SpacerWidget(self), 1) - def _on_root_value_change(self): - self.value_changed.emit() - def local_default_project_values(self): default_project = self._parent_widget.per_project_settings.get(None) if default_project: @@ -427,6 +427,53 @@ class RootsWidget(QtWidgets.QWidget): return output +class ProjectSpecificWidget(QtWidgets.QWidget): + value_changed = QtCore.Signal() + + def __init__(self, project_settings, parent): + self._parent_widget = parent + super(ProjectSpecificWidget, self).__init__(parent) + + self.project_settings = project_settings + self.widgts_by_root_name = {} + + sites_widget = QtWidgets.QWidget(self) + sites_layout = QtWidgets.QHBoxLayout(sites_widget) + active_site_combo = QtWidgets.QComboBox(sites_widget) + remote_site_combo = QtWidgets.QComboBox(sites_widget) + sites_layout.addWidget(QtWidgets.QLabel("Active Site", sites_widget)) + sites_layout.addWidget(active_site_combo) + sites_layout.addWidget(QtWidgets.QLabel("Remote Site", sites_widget)) + sites_layout.addWidget(remote_site_combo) + + main_layout = QtWidgets.QVBoxLayout(self) + main_layout.addWidget(sites_widget) + main_layout.addWidget(SpacerWidget(self), 1) + + def set_value(self, value): + pass + # if not value: + # value = {} + # + # for root_name, widget in self.widgts_by_root_name.items(): + # root_value = value.get(root_name) or "" + # widget.setText(root_value) + + def settings_value(self): + return {} + # output = {} + # for root_name, widget in self.widgts_by_root_name.items(): + # value = widget.text() + # if value: + # output[root_name] = value + # if not output: + # return None + # return output + + def change_project(self, project_name): + pass + + class _ProjectListWidget(ProjectListWidget): def on_item_clicked(self, new_index): new_project_name = new_index.data(QtCore.Qt.DisplayRole) @@ -448,23 +495,25 @@ class ProjectSettingsWidget(QtWidgets.QWidget): self.per_project_settings = {} projects_widget = _ProjectListWidget(self) - roots_widget = RootsWidget(project_settings, self) + project_specific_widget = ProjectSpecificWidget(project_settings, self) main_layout = QtWidgets.QHBoxLayout(self) main_layout.setContentsMargins(0, 0, 0, 0) main_layout.addWidget(projects_widget, 0) - main_layout.addWidget(roots_widget, 1) + main_layout.addWidget(project_specific_widget, 1) projects_widget.project_changed.connect(self._on_project_change) - roots_widget.value_changed.connect(self._on_root_value_change) + # project_specific_widget.value_changed.connect( + # self._on_root_value_change + # ) self.project_settings = project_settings self.projects_widget = projects_widget - self.roots_widget = roots_widget + self.project_specific_widget = project_specific_widget def _current_value(self): - roots_value = self.roots_widget.settings_value() + roots_value = self.project_specific_widget.settings_value() current_value = {} if roots_value: current_value[LOCAL_ROOTS_KEY] = roots_value @@ -477,10 +526,7 @@ class ProjectSettingsWidget(QtWidgets.QWidget): project_name = self.project_name() self.project_settings.change_project(project_name) - self.roots_widget.refresh() - - project_value = self.per_project_settings.get(project_name) or {} - self.roots_widget.set_value(project_value.get(LOCAL_ROOTS_KEY)) + self.project_specific_widget.change_project(project_name) def _on_root_value_change(self): self.per_project_settings[self.project_name()] = ( @@ -493,11 +539,8 @@ class ProjectSettingsWidget(QtWidgets.QWidget): self.per_project_settings = value self.projects_widget.refresh() - self.roots_widget.refresh() - project_name = self.project_name() - project_value = self.per_project_settings.get(project_name) or {} - self.roots_widget.set_value(project_value.get(LOCAL_ROOTS_KEY)) + self.project_specific_widget.set_value(self.per_project_settings) def settings_value(self): output = {} diff --git a/pype/tools/settings/settings/__init__.py b/pype/tools/settings/settings/__init__.py index 4d930b3fda..3c12a73639 100644 --- a/pype/tools/settings/settings/__init__.py +++ b/pype/tools/settings/settings/__init__.py @@ -1,7 +1,6 @@ from . import style from .widgets import ( MainWidget, - LocalSettingsWindow, ProjectListWidget ) @@ -9,6 +8,5 @@ from .widgets import ( __all__ = ( "style", "MainWidget", - "LocalSettingsWindow", "ProjectListWidget" ) diff --git a/pype/tools/settings/settings/widgets/__init__.py b/pype/tools/settings/settings/widgets/__init__.py index 6e31232818..c9fec16f6e 100644 --- a/pype/tools/settings/settings/widgets/__init__.py +++ b/pype/tools/settings/settings/widgets/__init__.py @@ -1,10 +1,8 @@ from .window import MainWidget from .widgets import ProjectListWidget -from .local_settings import LocalSettingsWindow __all__ = [ "MainWidget", - "ProjectListWidget", - "LocalSettingsWindow" + "ProjectListWidget" ] From 33927afc1f4d212e99fd24ba1bf199b6933bb736 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 24 Feb 2021 16:38:20 +0100 Subject: [PATCH 31/61] split local settings gui into smaller parts --- .../settings/local_settings/apps_widget.py | 195 +++++++ .../settings/local_settings/mongo_widget.py | 80 +++ .../local_settings/projects_widget.py | 217 ++++++++ pype/tools/settings/local_settings/widgets.py | 22 + pype/tools/settings/local_settings/window.py | 516 +----------------- 5 files changed, 527 insertions(+), 503 deletions(-) create mode 100644 pype/tools/settings/local_settings/apps_widget.py create mode 100644 pype/tools/settings/local_settings/mongo_widget.py create mode 100644 pype/tools/settings/local_settings/projects_widget.py create mode 100644 pype/tools/settings/local_settings/widgets.py diff --git a/pype/tools/settings/local_settings/apps_widget.py b/pype/tools/settings/local_settings/apps_widget.py new file mode 100644 index 0000000000..52fbc45fd6 --- /dev/null +++ b/pype/tools/settings/local_settings/apps_widget.py @@ -0,0 +1,195 @@ +import platform +from Qt import QtWidgets +from .widgets import ( + Separator, + ExpandingWidget, + CHILD_OFFSET +) + + +class AppVariantWidget(QtWidgets.QWidget): + exec_placeholder = "< Specific path for this machine >" + + def __init__(self, group_label, variant_entity, parent): + super(AppVariantWidget, self).__init__(parent) + + self.executable_input_widget = None + + label = " ".join([group_label, variant_entity.label]) + + expading_widget = ExpandingWidget(label, self) + content_widget = QtWidgets.QWidget(expading_widget) + content_layout = QtWidgets.QVBoxLayout(content_widget) + content_layout.setContentsMargins(CHILD_OFFSET, 5, 0, 0) + + expading_widget.set_content_widget(content_widget) + + # Add expanding widget to main layout + layout = QtWidgets.QHBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.addWidget(expading_widget) + + # TODO For celaction - not sure what is "Celaction publish" for + if not variant_entity["executables"].multiplatform: + warn_label = QtWidgets.QLabel( + "Application without multiplatform paths" + ) + content_layout.addWidget(warn_label) + return + + executable_input_widget = QtWidgets.QLineEdit(content_widget) + executable_input_widget.setPlaceholderText(self.exec_placeholder) + content_layout.addWidget(executable_input_widget) + + self.executable_input_widget = executable_input_widget + + studio_executables = ( + variant_entity["executables"][platform.system().lower()] + ) + if len(studio_executables) < 1: + return + + content_layout.addWidget(Separator(parent=self)) + content_layout.addWidget( + QtWidgets.QLabel("Studio paths:", self) + ) + + for item in studio_executables: + path_widget = QtWidgets.QLineEdit(content_widget) + path_widget.setText(item.value[0]) + path_widget.setEnabled(False) + content_layout.addWidget(path_widget) + + def set_value(self, value): + if not self.executable_input_widget: + return + + if not value: + value = {} + elif not isinstance(value, dict): + print("Got invalid value type {}. Expected {}".format( + type(value), dict + )) + value = {} + + executable_path = value.get("executable") + if not executable_path: + executable_path = "" + elif isinstance(executable_path, list): + print("Got list in executable path so using first item as value") + executable_path = executable_path[0] + + if not isinstance(executable_path, str): + executable_path = "" + print(( + "Got invalid value type of app executable {}. Expected {}" + ).format(type(value), str)) + + self.executable_input_widget.setText(executable_path) + + def settings_value(self): + if not self.executable_input_widget: + return None + value = self.executable_input_widget.text() + if not value: + return None + return {"executable": value} + + +class AppGroupWidget(QtWidgets.QWidget): + def __init__(self, group_entity, parent): + super(AppGroupWidget, self).__init__(parent) + + valid_variants = {} + for key, entity in group_entity["variants"].items(): + if entity["enabled"].value: + valid_variants[key] = entity + + group_label = group_entity.label + expading_widget = ExpandingWidget(group_label, self) + content_widget = QtWidgets.QWidget(expading_widget) + content_layout = QtWidgets.QVBoxLayout(content_widget) + content_layout.setContentsMargins(CHILD_OFFSET, 5, 0, 0) + + widgets_by_variant_name = {} + for variant_name, variant_entity in valid_variants.items(): + variant_widget = AppVariantWidget( + group_label, variant_entity, content_widget + ) + widgets_by_variant_name[variant_name] = variant_widget + content_layout.addWidget(variant_widget) + + expading_widget.set_content_widget(content_widget) + + layout = QtWidgets.QHBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.addWidget(expading_widget) + + self.widgets_by_variant_name = widgets_by_variant_name + + def set_value(self, value): + if not value: + value = {} + + for variant_name, widget in self.widgets_by_variant_name.items(): + widget.set_value(value.get(variant_name)) + + def settings_value(self): + output = {} + for variant_name, widget in self.widgets_by_variant_name.items(): + value = widget.settings_value() + if value: + output[variant_name] = value + + if not output: + return None + return output + + +class LocalApplicationsWidgets(QtWidgets.QWidget): + def __init__(self, system_settings_entity, parent): + super(LocalApplicationsWidgets, self).__init__(parent) + + widgets_by_group_name = {} + + layout = QtWidgets.QVBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + + for key, entity in system_settings_entity["applications"].items(): + # Filter not enabled app groups + if not entity["enabled"].value: + continue + + # Check if has enabled any variant + enabled_variant = False + for variant_entity in entity["variants"].values(): + if variant_entity["enabled"].value: + enabled_variant = True + break + + if not enabled_variant: + continue + + # Create App group specific widget and store it by the key + group_widget = AppGroupWidget(entity, self) + widgets_by_group_name[key] = group_widget + layout.addWidget(group_widget) + + self.widgets_by_group_name = widgets_by_group_name + + def set_value(self, value): + if not value: + value = {} + + for group_name, widget in self.widgets_by_group_name.items(): + widget.set_value(value.get(group_name)) + + def settings_value(self): + output = {} + for group_name, widget in self.widgets_by_group_name.items(): + value = widget.settings_value() + if value: + output[group_name] = value + if not output: + return None + return output diff --git a/pype/tools/settings/local_settings/mongo_widget.py b/pype/tools/settings/local_settings/mongo_widget.py new file mode 100644 index 0000000000..c6f6ab1591 --- /dev/null +++ b/pype/tools/settings/local_settings/mongo_widget.py @@ -0,0 +1,80 @@ +import os +import sys +import traceback + +from Qt import QtWidgets +from pymongo.errors import ServerSelectionTimeoutError + +from pype.api import change_pype_mongo_url + + +class PypeMongoWidget(QtWidgets.QWidget): + def __init__(self, parent): + super(PypeMongoWidget, self).__init__(parent) + + # Warning label + warning_label = QtWidgets.QLabel(( + "WARNING: Requires restart. Change of Pype Mongo requires to" + " restart of all running Pype processes and process using Pype" + " (Including this)." + "\n- all changes in different categories won't be saved." + ), self) + warning_label.setStyleSheet("font-weight: bold;") + + # Label + mongo_url_label = QtWidgets.QLabel("Pype Mongo URL", self) + + # Input + mongo_url_input = QtWidgets.QLineEdit(self) + mongo_url_input.setPlaceholderText("< Pype Mongo URL >") + mongo_url_input.setText(os.environ["PYPE_MONGO"]) + + # Confirm button + mongo_url_change_btn = QtWidgets.QPushButton("Confirm Change", self) + + layout = QtWidgets.QGridLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.addWidget(warning_label, 0, 0, 1, 3) + layout.addWidget(mongo_url_label, 1, 0) + layout.addWidget(mongo_url_input, 1, 1) + layout.addWidget(mongo_url_change_btn, 1, 2) + + mongo_url_change_btn.clicked.connect(self._on_confirm_click) + + self.mongo_url_input = mongo_url_input + + def _on_confirm_click(self): + value = self.mongo_url_input.text() + + dialog = QtWidgets.QMessageBox(self) + + title = "Pype mongo changed" + message = ( + "Pype mongo url was successfully changed. Restart Pype please." + ) + details = None + + try: + change_pype_mongo_url(value) + except Exception as exc: + if isinstance(exc, ServerSelectionTimeoutError): + error_message = ( + "Connection timeout passed." + " Probably can't connect to the Mongo server." + ) + else: + error_message = str(exc) + + title = "Pype mongo change failed" + # TODO catch exception message more gracefully + message = ( + "Pype mongo change was not successful." + " Full traceback can be found in details section.\n\n" + "Error message:\n{}" + ).format(error_message) + details = "\n".join(traceback.format_exception(*sys.exc_info())) + dialog.setWindowTitle(title) + dialog.setText(message) + if details: + dialog.setDetailedText(details) + dialog.exec_() diff --git a/pype/tools/settings/local_settings/projects_widget.py b/pype/tools/settings/local_settings/projects_widget.py new file mode 100644 index 0000000000..4426422299 --- /dev/null +++ b/pype/tools/settings/local_settings/projects_widget.py @@ -0,0 +1,217 @@ +from Qt import QtWidgets, QtCore +from pype.tools.settings.settings import ProjectListWidget +from .widgets import SpacerWidget +from pype.settings.constants import PROJECT_ANATOMY_KEY + + +class _ProjectListWidget(ProjectListWidget): + def on_item_clicked(self, new_index): + new_project_name = new_index.data(QtCore.Qt.DisplayRole) + if new_project_name is None: + return + + if self.current_project == new_project_name: + return + + self.select_project(new_project_name) + self.current_project = new_project_name + self.project_changed.emit() + + +class RootsWidget(QtWidgets.QWidget): + value_changed = QtCore.Signal() + + def __init__(self, project_settings, parent): + self._parent_widget = parent + super(RootsWidget, self).__init__(parent) + + self.project_settings = project_settings + self.widgts_by_root_name = {} + + main_layout = QtWidgets.QVBoxLayout(self) + + self.content_layout = main_layout + + def _on_root_value_change(self): + self.value_changed.emit() + + def refresh(self): + while self.content_layout.count(): + item = self.content_layout.itemAt(0) + item.widget().hide() + self.content_layout.removeItem(item) + + self.widgts_by_root_name.clear() + + default_root_values = self.local_default_project_values() or {} + + roots_entity = ( + self.project_settings[PROJECT_ANATOMY_KEY][LOCAL_ROOTS_KEY] + ) + is_in_default = self.project_settings.project_name is None + for root_name, path_entity in roots_entity.items(): + platform_entity = path_entity[platform.system().lower()] + root_widget = QtWidgets.QWidget(self) + + key_label = QtWidgets.QLabel(root_name, root_widget) + + root_input_widget = QtWidgets.QWidget(root_widget) + root_input_layout = QtWidgets.QVBoxLayout(root_input_widget) + + value_input = QtWidgets.QLineEdit(root_input_widget) + placeholder = None + if not is_in_default: + placeholder = default_root_values.get(root_name) + if placeholder: + placeholder = "< {} >".format(placeholder) + + if not placeholder: + placeholder = platform_entity.value + value_input.setPlaceholderText(placeholder) + value_input.textChanged.connect(self._on_root_value_change) + + root_input_layout.addWidget(value_input) + + root_layout = QtWidgets.QHBoxLayout(root_widget) + root_layout.addWidget(key_label) + root_layout.addWidget(root_input_widget) + + self.content_layout.addWidget(root_widget) + self.widgts_by_root_name[root_name] = value_input + + self.content_layout.addWidget(SpacerWidget(self), 1) + + def local_default_project_values(self): + default_project = self._parent_widget.per_project_settings.get(None) + if default_project: + return default_project.get(LOCAL_ROOTS_KEY) + return None + + def set_value(self, value): + if not value: + value = {} + + for root_name, widget in self.widgts_by_root_name.items(): + root_value = value.get(root_name) or "" + widget.setText(root_value) + + def settings_value(self): + output = {} + for root_name, widget in self.widgts_by_root_name.items(): + value = widget.text() + if value: + output[root_name] = value + if not output: + return None + return output + + +class ProjectSpecificWidget(QtWidgets.QWidget): + value_changed = QtCore.Signal() + + def __init__(self, project_settings, parent): + self._parent_widget = parent + super(ProjectSpecificWidget, self).__init__(parent) + + self.project_settings = project_settings + self.widgts_by_root_name = {} + + sites_widget = QtWidgets.QWidget(self) + sites_layout = QtWidgets.QHBoxLayout(sites_widget) + active_site_combo = QtWidgets.QComboBox(sites_widget) + remote_site_combo = QtWidgets.QComboBox(sites_widget) + sites_layout.addWidget(QtWidgets.QLabel("Active Site", sites_widget)) + sites_layout.addWidget(active_site_combo) + sites_layout.addWidget(QtWidgets.QLabel("Remote Site", sites_widget)) + sites_layout.addWidget(remote_site_combo) + + main_layout = QtWidgets.QVBoxLayout(self) + main_layout.addWidget(sites_widget) + main_layout.addWidget(SpacerWidget(self), 1) + + def set_value(self, value): + pass + # if not value: + # value = {} + # + # for root_name, widget in self.widgts_by_root_name.items(): + # root_value = value.get(root_name) or "" + # widget.setText(root_value) + + def settings_value(self): + return {} + # output = {} + # for root_name, widget in self.widgts_by_root_name.items(): + # value = widget.text() + # if value: + # output[root_name] = value + # if not output: + # return None + # return output + + def change_project(self, project_name): + pass + + +class ProjectSettingsWidget(QtWidgets.QWidget): + def __init__(self, project_settings, parent): + super(ProjectSettingsWidget, self).__init__(parent) + + self.per_project_settings = {} + + projects_widget = _ProjectListWidget(self) + project_specific_widget = ProjectSpecificWidget(project_settings, self) + + main_layout = QtWidgets.QHBoxLayout(self) + main_layout.setContentsMargins(0, 0, 0, 0) + main_layout.addWidget(projects_widget, 0) + main_layout.addWidget(project_specific_widget, 1) + + projects_widget.project_changed.connect(self._on_project_change) + # project_specific_widget.value_changed.connect( + # self._on_root_value_change + # ) + + self.project_settings = project_settings + + self.projects_widget = projects_widget + self.project_specific_widget = project_specific_widget + + def _current_value(self): + roots_value = self.project_specific_widget.settings_value() + current_value = {} + if roots_value: + current_value[LOCAL_ROOTS_KEY] = roots_value + return current_value + + def project_name(self): + return self.projects_widget.project_name() + + def _on_project_change(self): + project_name = self.project_name() + + self.project_settings.change_project(project_name) + self.project_specific_widget.change_project(project_name) + + def _on_root_value_change(self): + self.per_project_settings[self.project_name()] = ( + self._current_value() + ) + + def set_value(self, value): + if not value: + value = {} + self.per_project_settings = value + + self.projects_widget.refresh() + + self.project_specific_widget.set_value(self.per_project_settings) + + def settings_value(self): + output = {} + for project_name, value in self.per_project_settings.items(): + if value: + output[project_name] = value + if not output: + return None + return output diff --git a/pype/tools/settings/local_settings/widgets.py b/pype/tools/settings/local_settings/widgets.py new file mode 100644 index 0000000000..ebb14a3102 --- /dev/null +++ b/pype/tools/settings/local_settings/widgets.py @@ -0,0 +1,22 @@ +from Qt import QtWidgets +from pype.tools.settings.settings.widgets.widgets import ( + ExpandingWidget, + SpacerWidget +) +from pype.tools.settings.settings.widgets.lib import CHILD_OFFSET + + +class Separator(QtWidgets.QFrame): + def __init__(self, height=None, parent=None): + super(Separator, self).__init__(parent) + if height is None: + height = 2 + + splitter_item = QtWidgets.QWidget(self) + splitter_item.setStyleSheet("background-color: #21252B;") + splitter_item.setMinimumHeight(height) + splitter_item.setMaximumHeight(height) + + layout = QtWidgets.QHBoxLayout(self) + layout.setContentsMargins(5, 5, 5, 5) + layout.addWidget(splitter_item) diff --git a/pype/tools/settings/local_settings/window.py b/pype/tools/settings/local_settings/window.py index be31994425..1fd2ca8e06 100644 --- a/pype/tools/settings/local_settings/window.py +++ b/pype/tools/settings/local_settings/window.py @@ -1,27 +1,26 @@ -import os -import sys -import traceback -import platform import logging from Qt import QtWidgets, QtCore, QtGui -from pype.tools.settings.settings.widgets.widgets import ( - ExpandingWidget, - SpacerWidget, - ProjectListWidget -) + from ..settings import style -from pype.tools.settings.settings.widgets.lib import CHILD_OFFSET -from pype.settings.constants import PROJECT_ANATOMY_KEY + from pype.settings.lib import ( get_local_settings, save_local_settings ) from pype.api import ( SystemSettings, - ProjectSettings, - change_pype_mongo_url + ProjectSettings ) -from pymongo.errors import ServerSelectionTimeoutError + +from .widgets import ( + Separator, + SpacerWidget, + ExpandingWidget, + CHILD_OFFSET +) +from .mongo_widget import PypeMongoWidget +from .apps_widget import LocalApplicationsWidgets +from .projects_widget import ProjectSettingsWidget log = logging.getLogger(__name__) @@ -32,94 +31,6 @@ LOCAL_APPS_KEY = "applications" LOCAL_ROOTS_KEY = "roots" -class Separator(QtWidgets.QFrame): - def __init__(self, height=None, parent=None): - super(Separator, self).__init__(parent) - if height is None: - height = 2 - - splitter_item = QtWidgets.QWidget(self) - splitter_item.setStyleSheet("background-color: #21252B;") - splitter_item.setMinimumHeight(height) - splitter_item.setMaximumHeight(height) - - layout = QtWidgets.QHBoxLayout(self) - layout.setContentsMargins(5, 5, 5, 5) - layout.addWidget(splitter_item) - - -class PypeMongoWidget(QtWidgets.QWidget): - def __init__(self, parent): - super(PypeMongoWidget, self).__init__(parent) - - # Warning label - warning_label = QtWidgets.QLabel(( - "WARNING: Requires restart. Change of Pype Mongo requires to" - " restart of all running Pype processes and process using Pype" - " (Including this)." - "\n- all changes in different categories won't be saved." - ), self) - warning_label.setStyleSheet("font-weight: bold;") - - # Label - mongo_url_label = QtWidgets.QLabel("Pype Mongo URL", self) - - # Input - mongo_url_input = QtWidgets.QLineEdit(self) - mongo_url_input.setPlaceholderText("< Pype Mongo URL >") - mongo_url_input.setText(os.environ["PYPE_MONGO"]) - - # Confirm button - mongo_url_change_btn = QtWidgets.QPushButton("Confirm Change", self) - - layout = QtWidgets.QGridLayout(self) - layout.setContentsMargins(0, 0, 0, 0) - layout.addWidget(warning_label, 0, 0, 1, 3) - layout.addWidget(mongo_url_label, 1, 0) - layout.addWidget(mongo_url_input, 1, 1) - layout.addWidget(mongo_url_change_btn, 1, 2) - - mongo_url_change_btn.clicked.connect(self._on_confirm_click) - - self.mongo_url_input = mongo_url_input - - def _on_confirm_click(self): - value = self.mongo_url_input.text() - - dialog = QtWidgets.QMessageBox(self) - - title = "Pype mongo changed" - message = ( - "Pype mongo url was successfully changed. Restart Pype please." - ) - details = None - - try: - change_pype_mongo_url(value) - except Exception as exc: - if isinstance(exc, ServerSelectionTimeoutError): - error_message = ( - "Connection timeout passed." - " Probably can't connect to the Mongo server." - ) - else: - error_message = str(exc) - - title = "Pype mongo change failed" - # TODO catch exception message more gracefully - message = ( - "Pype mongo change was not successful." - " Full traceback can be found in details section.\n\n" - "Error message:\n{}" - ).format(error_message) - details = "\n".join(traceback.format_exception(*sys.exc_info())) - dialog.setWindowTitle(title) - dialog.setText(message) - if details: - dialog.setDetailedText(details) - dialog.exec_() - - class LocalGeneralWidgets(QtWidgets.QWidget): def __init__(self, parent): super(LocalGeneralWidgets, self).__init__(parent) @@ -151,407 +62,6 @@ class LocalGeneralWidgets(QtWidgets.QWidget): return output -class AppVariantWidget(QtWidgets.QWidget): - exec_placeholder = "< Specific path for this machine >" - - def __init__(self, group_label, variant_entity, parent): - super(AppVariantWidget, self).__init__(parent) - - self.executable_input_widget = None - - label = " ".join([group_label, variant_entity.label]) - - expading_widget = ExpandingWidget(label, self) - content_widget = QtWidgets.QWidget(expading_widget) - content_layout = QtWidgets.QVBoxLayout(content_widget) - content_layout.setContentsMargins(CHILD_OFFSET, 5, 0, 0) - - expading_widget.set_content_widget(content_widget) - - # Add expanding widget to main layout - layout = QtWidgets.QHBoxLayout(self) - layout.setContentsMargins(0, 0, 0, 0) - layout.addWidget(expading_widget) - - # TODO For celaction - not sure what is "Celaction publish" for - if not variant_entity["executables"].multiplatform: - warn_label = QtWidgets.QLabel( - "Application without multiplatform paths" - ) - content_layout.addWidget(warn_label) - return - - executable_input_widget = QtWidgets.QLineEdit(content_widget) - executable_input_widget.setPlaceholderText(self.exec_placeholder) - content_layout.addWidget(executable_input_widget) - - self.executable_input_widget = executable_input_widget - - studio_executables = ( - variant_entity["executables"][platform.system().lower()] - ) - if len(studio_executables) < 1: - return - - content_layout.addWidget(Separator(parent=self)) - content_layout.addWidget( - QtWidgets.QLabel("Studio paths:", self) - ) - - for item in studio_executables: - path_widget = QtWidgets.QLineEdit(content_widget) - path_widget.setText(item.value[0]) - path_widget.setEnabled(False) - content_layout.addWidget(path_widget) - - def set_value(self, value): - if not self.executable_input_widget: - return - - if not value: - value = {} - elif not isinstance(value, dict): - print("Got invalid value type {}. Expected {}".format( - type(value), dict - )) - value = {} - - executable_path = value.get("executable") - if not executable_path: - executable_path = "" - elif isinstance(executable_path, list): - print("Got list in executable path so using first item as value") - executable_path = executable_path[0] - - if not isinstance(executable_path, str): - executable_path = "" - print(( - "Got invalid value type of app executable {}. Expected {}" - ).format(type(value), str)) - - self.executable_input_widget.setText(executable_path) - - def settings_value(self): - if not self.executable_input_widget: - return None - value = self.executable_input_widget.text() - if not value: - return None - return {"executable": value} - - -class AppGroupWidget(QtWidgets.QWidget): - def __init__(self, group_entity, parent): - super(AppGroupWidget, self).__init__(parent) - - valid_variants = {} - for key, entity in group_entity["variants"].items(): - if entity["enabled"].value: - valid_variants[key] = entity - - group_label = group_entity.label - expading_widget = ExpandingWidget(group_label, self) - content_widget = QtWidgets.QWidget(expading_widget) - content_layout = QtWidgets.QVBoxLayout(content_widget) - content_layout.setContentsMargins(CHILD_OFFSET, 5, 0, 0) - - widgets_by_variant_name = {} - for variant_name, variant_entity in valid_variants.items(): - variant_widget = AppVariantWidget( - group_label, variant_entity, content_widget - ) - widgets_by_variant_name[variant_name] = variant_widget - content_layout.addWidget(variant_widget) - - expading_widget.set_content_widget(content_widget) - - layout = QtWidgets.QHBoxLayout(self) - layout.setContentsMargins(0, 0, 0, 0) - layout.addWidget(expading_widget) - - self.widgets_by_variant_name = widgets_by_variant_name - - def set_value(self, value): - if not value: - value = {} - - for variant_name, widget in self.widgets_by_variant_name.items(): - widget.set_value(value.get(variant_name)) - - def settings_value(self): - output = {} - for variant_name, widget in self.widgets_by_variant_name.items(): - value = widget.settings_value() - if value: - output[variant_name] = value - - if not output: - return None - return output - - -class LocalApplicationsWidgets(QtWidgets.QWidget): - def __init__(self, system_settings_entity, parent): - super(LocalApplicationsWidgets, self).__init__(parent) - - widgets_by_group_name = {} - - layout = QtWidgets.QVBoxLayout(self) - layout.setContentsMargins(0, 0, 0, 0) - - for key, entity in system_settings_entity["applications"].items(): - # Filter not enabled app groups - if not entity["enabled"].value: - continue - - # Check if has enabled any variant - enabled_variant = False - for variant_entity in entity["variants"].values(): - if variant_entity["enabled"].value: - enabled_variant = True - break - - if not enabled_variant: - continue - - # Create App group specific widget and store it by the key - group_widget = AppGroupWidget(entity, self) - widgets_by_group_name[key] = group_widget - layout.addWidget(group_widget) - - self.widgets_by_group_name = widgets_by_group_name - - def set_value(self, value): - if not value: - value = {} - - for group_name, widget in self.widgets_by_group_name.items(): - widget.set_value(value.get(group_name)) - - def settings_value(self): - output = {} - for group_name, widget in self.widgets_by_group_name.items(): - value = widget.settings_value() - if value: - output[group_name] = value - if not output: - return None - return output - - -class RootsWidget(QtWidgets.QWidget): - value_changed = QtCore.Signal() - - def __init__(self, project_settings, parent): - self._parent_widget = parent - super(RootsWidget, self).__init__(parent) - - self.project_settings = project_settings - self.widgts_by_root_name = {} - - main_layout = QtWidgets.QVBoxLayout(self) - - self.content_layout = main_layout - - def _on_root_value_change(self): - self.value_changed.emit() - - def refresh(self): - while self.content_layout.count(): - item = self.content_layout.itemAt(0) - item.widget().hide() - self.content_layout.removeItem(item) - - self.widgts_by_root_name.clear() - - default_root_values = self.local_default_project_values() or {} - - roots_entity = ( - self.project_settings[PROJECT_ANATOMY_KEY][LOCAL_ROOTS_KEY] - ) - is_in_default = self.project_settings.project_name is None - for root_name, path_entity in roots_entity.items(): - platform_entity = path_entity[platform.system().lower()] - root_widget = QtWidgets.QWidget(self) - - key_label = QtWidgets.QLabel(root_name, root_widget) - - root_input_widget = QtWidgets.QWidget(root_widget) - root_input_layout = QtWidgets.QVBoxLayout(root_input_widget) - - value_input = QtWidgets.QLineEdit(root_input_widget) - placeholder = None - if not is_in_default: - placeholder = default_root_values.get(root_name) - if placeholder: - placeholder = "< {} >".format(placeholder) - - if not placeholder: - placeholder = platform_entity.value - value_input.setPlaceholderText(placeholder) - value_input.textChanged.connect(self._on_root_value_change) - - root_input_layout.addWidget(value_input) - - root_layout = QtWidgets.QHBoxLayout(root_widget) - root_layout.addWidget(key_label) - root_layout.addWidget(root_input_widget) - - self.content_layout.addWidget(root_widget) - self.widgts_by_root_name[root_name] = value_input - - self.content_layout.addWidget(SpacerWidget(self), 1) - - def local_default_project_values(self): - default_project = self._parent_widget.per_project_settings.get(None) - if default_project: - return default_project.get(LOCAL_ROOTS_KEY) - return None - - def set_value(self, value): - if not value: - value = {} - - for root_name, widget in self.widgts_by_root_name.items(): - root_value = value.get(root_name) or "" - widget.setText(root_value) - - def settings_value(self): - output = {} - for root_name, widget in self.widgts_by_root_name.items(): - value = widget.text() - if value: - output[root_name] = value - if not output: - return None - return output - - -class ProjectSpecificWidget(QtWidgets.QWidget): - value_changed = QtCore.Signal() - - def __init__(self, project_settings, parent): - self._parent_widget = parent - super(ProjectSpecificWidget, self).__init__(parent) - - self.project_settings = project_settings - self.widgts_by_root_name = {} - - sites_widget = QtWidgets.QWidget(self) - sites_layout = QtWidgets.QHBoxLayout(sites_widget) - active_site_combo = QtWidgets.QComboBox(sites_widget) - remote_site_combo = QtWidgets.QComboBox(sites_widget) - sites_layout.addWidget(QtWidgets.QLabel("Active Site", sites_widget)) - sites_layout.addWidget(active_site_combo) - sites_layout.addWidget(QtWidgets.QLabel("Remote Site", sites_widget)) - sites_layout.addWidget(remote_site_combo) - - main_layout = QtWidgets.QVBoxLayout(self) - main_layout.addWidget(sites_widget) - main_layout.addWidget(SpacerWidget(self), 1) - - def set_value(self, value): - pass - # if not value: - # value = {} - # - # for root_name, widget in self.widgts_by_root_name.items(): - # root_value = value.get(root_name) or "" - # widget.setText(root_value) - - def settings_value(self): - return {} - # output = {} - # for root_name, widget in self.widgts_by_root_name.items(): - # value = widget.text() - # if value: - # output[root_name] = value - # if not output: - # return None - # return output - - def change_project(self, project_name): - pass - - -class _ProjectListWidget(ProjectListWidget): - def on_item_clicked(self, new_index): - new_project_name = new_index.data(QtCore.Qt.DisplayRole) - if new_project_name is None: - return - - if self.current_project == new_project_name: - return - - self.select_project(new_project_name) - self.current_project = new_project_name - self.project_changed.emit() - - -class ProjectSettingsWidget(QtWidgets.QWidget): - def __init__(self, project_settings, parent): - super(ProjectSettingsWidget, self).__init__(parent) - - self.per_project_settings = {} - - projects_widget = _ProjectListWidget(self) - project_specific_widget = ProjectSpecificWidget(project_settings, self) - - main_layout = QtWidgets.QHBoxLayout(self) - main_layout.setContentsMargins(0, 0, 0, 0) - main_layout.addWidget(projects_widget, 0) - main_layout.addWidget(project_specific_widget, 1) - - projects_widget.project_changed.connect(self._on_project_change) - # project_specific_widget.value_changed.connect( - # self._on_root_value_change - # ) - - self.project_settings = project_settings - - self.projects_widget = projects_widget - self.project_specific_widget = project_specific_widget - - def _current_value(self): - roots_value = self.project_specific_widget.settings_value() - current_value = {} - if roots_value: - current_value[LOCAL_ROOTS_KEY] = roots_value - return current_value - - def project_name(self): - return self.projects_widget.project_name() - - def _on_project_change(self): - project_name = self.project_name() - - self.project_settings.change_project(project_name) - self.project_specific_widget.change_project(project_name) - - def _on_root_value_change(self): - self.per_project_settings[self.project_name()] = ( - self._current_value() - ) - - def set_value(self, value): - if not value: - value = {} - self.per_project_settings = value - - self.projects_widget.refresh() - - self.project_specific_widget.set_value(self.per_project_settings) - - def settings_value(self): - output = {} - for project_name, value in self.per_project_settings.items(): - if value: - output[project_name] = value - if not output: - return None - return output - - class LocalSettingsWidget(QtWidgets.QWidget): def __init__(self, parent=None): super(LocalSettingsWidget, self).__init__(parent) From f061e604296398c853733351856695ee19563e7f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 24 Feb 2021 16:42:21 +0100 Subject: [PATCH 32/61] fixed smaller bugs --- pype/tools/settings/local_settings/projects_widget.py | 3 +++ pype/tools/settings/local_settings/window.py | 2 -- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/pype/tools/settings/local_settings/projects_widget.py b/pype/tools/settings/local_settings/projects_widget.py index 4426422299..d6468cc0af 100644 --- a/pype/tools/settings/local_settings/projects_widget.py +++ b/pype/tools/settings/local_settings/projects_widget.py @@ -1,8 +1,11 @@ +import platform from Qt import QtWidgets, QtCore from pype.tools.settings.settings import ProjectListWidget from .widgets import SpacerWidget from pype.settings.constants import PROJECT_ANATOMY_KEY +LOCAL_ROOTS_KEY = "roots" + class _ProjectListWidget(ProjectListWidget): def on_item_clicked(self, new_index): diff --git a/pype/tools/settings/local_settings/window.py b/pype/tools/settings/local_settings/window.py index 1fd2ca8e06..80ad811b60 100644 --- a/pype/tools/settings/local_settings/window.py +++ b/pype/tools/settings/local_settings/window.py @@ -24,11 +24,9 @@ from .projects_widget import ProjectSettingsWidget log = logging.getLogger(__name__) - LOCAL_GENERAL_KEY = "general" LOCAL_PROJECTS_KEY = "projects" LOCAL_APPS_KEY = "applications" -LOCAL_ROOTS_KEY = "roots" class LocalGeneralWidgets(QtWidgets.QWidget): From 8ba54577fbf85e11b51e7ad4a2d9cb87348f7a60 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 24 Feb 2021 16:50:23 +0100 Subject: [PATCH 33/61] cleaned up projects widget --- .../local_settings/projects_widget.py | 84 +++++-------------- 1 file changed, 21 insertions(+), 63 deletions(-) diff --git a/pype/tools/settings/local_settings/projects_widget.py b/pype/tools/settings/local_settings/projects_widget.py index d6468cc0af..ada8da6bc1 100644 --- a/pype/tools/settings/local_settings/projects_widget.py +++ b/pype/tools/settings/local_settings/projects_widget.py @@ -29,6 +29,7 @@ class RootsWidget(QtWidgets.QWidget): super(RootsWidget, self).__init__(parent) self.project_settings = project_settings + self.local_project_settings = local_project_settings self.widgts_by_root_name = {} main_layout = QtWidgets.QVBoxLayout(self) @@ -90,31 +91,16 @@ class RootsWidget(QtWidgets.QWidget): return default_project.get(LOCAL_ROOTS_KEY) return None - def set_value(self, value): - if not value: - value = {} - - for root_name, widget in self.widgts_by_root_name.items(): - root_value = value.get(root_name) or "" - widget.setText(root_value) - - def settings_value(self): - output = {} - for root_name, widget in self.widgts_by_root_name.items(): - value = widget.text() - if value: - output[root_name] = value - if not output: - return None - return output + def set_value(self, local_project_settings): + self.local_project_settings = local_project_settings -class ProjectSpecificWidget(QtWidgets.QWidget): +class RootSiteWidget(QtWidgets.QWidget): value_changed = QtCore.Signal() def __init__(self, project_settings, parent): self._parent_widget = parent - super(ProjectSpecificWidget, self).__init__(parent) + super(RootSiteWidget, self).__init__(parent) self.project_settings = project_settings self.widgts_by_root_name = {} @@ -132,87 +118,59 @@ class ProjectSpecificWidget(QtWidgets.QWidget): main_layout.addWidget(sites_widget) main_layout.addWidget(SpacerWidget(self), 1) - def set_value(self, value): - pass - # if not value: - # value = {} - # - # for root_name, widget in self.widgts_by_root_name.items(): - # root_value = value.get(root_name) or "" - # widget.setText(root_value) - - def settings_value(self): - return {} - # output = {} - # for root_name, widget in self.widgts_by_root_name.items(): - # value = widget.text() - # if value: - # output[root_name] = value - # if not output: - # return None - # return output + def set_value(self, local_project_settings): + self.local_project_settings = local_project_settings def change_project(self, project_name): + # TODO update values pass +class ProjectValue(dict): + pass + + class ProjectSettingsWidget(QtWidgets.QWidget): def __init__(self, project_settings, parent): super(ProjectSettingsWidget, self).__init__(parent) - self.per_project_settings = {} + self.local_project_settings = {} projects_widget = _ProjectListWidget(self) - project_specific_widget = ProjectSpecificWidget(project_settings, self) + roos_site_widget = RootSiteWidget(project_settings, self) main_layout = QtWidgets.QHBoxLayout(self) main_layout.setContentsMargins(0, 0, 0, 0) main_layout.addWidget(projects_widget, 0) - main_layout.addWidget(project_specific_widget, 1) + main_layout.addWidget(roos_site_widget, 1) projects_widget.project_changed.connect(self._on_project_change) - # project_specific_widget.value_changed.connect( - # self._on_root_value_change - # ) self.project_settings = project_settings self.projects_widget = projects_widget - self.project_specific_widget = project_specific_widget - - def _current_value(self): - roots_value = self.project_specific_widget.settings_value() - current_value = {} - if roots_value: - current_value[LOCAL_ROOTS_KEY] = roots_value - return current_value + self.roos_site_widget = roos_site_widget def project_name(self): return self.projects_widget.project_name() def _on_project_change(self): project_name = self.project_name() - self.project_settings.change_project(project_name) - self.project_specific_widget.change_project(project_name) - - def _on_root_value_change(self): - self.per_project_settings[self.project_name()] = ( - self._current_value() - ) + self.roos_site_widget.change_project(project_name) def set_value(self, value): if not value: value = {} - self.per_project_settings = value + self.local_project_settings = ProjectValue(value) + + self.roos_site_widget.set_value(self.local_project_settings) self.projects_widget.refresh() - self.project_specific_widget.set_value(self.per_project_settings) - def settings_value(self): output = {} - for project_name, value in self.per_project_settings.items(): + for project_name, value in self.local_project_settings.items(): if value: output[project_name] = value if not output: From 367b6c8eec99f60a8ba7170dadfb93c2e383e258 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 24 Feb 2021 17:11:50 +0100 Subject: [PATCH 34/61] prepare structure for project overrides of active/remove site --- .../local_settings/projects_widget.py | 75 +++++++++++++++---- 1 file changed, 61 insertions(+), 14 deletions(-) diff --git a/pype/tools/settings/local_settings/projects_widget.py b/pype/tools/settings/local_settings/projects_widget.py index ada8da6bc1..831dbfcbd7 100644 --- a/pype/tools/settings/local_settings/projects_widget.py +++ b/pype/tools/settings/local_settings/projects_widget.py @@ -1,8 +1,8 @@ import platform from Qt import QtWidgets, QtCore from pype.tools.settings.settings import ProjectListWidget -from .widgets import SpacerWidget from pype.settings.constants import PROJECT_ANATOMY_KEY +from .widgets import SpacerWidget LOCAL_ROOTS_KEY = "roots" @@ -25,28 +25,32 @@ class RootsWidget(QtWidgets.QWidget): value_changed = QtCore.Signal() def __init__(self, project_settings, parent): - self._parent_widget = parent super(RootsWidget, self).__init__(parent) self.project_settings = project_settings - self.local_project_settings = local_project_settings + self.local_project_settings = {} self.widgts_by_root_name = {} + self._project_name = None + self._site_name = None - main_layout = QtWidgets.QVBoxLayout(self) + self.content_layout = QtWidgets.QVBoxLayout(self) - self.content_layout = main_layout + def _on_root_value_change(self, root_key): + print("root value or key {} changed".format(root_key)) - def _on_root_value_change(self): - self.value_changed.emit() - - def refresh(self): + def _clear_widgets(self): while self.content_layout.count(): item = self.content_layout.itemAt(0) item.widget().hide() self.content_layout.removeItem(item) - self.widgts_by_root_name.clear() + def refresh(self): + self._clear_widgets() + + if self._project_name is None or self._site_name is None: + return + default_root_values = self.local_default_project_values() or {} roots_entity = ( @@ -72,7 +76,11 @@ class RootsWidget(QtWidgets.QWidget): if not placeholder: placeholder = platform_entity.value value_input.setPlaceholderText(placeholder) - value_input.textChanged.connect(self._on_root_value_change) + + def _on_root_change(): + self._on_root_value_change(root_name) + + value_input.textChanged.connect(_on_root_change) root_input_layout.addWidget(value_input) @@ -86,7 +94,7 @@ class RootsWidget(QtWidgets.QWidget): self.content_layout.addWidget(SpacerWidget(self), 1) def local_default_project_values(self): - default_project = self._parent_widget.per_project_settings.get(None) + default_project = self.local_project_settings.get(None) if default_project: return default_project.get(LOCAL_ROOTS_KEY) return None @@ -94,6 +102,14 @@ class RootsWidget(QtWidgets.QWidget): def set_value(self, local_project_settings): self.local_project_settings = local_project_settings + def change_site(self, site_name): + self._site_name = site_name + self.refresh() + + def change_project(self, project_name): + self._project_name = project_name + self.refresh() + class RootSiteWidget(QtWidgets.QWidget): value_changed = QtCore.Signal() @@ -104,6 +120,7 @@ class RootSiteWidget(QtWidgets.QWidget): self.project_settings = project_settings self.widgts_by_root_name = {} + self._project_name = None sites_widget = QtWidgets.QWidget(self) sites_layout = QtWidgets.QHBoxLayout(sites_widget) @@ -114,16 +131,46 @@ class RootSiteWidget(QtWidgets.QWidget): sites_layout.addWidget(QtWidgets.QLabel("Remote Site", sites_widget)) sites_layout.addWidget(remote_site_combo) + roots_widget = RootsWidget(project_settings, self) + main_layout = QtWidgets.QVBoxLayout(self) main_layout.addWidget(sites_widget) + main_layout.addWidget(roots_widget) main_layout.addWidget(SpacerWidget(self), 1) + self.active_site_combo = active_site_combo + self.remote_site_combo = remote_site_combo + self.roots_widget = roots_widget + + def _fill_active_site_combo(self): + if self._project_name is None: + return + + def _fill_remote_site_combo(self): + if self._project_name is None: + return + + def _change_combobox_values(self): + # Set sites from local settings in comboboxes + pass + def set_value(self, local_project_settings): self.local_project_settings = local_project_settings + def _change_active_site(self, site_name): + self.roots_widget.change_site(site_name) + def change_project(self, project_name): - # TODO update values - pass + self._project_name = project_name + # Set roots project to None so all changes below are ignored + self.roots_widget.change_project(None) + + self._fill_active_site_combo() + self._fill_remote_site_combo() + self._change_combobox_values() + + # Change project name in roots widget + self.roots_widget.change_project(project_name) class ProjectValue(dict): From ff1a694cad98936a8a9b41f673c9ecd6137e733f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 24 Feb 2021 17:53:02 +0100 Subject: [PATCH 35/61] added temporary fix of application executables --- pype/settings/lib.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pype/settings/lib.py b/pype/settings/lib.py index 24e16dd0ff..fb0bb733c9 100644 --- a/pype/settings/lib.py +++ b/pype/settings/lib.py @@ -363,7 +363,10 @@ def apply_local_settings_on_system_settings(system_settings, local_settings): platform_executables = variants[app_name]["executables"].get( current_platform ) - new_executables = [executable] + # TODO This is temporary fix until launch arguments will be stored + # per platform and not per executable. + # - local settings store only executable + new_executables = [[executable, ""]] new_executables.extend(platform_executables) variants[app_name]["executables"] = new_executables From 7b6d0d20df354c84d2dc66324d0c95af066924cf Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 24 Feb 2021 17:53:33 +0100 Subject: [PATCH 36/61] default project is stored under constant key in local settings --- pype/settings/constants.py | 1 + pype/settings/handlers.py | 20 -------------------- pype/settings/lib.py | 7 ++++--- 3 files changed, 5 insertions(+), 23 deletions(-) diff --git a/pype/settings/constants.py b/pype/settings/constants.py index fcc3a1d2dc..ce19ad3f93 100644 --- a/pype/settings/constants.py +++ b/pype/settings/constants.py @@ -17,6 +17,7 @@ PROJECT_SETTINGS_KEY = "project_settings" PROJECT_ANATOMY_KEY = "project_anatomy" LOCAL_SETTING_KEY = "local_settings" +DEFAULT_PROJECT_KEY = "__default_project__" __all__ = ( "M_OVERRIDEN_KEY", diff --git a/pype/settings/handlers.py b/pype/settings/handlers.py index 135201048a..89f9645be7 100644 --- a/pype/settings/handlers.py +++ b/pype/settings/handlers.py @@ -526,13 +526,7 @@ class MongoLocalSettingsHandler(LocalSettingsHandler): Data have 2 query criteria. First is key "type" stored in constant `LOCAL_SETTING_KEY`. Second is key "site_id" which value can be obstained with `get_local_site_id` function. - - Because project specific values are stored by project name the default - project would have key `None` which is not allowed. Because of that is - `None` replaced with `default_project_key` value on save and the key - is replaced with `None` of load. """ - default_project_key = "__default_project__" def __init__(self, local_site_id=None): # Get mongo connection @@ -571,12 +565,6 @@ class MongoLocalSettingsHandler(LocalSettingsHandler): """ data = data or {} - # Replace key `None` (default project values) with constant string - if "projects" in data and None in data["projects"]: - data["projects"][self.default_project_key] = ( - data["projects"].pop(None) - ) - self.local_settings_cache.update_data(data) self.collection.replace_one( @@ -601,13 +589,5 @@ class MongoLocalSettingsHandler(LocalSettingsHandler): }) self.local_settings_cache.update_from_document(document) - data = self.local_settings_cache.data - if ( - "projects" in data - and self.default_project_key in data["projects"] - ): - data["projects"][None] = data["projects"].pop( - self.default_project_key - ) return self.local_settings_cache.data_copy() diff --git a/pype/settings/lib.py b/pype/settings/lib.py index fb0bb733c9..1fbcbeabb8 100644 --- a/pype/settings/lib.py +++ b/pype/settings/lib.py @@ -12,7 +12,8 @@ from .constants import ( SYSTEM_SETTINGS_KEY, PROJECT_SETTINGS_KEY, - PROJECT_ANATOMY_KEY + PROJECT_ANATOMY_KEY, + DEFAULT_PROJECT_KEY ) log = logging.getLogger(__name__) @@ -402,7 +403,7 @@ def apply_local_settings_on_anatomy_settings( return current_platform = platform.system().lower() - local_defaults = local_project_settings.get(None) + local_defaults = local_project_settings.get(DEFAULT_PROJECT_KEY) root_data = anatomy_settings["roots"] if local_defaults and "roots" in local_defaults: for root_name, path in local_defaults["roots"].items(): @@ -411,7 +412,7 @@ def apply_local_settings_on_anatomy_settings( anatomy_settings["roots"][root_name][current_platform] = ( path ) - if project_name is None: + if project_name == DEFAULT_PROJECT_KEY: return local_projects = local_project_settings.get(project_name) From 60e36787dba0e4dcaa3fcb03f99f15a506ccd385 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 24 Feb 2021 18:03:14 +0100 Subject: [PATCH 37/61] fill comboboxes with sites and added ability to define project settings --- .../local_settings/projects_widget.py | 125 ++++++++++++++---- 1 file changed, 100 insertions(+), 25 deletions(-) diff --git a/pype/tools/settings/local_settings/projects_widget.py b/pype/tools/settings/local_settings/projects_widget.py index 831dbfcbd7..303bb39e3d 100644 --- a/pype/tools/settings/local_settings/projects_widget.py +++ b/pype/tools/settings/local_settings/projects_widget.py @@ -1,7 +1,10 @@ import platform from Qt import QtWidgets, QtCore from pype.tools.settings.settings import ProjectListWidget -from pype.settings.constants import PROJECT_ANATOMY_KEY +from pype.settings.constants import ( + PROJECT_ANATOMY_KEY, + DEFAULT_PROJECT_KEY +) from .widgets import SpacerWidget LOCAL_ROOTS_KEY = "roots" @@ -20,6 +23,11 @@ class _ProjectListWidget(ProjectListWidget): self.current_project = new_project_name self.project_changed.emit() + def project_name(self): + if self.current_project == self.default: + return DEFAULT_PROJECT_KEY + return self.current_project + class RootsWidget(QtWidgets.QWidget): value_changed = QtCore.Signal() @@ -51,22 +59,27 @@ class RootsWidget(QtWidgets.QWidget): if self._project_name is None or self._site_name is None: return - default_root_values = self.local_default_project_values() or {} + default_root_values = self._get_site_value_for_project( + DEFAULT_PROJECT_KEY + ) + if self._project_name == DEFAULT_PROJECT_KEY: + project_root_values = default_root_values + else: + project_root_values = self._get_site_value_for_project( + self._project_name + ) roots_entity = ( self.project_settings[PROJECT_ANATOMY_KEY][LOCAL_ROOTS_KEY] ) - is_in_default = self.project_settings.project_name is None + is_in_default = self._project_name == DEFAULT_PROJECT_KEY for root_name, path_entity in roots_entity.items(): platform_entity = path_entity[platform.system().lower()] root_widget = QtWidgets.QWidget(self) key_label = QtWidgets.QLabel(root_name, root_widget) - - root_input_widget = QtWidgets.QWidget(root_widget) - root_input_layout = QtWidgets.QVBoxLayout(root_input_widget) - - value_input = QtWidgets.QLineEdit(root_input_widget) + value_input = QtWidgets.QLineEdit(root_widget) + # Placeholder placeholder = None if not is_in_default: placeholder = default_root_values.get(root_name) @@ -75,29 +88,36 @@ class RootsWidget(QtWidgets.QWidget): if not placeholder: placeholder = platform_entity.value + value_input.setPlaceholderText(placeholder) + # Root value + project_value = project_root_values.get(root_name) + if project_value: + value_input.setText(project_value) + + # Register change callback def _on_root_change(): self._on_root_value_change(root_name) value_input.textChanged.connect(_on_root_change) - root_input_layout.addWidget(value_input) - root_layout = QtWidgets.QHBoxLayout(root_widget) root_layout.addWidget(key_label) - root_layout.addWidget(root_input_widget) + root_layout.addWidget(value_input) self.content_layout.addWidget(root_widget) self.widgts_by_root_name[root_name] = value_input self.content_layout.addWidget(SpacerWidget(self), 1) - def local_default_project_values(self): - default_project = self.local_project_settings.get(None) + def _get_site_value_for_project(self, project_name): + default_project = self.local_project_settings.get(project_name) if default_project: - return default_project.get(LOCAL_ROOTS_KEY) - return None + root_value = default_project.get(LOCAL_ROOTS_KEY) + if root_value: + return root_value.get(self._site_name) or {} + return {} def set_value(self, local_project_settings): self.local_project_settings = local_project_settings @@ -119,7 +139,6 @@ class RootSiteWidget(QtWidgets.QWidget): super(RootSiteWidget, self).__init__(parent) self.project_settings = project_settings - self.widgts_by_root_name = {} self._project_name = None sites_widget = QtWidgets.QWidget(self) @@ -142,17 +161,74 @@ class RootSiteWidget(QtWidgets.QWidget): self.remote_site_combo = remote_site_combo self.roots_widget = roots_widget - def _fill_active_site_combo(self): - if self._project_name is None: - return + def _active_site_values(self): + global_entity = self.project_settings["project_settings"]["global"] + sites_entity = global_entity["sync_server"]["sites"] + return tuple(sites_entity.keys()) - def _fill_remote_site_combo(self): - if self._project_name is None: - return + def _remote_site_values(self): + global_entity = self.project_settings["project_settings"]["global"] + sites_entity = global_entity["sync_server"]["sites"] + return tuple(sites_entity.keys()) def _change_combobox_values(self): + self.active_site_combo.clear() + self.remote_site_combo.clear() + if self._project_name is None: + return + + active_site_values = self._active_site_values() + remote_site_values = self._remote_site_values() + # Set sites from local settings in comboboxes - pass + active_site = None + remote_site = None + + project_values = self.local_project_settings.get(self._project_name) + if project_values: + active_site = project_values.get("active_site") + remote_site = project_values.get("remote_site") + + if ( + (not active_site or not remote_site) + and self._project_name is not DEFAULT_PROJECT_KEY + ): + default_values = self.local_project_settings.get( + DEFAULT_PROJECT_KEY + ) + if default_values: + if not active_site: + active_site = default_values.get("active_site") + if not remote_site: + remote_site = default_values.get("remote_site") + + self.active_site_combo.addItems(active_site_values) + self.remote_site_combo.addItems(remote_site_values) + + # Find and set remote site in combobox + if remote_site: + idx = self.remote_site_combo.findText(active_site) + if idx >= 0: + index = self.remote_site_combo.model().index(idx, 0) + self.remote_site_combo.setCurrentIndex(index) + + # Find and set active site in combobox + if active_site: + idx = self.active_site_combo.findText(active_site) + if idx < 0: + active_site = None + else: + index = self.active_site_combo.model().index(idx, 0) + self.active_site_combo.setCurrentIndex(index) + + # Prepare value to change active site in roots widget + if not active_site: + if not active_site_values: + active_site = None + else: + active_site = self.active_site_combo.currentText() + + self._change_active_site(active_site) def set_value(self, local_project_settings): self.local_project_settings = local_project_settings @@ -165,8 +241,7 @@ class RootSiteWidget(QtWidgets.QWidget): # Set roots project to None so all changes below are ignored self.roots_widget.change_project(None) - self._fill_active_site_combo() - self._fill_remote_site_combo() + # Aply changes in site comboboxes self._change_combobox_values() # Change project name in roots widget From 13053fad6ef8ed5a33b2b8e5db3197ecbff9fc8d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 24 Feb 2021 18:34:43 +0100 Subject: [PATCH 38/61] roots are handled in specific widget --- .../local_settings/projects_widget.py | 159 ++++++++++++------ 1 file changed, 108 insertions(+), 51 deletions(-) diff --git a/pype/tools/settings/local_settings/projects_widget.py b/pype/tools/settings/local_settings/projects_widget.py index 303bb39e3d..e553bab965 100644 --- a/pype/tools/settings/local_settings/projects_widget.py +++ b/pype/tools/settings/local_settings/projects_widget.py @@ -1,4 +1,5 @@ import platform +import copy from Qt import QtWidgets, QtCore from pype.tools.settings.settings import ProjectListWidget from pype.settings.constants import ( @@ -29,6 +30,97 @@ class _ProjectListWidget(ProjectListWidget): return self.current_project +class RootInputWidget(QtWidgets.QWidget): + def __init__( + self, + local_project_settings, + local_project_settings_orig, + platform_root_entity, + root_name, + project_name, + site_name, + parent + ): + super(RootInputWidget, self).__init__(parent) + + self.local_project_settings = local_project_settings + self.local_project_settings_orig = local_project_settings_orig + self.platform_root_entity = platform_root_entity + self.root_name = root_name + self.site_name = site_name + self.project_name = project_name + + self.origin_value = self._get_site_value_for_project( + self.project_name, self.local_project_settings_orig + ) + + key_label = QtWidgets.QLabel(root_name, self) + value_input = QtWidgets.QLineEdit(self) + + is_default_project = bool(project_name == DEFAULT_PROJECT_KEY) + + default_input_value = self._get_site_value_for_project( + DEFAULT_PROJECT_KEY + ) + if is_default_project: + project_value = None + input_value = default_input_value + else: + input_value = self._get_site_value_for_project(self.project_name) + project_value = input_value + + # Placeholder + placeholder = None + if not is_default_project: + placeholder = default_input_value + + if not placeholder: + placeholder = platform_root_entity.value + + value_input.setPlaceholderText("< {} >".format(placeholder)) + + # Root value + if input_value: + value_input.setText(input_value) + + value_input.textChanged.connect(self._on_value_change) + + root_layout = QtWidgets.QHBoxLayout(self) + root_layout.addWidget(key_label) + root_layout.addWidget(value_input) + + self.value_input = value_input + + self.is_default_project = is_default_project + self.studio_value = platform_root_entity.value + self.default_value = default_input_value + self.project_value = project_value + + @property + def is_modified(self): + return self.origin_value != self.value_input.text() + + def _get_site_value_for_project(self, project_name, data=None): + if data is None: + data = self.local_project_settings + project_values = data.get(project_name) + site_value = {} + if project_values: + root_value = project_values.get(LOCAL_ROOTS_KEY) + if root_value: + site_value = root_value.get(self.site_name) or {} + return site_value.get(self.root_name) + + def _on_value_change(self): + value = self.value_input.text() + data = self.local_project_settings + for key in (self.project_name, LOCAL_ROOTS_KEY, self.site_name): + if key not in data: + data[key] = {} + data = data[key] + data[self.root_name] = value + + class RootsWidget(QtWidgets.QWidget): value_changed = QtCore.Signal() @@ -36,8 +128,9 @@ class RootsWidget(QtWidgets.QWidget): super(RootsWidget, self).__init__(parent) self.project_settings = project_settings - self.local_project_settings = {} self.widgts_by_root_name = {} + self.local_project_settings = None + self.local_project_settings_orig = None self._project_name = None self._site_name = None @@ -59,68 +152,31 @@ class RootsWidget(QtWidgets.QWidget): if self._project_name is None or self._site_name is None: return - default_root_values = self._get_site_value_for_project( - DEFAULT_PROJECT_KEY - ) - if self._project_name == DEFAULT_PROJECT_KEY: - project_root_values = default_root_values - else: - project_root_values = self._get_site_value_for_project( - self._project_name - ) - roots_entity = ( self.project_settings[PROJECT_ANATOMY_KEY][LOCAL_ROOTS_KEY] ) - is_in_default = self._project_name == DEFAULT_PROJECT_KEY for root_name, path_entity in roots_entity.items(): platform_entity = path_entity[platform.system().lower()] - root_widget = QtWidgets.QWidget(self) - - key_label = QtWidgets.QLabel(root_name, root_widget) - value_input = QtWidgets.QLineEdit(root_widget) - # Placeholder - placeholder = None - if not is_in_default: - placeholder = default_root_values.get(root_name) - if placeholder: - placeholder = "< {} >".format(placeholder) - - if not placeholder: - placeholder = platform_entity.value - - value_input.setPlaceholderText(placeholder) - - # Root value - project_value = project_root_values.get(root_name) - if project_value: - value_input.setText(project_value) - - # Register change callback - def _on_root_change(): - self._on_root_value_change(root_name) - - value_input.textChanged.connect(_on_root_change) - - root_layout = QtWidgets.QHBoxLayout(root_widget) - root_layout.addWidget(key_label) - root_layout.addWidget(value_input) + root_widget = RootInputWidget( + self.local_project_settings, + self.local_project_settings_orig, + platform_entity, + root_name, + self._project_name, + self._site_name, + self + ) self.content_layout.addWidget(root_widget) - self.widgts_by_root_name[root_name] = value_input + self.widgts_by_root_name[root_name] = root_widget self.content_layout.addWidget(SpacerWidget(self), 1) - def _get_site_value_for_project(self, project_name): - default_project = self.local_project_settings.get(project_name) - if default_project: - root_value = default_project.get(LOCAL_ROOTS_KEY) - if root_value: - return root_value.get(self._site_name) or {} - return {} - def set_value(self, local_project_settings): self.local_project_settings = local_project_settings + self.local_project_settings_orig = copy.deepcopy( + dict(local_project_settings) + ) def change_site(self, site_name): self._site_name = site_name @@ -232,6 +288,7 @@ class RootSiteWidget(QtWidgets.QWidget): def set_value(self, local_project_settings): self.local_project_settings = local_project_settings + self.roots_widget.set_value(local_project_settings) def _change_active_site(self, site_name): self.roots_widget.change_site(site_name) From 374b342bb42a3c8841dbb3f8ba966e98d19cdf1e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 25 Feb 2021 10:50:40 +0100 Subject: [PATCH 39/61] implemented comboboxes for sites --- .../local_settings/projects_widget.py | 237 +++++++++++------- 1 file changed, 153 insertions(+), 84 deletions(-) diff --git a/pype/tools/settings/local_settings/projects_widget.py b/pype/tools/settings/local_settings/projects_widget.py index e553bab965..6cc4e89682 100644 --- a/pype/tools/settings/local_settings/projects_widget.py +++ b/pype/tools/settings/local_settings/projects_widget.py @@ -24,11 +24,6 @@ class _ProjectListWidget(ProjectListWidget): self.current_project = new_project_name self.project_changed.emit() - def project_name(self): - if self.current_project == self.default: - return DEFAULT_PROJECT_KEY - return self.current_project - class RootInputWidget(QtWidgets.QWidget): def __init__( @@ -54,17 +49,14 @@ class RootInputWidget(QtWidgets.QWidget): self.project_name, self.local_project_settings_orig ) - key_label = QtWidgets.QLabel(root_name, self) - value_input = QtWidgets.QLineEdit(self) - is_default_project = bool(project_name == DEFAULT_PROJECT_KEY) default_input_value = self._get_site_value_for_project( DEFAULT_PROJECT_KEY ) if is_default_project: - project_value = None input_value = default_input_value + project_value = None else: input_value = self._get_site_value_for_project(self.project_name) project_value = input_value @@ -77,6 +69,8 @@ class RootInputWidget(QtWidgets.QWidget): if not placeholder: placeholder = platform_root_entity.value + key_label = QtWidgets.QLabel(root_name, self) + value_input = QtWidgets.QLineEdit(self) value_input.setPlaceholderText("< {} >".format(placeholder)) # Root value @@ -122,8 +116,6 @@ class RootInputWidget(QtWidgets.QWidget): class RootsWidget(QtWidgets.QWidget): - value_changed = QtCore.Signal() - def __init__(self, project_settings, parent): super(RootsWidget, self).__init__(parent) @@ -136,9 +128,6 @@ class RootsWidget(QtWidgets.QWidget): self.content_layout = QtWidgets.QVBoxLayout(self) - def _on_root_value_change(self, root_key): - print("root value or key {} changed".format(root_key)) - def _clear_widgets(self): while self.content_layout.count(): item = self.content_layout.itemAt(0) @@ -152,6 +141,10 @@ class RootsWidget(QtWidgets.QWidget): if self._project_name is None or self._site_name is None: return + # Site label + self.content_layout.addWidget(QtWidgets.QLabel(self._site_name, self)) + + # Root inputs roots_entity = ( self.project_settings[PROJECT_ANATOMY_KEY][LOCAL_ROOTS_KEY] ) @@ -170,6 +163,7 @@ class RootsWidget(QtWidgets.QWidget): self.content_layout.addWidget(root_widget) self.widgts_by_root_name[root_name] = root_widget + # Add spacer so other widgets are squeezed to top self.content_layout.addWidget(SpacerWidget(self), 1) def set_value(self, local_project_settings): @@ -187,9 +181,135 @@ class RootsWidget(QtWidgets.QWidget): self.refresh() -class RootSiteWidget(QtWidgets.QWidget): - value_changed = QtCore.Signal() +class _SiteCombobox(QtWidgets.QWidget): + site_changed = QtCore.Signal(str) + def __init__(self, project_settings, parent): + super(_SiteCombobox, self).__init__(parent) + self.project_settings = project_settings + + self.local_project_settings = None + self.local_project_settings_orig = None + self.project_name = None + self.is_default_project = None + + self.default_override_value = None + self.project_override_value = None + + label_widget = QtWidgets.QLabel(self) + combobox_input = QtWidgets.QComboBox(self) + + main_layout = QtWidgets.QHBoxLayout(self) + main_layout.addWidget(label_widget) + main_layout.addWidget(combobox_input) + + combobox_input.currentIndexChanged.connect(self._on_index_change) + self.label_widget = label_widget + self.combobox_input = combobox_input + + self._ui_tweaks() + + def set_value(self, local_project_settings): + self.local_project_settings = local_project_settings + self.local_project_settings_orig = copy.deepcopy( + dict(local_project_settings) + ) + + def change_project(self, project_name): + self.default_override_value = None + self.project_override_value = None + + self.project_name = None + self.combobox_input.clear() + if project_name is None: + return + + self.is_default_project = bool(project_name == DEFAULT_PROJECT_KEY) + site_items = self._get_project_sites() + self.combobox_input.addItems(site_items) + + default_item = self._get_local_settings_item(DEFAULT_PROJECT_KEY) + if self.is_default_project: + project_item = None + else: + project_item = self._get_local_settings_item(project_name) + + index = None + if project_item: + idx = self.combobox_input.findText(project_item) + if idx >= 0: + self.project_override_value = project_item + index = self.combobox_input.model().index(idx, 0) + + if default_item: + idx = self.combobox_input.findText(default_item) + if idx >= 0: + self.default_override_value = default_item + if not index: + index = self.combobox_input.model().index(idx, 0) + if index: + self.combobox_input.setCurrentIndex(index) + + self.project_name = project_name + self.site_changed.emit(self.combobox_input.currentText()) + + def _on_index_change(self): + if self.project_name is None: + return + self.site_changed.emit(self.combobox_input.currentText()) + print("here") + + def _ui_tweaks(self): + raise NotImplementedError("_ui_tweaks not implemented {}".format( + self.__class__.__name__ + )) + + def _get_project_sites(self): + raise NotImplementedError("_ui_tweaks not implemented {}".format( + self.__class__.__name__ + )) + + def _get_local_settings_item(self, project_name): + raise NotImplementedError("_ui_tweaks not implemented {}".format( + self.__class__.__name__ + )) + + +class AciveSiteCombo(_SiteCombobox): + def _ui_tweaks(self): + self.label_widget.setText("Active site") + + def _get_project_sites(self): + global_entity = self.project_settings["project_settings"]["global"] + sites_entity = global_entity["sync_server"]["sites"] + return tuple(sites_entity.keys()) + + def _get_local_settings_item(self, project_name): + project_values = self.local_project_settings.get(project_name) + value = None + if project_values: + value = project_values.get("active_site") + return value + + +class RemoteSiteCombo(_SiteCombobox): + def _ui_tweaks(self): + self.label_widget.setText("Remote site") + + def _get_project_sites(self): + global_entity = self.project_settings["project_settings"]["global"] + sites_entity = global_entity["sync_server"]["sites"] + return tuple(sites_entity.keys()) + + def _get_local_settings_item(self, project_name): + project_values = self.local_project_settings.get(project_name) + value = None + if project_values: + value = project_values.get("remote_site") + return value + + +class RootSiteWidget(QtWidgets.QWidget): def __init__(self, project_settings, parent): self._parent_widget = parent super(RootSiteWidget, self).__init__(parent) @@ -199,12 +319,11 @@ class RootSiteWidget(QtWidgets.QWidget): sites_widget = QtWidgets.QWidget(self) sites_layout = QtWidgets.QHBoxLayout(sites_widget) - active_site_combo = QtWidgets.QComboBox(sites_widget) - remote_site_combo = QtWidgets.QComboBox(sites_widget) - sites_layout.addWidget(QtWidgets.QLabel("Active Site", sites_widget)) - sites_layout.addWidget(active_site_combo) - sites_layout.addWidget(QtWidgets.QLabel("Remote Site", sites_widget)) - sites_layout.addWidget(remote_site_combo) + + active_site_widget = AciveSiteCombo(project_settings, sites_widget) + remote_site_widget = RemoteSiteCombo(project_settings, sites_widget) + sites_layout.addWidget(active_site_widget) + sites_layout.addWidget(remote_site_widget) roots_widget = RootsWidget(project_settings, self) @@ -213,8 +332,9 @@ class RootSiteWidget(QtWidgets.QWidget): main_layout.addWidget(roots_widget) main_layout.addWidget(SpacerWidget(self), 1) - self.active_site_combo = active_site_combo - self.remote_site_combo = remote_site_combo + active_site_widget.site_changed.connect(self._on_acite_site_change) + self.active_site_widget = active_site_widget + self.remote_site_widget = remote_site_widget self.roots_widget = roots_widget def _active_site_values(self): @@ -227,69 +347,15 @@ class RootSiteWidget(QtWidgets.QWidget): sites_entity = global_entity["sync_server"]["sites"] return tuple(sites_entity.keys()) - def _change_combobox_values(self): - self.active_site_combo.clear() - self.remote_site_combo.clear() - if self._project_name is None: - return - - active_site_values = self._active_site_values() - remote_site_values = self._remote_site_values() - - # Set sites from local settings in comboboxes - active_site = None - remote_site = None - - project_values = self.local_project_settings.get(self._project_name) - if project_values: - active_site = project_values.get("active_site") - remote_site = project_values.get("remote_site") - - if ( - (not active_site or not remote_site) - and self._project_name is not DEFAULT_PROJECT_KEY - ): - default_values = self.local_project_settings.get( - DEFAULT_PROJECT_KEY - ) - if default_values: - if not active_site: - active_site = default_values.get("active_site") - if not remote_site: - remote_site = default_values.get("remote_site") - - self.active_site_combo.addItems(active_site_values) - self.remote_site_combo.addItems(remote_site_values) - - # Find and set remote site in combobox - if remote_site: - idx = self.remote_site_combo.findText(active_site) - if idx >= 0: - index = self.remote_site_combo.model().index(idx, 0) - self.remote_site_combo.setCurrentIndex(index) - - # Find and set active site in combobox - if active_site: - idx = self.active_site_combo.findText(active_site) - if idx < 0: - active_site = None - else: - index = self.active_site_combo.model().index(idx, 0) - self.active_site_combo.setCurrentIndex(index) - - # Prepare value to change active site in roots widget - if not active_site: - if not active_site_values: - active_site = None - else: - active_site = self.active_site_combo.currentText() - - self._change_active_site(active_site) - def set_value(self, local_project_settings): self.local_project_settings = local_project_settings + self.active_site_widget.set_value(local_project_settings) + self.remote_site_widget.set_value(local_project_settings) self.roots_widget.set_value(local_project_settings) + def _on_acite_site_change(self, site_name): + self._change_active_site(site_name) + def _change_active_site(self, site_name): self.roots_widget.change_site(site_name) @@ -299,7 +365,8 @@ class RootSiteWidget(QtWidgets.QWidget): self.roots_widget.change_project(None) # Aply changes in site comboboxes - self._change_combobox_values() + self.active_site_widget.change_project(project_name) + self.remote_site_widget.change_project(project_name) # Change project name in roots widget self.roots_widget.change_project(project_name) @@ -336,6 +403,8 @@ class ProjectSettingsWidget(QtWidgets.QWidget): def _on_project_change(self): project_name = self.project_name() self.project_settings.change_project(project_name) + if project_name is None: + project_name = DEFAULT_PROJECT_KEY self.roos_site_widget.change_project(project_name) def set_value(self, value): From e17ae80de139014b80be856d55cf30be9672f365 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 25 Feb 2021 10:54:46 +0100 Subject: [PATCH 40/61] reduce margins and squeeze comboboxes --- pype/tools/settings/local_settings/projects_widget.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pype/tools/settings/local_settings/projects_widget.py b/pype/tools/settings/local_settings/projects_widget.py index 6cc4e89682..3122b47bc5 100644 --- a/pype/tools/settings/local_settings/projects_widget.py +++ b/pype/tools/settings/local_settings/projects_widget.py @@ -318,12 +318,15 @@ class RootSiteWidget(QtWidgets.QWidget): self._project_name = None sites_widget = QtWidgets.QWidget(self) - sites_layout = QtWidgets.QHBoxLayout(sites_widget) active_site_widget = AciveSiteCombo(project_settings, sites_widget) remote_site_widget = RemoteSiteCombo(project_settings, sites_widget) + + sites_layout = QtWidgets.QHBoxLayout(sites_widget) + sites_layout.setContentsMargins(0, 0, 0, 0) sites_layout.addWidget(active_site_widget) sites_layout.addWidget(remote_site_widget) + sites_layout.addWidget(SpacerWidget(self), 1) roots_widget = RootsWidget(project_settings, self) From bb49592adf95de2b99b6aea35fa6616e479216f7 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 25 Feb 2021 12:04:18 +0100 Subject: [PATCH 41/61] implemented proxy label for actions --- pype/tools/settings/local_settings/widgets.py | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/pype/tools/settings/local_settings/widgets.py b/pype/tools/settings/local_settings/widgets.py index ebb14a3102..e3c9590438 100644 --- a/pype/tools/settings/local_settings/widgets.py +++ b/pype/tools/settings/local_settings/widgets.py @@ -1,4 +1,4 @@ -from Qt import QtWidgets +from Qt import QtWidgets, QtCore from pype.tools.settings.settings.widgets.widgets import ( ExpandingWidget, SpacerWidget @@ -20,3 +20,29 @@ class Separator(QtWidgets.QFrame): layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(5, 5, 5, 5) layout.addWidget(splitter_item) + + +class ProxyLabelWidget(QtWidgets.QWidget): + def __init__(self, label, mouse_release_callback, parent=None): + super(ProxyLabelWidget, self).__init__(parent) + + self.mouse_release_callback = mouse_release_callback + + layout = QtWidgets.QVBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(0) + + label_widget = QtWidgets.QLabel(label, self) + layout.addWidget(label_widget) + + self.setAttribute(QtCore.Qt.WA_TranslucentBackground) + + self.label_widget = label_widget + + def setText(self, text): + self.label_widget.setText(text) + + def mouseReleaseEvent(self, event): + if self.mouse_release_callback: + return self.mouse_release_callback(event) + return super(ProxyLabelWidget, self).mouseReleaseEvent(event) From 6e377f8634832e478bd911f0b23dff6184cd0d46 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 25 Feb 2021 12:05:20 +0100 Subject: [PATCH 42/61] it is possible to set different sites and overrides should work --- .../local_settings/projects_widget.py | 206 +++++++++++++++--- 1 file changed, 181 insertions(+), 25 deletions(-) diff --git a/pype/tools/settings/local_settings/projects_widget.py b/pype/tools/settings/local_settings/projects_widget.py index 3122b47bc5..753732ab34 100644 --- a/pype/tools/settings/local_settings/projects_widget.py +++ b/pype/tools/settings/local_settings/projects_widget.py @@ -1,12 +1,15 @@ import platform import copy -from Qt import QtWidgets, QtCore +from Qt import QtWidgets, QtCore, QtGui from pype.tools.settings.settings import ProjectListWidget from pype.settings.constants import ( PROJECT_ANATOMY_KEY, DEFAULT_PROJECT_KEY ) -from .widgets import SpacerWidget +from .widgets import ( + SpacerWidget, + ProxyLabelWidget +) LOCAL_ROOTS_KEY = "roots" @@ -196,25 +199,138 @@ class _SiteCombobox(QtWidgets.QWidget): self.default_override_value = None self.project_override_value = None - label_widget = QtWidgets.QLabel(self) + label_widget = ProxyLabelWidget("", self._mouse_release_callback, self) combobox_input = QtWidgets.QComboBox(self) main_layout = QtWidgets.QHBoxLayout(self) main_layout.addWidget(label_widget) main_layout.addWidget(combobox_input) + # --- START --- DEBUG widget + self._debug_label = QtWidgets.QLabel("*", self) + main_layout.addWidget(self._debug_label) + # --- END --- + combobox_input.currentIndexChanged.connect(self._on_index_change) self.label_widget = label_widget self.combobox_input = combobox_input self._ui_tweaks() + def _set_current_text(self, text): + index = None + if text: + idx = self.combobox_input.findText(text) + if idx >= 0: + index = idx + + if index: + self.combobox_input.setCurrentIndex(index) + return True + return False + + def update_style(self): + if self.project_name is None: + self._debug_label.setText("None") + return + + current_value = self._get_local_settings_item(self.project_name) + orig_value = self._get_local_settings_item( + self.project_name, self.local_project_settings_orig + ) + if current_value and orig_value: + modified = current_value != orig_value + elif not current_value and not orig_value: + modified = False + else: + modified = True + + if modified: + self._debug_label.setText("Modified") + return + + if self.project_name == DEFAULT_PROJECT_KEY: + if not current_value: + self._debug_label.setText("No active site") + else: + self._debug_label.setText("Active default") + else: + if not current_value: + self._debug_label.setText("Default active site") + else: + self._debug_label.setText("Active project") + + def _mouse_release_callback(self, event): + if event.button() != QtCore.Qt.RightButton: + return + self._show_actions() + + def _remove_from_local(self): + if ( + self.project_name != DEFAULT_PROJECT_KEY + and self.default_override_value + ): + _project_name = self.project_name + self.project_name = None + self._set_current_text(self.default_override_value) + self.project_name = _project_name + + self._set_local_settings_value("") + self.update_style() + + def _add_to_local(self): + self._set_local_settings_value(self.current_text()) + self.update_style() + + def _add_actions(self, menu, actions_mapping): + # TODO better labels + if self.project_name == DEFAULT_PROJECT_KEY: + if self.default_override_value: + action = QtWidgets.QAction("Remove from default") + callback = self._remove_from_local + else: + action = QtWidgets.QAction("Add to default") + callback = self._add_to_local + else: + if self.project_override_value: + action = QtWidgets.QAction("Remove from project") + callback = self._remove_from_local + else: + action = QtWidgets.QAction("Add to project") + callback = self._add_to_local + + actions_mapping[action] = callback + menu.addAction(action) + + def _show_actions(self): + if self.project_name is None: + return + + menu = QtWidgets.QMenu(self) + actions_mapping = {} + + self._add_actions(menu, actions_mapping) + + if not actions_mapping: + action = QtWidgets.QAction("< No action >") + actions_mapping[action] = None + menu.addAction(action) + + result = menu.exec_(QtGui.QCursor.pos()) + if result: + to_run = actions_mapping[result] + if to_run: + to_run() + def set_value(self, local_project_settings): self.local_project_settings = local_project_settings self.local_project_settings_orig = copy.deepcopy( dict(local_project_settings) ) + def current_text(self): + return self.combobox_input.currentText() + def change_project(self, project_name): self.default_override_value = None self.project_override_value = None @@ -222,6 +338,7 @@ class _SiteCombobox(QtWidgets.QWidget): self.project_name = None self.combobox_input.clear() if project_name is None: + self.update_style() return self.is_default_project = bool(project_name == DEFAULT_PROJECT_KEY) @@ -239,40 +356,54 @@ class _SiteCombobox(QtWidgets.QWidget): idx = self.combobox_input.findText(project_item) if idx >= 0: self.project_override_value = project_item - index = self.combobox_input.model().index(idx, 0) + index = idx if default_item: idx = self.combobox_input.findText(default_item) if idx >= 0: self.default_override_value = default_item - if not index: - index = self.combobox_input.model().index(idx, 0) + if index is None: + index = idx if index: self.combobox_input.setCurrentIndex(index) self.project_name = project_name - self.site_changed.emit(self.combobox_input.currentText()) + self.site_changed.emit(self.current_text()) + self.update_style() def _on_index_change(self): if self.project_name is None: return - self.site_changed.emit(self.combobox_input.currentText()) - print("here") + + self._set_local_settings_value(self.current_text()) + self.site_changed.emit(self.current_text()) + self.update_style() + + def _set_local_settings_value(self, value): + raise NotImplementedError( + "{} `_set_local_settings_value` not implemented".format( + self.__class__.__name__ + ) + ) def _ui_tweaks(self): - raise NotImplementedError("_ui_tweaks not implemented {}".format( + raise NotImplementedError("{} `_ui_tweaks` not implemented".format( self.__class__.__name__ )) def _get_project_sites(self): - raise NotImplementedError("_ui_tweaks not implemented {}".format( - self.__class__.__name__ - )) + raise NotImplementedError( + "{} `_get_project_sites` not implemented".format( + self.__class__.__name__ + ) + ) - def _get_local_settings_item(self, project_name): - raise NotImplementedError("_ui_tweaks not implemented {}".format( - self.__class__.__name__ - )) + def _get_local_settings_item(self, project_name, data=None): + raise NotImplementedError( + "{}`_get_local_settings_item` not implemented".format( + self.__class__.__name__ + ) + ) class AciveSiteCombo(_SiteCombobox): @@ -284,13 +415,20 @@ class AciveSiteCombo(_SiteCombobox): sites_entity = global_entity["sync_server"]["sites"] return tuple(sites_entity.keys()) - def _get_local_settings_item(self, project_name): - project_values = self.local_project_settings.get(project_name) + def _get_local_settings_item(self, project_name, data=None): + if data is None: + data = self.local_project_settings + project_values = data.get(project_name) value = None if project_values: value = project_values.get("active_site") return value + def _set_local_settings_value(self, value): + if self.project_name not in self.local_project_settings: + self.local_project_settings[self.project_name] = {} + self.local_project_settings[self.project_name]["active_site"] = value + class RemoteSiteCombo(_SiteCombobox): def _ui_tweaks(self): @@ -301,13 +439,20 @@ class RemoteSiteCombo(_SiteCombobox): sites_entity = global_entity["sync_server"]["sites"] return tuple(sites_entity.keys()) - def _get_local_settings_item(self, project_name): - project_values = self.local_project_settings.get(project_name) + def _get_local_settings_item(self, project_name, data=None): + if data is None: + data = self.local_project_settings + project_values = data.get(project_name) value = None if project_values: value = project_values.get("remote_site") return value + def _set_local_settings_value(self, value): + if self.project_name not in self.local_project_settings: + self.local_project_settings[self.project_name] = {} + self.local_project_settings[self.project_name]["remote_site"] = value + class RootSiteWidget(QtWidgets.QWidget): def __init__(self, project_settings, parent): @@ -419,11 +564,22 @@ class ProjectSettingsWidget(QtWidgets.QWidget): self.projects_widget.refresh() - def settings_value(self): + def _clear_value(self, value): + if not value: + return None + + if not isinstance(value, dict): + return value + output = {} - for project_name, value in self.local_project_settings.items(): - if value: - output[project_name] = value + for _key, _value in value.items(): + _modified_value = self._clear_value(_value) + if _modified_value: + output[_key] = _modified_value + return output + + def settings_value(self): + output = self._clear_value(self.local_project_settings) if not output: return None return output From 1cf3d924802829c6b059ab7a263e85c9203dc2bf Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 25 Feb 2021 12:21:46 +0100 Subject: [PATCH 43/61] changed site roots modification on anatomy data load --- pype/settings/lib.py | 43 ++++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/pype/settings/lib.py b/pype/settings/lib.py index 1fbcbeabb8..ad1292b326 100644 --- a/pype/settings/lib.py +++ b/pype/settings/lib.py @@ -402,28 +402,33 @@ def apply_local_settings_on_anatomy_settings( if not local_project_settings: return - current_platform = platform.system().lower() - local_defaults = local_project_settings.get(DEFAULT_PROJECT_KEY) - root_data = anatomy_settings["roots"] - if local_defaults and "roots" in local_defaults: - for root_name, path in local_defaults["roots"].items(): - if root_name not in root_data: - continue - anatomy_settings["roots"][root_name][current_platform] = ( - path - ) - if project_name == DEFAULT_PROJECT_KEY: + project_locals = local_project_settings.get(project_name) or {} + default_locals = local_project_settings.get(DEFAULT_PROJECT_KEY) or {} + active_site = project_locals.get("active_site") + if not active_site: + active_site = default_locals.get("active_site") + + if not active_site: return - local_projects = local_project_settings.get(project_name) - if local_projects and "roots" in local_projects: - for root_name, path in local_projects["roots"].items(): - if root_name not in root_data: - continue + roots_locals = default_locals.get("roots", {}).get(active_site, {}) + if project_name != DEFAULT_PROJECT_KEY: + roots_locals.update( + project_locals.get("roots", {}).get(active_site, {}) + ) - anatomy_settings["roots"][root_name][current_platform] = ( - path - ) + if not roots_locals: + return + + current_platform = platform.system().lower() + + root_data = anatomy_settings["roots"] + for root_name, path in roots_locals.items(): + if root_name not in root_data: + continue + anatomy_settings["roots"][root_name][current_platform] = ( + path + ) def get_system_settings(clear_metadata=True): From 724ba49bd1f7aea197ed6ef5794febceaac1abfe Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 25 Feb 2021 12:33:55 +0100 Subject: [PATCH 44/61] revert debug changes --- pype/tools/settings/__init__.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pype/tools/settings/__init__.py b/pype/tools/settings/__init__.py index 0a5d6933a1..3f47d1c2c3 100644 --- a/pype/tools/settings/__init__.py +++ b/pype/tools/settings/__init__.py @@ -22,8 +22,7 @@ def main(user_role=None): app = QtWidgets.QApplication(sys.argv) app.setWindowIcon(QtGui.QIcon(style.app_icon_path())) - # widget = MainWidget(user_role) - widget = LocalSettingsWindow() + widget = MainWidget(user_role) widget.show() widget.reset() From 054a79f6ee4a77b043cf859f68b0fb26e6cf6d83 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 25 Feb 2021 13:07:03 +0100 Subject: [PATCH 45/61] color changes work for site comboboxes --- .../local_settings/projects_widget.py | 40 ++++++++++--------- pype/tools/settings/local_settings/widgets.py | 4 ++ 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/pype/tools/settings/local_settings/projects_widget.py b/pype/tools/settings/local_settings/projects_widget.py index 753732ab34..d09c67af08 100644 --- a/pype/tools/settings/local_settings/projects_widget.py +++ b/pype/tools/settings/local_settings/projects_widget.py @@ -206,11 +206,6 @@ class _SiteCombobox(QtWidgets.QWidget): main_layout.addWidget(label_widget) main_layout.addWidget(combobox_input) - # --- START --- DEBUG widget - self._debug_label = QtWidgets.QLabel("*", self) - main_layout.addWidget(self._debug_label) - # --- END --- - combobox_input.currentIndexChanged.connect(self._on_index_change) self.label_widget = label_widget self.combobox_input = combobox_input @@ -229,10 +224,9 @@ class _SiteCombobox(QtWidgets.QWidget): return True return False - def update_style(self): + def _get_style_state(self): if self.project_name is None: - self._debug_label.setText("None") - return + return "" current_value = self._get_local_settings_item(self.project_name) orig_value = self._get_local_settings_item( @@ -246,19 +240,29 @@ class _SiteCombobox(QtWidgets.QWidget): modified = True if modified: - self._debug_label.setText("Modified") - return + return "modified" if self.project_name == DEFAULT_PROJECT_KEY: - if not current_value: - self._debug_label.setText("No active site") - else: - self._debug_label.setText("Active default") + if current_value: + return "studio" else: - if not current_value: - self._debug_label.setText("Default active site") - else: - self._debug_label.setText("Active project") + if current_value: + return "overriden" + + studio_value = current_value = self._get_local_settings_item( + DEFAULT_PROJECT_KEY + ) + if studio_value: + return "studio" + return "" + + def update_style(self): + state = self._get_style_state() + + self.combobox_input.setProperty("input-state", state) + self.combobox_input.style().polish(self.combobox_input) + + self.label_widget.set_label_property("state", state) def _mouse_release_callback(self, event): if event.button() != QtCore.Qt.RightButton: diff --git a/pype/tools/settings/local_settings/widgets.py b/pype/tools/settings/local_settings/widgets.py index e3c9590438..d69ad816e0 100644 --- a/pype/tools/settings/local_settings/widgets.py +++ b/pype/tools/settings/local_settings/widgets.py @@ -42,6 +42,10 @@ class ProxyLabelWidget(QtWidgets.QWidget): def setText(self, text): self.label_widget.setText(text) + def set_label_property(self, *args, **kwargs): + self.label_widget.setProperty(*args, **kwargs) + self.label_widget.style().polish(self.label_widget) + def mouseReleaseEvent(self, event): if self.mouse_release_callback: return self.mouse_release_callback(event) From 7969441ec69f2f5f6b56fdb08b51565198cc5e29 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 25 Feb 2021 13:11:20 +0100 Subject: [PATCH 46/61] removed `_ui_tweaks` --- .../local_settings/projects_widget.py | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/pype/tools/settings/local_settings/projects_widget.py b/pype/tools/settings/local_settings/projects_widget.py index d09c67af08..7f05ebe7a8 100644 --- a/pype/tools/settings/local_settings/projects_widget.py +++ b/pype/tools/settings/local_settings/projects_widget.py @@ -186,6 +186,7 @@ class RootsWidget(QtWidgets.QWidget): class _SiteCombobox(QtWidgets.QWidget): site_changed = QtCore.Signal(str) + input_label = None def __init__(self, project_settings, parent): super(_SiteCombobox, self).__init__(parent) @@ -199,7 +200,11 @@ class _SiteCombobox(QtWidgets.QWidget): self.default_override_value = None self.project_override_value = None - label_widget = ProxyLabelWidget("", self._mouse_release_callback, self) + label_widget = ProxyLabelWidget( + self.input_label, + self._mouse_release_callback, + self + ) combobox_input = QtWidgets.QComboBox(self) main_layout = QtWidgets.QHBoxLayout(self) @@ -210,8 +215,6 @@ class _SiteCombobox(QtWidgets.QWidget): self.label_widget = label_widget self.combobox_input = combobox_input - self._ui_tweaks() - def _set_current_text(self, text): index = None if text: @@ -390,11 +393,6 @@ class _SiteCombobox(QtWidgets.QWidget): ) ) - def _ui_tweaks(self): - raise NotImplementedError("{} `_ui_tweaks` not implemented".format( - self.__class__.__name__ - )) - def _get_project_sites(self): raise NotImplementedError( "{} `_get_project_sites` not implemented".format( @@ -411,8 +409,7 @@ class _SiteCombobox(QtWidgets.QWidget): class AciveSiteCombo(_SiteCombobox): - def _ui_tweaks(self): - self.label_widget.setText("Active site") + input_label = "Active site" def _get_project_sites(self): global_entity = self.project_settings["project_settings"]["global"] @@ -435,8 +432,7 @@ class AciveSiteCombo(_SiteCombobox): class RemoteSiteCombo(_SiteCombobox): - def _ui_tweaks(self): - self.label_widget.setText("Remote site") + input_label = "Remote site" def _get_project_sites(self): global_entity = self.project_settings["project_settings"]["global"] From 610728aaff59b627d39b7310acd42b1d07ec368e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 25 Feb 2021 13:13:28 +0100 Subject: [PATCH 47/61] renamed `site_name` key to `site_label` --- pype/tools/settings/local_settings/window.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pype/tools/settings/local_settings/window.py b/pype/tools/settings/local_settings/window.py index 80ad811b60..242cbf8817 100644 --- a/pype/tools/settings/local_settings/window.py +++ b/pype/tools/settings/local_settings/window.py @@ -38,15 +38,15 @@ class LocalGeneralWidgets(QtWidgets.QWidget): layout = QtWidgets.QFormLayout(self) layout.setContentsMargins(0, 0, 0, 0) - layout.addRow("Local site name", local_site_name_input) + layout.addRow("Local site label", local_site_name_input) self.local_site_name_input = local_site_name_input def set_value(self, value): - site_name = "" + site_label = "" if value: - site_name = value.get("site_name", site_name) - self.local_site_name_input.setText(site_name) + site_label = value.get("site_label", site_label) + self.local_site_name_input.setText(site_label) def settings_value(self): # Add changed @@ -54,7 +54,7 @@ class LocalGeneralWidgets(QtWidgets.QWidget): output = {} local_site_name = self.local_site_name_input.text() if local_site_name: - output["site_name"] = local_site_name + output["site_label"] = local_site_name # Do not return output yet since we don't have mechanism to save or # load these data through api calls return output From 40fb974d4de749d3ccf76021c3d5240598f85025 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 25 Feb 2021 13:15:03 +0100 Subject: [PATCH 48/61] renamed `set_value` method to `update_local_settings` --- .../settings/local_settings/apps_widget.py | 10 +++++----- .../settings/local_settings/projects_widget.py | 16 ++++++++-------- pype/tools/settings/local_settings/window.py | 18 ++++++++++++------ 3 files changed, 25 insertions(+), 19 deletions(-) diff --git a/pype/tools/settings/local_settings/apps_widget.py b/pype/tools/settings/local_settings/apps_widget.py index 52fbc45fd6..e948847992 100644 --- a/pype/tools/settings/local_settings/apps_widget.py +++ b/pype/tools/settings/local_settings/apps_widget.py @@ -60,7 +60,7 @@ class AppVariantWidget(QtWidgets.QWidget): path_widget.setEnabled(False) content_layout.addWidget(path_widget) - def set_value(self, value): + def update_local_settings(self, value): if not self.executable_input_widget: return @@ -127,12 +127,12 @@ class AppGroupWidget(QtWidgets.QWidget): self.widgets_by_variant_name = widgets_by_variant_name - def set_value(self, value): + def update_local_settings(self, value): if not value: value = {} for variant_name, widget in self.widgets_by_variant_name.items(): - widget.set_value(value.get(variant_name)) + widget.update_local_settings(value.get(variant_name)) def settings_value(self): output = {} @@ -177,12 +177,12 @@ class LocalApplicationsWidgets(QtWidgets.QWidget): self.widgets_by_group_name = widgets_by_group_name - def set_value(self, value): + def update_local_settings(self, value): if not value: value = {} for group_name, widget in self.widgets_by_group_name.items(): - widget.set_value(value.get(group_name)) + widget.update_local_settings(value.get(group_name)) def settings_value(self): output = {} diff --git a/pype/tools/settings/local_settings/projects_widget.py b/pype/tools/settings/local_settings/projects_widget.py index 7f05ebe7a8..7be2b73075 100644 --- a/pype/tools/settings/local_settings/projects_widget.py +++ b/pype/tools/settings/local_settings/projects_widget.py @@ -169,7 +169,7 @@ class RootsWidget(QtWidgets.QWidget): # Add spacer so other widgets are squeezed to top self.content_layout.addWidget(SpacerWidget(self), 1) - def set_value(self, local_project_settings): + def update_local_settings(self, local_project_settings): self.local_project_settings = local_project_settings self.local_project_settings_orig = copy.deepcopy( dict(local_project_settings) @@ -329,7 +329,7 @@ class _SiteCombobox(QtWidgets.QWidget): if to_run: to_run() - def set_value(self, local_project_settings): + def update_local_settings(self, local_project_settings): self.local_project_settings = local_project_settings self.local_project_settings_orig = copy.deepcopy( dict(local_project_settings) @@ -495,11 +495,11 @@ class RootSiteWidget(QtWidgets.QWidget): sites_entity = global_entity["sync_server"]["sites"] return tuple(sites_entity.keys()) - def set_value(self, local_project_settings): + def update_local_settings(self, local_project_settings): self.local_project_settings = local_project_settings - self.active_site_widget.set_value(local_project_settings) - self.remote_site_widget.set_value(local_project_settings) - self.roots_widget.set_value(local_project_settings) + self.active_site_widget.update_local_settings(local_project_settings) + self.remote_site_widget.update_local_settings(local_project_settings) + self.roots_widget.update_local_settings(local_project_settings) def _on_acite_site_change(self, site_name): self._change_active_site(site_name) @@ -555,12 +555,12 @@ class ProjectSettingsWidget(QtWidgets.QWidget): project_name = DEFAULT_PROJECT_KEY self.roos_site_widget.change_project(project_name) - def set_value(self, value): + def update_local_settings(self, value): if not value: value = {} self.local_project_settings = ProjectValue(value) - self.roos_site_widget.set_value(self.local_project_settings) + self.roos_site_widget.update_local_settings(self.local_project_settings) self.projects_widget.refresh() diff --git a/pype/tools/settings/local_settings/window.py b/pype/tools/settings/local_settings/window.py index 242cbf8817..c53d16ab8d 100644 --- a/pype/tools/settings/local_settings/window.py +++ b/pype/tools/settings/local_settings/window.py @@ -42,7 +42,7 @@ class LocalGeneralWidgets(QtWidgets.QWidget): self.local_site_name_input = local_site_name_input - def set_value(self, value): + def update_local_settings(self, value): site_label = "" if value: site_label = value.get("site_label", site_label) @@ -144,13 +144,19 @@ class LocalSettingsWidget(QtWidgets.QWidget): self.projects_widget = projects_widget - def set_value(self, value): + def update_local_settings(self, value): if not value: value = {} - self.general_widget.set_value(value.get(LOCAL_GENERAL_KEY)) - self.app_widget.set_value(value.get(LOCAL_APPS_KEY)) - self.projects_widget.set_value(value.get(LOCAL_PROJECTS_KEY)) + self.general_widget.update_local_settings( + value.get(LOCAL_GENERAL_KEY) + ) + self.app_widget.update_local_settings( + value.get(LOCAL_APPS_KEY) + ) + self.projects_widget.update_local_settings( + value.get(LOCAL_PROJECTS_KEY) + ) def settings_value(self): output = {} @@ -207,7 +213,7 @@ class LocalSettingsWindow(QtWidgets.QWidget): def reset(self): value = get_local_settings() - self.settings_widget.set_value(value) + self.settings_widget.update_local_settings(value) def _on_save_clicked(self): try: From 33632e2e42ca6572ef69c6954320e39f24101673 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 25 Feb 2021 13:27:34 +0100 Subject: [PATCH 49/61] moved general settings widget to specific file --- .../settings/local_settings/general_widget.py | 32 +++++++++++++++++++ pype/tools/settings/local_settings/window.py | 32 +------------------ 2 files changed, 33 insertions(+), 31 deletions(-) create mode 100644 pype/tools/settings/local_settings/general_widget.py diff --git a/pype/tools/settings/local_settings/general_widget.py b/pype/tools/settings/local_settings/general_widget.py new file mode 100644 index 0000000000..7732157122 --- /dev/null +++ b/pype/tools/settings/local_settings/general_widget.py @@ -0,0 +1,32 @@ +from Qt import QtWidgets + + +class LocalGeneralWidgets(QtWidgets.QWidget): + def __init__(self, parent): + super(LocalGeneralWidgets, self).__init__(parent) + + local_site_name_input = QtWidgets.QLineEdit(self) + + layout = QtWidgets.QFormLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + + layout.addRow("Local site label", local_site_name_input) + + self.local_site_name_input = local_site_name_input + + def update_local_settings(self, value): + site_label = "" + if value: + site_label = value.get("site_label", site_label) + self.local_site_name_input.setText(site_label) + + def settings_value(self): + # Add changed + # If these have changed then + output = {} + local_site_name = self.local_site_name_input.text() + if local_site_name: + output["site_label"] = local_site_name + # Do not return output yet since we don't have mechanism to save or + # load these data through api calls + return output diff --git a/pype/tools/settings/local_settings/window.py b/pype/tools/settings/local_settings/window.py index c53d16ab8d..32a480a82f 100644 --- a/pype/tools/settings/local_settings/window.py +++ b/pype/tools/settings/local_settings/window.py @@ -19,6 +19,7 @@ from .widgets import ( CHILD_OFFSET ) from .mongo_widget import PypeMongoWidget +from .general_widget import LocalGeneralWidgets from .apps_widget import LocalApplicationsWidgets from .projects_widget import ProjectSettingsWidget @@ -29,37 +30,6 @@ LOCAL_PROJECTS_KEY = "projects" LOCAL_APPS_KEY = "applications" -class LocalGeneralWidgets(QtWidgets.QWidget): - def __init__(self, parent): - super(LocalGeneralWidgets, self).__init__(parent) - - local_site_name_input = QtWidgets.QLineEdit(self) - - layout = QtWidgets.QFormLayout(self) - layout.setContentsMargins(0, 0, 0, 0) - - layout.addRow("Local site label", local_site_name_input) - - self.local_site_name_input = local_site_name_input - - def update_local_settings(self, value): - site_label = "" - if value: - site_label = value.get("site_label", site_label) - self.local_site_name_input.setText(site_label) - - def settings_value(self): - # Add changed - # If these have changed then - output = {} - local_site_name = self.local_site_name_input.text() - if local_site_name: - output["site_label"] = local_site_name - # Do not return output yet since we don't have mechanism to save or - # load these data through api calls - return output - - class LocalSettingsWidget(QtWidgets.QWidget): def __init__(self, parent=None): super(LocalSettingsWidget, self).__init__(parent) From 6fc81bd41a4dedaf09f7d5f7e7a317176c32761c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 25 Feb 2021 13:28:18 +0100 Subject: [PATCH 50/61] update_local_settings triggers reset of widgets --- .../settings/local_settings/apps_widget.py | 22 ++++++++++++++----- .../local_settings/projects_widget.py | 9 +++++++- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/pype/tools/settings/local_settings/apps_widget.py b/pype/tools/settings/local_settings/apps_widget.py index e948847992..f2a47a8f27 100644 --- a/pype/tools/settings/local_settings/apps_widget.py +++ b/pype/tools/settings/local_settings/apps_widget.py @@ -150,12 +150,22 @@ class LocalApplicationsWidgets(QtWidgets.QWidget): def __init__(self, system_settings_entity, parent): super(LocalApplicationsWidgets, self).__init__(parent) - widgets_by_group_name = {} + self.widgets_by_group_name = {} + self.system_settings_entity = system_settings_entity layout = QtWidgets.QVBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) - for key, entity in system_settings_entity["applications"].items(): + self.content_layout = layout + + def _reset_app_widgets(self): + while self.content_layout.count() > 0: + item = self.content_layout.itemAt(0) + item.widget().hide() + self.content_layout.removeItem(item) + self.widgets_by_group_name.clear() + + for key, entity in self.system_settings_entity["applications"].items(): # Filter not enabled app groups if not entity["enabled"].value: continue @@ -172,15 +182,15 @@ class LocalApplicationsWidgets(QtWidgets.QWidget): # Create App group specific widget and store it by the key group_widget = AppGroupWidget(entity, self) - widgets_by_group_name[key] = group_widget - layout.addWidget(group_widget) - - self.widgets_by_group_name = widgets_by_group_name + self.widgets_by_group_name[key] = group_widget + self.content_layout.addWidget(group_widget) def update_local_settings(self, value): if not value: value = {} + self._reset_app_widgets() + for group_name, widget in self.widgets_by_group_name.items(): widget.update_local_settings(value.get(group_name)) diff --git a/pype/tools/settings/local_settings/projects_widget.py b/pype/tools/settings/local_settings/projects_widget.py index 7be2b73075..7859996490 100644 --- a/pype/tools/settings/local_settings/projects_widget.py +++ b/pype/tools/settings/local_settings/projects_widget.py @@ -500,6 +500,11 @@ class RootSiteWidget(QtWidgets.QWidget): self.active_site_widget.update_local_settings(local_project_settings) self.remote_site_widget.update_local_settings(local_project_settings) self.roots_widget.update_local_settings(local_project_settings) + project_name = self._project_name + if project_name is None: + project_name = DEFAULT_PROJECT_KEY + + self.change_project(project_name) def _on_acite_site_change(self, site_name): self._change_active_site(site_name) @@ -560,7 +565,9 @@ class ProjectSettingsWidget(QtWidgets.QWidget): value = {} self.local_project_settings = ProjectValue(value) - self.roos_site_widget.update_local_settings(self.local_project_settings) + self.roos_site_widget.update_local_settings( + self.local_project_settings + ) self.projects_widget.refresh() From 81180738f076e7e15ec8711790c2da9a7d88fa9e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 25 Feb 2021 13:28:41 +0100 Subject: [PATCH 51/61] save local values triggers reset --- pype/tools/settings/local_settings/window.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/pype/tools/settings/local_settings/window.py b/pype/tools/settings/local_settings/window.py index 32a480a82f..ee7437d184 100644 --- a/pype/tools/settings/local_settings/window.py +++ b/pype/tools/settings/local_settings/window.py @@ -118,6 +118,9 @@ class LocalSettingsWidget(QtWidgets.QWidget): if not value: value = {} + self.system_settings.reset() + self.project_settings.reset() + self.general_widget.update_local_settings( value.get(LOCAL_GENERAL_KEY) ) @@ -186,10 +189,6 @@ class LocalSettingsWindow(QtWidgets.QWidget): self.settings_widget.update_local_settings(value) def _on_save_clicked(self): - try: - value = self.settings_widget.settings_value() - except Exception: - log.warning("Failed to save", exc_info=True) - return - + value = self.settings_widget.settings_value() save_local_settings(value) + self.reset() From d72549bdef5b61e1cd944fabdc0b6f1ddf2d099b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 25 Feb 2021 13:31:39 +0100 Subject: [PATCH 52/61] added reset button --- pype/tools/settings/local_settings/window.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pype/tools/settings/local_settings/window.py b/pype/tools/settings/local_settings/window.py index ee7437d184..b8113fbfbc 100644 --- a/pype/tools/settings/local_settings/window.py +++ b/pype/tools/settings/local_settings/window.py @@ -167,8 +167,12 @@ class LocalSettingsWindow(QtWidgets.QWidget): scroll_widget.setWidgetResizable(True) footer = QtWidgets.QWidget(self) + save_btn = QtWidgets.QPushButton("Save", footer) + reset_btn = QtWidgets.QPushButton("Reset", footer) + footer_layout = QtWidgets.QHBoxLayout(footer) + footer_layout.addWidget(reset_btn, 0) footer_layout.addWidget(SpacerWidget(footer), 1) footer_layout.addWidget(save_btn, 0) @@ -178,8 +182,10 @@ class LocalSettingsWindow(QtWidgets.QWidget): main_layout.addWidget(footer, 0) save_btn.clicked.connect(self._on_save_clicked) + reset_btn.clicked.connect(self._on_reset_clicked) self.settings_widget = settings_widget + self.reset_btn = reset_btn self.save_btn = save_btn self.reset() @@ -188,6 +194,9 @@ class LocalSettingsWindow(QtWidgets.QWidget): value = get_local_settings() self.settings_widget.update_local_settings(value) + def _on_reset_clicked(self): + self.reset() + def _on_save_clicked(self): value = self.settings_widget.settings_value() save_local_settings(value) From baa5b07610b45bacf710d14fceb2045909b54ef9 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 25 Feb 2021 14:27:23 +0100 Subject: [PATCH 53/61] roots for all sites are always visible --- .../local_settings/projects_widget.py | 75 +++++++++---------- 1 file changed, 36 insertions(+), 39 deletions(-) diff --git a/pype/tools/settings/local_settings/projects_widget.py b/pype/tools/settings/local_settings/projects_widget.py index 7859996490..959bbafdd0 100644 --- a/pype/tools/settings/local_settings/projects_widget.py +++ b/pype/tools/settings/local_settings/projects_widget.py @@ -14,6 +14,12 @@ from .widgets import ( LOCAL_ROOTS_KEY = "roots" +def get_active_sites(project_settings): + global_entity = project_settings["project_settings"]["global"] + sites_entity = global_entity["sync_server"]["sites"] + return tuple(sites_entity.keys()) + + class _ProjectListWidget(ProjectListWidget): def on_item_clicked(self, new_index): new_project_name = new_index.data(QtCore.Qt.DisplayRole) @@ -123,11 +129,10 @@ class RootsWidget(QtWidgets.QWidget): super(RootsWidget, self).__init__(parent) self.project_settings = project_settings - self.widgts_by_root_name = {} + self.site_widgets = [] self.local_project_settings = None self.local_project_settings_orig = None self._project_name = None - self._site_name = None self.content_layout = QtWidgets.QVBoxLayout(self) @@ -136,35 +141,43 @@ class RootsWidget(QtWidgets.QWidget): item = self.content_layout.itemAt(0) item.widget().hide() self.content_layout.removeItem(item) - self.widgts_by_root_name.clear() + self.site_widgets = [] def refresh(self): self._clear_widgets() - if self._project_name is None or self._site_name is None: + if self._project_name is None: return - # Site label - self.content_layout.addWidget(QtWidgets.QLabel(self._site_name, self)) - - # Root inputs roots_entity = ( self.project_settings[PROJECT_ANATOMY_KEY][LOCAL_ROOTS_KEY] ) - for root_name, path_entity in roots_entity.items(): - platform_entity = path_entity[platform.system().lower()] - root_widget = RootInputWidget( - self.local_project_settings, - self.local_project_settings_orig, - platform_entity, - root_name, - self._project_name, - self._site_name, - self - ) + # Site label + for site_name in get_active_sites(self.project_settings): + site_widget = QtWidgets.QWidget(self) + site_layout = QtWidgets.QVBoxLayout(site_widget) - self.content_layout.addWidget(root_widget) - self.widgts_by_root_name[root_name] = root_widget + site_label = QtWidgets.QLabel(site_name, site_widget) + + site_layout.addWidget(site_label) + + # Root inputs + for root_name, path_entity in roots_entity.items(): + platform_entity = path_entity[platform.system().lower()] + root_widget = RootInputWidget( + self.local_project_settings, + self.local_project_settings_orig, + platform_entity, + root_name, + self._project_name, + site_name, + site_widget + ) + + site_layout.addWidget(root_widget) + + self.site_widgets.append(site_widget) + self.content_layout.addWidget(site_widget) # Add spacer so other widgets are squeezed to top self.content_layout.addWidget(SpacerWidget(self), 1) @@ -175,17 +188,12 @@ class RootsWidget(QtWidgets.QWidget): dict(local_project_settings) ) - def change_site(self, site_name): - self._site_name = site_name - self.refresh() - def change_project(self, project_name): self._project_name = project_name self.refresh() class _SiteCombobox(QtWidgets.QWidget): - site_changed = QtCore.Signal(str) input_label = None def __init__(self, project_settings, parent): @@ -375,7 +383,6 @@ class _SiteCombobox(QtWidgets.QWidget): self.combobox_input.setCurrentIndex(index) self.project_name = project_name - self.site_changed.emit(self.current_text()) self.update_style() def _on_index_change(self): @@ -383,7 +390,6 @@ class _SiteCombobox(QtWidgets.QWidget): return self._set_local_settings_value(self.current_text()) - self.site_changed.emit(self.current_text()) self.update_style() def _set_local_settings_value(self, value): @@ -412,9 +418,7 @@ class AciveSiteCombo(_SiteCombobox): input_label = "Active site" def _get_project_sites(self): - global_entity = self.project_settings["project_settings"]["global"] - sites_entity = global_entity["sync_server"]["sites"] - return tuple(sites_entity.keys()) + return get_active_sites(self.project_settings) def _get_local_settings_item(self, project_name, data=None): if data is None: @@ -480,7 +484,6 @@ class RootSiteWidget(QtWidgets.QWidget): main_layout.addWidget(roots_widget) main_layout.addWidget(SpacerWidget(self), 1) - active_site_widget.site_changed.connect(self._on_acite_site_change) self.active_site_widget = active_site_widget self.remote_site_widget = remote_site_widget self.roots_widget = roots_widget @@ -504,13 +507,7 @@ class RootSiteWidget(QtWidgets.QWidget): if project_name is None: project_name = DEFAULT_PROJECT_KEY - self.change_project(project_name) - - def _on_acite_site_change(self, site_name): - self._change_active_site(site_name) - - def _change_active_site(self, site_name): - self.roots_widget.change_site(site_name) + self.change_project(project_name) def change_project(self, project_name): self._project_name = project_name From 812abd3a905950f9e7e40ffc491fa5fc2f9b8dfe Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 25 Feb 2021 14:58:04 +0100 Subject: [PATCH 54/61] active and remote site comboboxes refers to project settings --- .../local_settings/projects_widget.py | 85 +++++++++++++------ 1 file changed, 60 insertions(+), 25 deletions(-) diff --git a/pype/tools/settings/local_settings/projects_widget.py b/pype/tools/settings/local_settings/projects_widget.py index 959bbafdd0..a38d22c5cd 100644 --- a/pype/tools/settings/local_settings/projects_widget.py +++ b/pype/tools/settings/local_settings/projects_widget.py @@ -12,6 +12,7 @@ from .widgets import ( ) LOCAL_ROOTS_KEY = "roots" +NOT_SET = type("NOT_SET", (), {})() def get_active_sites(project_settings): @@ -94,7 +95,6 @@ class RootInputWidget(QtWidgets.QWidget): self.value_input = value_input - self.is_default_project = is_default_project self.studio_value = platform_root_entity.value self.default_value = default_input_value self.project_value = project_value @@ -203,7 +203,6 @@ class _SiteCombobox(QtWidgets.QWidget): self.local_project_settings = None self.local_project_settings_orig = None self.project_name = None - self.is_default_project = None self.default_override_value = None self.project_override_value = None @@ -281,13 +280,22 @@ class _SiteCombobox(QtWidgets.QWidget): self._show_actions() def _remove_from_local(self): - if ( - self.project_name != DEFAULT_PROJECT_KEY - and self.default_override_value - ): + settings_value = self._get_value_from_project_settings() + combobox_value = None + if self.project_name == DEFAULT_PROJECT_KEY: + combobox_value = self._get_local_settings_item(DEFAULT_PROJECT_KEY) + if combobox_value: + idx = self.combobox_input.findText(combobox_value) + if idx < 0: + combobox_value = None + + if not combobox_value: + combobox_value = settings_value + + if combobox_value: _project_name = self.project_name self.project_name = None - self._set_current_text(self.default_override_value) + self._set_current_text(combobox_value) self.project_name = _project_name self._set_local_settings_value("") @@ -300,19 +308,19 @@ class _SiteCombobox(QtWidgets.QWidget): def _add_actions(self, menu, actions_mapping): # TODO better labels if self.project_name == DEFAULT_PROJECT_KEY: - if self.default_override_value: - action = QtWidgets.QAction("Remove from default") - callback = self._remove_from_local - else: - action = QtWidgets.QAction("Add to default") - callback = self._add_to_local + remove_label = "Remove from default" + add_label = "Add to default" else: - if self.project_override_value: - action = QtWidgets.QAction("Remove from project") - callback = self._remove_from_local - else: - action = QtWidgets.QAction("Add to project") - callback = self._add_to_local + remove_label = "Remove from project" + add_label = "Add to project" + + has_value = self._get_local_settings_item(self.project_name) + if has_value: + action = QtWidgets.QAction(remove_label) + callback = self._remove_from_local + else: + action = QtWidgets.QAction(add_label) + callback = self._add_to_local actions_mapping[action] = callback menu.addAction(action) @@ -356,12 +364,12 @@ class _SiteCombobox(QtWidgets.QWidget): self.update_style() return - self.is_default_project = bool(project_name == DEFAULT_PROJECT_KEY) + is_default_project = bool(project_name == DEFAULT_PROJECT_KEY) site_items = self._get_project_sites() self.combobox_input.addItems(site_items) default_item = self._get_local_settings_item(DEFAULT_PROJECT_KEY) - if self.is_default_project: + if is_default_project: project_item = None else: project_item = self._get_local_settings_item(project_name) @@ -379,7 +387,14 @@ class _SiteCombobox(QtWidgets.QWidget): self.default_override_value = default_item if index is None: index = idx - if index: + + if index is None: + settings_value = self._get_value_from_project_settings() + idx = self.combobox_input.findText(settings_value) + if idx >= 0: + index = idx + + if index is not None: self.combobox_input.setCurrentIndex(index) self.project_name = project_name @@ -406,13 +421,20 @@ class _SiteCombobox(QtWidgets.QWidget): ) ) - def _get_local_settings_item(self, project_name, data=None): + def _get_local_settings_item(self, project_name=None, data=None): raise NotImplementedError( "{}`_get_local_settings_item` not implemented".format( self.__class__.__name__ ) ) + def _get_value_from_project_settings(self): + raise NotImplementedError( + "{}`_get_value_from_project_settings` not implemented".format( + self.__class__.__name__ + ) + ) + class AciveSiteCombo(_SiteCombobox): input_label = "Active site" @@ -420,7 +442,10 @@ class AciveSiteCombo(_SiteCombobox): def _get_project_sites(self): return get_active_sites(self.project_settings) - def _get_local_settings_item(self, project_name, data=None): + def _get_local_settings_item(self, project_name=None, data=None): + if project_name is None: + project_name = self.project_name + if data is None: data = self.local_project_settings project_values = data.get(project_name) @@ -429,6 +454,10 @@ class AciveSiteCombo(_SiteCombobox): value = project_values.get("active_site") return value + def _get_value_from_project_settings(self): + global_entity = self.project_settings["project_settings"]["global"] + return global_entity["sync_server"]["config"]["active_site"].value + def _set_local_settings_value(self, value): if self.project_name not in self.local_project_settings: self.local_project_settings[self.project_name] = {} @@ -443,7 +472,9 @@ class RemoteSiteCombo(_SiteCombobox): sites_entity = global_entity["sync_server"]["sites"] return tuple(sites_entity.keys()) - def _get_local_settings_item(self, project_name, data=None): + def _get_local_settings_item(self, project_name=None, data=None): + if project_name is None: + project_name = self.project_name if data is None: data = self.local_project_settings project_values = data.get(project_name) @@ -452,6 +483,10 @@ class RemoteSiteCombo(_SiteCombobox): value = project_values.get("remote_site") return value + def _get_value_from_project_settings(self): + global_entity = self.project_settings["project_settings"]["global"] + return global_entity["sync_server"]["config"]["remote_site"].value + def _set_local_settings_value(self, value): if self.project_name not in self.local_project_settings: self.local_project_settings[self.project_name] = {} From 1c727612f64d2eeaec67a36622a7732c4cc8a90a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 25 Feb 2021 15:01:09 +0100 Subject: [PATCH 55/61] active site is also used from sync server when roots are filled --- pype/settings/lib.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/pype/settings/lib.py b/pype/settings/lib.py index ad1292b326..feeeaf3813 100644 --- a/pype/settings/lib.py +++ b/pype/settings/lib.py @@ -408,6 +408,17 @@ def apply_local_settings_on_anatomy_settings( if not active_site: active_site = default_locals.get("active_site") + if not active_site: + project_settings = get_project_settings(project_name) + active_site = ( + project_settings + ["global"] + ["sync_server"] + ["config"] + ["active_site"] + ) + + # QUESTION should raise an exception? if not active_site: return From 5a261477fabb1c72f0a6cb6bffd9f3f233049418 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 25 Feb 2021 16:15:59 +0100 Subject: [PATCH 56/61] added discard changes and actions to root inputs --- .../settings/local_settings/constants.py | 30 +++ .../local_settings/projects_widget.py | 185 ++++++++++++++---- pype/tools/settings/local_settings/window.py | 10 +- 3 files changed, 181 insertions(+), 44 deletions(-) create mode 100644 pype/tools/settings/local_settings/constants.py diff --git a/pype/tools/settings/local_settings/constants.py b/pype/tools/settings/local_settings/constants.py new file mode 100644 index 0000000000..7a8774467f --- /dev/null +++ b/pype/tools/settings/local_settings/constants.py @@ -0,0 +1,30 @@ +# Action labels +LABEL_REMOVE_DEFAULT = "Remove from default" +LABEL_ADD_DEFAULT = "Add to default" +LABEL_REMOVE_PROJECT = "Remove from project" +LABEL_ADD_PROJECT = "Add to project" +LABEL_DISCARD_CHANGES = "Discard changes" + +# Local setting contants +# TODO move to settings constants +LOCAL_GENERAL_KEY = "general" +LOCAL_PROJECTS_KEY = "projects" +LOCAL_APPS_KEY = "applications" + +# Roots key constant +LOCAL_ROOTS_KEY = "roots" + + +__all__ = ( + "LABEL_REMOVE_DEFAULT", + "LABEL_ADD_DEFAULT", + "LABEL_REMOVE_PROJECT", + "LABEL_ADD_PROJECT", + "LABEL_DISCARD_CHANGES", + + "LOCAL_GENERAL_KEY", + "LOCAL_PROJECTS_KEY", + "LOCAL_APPS_KEY", + + "LOCAL_ROOTS_KEY" +) diff --git a/pype/tools/settings/local_settings/projects_widget.py b/pype/tools/settings/local_settings/projects_widget.py index a38d22c5cd..37e31d6de0 100644 --- a/pype/tools/settings/local_settings/projects_widget.py +++ b/pype/tools/settings/local_settings/projects_widget.py @@ -10,8 +10,15 @@ from .widgets import ( SpacerWidget, ProxyLabelWidget ) +from .constants import ( + LABEL_REMOVE_DEFAULT, + LABEL_ADD_DEFAULT, + LABEL_REMOVE_PROJECT, + LABEL_ADD_PROJECT, + LABEL_DISCARD_CHANGES, + LOCAL_ROOTS_KEY +) -LOCAL_ROOTS_KEY = "roots" NOT_SET = type("NOT_SET", (), {})() @@ -57,7 +64,7 @@ class RootInputWidget(QtWidgets.QWidget): self.origin_value = self._get_site_value_for_project( self.project_name, self.local_project_settings_orig - ) + ) or "" is_default_project = bool(project_name == DEFAULT_PROJECT_KEY) @@ -79,7 +86,11 @@ class RootInputWidget(QtWidgets.QWidget): if not placeholder: placeholder = platform_root_entity.value - key_label = QtWidgets.QLabel(root_name, self) + key_label = ProxyLabelWidget( + root_name, + self._mouse_release_callback, + self + ) value_input = QtWidgets.QLineEdit(self) value_input.setPlaceholderText("< {} >".format(placeholder)) @@ -94,15 +105,99 @@ class RootInputWidget(QtWidgets.QWidget): root_layout.addWidget(value_input) self.value_input = value_input + self.label_widget = key_label self.studio_value = platform_root_entity.value self.default_value = default_input_value self.project_value = project_value + self.placeholder_value = placeholder - @property def is_modified(self): return self.origin_value != self.value_input.text() + def _mouse_release_callback(self, event): + if event.button() != QtCore.Qt.RightButton: + return + self._show_actions() + event.accept() + + def _get_style_state(self): + if self.project_name is None: + return "" + + if self.is_modified(): + return "modified" + + current_value = self.value_input.text() + if self.project_name == DEFAULT_PROJECT_KEY: + if current_value: + return "studio" + else: + if current_value: + return "overriden" + + studio_value = self._get_site_value_for_project( + DEFAULT_PROJECT_KEY + ) + if studio_value: + return "studio" + return "" + + def _update_style(self): + state = self._get_style_state() + + self.value_input.setProperty("input-state", state) + self.value_input.style().polish(self.value_input) + + self.label_widget.set_label_property("state", state) + + def _remove_from_local(self): + self.value_input.setText("") + self._update_style() + + def _add_to_local(self): + self.value_input.setText(self.placeholder_value) + self._update_style() + + def discard_changes(self): + self.value_input.setText(self.origin_value) + self._update_style() + + def _show_actions(self): + if self.project_name is None: + return + + menu = QtWidgets.QMenu(self) + actions_mapping = {} + + if self.project_name == DEFAULT_PROJECT_KEY: + remove_label = LABEL_REMOVE_DEFAULT + add_label = LABEL_ADD_DEFAULT + else: + remove_label = LABEL_REMOVE_PROJECT + add_label = LABEL_ADD_PROJECT + + if self.value_input.text(): + action = QtWidgets.QAction(remove_label) + callback = self._remove_from_local + else: + action = QtWidgets.QAction(add_label) + callback = self._add_to_local + + actions_mapping[action] = callback + menu.addAction(action) + + if self.is_modified(): + discard_changes_action = QtWidgets.QAction(LABEL_DISCARD_CHANGES) + actions_mapping[discard_changes_action] = self.discard_changes + menu.addAction(discard_changes_action) + + result = menu.exec_(QtGui.QCursor.pos()) + if result: + to_run = actions_mapping[result] + if to_run: + to_run() + def _get_site_value_for_project(self, project_name, data=None): if data is None: data = self.local_project_settings @@ -122,6 +217,7 @@ class RootInputWidget(QtWidgets.QWidget): data[key] = {} data = data[key] data[self.root_name] = value + self._update_style() class RootsWidget(QtWidgets.QWidget): @@ -229,11 +325,26 @@ class _SiteCombobox(QtWidgets.QWidget): if idx >= 0: index = idx - if index: + if index is not None: self.combobox_input.setCurrentIndex(index) return True return False + def is_modified(self, current_value=NOT_SET, orig_value=NOT_SET): + if current_value is NOT_SET: + current_value = self._get_local_settings_item(self.project_name) + if orig_value is NOT_SET: + orig_value = self._get_local_settings_item( + self.project_name, self.local_project_settings_orig + ) + if current_value and orig_value: + modified = current_value != orig_value + elif not current_value and not orig_value: + modified = False + else: + modified = True + return modified + def _get_style_state(self): if self.project_name is None: return "" @@ -242,14 +353,8 @@ class _SiteCombobox(QtWidgets.QWidget): orig_value = self._get_local_settings_item( self.project_name, self.local_project_settings_orig ) - if current_value and orig_value: - modified = current_value != orig_value - elif not current_value and not orig_value: - modified = False - else: - modified = True - if modified: + if self.is_modified(current_value, orig_value): return "modified" if self.project_name == DEFAULT_PROJECT_KEY: @@ -259,14 +364,12 @@ class _SiteCombobox(QtWidgets.QWidget): if current_value: return "overriden" - studio_value = current_value = self._get_local_settings_item( - DEFAULT_PROJECT_KEY - ) + studio_value = self._get_local_settings_item(DEFAULT_PROJECT_KEY) if studio_value: return "studio" return "" - def update_style(self): + def _update_style(self): state = self._get_style_state() self.combobox_input.setProperty("input-state", state) @@ -299,20 +402,31 @@ class _SiteCombobox(QtWidgets.QWidget): self.project_name = _project_name self._set_local_settings_value("") - self.update_style() + self._update_style() def _add_to_local(self): self._set_local_settings_value(self.current_text()) - self.update_style() + self._update_style() + + def discard_changes(self): + orig_value = self._get_local_settings_item( + self.project_name, self.local_project_settings_orig + ) + self._set_current_text(orig_value) + + def _show_actions(self): + if self.project_name is None: + return + + menu = QtWidgets.QMenu(self) + actions_mapping = {} - def _add_actions(self, menu, actions_mapping): - # TODO better labels if self.project_name == DEFAULT_PROJECT_KEY: - remove_label = "Remove from default" - add_label = "Add to default" + remove_label = LABEL_REMOVE_DEFAULT + add_label = LABEL_ADD_DEFAULT else: - remove_label = "Remove from project" - add_label = "Add to project" + remove_label = LABEL_REMOVE_PROJECT + add_label = LABEL_ADD_PROJECT has_value = self._get_local_settings_item(self.project_name) if has_value: @@ -325,19 +439,10 @@ class _SiteCombobox(QtWidgets.QWidget): actions_mapping[action] = callback menu.addAction(action) - def _show_actions(self): - if self.project_name is None: - return - - menu = QtWidgets.QMenu(self) - actions_mapping = {} - - self._add_actions(menu, actions_mapping) - - if not actions_mapping: - action = QtWidgets.QAction("< No action >") - actions_mapping[action] = None - menu.addAction(action) + if self.is_modified(): + discard_changes_action = QtWidgets.QAction(LABEL_DISCARD_CHANGES) + actions_mapping[discard_changes_action] = self.discard_changes + menu.addAction(discard_changes_action) result = menu.exec_(QtGui.QCursor.pos()) if result: @@ -361,7 +466,7 @@ class _SiteCombobox(QtWidgets.QWidget): self.project_name = None self.combobox_input.clear() if project_name is None: - self.update_style() + self._update_style() return is_default_project = bool(project_name == DEFAULT_PROJECT_KEY) @@ -398,14 +503,14 @@ class _SiteCombobox(QtWidgets.QWidget): self.combobox_input.setCurrentIndex(index) self.project_name = project_name - self.update_style() + self._update_style() def _on_index_change(self): if self.project_name is None: return self._set_local_settings_value(self.current_text()) - self.update_style() + self._update_style() def _set_local_settings_value(self, value): raise NotImplementedError( diff --git a/pype/tools/settings/local_settings/window.py b/pype/tools/settings/local_settings/window.py index b8113fbfbc..d8d8adfea9 100644 --- a/pype/tools/settings/local_settings/window.py +++ b/pype/tools/settings/local_settings/window.py @@ -23,11 +23,13 @@ from .general_widget import LocalGeneralWidgets from .apps_widget import LocalApplicationsWidgets from .projects_widget import ProjectSettingsWidget -log = logging.getLogger(__name__) +from .constants import ( + LOCAL_GENERAL_KEY, + LOCAL_PROJECTS_KEY, + LOCAL_APPS_KEY +) -LOCAL_GENERAL_KEY = "general" -LOCAL_PROJECTS_KEY = "projects" -LOCAL_APPS_KEY = "applications" +log = logging.getLogger(__name__) class LocalSettingsWidget(QtWidgets.QWidget): From cec90430e80cf011997b96c3f81b528345b1aa13 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 25 Feb 2021 16:30:32 +0100 Subject: [PATCH 57/61] update style on root input initialization --- pype/tools/settings/local_settings/projects_widget.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pype/tools/settings/local_settings/projects_widget.py b/pype/tools/settings/local_settings/projects_widget.py index 37e31d6de0..28765155c2 100644 --- a/pype/tools/settings/local_settings/projects_widget.py +++ b/pype/tools/settings/local_settings/projects_widget.py @@ -112,6 +112,8 @@ class RootInputWidget(QtWidgets.QWidget): self.project_value = project_value self.placeholder_value = placeholder + self._update_style() + def is_modified(self): return self.origin_value != self.value_input.text() From 78bca249ffdf7c6f79c8241451df214a71553016 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 25 Feb 2021 17:07:21 +0100 Subject: [PATCH 58/61] a little bit faster project gui creation --- pype/tools/settings/settings/widgets/widgets.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pype/tools/settings/settings/widgets/widgets.py b/pype/tools/settings/settings/widgets/widgets.py index fd8d9d753c..656aaaa652 100644 --- a/pype/tools/settings/settings/widgets/widgets.py +++ b/pype/tools/settings/settings/widgets/widgets.py @@ -664,9 +664,8 @@ class ProjectListWidget(QtWidgets.QWidget): self.current_project = None if self.dbcon: - for project_doc in tuple(self.dbcon.projects()): - items.append(project_doc["name"]) - + for project_name in self.dbcon.database.collection_names(): + items.append(project_name) for item in items: model.appendRow(QtGui.QStandardItem(item)) From 3101c91596a02c5f1dd3e7f0279f1daa86f19941 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 25 Feb 2021 17:12:51 +0100 Subject: [PATCH 59/61] hound fixes --- pype/tools/settings/local_settings/apps_widget.py | 4 ++-- pype/tools/settings/local_settings/constants.py | 2 ++ pype/tools/settings/local_settings/widgets.py | 9 ++++++++- pype/tools/settings/local_settings/window.py | 7 +++---- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/pype/tools/settings/local_settings/apps_widget.py b/pype/tools/settings/local_settings/apps_widget.py index f2a47a8f27..d63cd6a834 100644 --- a/pype/tools/settings/local_settings/apps_widget.py +++ b/pype/tools/settings/local_settings/apps_widget.py @@ -2,9 +2,9 @@ import platform from Qt import QtWidgets from .widgets import ( Separator, - ExpandingWidget, - CHILD_OFFSET + ExpandingWidget ) +from .constants import CHILD_OFFSET class AppVariantWidget(QtWidgets.QWidget): diff --git a/pype/tools/settings/local_settings/constants.py b/pype/tools/settings/local_settings/constants.py index 7a8774467f..83c45afba8 100644 --- a/pype/tools/settings/local_settings/constants.py +++ b/pype/tools/settings/local_settings/constants.py @@ -14,6 +14,8 @@ LOCAL_APPS_KEY = "applications" # Roots key constant LOCAL_ROOTS_KEY = "roots" +# Child offset in expandable widget +CHILD_OFFSET = 15 __all__ = ( "LABEL_REMOVE_DEFAULT", diff --git a/pype/tools/settings/local_settings/widgets.py b/pype/tools/settings/local_settings/widgets.py index d69ad816e0..1b077f93be 100644 --- a/pype/tools/settings/local_settings/widgets.py +++ b/pype/tools/settings/local_settings/widgets.py @@ -3,7 +3,6 @@ from pype.tools.settings.settings.widgets.widgets import ( ExpandingWidget, SpacerWidget ) -from pype.tools.settings.settings.widgets.lib import CHILD_OFFSET class Separator(QtWidgets.QFrame): @@ -50,3 +49,11 @@ class ProxyLabelWidget(QtWidgets.QWidget): if self.mouse_release_callback: return self.mouse_release_callback(event) return super(ProxyLabelWidget, self).mouseReleaseEvent(event) + + +__all__ = ( + "ExpandingWidget", + "SpacerWidget", + "Separator", + "SpacerWidget" +) diff --git a/pype/tools/settings/local_settings/window.py b/pype/tools/settings/local_settings/window.py index d8d8adfea9..87a276c78c 100644 --- a/pype/tools/settings/local_settings/window.py +++ b/pype/tools/settings/local_settings/window.py @@ -1,5 +1,5 @@ import logging -from Qt import QtWidgets, QtCore, QtGui +from Qt import QtWidgets, QtGui from ..settings import style @@ -13,10 +13,8 @@ from pype.api import ( ) from .widgets import ( - Separator, SpacerWidget, - ExpandingWidget, - CHILD_OFFSET + ExpandingWidget ) from .mongo_widget import PypeMongoWidget from .general_widget import LocalGeneralWidgets @@ -24,6 +22,7 @@ from .apps_widget import LocalApplicationsWidgets from .projects_widget import ProjectSettingsWidget from .constants import ( + CHILD_OFFSET, LOCAL_GENERAL_KEY, LOCAL_PROJECTS_KEY, LOCAL_APPS_KEY From 45dbc6d5263067b90be5914ecb2d4da5d75c0531 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 25 Feb 2021 17:13:33 +0100 Subject: [PATCH 60/61] added `__all__` to local settings init file --- pype/tools/settings/local_settings/__init__.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pype/tools/settings/local_settings/__init__.py b/pype/tools/settings/local_settings/__init__.py index ddb9741b79..135a719a09 100644 --- a/pype/tools/settings/local_settings/__init__.py +++ b/pype/tools/settings/local_settings/__init__.py @@ -1 +1,6 @@ from .window import LocalSettingsWindow + + +__all__ = ( + "LocalSettingsWindow", +) From 03b9908570266b03dfc4f56a65abd8eaebf3ebdb Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 25 Feb 2021 17:14:50 +0100 Subject: [PATCH 61/61] added modifications to local settings md --- pype/settings/local_settings.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/settings/local_settings.md b/pype/settings/local_settings.md index 66c5b753d5..fbb5cf3df1 100644 --- a/pype/settings/local_settings.md +++ b/pype/settings/local_settings.md @@ -10,7 +10,7 @@ ```json { "general": { - "site_name": "MySite" + "site_label": "MySite" } } ``` @@ -55,7 +55,7 @@ "_id": "", "site_id": "", "general": { - "site_name": "MySite" + "site_label": "MySite" }, "applications": { "": {