Merge pull request #1049 from pypeclub/feature/local_settings

Local settings
This commit is contained in:
Milan Kolar 2021-02-26 11:10:27 +01:00 committed by GitHub
commit d8d16ca80e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 1833 additions and 13 deletions

View file

@ -1,6 +1,6 @@
import sys
from Qt import QtWidgets, QtGui
from .local_settings import LocalSettingsWindow
from .settings import (
style,
MainWidget,
@ -33,5 +33,6 @@ __all__ = (
"style",
"MainWidget",
"ProjectListWidget",
"LocalSettingsWindow",
"main"
)

View file

@ -0,0 +1,6 @@
from .window import LocalSettingsWindow
__all__ = (
"LocalSettingsWindow",
)

View file

@ -0,0 +1,205 @@
import platform
from Qt import QtWidgets
from .widgets import (
Separator,
ExpandingWidget
)
from .constants import 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 update_local_settings(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 update_local_settings(self, value):
if not value:
value = {}
for variant_name, widget in self.widgets_by_variant_name.items():
widget.update_local_settings(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)
self.widgets_by_group_name = {}
self.system_settings_entity = system_settings_entity
layout = QtWidgets.QVBoxLayout(self)
layout.setContentsMargins(0, 0, 0, 0)
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
# 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)
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))
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

View file

@ -0,0 +1,32 @@
# 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"
# Child offset in expandable widget
CHILD_OFFSET = 15
__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"
)

View file

@ -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

View file

@ -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_()

View file

@ -0,0 +1,731 @@
import platform
import copy
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,
ProxyLabelWidget
)
from .constants import (
LABEL_REMOVE_DEFAULT,
LABEL_ADD_DEFAULT,
LABEL_REMOVE_PROJECT,
LABEL_ADD_PROJECT,
LABEL_DISCARD_CHANGES,
LOCAL_ROOTS_KEY
)
NOT_SET = type("NOT_SET", (), {})()
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)
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 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
) or ""
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:
input_value = default_input_value
project_value = None
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
key_label = ProxyLabelWidget(
root_name,
self._mouse_release_callback,
self
)
value_input = QtWidgets.QLineEdit(self)
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.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
self._update_style()
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
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
self._update_style()
class RootsWidget(QtWidgets.QWidget):
def __init__(self, project_settings, parent):
super(RootsWidget, self).__init__(parent)
self.project_settings = project_settings
self.site_widgets = []
self.local_project_settings = None
self.local_project_settings_orig = None
self._project_name = None
self.content_layout = QtWidgets.QVBoxLayout(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.site_widgets = []
def refresh(self):
self._clear_widgets()
if self._project_name is None:
return
roots_entity = (
self.project_settings[PROJECT_ANATOMY_KEY][LOCAL_ROOTS_KEY]
)
# Site label
for site_name in get_active_sites(self.project_settings):
site_widget = QtWidgets.QWidget(self)
site_layout = QtWidgets.QVBoxLayout(site_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)
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)
)
def change_project(self, project_name):
self._project_name = project_name
self.refresh()
class _SiteCombobox(QtWidgets.QWidget):
input_label = None
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.default_override_value = None
self.project_override_value = None
label_widget = ProxyLabelWidget(
self.input_label,
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)
combobox_input.currentIndexChanged.connect(self._on_index_change)
self.label_widget = label_widget
self.combobox_input = combobox_input
def _set_current_text(self, text):
index = None
if text:
idx = self.combobox_input.findText(text)
if idx >= 0:
index = idx
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 ""
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 self.is_modified(current_value, orig_value):
return "modified"
if self.project_name == DEFAULT_PROJECT_KEY:
if current_value:
return "studio"
else:
if current_value:
return "overriden"
studio_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:
return
self._show_actions()
def _remove_from_local(self):
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(combobox_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 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 = {}
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
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)
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 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)
)
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
self.project_name = None
self.combobox_input.clear()
if project_name is None:
self._update_style()
return
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 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 = idx
if default_item:
idx = self.combobox_input.findText(default_item)
if idx >= 0:
self.default_override_value = default_item
if index is None:
index = idx
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
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()
def _set_local_settings_value(self, value):
raise NotImplementedError(
"{} `_set_local_settings_value` not implemented".format(
self.__class__.__name__
)
)
def _get_project_sites(self):
raise NotImplementedError(
"{} `_get_project_sites` not implemented".format(
self.__class__.__name__
)
)
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"
def _get_project_sites(self):
return get_active_sites(self.project_settings)
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)
value = None
if project_values:
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] = {}
self.local_project_settings[self.project_name]["active_site"] = value
class RemoteSiteCombo(_SiteCombobox):
input_label = "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=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)
value = None
if project_values:
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] = {}
self.local_project_settings[self.project_name]["remote_site"] = value
class RootSiteWidget(QtWidgets.QWidget):
def __init__(self, project_settings, parent):
self._parent_widget = parent
super(RootSiteWidget, self).__init__(parent)
self.project_settings = project_settings
self._project_name = None
sites_widget = QtWidgets.QWidget(self)
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)
main_layout = QtWidgets.QVBoxLayout(self)
main_layout.addWidget(sites_widget)
main_layout.addWidget(roots_widget)
main_layout.addWidget(SpacerWidget(self), 1)
self.active_site_widget = active_site_widget
self.remote_site_widget = remote_site_widget
self.roots_widget = roots_widget
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 _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 update_local_settings(self, local_project_settings):
self.local_project_settings = 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)
project_name = self._project_name
if project_name is None:
project_name = DEFAULT_PROJECT_KEY
self.change_project(project_name)
def change_project(self, project_name):
self._project_name = project_name
# Set roots project to None so all changes below are ignored
self.roots_widget.change_project(None)
# Aply changes in site comboboxes
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)
class ProjectValue(dict):
pass
class ProjectSettingsWidget(QtWidgets.QWidget):
def __init__(self, project_settings, parent):
super(ProjectSettingsWidget, self).__init__(parent)
self.local_project_settings = {}
projects_widget = _ProjectListWidget(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(roos_site_widget, 1)
projects_widget.project_changed.connect(self._on_project_change)
self.project_settings = project_settings
self.projects_widget = projects_widget
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)
if project_name is None:
project_name = DEFAULT_PROJECT_KEY
self.roos_site_widget.change_project(project_name)
def update_local_settings(self, value):
if not value:
value = {}
self.local_project_settings = ProjectValue(value)
self.roos_site_widget.update_local_settings(
self.local_project_settings
)
self.projects_widget.refresh()
def _clear_value(self, value):
if not value:
return None
if not isinstance(value, dict):
return value
output = {}
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

View file

@ -0,0 +1,59 @@
from Qt import QtWidgets, QtCore
from pype.tools.settings.settings.widgets.widgets import (
ExpandingWidget,
SpacerWidget
)
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 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 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)
return super(ProxyLabelWidget, self).mouseReleaseEvent(event)
__all__ = (
"ExpandingWidget",
"SpacerWidget",
"Separator",
"SpacerWidget"
)

View file

@ -0,0 +1,204 @@
import logging
from Qt import QtWidgets, QtGui
from ..settings import style
from pype.settings.lib import (
get_local_settings,
save_local_settings
)
from pype.api import (
SystemSettings,
ProjectSettings
)
from .widgets import (
SpacerWidget,
ExpandingWidget
)
from .mongo_widget import PypeMongoWidget
from .general_widget import LocalGeneralWidgets
from .apps_widget import LocalApplicationsWidgets
from .projects_widget import ProjectSettingsWidget
from .constants import (
CHILD_OFFSET,
LOCAL_GENERAL_KEY,
LOCAL_PROJECTS_KEY,
LOCAL_APPS_KEY
)
log = logging.getLogger(__name__)
class LocalSettingsWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(LocalSettingsWidget, self).__init__(parent)
self.system_settings = SystemSettings()
self.project_settings = ProjectSettings()
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()
# Add spacer to main layout
self.main_layout.addWidget(SpacerWidget(self), 1)
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", 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 _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 update_local_settings(self, value):
if not value:
value = {}
self.system_settings.reset()
self.project_settings.reset()
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 = {}
general_value = self.general_widget.settings_value()
if general_value:
output[LOCAL_GENERAL_KEY] = general_value
app_value = self.app_widget.settings_value()
if app_value:
output[LOCAL_APPS_KEY] = app_value
projects_value = self.projects_widget.settings_value()
if projects_value:
output[LOCAL_PROJECTS_KEY] = projects_value
return output
class LocalSettingsWindow(QtWidgets.QWidget):
def __init__(self, parent=None):
super(LocalSettingsWindow, self).__init__(parent)
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")
settings_widget = LocalSettingsWidget(scroll_widget)
scroll_widget.setWidget(settings_widget)
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)
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)
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()
def reset(self):
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)
self.reset()

View file

@ -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))