mirror of
https://github.com/ynput/ayon-core.git
synced 2026-01-02 00:44:52 +01:00
Merge branch 'develop' of github.com:pypeclub/OpenPype into chore/OP-2414_Move-harmony-to-openpype
This commit is contained in:
commit
28a745d54d
71 changed files with 2628 additions and 1165 deletions
|
|
@ -15,8 +15,12 @@ from .constants import (
|
|||
from .actions import ApplicationAction
|
||||
from Qt import QtCore, QtGui
|
||||
from avalon.vendor import qtawesome
|
||||
from avalon import style, api
|
||||
from openpype.lib import ApplicationManager, JSONSettingRegistry
|
||||
from avalon import api
|
||||
from openpype.lib import JSONSettingRegistry
|
||||
from openpype.lib.applications import (
|
||||
CUSTOM_LAUNCH_APP_GROUPS,
|
||||
ApplicationManager
|
||||
)
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -72,6 +76,9 @@ class ActionModel(QtGui.QStandardItemModel):
|
|||
if not app or not app.enabled:
|
||||
continue
|
||||
|
||||
if app.group.name in CUSTOM_LAUNCH_APP_GROUPS:
|
||||
continue
|
||||
|
||||
# Get from app definition, if not there from app in project
|
||||
action = type(
|
||||
"app_{}".format(app_name),
|
||||
|
|
@ -313,7 +320,7 @@ class ActionModel(QtGui.QStandardItemModel):
|
|||
action = action[0]
|
||||
|
||||
compare_data = {}
|
||||
if action:
|
||||
if action and action.label:
|
||||
compare_data = {
|
||||
"app_label": action.label.lower(),
|
||||
"project_name": self.dbcon.Session["AVALON_PROJECT"],
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ from avalon.vendor import qtawesome
|
|||
|
||||
from .delegates import ActionDelegate
|
||||
from . import lib
|
||||
from .actions import ApplicationAction
|
||||
from .models import ActionModel
|
||||
from openpype.tools.flickcharm import FlickCharm
|
||||
from .constants import (
|
||||
|
|
@ -239,10 +240,12 @@ class ActionBar(QtWidgets.QWidget):
|
|||
is_variant_group = index.data(VARIANT_GROUP_ROLE)
|
||||
if not is_group and not is_variant_group:
|
||||
action = index.data(ACTION_ROLE)
|
||||
if index.data(FORCE_NOT_OPEN_WORKFILE_ROLE):
|
||||
action.data["start_last_workfile"] = False
|
||||
else:
|
||||
action.data.pop("start_last_workfile", None)
|
||||
# Change data of application action
|
||||
if issubclass(action, ApplicationAction):
|
||||
if index.data(FORCE_NOT_OPEN_WORKFILE_ROLE):
|
||||
action.data["start_last_workfile"] = False
|
||||
else:
|
||||
action.data.pop("start_last_workfile", None)
|
||||
self._start_animation(index)
|
||||
self.action_clicked.emit(action)
|
||||
return
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@ from Qt import QtWidgets, QtCore
|
|||
|
||||
from .widgets import (
|
||||
NameTextEdit,
|
||||
FilterComboBox
|
||||
FilterComboBox,
|
||||
SpinBoxScrollFixed,
|
||||
DoubleSpinBoxScrollFixed
|
||||
)
|
||||
from .multiselection_combobox import MultiSelectionComboBox
|
||||
|
||||
|
|
@ -89,9 +91,9 @@ class NumberDelegate(QtWidgets.QStyledItemDelegate):
|
|||
|
||||
def createEditor(self, parent, option, index):
|
||||
if self.decimals > 0:
|
||||
editor = QtWidgets.QDoubleSpinBox(parent)
|
||||
editor = DoubleSpinBoxScrollFixed(parent)
|
||||
else:
|
||||
editor = QtWidgets.QSpinBox(parent)
|
||||
editor = SpinBoxScrollFixed(parent)
|
||||
|
||||
editor.setObjectName("NumberEditor")
|
||||
# Set min/max
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import os
|
||||
from Qt import QtCore, QtGui
|
||||
|
||||
from openpype.style import get_objected_colors
|
||||
from avalon.vendor import qtawesome
|
||||
from openpype.tools.utils import paint_image_with_color
|
||||
|
||||
|
||||
class ResourceCache:
|
||||
|
|
@ -91,17 +91,6 @@ class ResourceCache:
|
|||
icon.addPixmap(disabled_pix, QtGui.QIcon.Disabled, QtGui.QIcon.Off)
|
||||
return icon
|
||||
|
||||
@classmethod
|
||||
def get_warning_pixmap(cls):
|
||||
src_image = get_warning_image()
|
||||
colors = get_objected_colors()
|
||||
color_value = colors["delete-btn-bg"]
|
||||
|
||||
return paint_image_with_color(
|
||||
src_image,
|
||||
color_value.get_qcolor()
|
||||
)
|
||||
|
||||
|
||||
def get_remove_image():
|
||||
image_path = os.path.join(
|
||||
|
|
@ -110,36 +99,3 @@ def get_remove_image():
|
|||
"bin.png"
|
||||
)
|
||||
return QtGui.QImage(image_path)
|
||||
|
||||
|
||||
def get_warning_image():
|
||||
image_path = os.path.join(
|
||||
os.path.dirname(os.path.abspath(__file__)),
|
||||
"images",
|
||||
"warning.png"
|
||||
)
|
||||
return QtGui.QImage(image_path)
|
||||
|
||||
|
||||
def paint_image_with_color(image, color):
|
||||
"""TODO: This function should be imported from utils.
|
||||
|
||||
At the moment of creation is not available yet.
|
||||
"""
|
||||
width = image.width()
|
||||
height = image.height()
|
||||
|
||||
alpha_mask = image.createAlphaMask()
|
||||
alpha_region = QtGui.QRegion(QtGui.QBitmap.fromImage(alpha_mask))
|
||||
|
||||
pixmap = QtGui.QPixmap(width, height)
|
||||
pixmap.fill(QtCore.Qt.transparent)
|
||||
|
||||
painter = QtGui.QPainter(pixmap)
|
||||
painter.setClipRegion(alpha_region)
|
||||
painter.setPen(QtCore.Qt.NoPen)
|
||||
painter.setBrush(color)
|
||||
painter.drawRect(QtCore.QRect(0, 0, width, height))
|
||||
painter.end()
|
||||
|
||||
return pixmap
|
||||
|
|
|
|||
|
|
@ -4,14 +4,16 @@ from .constants import (
|
|||
NAME_ALLOWED_SYMBOLS,
|
||||
NAME_REGEX
|
||||
)
|
||||
from .style import ResourceCache
|
||||
from openpype.lib import (
|
||||
create_project,
|
||||
PROJECT_NAME_ALLOWED_SYMBOLS,
|
||||
PROJECT_NAME_REGEX
|
||||
)
|
||||
from openpype.style import load_stylesheet
|
||||
from openpype.tools.utils import PlaceholderLineEdit
|
||||
from openpype.tools.utils import (
|
||||
PlaceholderLineEdit,
|
||||
get_warning_pixmap
|
||||
)
|
||||
from avalon.api import AvalonMongoDB
|
||||
|
||||
from Qt import QtWidgets, QtCore, QtGui
|
||||
|
|
@ -338,7 +340,7 @@ class ConfirmProjectDeletion(QtWidgets.QDialog):
|
|||
|
||||
top_widget = QtWidgets.QWidget(self)
|
||||
|
||||
warning_pixmap = ResourceCache.get_warning_pixmap()
|
||||
warning_pixmap = get_warning_pixmap()
|
||||
warning_icon_label = PixmapLabel(warning_pixmap, top_widget)
|
||||
|
||||
message_label = QtWidgets.QLabel(top_widget)
|
||||
|
|
@ -429,3 +431,29 @@ class ConfirmProjectDeletion(QtWidgets.QDialog):
|
|||
def _on_confirm_text_change(self):
|
||||
enabled = self._confirm_input.text() == self._project_name
|
||||
self._confirm_btn.setEnabled(enabled)
|
||||
|
||||
|
||||
class SpinBoxScrollFixed(QtWidgets.QSpinBox):
|
||||
"""QSpinBox which only allow edits change with scroll wheel when active"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(SpinBoxScrollFixed, self).__init__(*args, **kwargs)
|
||||
self.setFocusPolicy(QtCore.Qt.StrongFocus)
|
||||
|
||||
def wheelEvent(self, event):
|
||||
if not self.hasFocus():
|
||||
event.ignore()
|
||||
else:
|
||||
super(SpinBoxScrollFixed, self).wheelEvent(event)
|
||||
|
||||
|
||||
class DoubleSpinBoxScrollFixed(QtWidgets.QDoubleSpinBox):
|
||||
"""QDoubleSpinBox which only allow edits with scroll wheel when active"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(DoubleSpinBoxScrollFixed, self).__init__(*args, **kwargs)
|
||||
self.setFocusPolicy(QtCore.Qt.StrongFocus)
|
||||
|
||||
def wheelEvent(self, event):
|
||||
if not self.hasFocus():
|
||||
event.ignore()
|
||||
else:
|
||||
super(DoubleSpinBoxScrollFixed, self).wheelEvent(event)
|
||||
|
|
|
|||
|
|
@ -180,7 +180,16 @@ class LocalApplicationsWidgets(QtWidgets.QWidget):
|
|||
self.content_layout.removeItem(item)
|
||||
self.widgets_by_group_name.clear()
|
||||
|
||||
app_items = {}
|
||||
for key, entity in self.system_settings_entity["applications"].items():
|
||||
if key != "additional_apps":
|
||||
app_items[key] = entity
|
||||
continue
|
||||
|
||||
for _key, _entity in entity.items():
|
||||
app_items[_key] = _entity
|
||||
|
||||
for key, entity in app_items.items():
|
||||
# Filter not enabled app groups
|
||||
if not entity["enabled"].value:
|
||||
continue
|
||||
|
|
|
|||
|
|
@ -3,8 +3,10 @@ import sys
|
|||
import traceback
|
||||
import contextlib
|
||||
from enum import Enum
|
||||
from Qt import QtWidgets, QtCore, QtGui
|
||||
from Qt import QtWidgets, QtCore
|
||||
|
||||
from openpype.lib import get_openpype_version
|
||||
from openpype.tools.utils import set_style_property
|
||||
from openpype.settings.entities import (
|
||||
SystemSettings,
|
||||
ProjectSettings,
|
||||
|
|
@ -34,7 +36,10 @@ from openpype.settings.entities.op_version_entity import (
|
|||
)
|
||||
|
||||
from openpype.settings import SaveWarningExc
|
||||
from .widgets import ProjectListWidget
|
||||
from .widgets import (
|
||||
ProjectListWidget,
|
||||
VersionAction
|
||||
)
|
||||
from .breadcrumbs_widget import (
|
||||
BreadcrumbsAddressBar,
|
||||
SystemSettingsBreadcrumbs,
|
||||
|
|
@ -88,6 +93,20 @@ class SettingsCategoryWidget(QtWidgets.QWidget):
|
|||
restart_required_trigger = QtCore.Signal()
|
||||
full_path_requested = QtCore.Signal(str, str)
|
||||
|
||||
require_restart_label_text = (
|
||||
"Your changes require restart of"
|
||||
" all running OpenPype processes to take affect."
|
||||
)
|
||||
outdated_version_label_text = (
|
||||
"Your settings are loaded from an older version."
|
||||
)
|
||||
source_version_tooltip = "Using settings of current OpenPype version"
|
||||
source_version_tooltip_outdated = (
|
||||
"Please check that all settings are still correct (blue colour\n"
|
||||
"indicates potential changes in the new version) and save your\n"
|
||||
"settings to update them to you current running OpenPype version."
|
||||
)
|
||||
|
||||
def __init__(self, user_role, parent=None):
|
||||
super(SettingsCategoryWidget, self).__init__(parent)
|
||||
|
||||
|
|
@ -98,6 +117,10 @@ class SettingsCategoryWidget(QtWidgets.QWidget):
|
|||
self._state = CategoryState.Idle
|
||||
|
||||
self._hide_studio_overrides = False
|
||||
self._updating_root = False
|
||||
self._use_version = None
|
||||
self._current_version = get_openpype_version()
|
||||
|
||||
self.ignore_input_changes = IgnoreInputChangesObj(self)
|
||||
|
||||
self.keys = []
|
||||
|
|
@ -183,77 +206,126 @@ class SettingsCategoryWidget(QtWidgets.QWidget):
|
|||
def initialize_attributes(self):
|
||||
return
|
||||
|
||||
@property
|
||||
def is_modifying_defaults(self):
|
||||
if self.modify_defaults_checkbox is None:
|
||||
return False
|
||||
return self.modify_defaults_checkbox.isChecked()
|
||||
|
||||
def create_ui(self):
|
||||
self.modify_defaults_checkbox = None
|
||||
|
||||
scroll_widget = QtWidgets.QScrollArea(self)
|
||||
scroll_widget.setObjectName("GroupWidget")
|
||||
content_widget = QtWidgets.QWidget(scroll_widget)
|
||||
conf_wrapper_widget = QtWidgets.QWidget(self)
|
||||
configurations_widget = QtWidgets.QWidget(conf_wrapper_widget)
|
||||
|
||||
breadcrumbs_label = QtWidgets.QLabel("Path:", content_widget)
|
||||
breadcrumbs_widget = BreadcrumbsAddressBar(content_widget)
|
||||
# Breadcrumbs/Path widget
|
||||
breadcrumbs_widget = QtWidgets.QWidget(self)
|
||||
breadcrumbs_label = QtWidgets.QLabel("Path:", breadcrumbs_widget)
|
||||
breadcrumbs_bar = BreadcrumbsAddressBar(breadcrumbs_widget)
|
||||
|
||||
breadcrumbs_layout = QtWidgets.QHBoxLayout()
|
||||
refresh_icon = qtawesome.icon("fa.refresh", color="white")
|
||||
refresh_btn = QtWidgets.QPushButton(breadcrumbs_widget)
|
||||
refresh_btn.setIcon(refresh_icon)
|
||||
|
||||
breadcrumbs_layout = QtWidgets.QHBoxLayout(breadcrumbs_widget)
|
||||
breadcrumbs_layout.setContentsMargins(5, 5, 5, 5)
|
||||
breadcrumbs_layout.setSpacing(5)
|
||||
breadcrumbs_layout.addWidget(breadcrumbs_label)
|
||||
breadcrumbs_layout.addWidget(breadcrumbs_widget)
|
||||
breadcrumbs_layout.addWidget(breadcrumbs_label, 0)
|
||||
breadcrumbs_layout.addWidget(breadcrumbs_bar, 1)
|
||||
breadcrumbs_layout.addWidget(refresh_btn, 0)
|
||||
|
||||
# Widgets representing settings entities
|
||||
scroll_widget = QtWidgets.QScrollArea(configurations_widget)
|
||||
content_widget = QtWidgets.QWidget(scroll_widget)
|
||||
scroll_widget.setWidgetResizable(True)
|
||||
scroll_widget.setWidget(content_widget)
|
||||
|
||||
content_layout = QtWidgets.QVBoxLayout(content_widget)
|
||||
content_layout.setContentsMargins(3, 3, 3, 3)
|
||||
content_layout.setSpacing(5)
|
||||
content_layout.setAlignment(QtCore.Qt.AlignTop)
|
||||
|
||||
scroll_widget.setWidgetResizable(True)
|
||||
scroll_widget.setWidget(content_widget)
|
||||
# Footer widget
|
||||
footer_widget = QtWidgets.QWidget(self)
|
||||
footer_widget.setObjectName("SettingsFooter")
|
||||
|
||||
refresh_icon = qtawesome.icon("fa.refresh", color="white")
|
||||
refresh_btn = QtWidgets.QPushButton(self)
|
||||
refresh_btn.setIcon(refresh_icon)
|
||||
# Info labels
|
||||
# TODO dynamic labels
|
||||
labels_alignment = QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter
|
||||
empty_label = QtWidgets.QLabel(footer_widget)
|
||||
|
||||
footer_layout = QtWidgets.QHBoxLayout()
|
||||
outdated_version_label = QtWidgets.QLabel(
|
||||
self.outdated_version_label_text, footer_widget
|
||||
)
|
||||
outdated_version_label.setToolTip(self.source_version_tooltip_outdated)
|
||||
outdated_version_label.setAlignment(labels_alignment)
|
||||
outdated_version_label.setVisible(False)
|
||||
outdated_version_label.setObjectName("SettingsOutdatedSourceVersion")
|
||||
|
||||
require_restart_label = QtWidgets.QLabel(
|
||||
self.require_restart_label_text, footer_widget
|
||||
)
|
||||
require_restart_label.setAlignment(labels_alignment)
|
||||
require_restart_label.setVisible(False)
|
||||
|
||||
# Label showing source version of loaded settings
|
||||
source_version_label = QtWidgets.QLabel("", footer_widget)
|
||||
source_version_label.setObjectName("SourceVersionLabel")
|
||||
set_style_property(source_version_label, "state", "")
|
||||
source_version_label.setToolTip(self.source_version_tooltip)
|
||||
|
||||
save_btn = QtWidgets.QPushButton("Save", footer_widget)
|
||||
|
||||
footer_layout = QtWidgets.QHBoxLayout(footer_widget)
|
||||
footer_layout.setContentsMargins(5, 5, 5, 5)
|
||||
if self.user_role == "developer":
|
||||
self._add_developer_ui(footer_layout)
|
||||
self._add_developer_ui(footer_layout, footer_widget)
|
||||
|
||||
save_btn = QtWidgets.QPushButton("Save", self)
|
||||
require_restart_label = QtWidgets.QLabel(self)
|
||||
require_restart_label.setAlignment(QtCore.Qt.AlignCenter)
|
||||
|
||||
footer_layout.addWidget(refresh_btn, 0)
|
||||
footer_layout.addWidget(empty_label, 1)
|
||||
footer_layout.addWidget(outdated_version_label, 1)
|
||||
footer_layout.addWidget(require_restart_label, 1)
|
||||
footer_layout.addWidget(source_version_label, 0)
|
||||
footer_layout.addWidget(save_btn, 0)
|
||||
|
||||
configurations_layout = QtWidgets.QVBoxLayout()
|
||||
configurations_layout = QtWidgets.QVBoxLayout(configurations_widget)
|
||||
configurations_layout.setContentsMargins(0, 0, 0, 0)
|
||||
configurations_layout.setSpacing(0)
|
||||
|
||||
configurations_layout.addWidget(scroll_widget, 1)
|
||||
configurations_layout.addLayout(footer_layout, 0)
|
||||
|
||||
conf_wrapper_layout = QtWidgets.QHBoxLayout()
|
||||
conf_wrapper_layout = QtWidgets.QHBoxLayout(conf_wrapper_widget)
|
||||
conf_wrapper_layout.setContentsMargins(0, 0, 0, 0)
|
||||
conf_wrapper_layout.setSpacing(0)
|
||||
conf_wrapper_layout.addLayout(configurations_layout, 1)
|
||||
conf_wrapper_layout.addWidget(configurations_widget, 1)
|
||||
|
||||
main_layout = QtWidgets.QVBoxLayout(self)
|
||||
main_layout.setContentsMargins(0, 0, 0, 0)
|
||||
main_layout.setSpacing(0)
|
||||
main_layout.addLayout(breadcrumbs_layout, 0)
|
||||
main_layout.addLayout(conf_wrapper_layout, 1)
|
||||
main_layout.addWidget(breadcrumbs_widget, 0)
|
||||
main_layout.addWidget(conf_wrapper_widget, 1)
|
||||
main_layout.addWidget(footer_widget, 0)
|
||||
|
||||
save_btn.clicked.connect(self._save)
|
||||
refresh_btn.clicked.connect(self._on_refresh)
|
||||
breadcrumbs_widget.path_edited.connect(self._on_path_edit)
|
||||
breadcrumbs_bar.path_edited.connect(self._on_path_edit)
|
||||
|
||||
self._require_restart_label = require_restart_label
|
||||
self._outdated_version_label = outdated_version_label
|
||||
self._empty_label = empty_label
|
||||
|
||||
self._is_loaded_version_outdated = False
|
||||
|
||||
self.save_btn = save_btn
|
||||
self.refresh_btn = refresh_btn
|
||||
self.require_restart_label = require_restart_label
|
||||
self._source_version_label = source_version_label
|
||||
|
||||
self.scroll_widget = scroll_widget
|
||||
self.content_layout = content_layout
|
||||
self.content_widget = content_widget
|
||||
self.breadcrumbs_widget = breadcrumbs_widget
|
||||
self.breadcrumbs_bar = breadcrumbs_bar
|
||||
|
||||
self.breadcrumbs_model = None
|
||||
self.refresh_btn = refresh_btn
|
||||
|
||||
self.conf_wrapper_layout = conf_wrapper_layout
|
||||
self.main_layout = main_layout
|
||||
|
||||
|
|
@ -308,21 +380,17 @@ class SettingsCategoryWidget(QtWidgets.QWidget):
|
|||
pass
|
||||
|
||||
def set_path(self, path):
|
||||
self.breadcrumbs_widget.set_path(path)
|
||||
self.breadcrumbs_bar.set_path(path)
|
||||
|
||||
def _add_developer_ui(self, footer_layout):
|
||||
modify_defaults_widget = QtWidgets.QWidget()
|
||||
modify_defaults_checkbox = QtWidgets.QCheckBox(modify_defaults_widget)
|
||||
def _add_developer_ui(self, footer_layout, footer_widget):
|
||||
modify_defaults_checkbox = QtWidgets.QCheckBox(footer_widget)
|
||||
modify_defaults_checkbox.setChecked(self._hide_studio_overrides)
|
||||
label_widget = QtWidgets.QLabel(
|
||||
"Modify defaults", modify_defaults_widget
|
||||
"Modify defaults", footer_widget
|
||||
)
|
||||
|
||||
modify_defaults_layout = QtWidgets.QHBoxLayout(modify_defaults_widget)
|
||||
modify_defaults_layout.addWidget(label_widget)
|
||||
modify_defaults_layout.addWidget(modify_defaults_checkbox)
|
||||
|
||||
footer_layout.addWidget(modify_defaults_widget, 0)
|
||||
footer_layout.addWidget(label_widget, 0)
|
||||
footer_layout.addWidget(modify_defaults_checkbox, 0)
|
||||
|
||||
modify_defaults_checkbox.stateChanged.connect(
|
||||
self._on_modify_defaults
|
||||
|
|
@ -361,6 +429,7 @@ class SettingsCategoryWidget(QtWidgets.QWidget):
|
|||
|
||||
try:
|
||||
self.entity.save()
|
||||
self._use_version = None
|
||||
|
||||
# NOTE There are relations to previous entities and C++ callbacks
|
||||
# so it is easier to just use new entity and recreate UI but
|
||||
|
|
@ -420,13 +489,7 @@ class SettingsCategoryWidget(QtWidgets.QWidget):
|
|||
return
|
||||
|
||||
def _on_require_restart_change(self):
|
||||
value = ""
|
||||
if self.entity.require_restart:
|
||||
value = (
|
||||
"Your changes require restart of"
|
||||
" all running OpenPype processes to take affect."
|
||||
)
|
||||
self.require_restart_label.setText(value)
|
||||
self._update_labels_visibility()
|
||||
|
||||
def reset(self):
|
||||
self.set_state(CategoryState.Working)
|
||||
|
|
@ -444,6 +507,8 @@ class SettingsCategoryWidget(QtWidgets.QWidget):
|
|||
widget.deleteLater()
|
||||
|
||||
dialog = None
|
||||
self._updating_root = True
|
||||
source_version = ""
|
||||
try:
|
||||
self._create_root_entity()
|
||||
|
||||
|
|
@ -459,6 +524,7 @@ class SettingsCategoryWidget(QtWidgets.QWidget):
|
|||
input_field.set_entity_value()
|
||||
|
||||
self.ignore_input_changes.set_ignore(False)
|
||||
source_version = self.entity.source_version
|
||||
|
||||
except DefaultsNotDefined:
|
||||
dialog = QtWidgets.QMessageBox(self)
|
||||
|
|
@ -502,6 +568,27 @@ class SettingsCategoryWidget(QtWidgets.QWidget):
|
|||
spacer, layout.rowCount(), 0, 1, layout.columnCount()
|
||||
)
|
||||
|
||||
self._updating_root = False
|
||||
|
||||
# Update source version label
|
||||
state_value = ""
|
||||
tooltip = ""
|
||||
outdated = False
|
||||
if source_version:
|
||||
if source_version != self._current_version:
|
||||
state_value = "different"
|
||||
tooltip = self.source_version_tooltip_outdated
|
||||
outdated = True
|
||||
else:
|
||||
state_value = "same"
|
||||
tooltip = self.source_version_tooltip
|
||||
|
||||
self._is_loaded_version_outdated = outdated
|
||||
self._source_version_label.setText(source_version)
|
||||
self._source_version_label.setToolTip(tooltip)
|
||||
set_style_property(self._source_version_label, "state", state_value)
|
||||
self._update_labels_visibility()
|
||||
|
||||
self.set_state(CategoryState.Idle)
|
||||
|
||||
if dialog:
|
||||
|
|
@ -510,6 +597,36 @@ class SettingsCategoryWidget(QtWidgets.QWidget):
|
|||
else:
|
||||
self._on_reset_success()
|
||||
|
||||
def _on_source_version_change(self, version):
|
||||
if self._updating_root:
|
||||
return
|
||||
|
||||
if version == self._current_version:
|
||||
version = None
|
||||
|
||||
self._use_version = version
|
||||
QtCore.QTimer.singleShot(20, self.reset)
|
||||
|
||||
def add_context_actions(self, menu):
|
||||
if not self.entity or self.is_modifying_defaults:
|
||||
return
|
||||
|
||||
versions = self.entity.get_available_studio_versions(sorted=True)
|
||||
if not versions:
|
||||
return
|
||||
|
||||
submenu = QtWidgets.QMenu("Use settings from version", menu)
|
||||
for version in reversed(versions):
|
||||
action = VersionAction(version, submenu)
|
||||
action.version_triggered.connect(
|
||||
self._on_context_version_trigger
|
||||
)
|
||||
submenu.addAction(action)
|
||||
menu.addMenu(submenu)
|
||||
|
||||
def _on_context_version_trigger(self, version):
|
||||
self._on_source_version_change(version)
|
||||
|
||||
def _on_reset_crash(self):
|
||||
self.save_btn.setEnabled(False)
|
||||
|
||||
|
|
@ -521,10 +638,10 @@ class SettingsCategoryWidget(QtWidgets.QWidget):
|
|||
self.save_btn.setEnabled(True)
|
||||
|
||||
if self.breadcrumbs_model is not None:
|
||||
path = self.breadcrumbs_widget.path()
|
||||
self.breadcrumbs_widget.set_path("")
|
||||
path = self.breadcrumbs_bar.path()
|
||||
self.breadcrumbs_bar.set_path("")
|
||||
self.breadcrumbs_model.set_entity(self.entity)
|
||||
self.breadcrumbs_widget.change_path(path)
|
||||
self.breadcrumbs_bar.change_path(path)
|
||||
|
||||
def add_children_gui(self):
|
||||
for child_obj in self.entity.children:
|
||||
|
|
@ -565,10 +682,7 @@ class SettingsCategoryWidget(QtWidgets.QWidget):
|
|||
|
||||
def _save(self):
|
||||
# Don't trigger restart if defaults are modified
|
||||
if (
|
||||
self.modify_defaults_checkbox
|
||||
and self.modify_defaults_checkbox.isChecked()
|
||||
):
|
||||
if self.is_modifying_defaults:
|
||||
require_restart = False
|
||||
else:
|
||||
require_restart = self.entity.require_restart
|
||||
|
|
@ -584,7 +698,29 @@ class SettingsCategoryWidget(QtWidgets.QWidget):
|
|||
|
||||
if require_restart:
|
||||
self.restart_required_trigger.emit()
|
||||
self.require_restart_label.setText("")
|
||||
|
||||
def _update_labels_visibility(self):
|
||||
visible_label = None
|
||||
labels = {
|
||||
self._empty_label,
|
||||
self._outdated_version_label,
|
||||
self._require_restart_label,
|
||||
}
|
||||
if self.entity.require_restart:
|
||||
visible_label = self._require_restart_label
|
||||
elif self._is_loaded_version_outdated:
|
||||
visible_label = self._outdated_version_label
|
||||
else:
|
||||
visible_label = self._empty_label
|
||||
|
||||
if visible_label.isVisible():
|
||||
return
|
||||
|
||||
for label in labels:
|
||||
if label is visible_label:
|
||||
visible_label.setVisible(True)
|
||||
else:
|
||||
label.setVisible(False)
|
||||
|
||||
def _on_refresh(self):
|
||||
self.reset()
|
||||
|
|
@ -594,25 +730,29 @@ class SettingsCategoryWidget(QtWidgets.QWidget):
|
|||
|
||||
|
||||
class SystemWidget(SettingsCategoryWidget):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self._actions = []
|
||||
super(SystemWidget, self).__init__(*args, **kwargs)
|
||||
|
||||
def contain_category_key(self, category):
|
||||
if category == "system_settings":
|
||||
return True
|
||||
return False
|
||||
|
||||
def set_category_path(self, category, path):
|
||||
self.breadcrumbs_widget.change_path(path)
|
||||
self.breadcrumbs_bar.change_path(path)
|
||||
|
||||
def _create_root_entity(self):
|
||||
self.entity = SystemSettings(set_studio_state=False)
|
||||
self.entity.on_change_callbacks.append(self._on_entity_change)
|
||||
entity = SystemSettings(
|
||||
set_studio_state=False, source_version=self._use_version
|
||||
)
|
||||
entity.on_change_callbacks.append(self._on_entity_change)
|
||||
self.entity = entity
|
||||
try:
|
||||
if (
|
||||
self.modify_defaults_checkbox
|
||||
and self.modify_defaults_checkbox.isChecked()
|
||||
):
|
||||
self.entity.set_defaults_state()
|
||||
if self.is_modifying_defaults:
|
||||
entity.set_defaults_state()
|
||||
else:
|
||||
self.entity.set_studio_state()
|
||||
entity.set_studio_state()
|
||||
|
||||
if self.modify_defaults_checkbox:
|
||||
self.modify_defaults_checkbox.setEnabled(True)
|
||||
|
|
@ -620,16 +760,16 @@ class SystemWidget(SettingsCategoryWidget):
|
|||
if not self.modify_defaults_checkbox:
|
||||
raise
|
||||
|
||||
self.entity.set_defaults_state()
|
||||
entity.set_defaults_state()
|
||||
self.modify_defaults_checkbox.setChecked(True)
|
||||
self.modify_defaults_checkbox.setEnabled(False)
|
||||
|
||||
def ui_tweaks(self):
|
||||
self.breadcrumbs_model = SystemSettingsBreadcrumbs()
|
||||
self.breadcrumbs_widget.set_model(self.breadcrumbs_model)
|
||||
self.breadcrumbs_bar.set_model(self.breadcrumbs_model)
|
||||
|
||||
def _on_modify_defaults(self):
|
||||
if self.modify_defaults_checkbox.isChecked():
|
||||
if self.is_modifying_defaults:
|
||||
if not self.entity.is_in_defaults_state():
|
||||
self.reset()
|
||||
else:
|
||||
|
|
@ -638,6 +778,9 @@ class SystemWidget(SettingsCategoryWidget):
|
|||
|
||||
|
||||
class ProjectWidget(SettingsCategoryWidget):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(ProjectWidget, self).__init__(*args, **kwargs)
|
||||
|
||||
def contain_category_key(self, category):
|
||||
if category in ("project_settings", "project_anatomy"):
|
||||
return True
|
||||
|
|
@ -651,28 +794,28 @@ class ProjectWidget(SettingsCategoryWidget):
|
|||
else:
|
||||
path = category
|
||||
|
||||
self.breadcrumbs_widget.change_path(path)
|
||||
self.breadcrumbs_bar.change_path(path)
|
||||
|
||||
def initialize_attributes(self):
|
||||
self.project_name = None
|
||||
|
||||
def ui_tweaks(self):
|
||||
self.breadcrumbs_model = ProjectSettingsBreadcrumbs()
|
||||
self.breadcrumbs_widget.set_model(self.breadcrumbs_model)
|
||||
self.breadcrumbs_bar.set_model(self.breadcrumbs_model)
|
||||
|
||||
project_list_widget = ProjectListWidget(self)
|
||||
|
||||
self.conf_wrapper_layout.insertWidget(0, project_list_widget, 0)
|
||||
|
||||
project_list_widget.project_changed.connect(self._on_project_change)
|
||||
project_list_widget.version_change_requested.connect(
|
||||
self._on_source_version_change
|
||||
)
|
||||
|
||||
self.project_list_widget = project_list_widget
|
||||
|
||||
def get_project_names(self):
|
||||
if (
|
||||
self.modify_defaults_checkbox
|
||||
and self.modify_defaults_checkbox.isChecked()
|
||||
):
|
||||
if self.is_modifying_defaults:
|
||||
return []
|
||||
return self.project_list_widget.get_project_names()
|
||||
|
||||
|
|
@ -684,6 +827,10 @@ class ProjectWidget(SettingsCategoryWidget):
|
|||
if self is saved_tab_widget:
|
||||
return
|
||||
|
||||
def _on_context_version_trigger(self, version):
|
||||
self.project_list_widget.select_project(None)
|
||||
super(ProjectWidget, self)._on_context_version_trigger(version)
|
||||
|
||||
def _on_reset_start(self):
|
||||
self.project_list_widget.refresh()
|
||||
|
||||
|
|
@ -696,32 +843,29 @@ class ProjectWidget(SettingsCategoryWidget):
|
|||
super(ProjectWidget, self)._on_reset_success()
|
||||
|
||||
def _set_enabled_project_list(self, enabled):
|
||||
if (
|
||||
enabled
|
||||
and self.modify_defaults_checkbox
|
||||
and self.modify_defaults_checkbox.isChecked()
|
||||
):
|
||||
if enabled and self.is_modifying_defaults:
|
||||
enabled = False
|
||||
if self.project_list_widget.isEnabled() != enabled:
|
||||
self.project_list_widget.setEnabled(enabled)
|
||||
|
||||
def _create_root_entity(self):
|
||||
self.entity = ProjectSettings(change_state=False)
|
||||
self.entity.on_change_callbacks.append(self._on_entity_change)
|
||||
entity = ProjectSettings(
|
||||
change_state=False, source_version=self._use_version
|
||||
)
|
||||
entity.on_change_callbacks.append(self._on_entity_change)
|
||||
self.project_list_widget.set_entity(entity)
|
||||
self.entity = entity
|
||||
try:
|
||||
if (
|
||||
self.modify_defaults_checkbox
|
||||
and self.modify_defaults_checkbox.isChecked()
|
||||
):
|
||||
if self.is_modifying_defaults:
|
||||
self.entity.set_defaults_state()
|
||||
|
||||
elif self.project_name is None:
|
||||
self.entity.set_studio_state()
|
||||
|
||||
elif self.project_name == self.entity.project_name:
|
||||
self.entity.set_project_state()
|
||||
else:
|
||||
self.entity.change_project(self.project_name)
|
||||
self.entity.change_project(
|
||||
self.project_name, self._use_version
|
||||
)
|
||||
|
||||
if self.modify_defaults_checkbox:
|
||||
self.modify_defaults_checkbox.setEnabled(True)
|
||||
|
|
@ -754,7 +898,7 @@ class ProjectWidget(SettingsCategoryWidget):
|
|||
self.set_state(CategoryState.Idle)
|
||||
|
||||
def _on_modify_defaults(self):
|
||||
if self.modify_defaults_checkbox.isChecked():
|
||||
if self.is_modifying_defaults:
|
||||
self._set_enabled_project_list(False)
|
||||
if not self.entity.is_in_defaults_state():
|
||||
self.reset()
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ DEFAULT_PROJECT_LABEL = "< Default >"
|
|||
PROJECT_NAME_ROLE = QtCore.Qt.UserRole + 1
|
||||
PROJECT_IS_ACTIVE_ROLE = QtCore.Qt.UserRole + 2
|
||||
PROJECT_IS_SELECTED_ROLE = QtCore.Qt.UserRole + 3
|
||||
PROJECT_VERSION_ROLE = QtCore.Qt.UserRole + 4
|
||||
|
||||
|
||||
__all__ = (
|
||||
|
|
@ -12,5 +13,6 @@ __all__ = (
|
|||
|
||||
"PROJECT_NAME_ROLE",
|
||||
"PROJECT_IS_ACTIVE_ROLE",
|
||||
"PROJECT_IS_SELECTED_ROLE"
|
||||
"PROJECT_IS_SELECTED_ROLE",
|
||||
"PROJECT_VERSION_ROLE",
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import os
|
||||
import copy
|
||||
import uuid
|
||||
from Qt import QtWidgets, QtCore, QtGui
|
||||
from avalon.vendor import qtawesome
|
||||
from avalon.mongodb import (
|
||||
|
|
@ -12,8 +13,12 @@ from openpype.tools.utils.widgets import ImageButton
|
|||
from openpype.tools.utils.lib import paint_image_with_color
|
||||
|
||||
from openpype.widgets.nice_checkbox import NiceCheckbox
|
||||
from openpype.tools.utils import PlaceholderLineEdit
|
||||
from openpype.settings.lib import get_system_settings
|
||||
from openpype.tools.utils import (
|
||||
PlaceholderLineEdit,
|
||||
DynamicQThread
|
||||
)
|
||||
from openpype.settings.lib import find_closest_version_for_projects
|
||||
from openpype.lib import get_openpype_version
|
||||
from .images import (
|
||||
get_pixmap,
|
||||
get_image
|
||||
|
|
@ -21,11 +26,40 @@ from .images import (
|
|||
from .constants import (
|
||||
DEFAULT_PROJECT_LABEL,
|
||||
PROJECT_NAME_ROLE,
|
||||
PROJECT_VERSION_ROLE,
|
||||
PROJECT_IS_ACTIVE_ROLE,
|
||||
PROJECT_IS_SELECTED_ROLE
|
||||
)
|
||||
|
||||
|
||||
class SettingsTabWidget(QtWidgets.QTabWidget):
|
||||
context_menu_requested = QtCore.Signal(int)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(SettingsTabWidget, self).__init__(*args, **kwargs)
|
||||
self._right_click_tab_idx = None
|
||||
|
||||
def mousePressEvent(self, event):
|
||||
super(SettingsTabWidget, self).mousePressEvent(event)
|
||||
if event.button() == QtCore.Qt.RightButton:
|
||||
tab_bar = self.tabBar()
|
||||
pos = tab_bar.mapFromGlobal(event.globalPos())
|
||||
tab_idx = tab_bar.tabAt(pos)
|
||||
if tab_idx < 0:
|
||||
tab_idx = None
|
||||
self._right_click_tab_idx = tab_idx
|
||||
|
||||
def mouseReleaseEvent(self, event):
|
||||
super(SettingsTabWidget, self).mouseReleaseEvent(event)
|
||||
if event.button() == QtCore.Qt.RightButton:
|
||||
tab_bar = self.tabBar()
|
||||
pos = tab_bar.mapFromGlobal(event.globalPos())
|
||||
tab_idx = tab_bar.tabAt(pos)
|
||||
if tab_idx == self._right_click_tab_idx:
|
||||
self.context_menu_requested.emit(tab_idx)
|
||||
self._right_click_tab = None
|
||||
|
||||
|
||||
class CompleterFilter(QtCore.QSortFilterProxyModel):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(CompleterFilter, self).__init__(*args, **kwargs)
|
||||
|
|
@ -603,7 +637,7 @@ class UnsavedChangesDialog(QtWidgets.QDialog):
|
|||
message = "You have unsaved changes. What do you want to do with them?"
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
super(UnsavedChangesDialog, self).__init__(parent)
|
||||
message_label = QtWidgets.QLabel(self.message)
|
||||
|
||||
btns_widget = QtWidgets.QWidget(self)
|
||||
|
|
@ -735,19 +769,65 @@ class SettingsNiceCheckbox(NiceCheckbox):
|
|||
|
||||
|
||||
class ProjectModel(QtGui.QStandardItemModel):
|
||||
_update_versions = QtCore.Signal()
|
||||
|
||||
def __init__(self, only_active, *args, **kwargs):
|
||||
super(ProjectModel, self).__init__(*args, **kwargs)
|
||||
|
||||
self.setColumnCount(2)
|
||||
|
||||
self.dbcon = None
|
||||
|
||||
self._only_active = only_active
|
||||
self._default_item = None
|
||||
self._items_by_name = {}
|
||||
self._versions_by_project = {}
|
||||
|
||||
colors = get_objected_colors()
|
||||
font_color = colors["font"].get_qcolor()
|
||||
font_color.setAlpha(67)
|
||||
self._version_font_color = font_color
|
||||
self._current_version = get_openpype_version()
|
||||
|
||||
self._version_refresh_threads = []
|
||||
self._version_refresh_id = None
|
||||
|
||||
self._update_versions.connect(self._on_update_versions_signal)
|
||||
|
||||
def _on_update_versions_signal(self):
|
||||
for project_name, version in self._versions_by_project.items():
|
||||
if project_name is None:
|
||||
item = self._default_item
|
||||
else:
|
||||
item = self._items_by_name.get(project_name)
|
||||
|
||||
if item and version != self._current_version:
|
||||
item.setData(version, PROJECT_VERSION_ROLE)
|
||||
|
||||
def _fetch_settings_versions(self):
|
||||
"""Used versions per project are loaded in thread to not stuck UI."""
|
||||
version_refresh_id = self._version_refresh_id
|
||||
all_project_names = list(self._items_by_name.keys())
|
||||
all_project_names.append(None)
|
||||
closest_by_project_name = find_closest_version_for_projects(
|
||||
all_project_names
|
||||
)
|
||||
if self._version_refresh_id == version_refresh_id:
|
||||
self._versions_by_project = closest_by_project_name
|
||||
self._update_versions.emit()
|
||||
|
||||
def flags(self, index):
|
||||
if index.column() == 1:
|
||||
index = self.index(index.row(), 0, index.parent())
|
||||
return super(ProjectModel, self).flags(index)
|
||||
|
||||
def set_dbcon(self, dbcon):
|
||||
self.dbcon = dbcon
|
||||
|
||||
def refresh(self):
|
||||
# Change id of versions refresh
|
||||
self._version_refresh_id = uuid.uuid4()
|
||||
|
||||
new_items = []
|
||||
if self._default_item is None:
|
||||
item = QtGui.QStandardItem(DEFAULT_PROJECT_LABEL)
|
||||
|
|
@ -757,6 +837,7 @@ class ProjectModel(QtGui.QStandardItemModel):
|
|||
new_items.append(item)
|
||||
self._default_item = item
|
||||
|
||||
self._default_item.setData("", PROJECT_VERSION_ROLE)
|
||||
project_names = set()
|
||||
if self.dbcon is not None:
|
||||
for project_doc in self.dbcon.projects(
|
||||
|
|
@ -776,6 +857,7 @@ class ProjectModel(QtGui.QStandardItemModel):
|
|||
is_active = project_doc.get("data", {}).get("active", True)
|
||||
item.setData(project_name, PROJECT_NAME_ROLE)
|
||||
item.setData(is_active, PROJECT_IS_ACTIVE_ROLE)
|
||||
item.setData("", PROJECT_VERSION_ROLE)
|
||||
item.setData(False, PROJECT_IS_SELECTED_ROLE)
|
||||
|
||||
if not is_active:
|
||||
|
|
@ -792,15 +874,87 @@ class ProjectModel(QtGui.QStandardItemModel):
|
|||
if new_items:
|
||||
root_item.appendRows(new_items)
|
||||
|
||||
# Fetch versions per project in thread
|
||||
thread = DynamicQThread(self._fetch_settings_versions)
|
||||
self._version_refresh_threads.append(thread)
|
||||
thread.start()
|
||||
|
||||
class ProjectListView(QtWidgets.QListView):
|
||||
# Cleanup done threads
|
||||
for thread in tuple(self._version_refresh_threads):
|
||||
if thread.isFinished():
|
||||
self._version_refresh_threads.remove(thread)
|
||||
|
||||
def data(self, index, role=QtCore.Qt.DisplayRole):
|
||||
if index.column() == 1:
|
||||
if role == QtCore.Qt.TextAlignmentRole:
|
||||
return QtCore.Qt.AlignRight
|
||||
if role == QtCore.Qt.ForegroundRole:
|
||||
return self._version_font_color
|
||||
index = self.index(index.row(), 0, index.parent())
|
||||
if role in (QtCore.Qt.DisplayRole, QtCore.Qt.EditRole):
|
||||
role = PROJECT_VERSION_ROLE
|
||||
|
||||
return super(ProjectModel, self).data(index, role)
|
||||
|
||||
def setData(self, index, value, role=QtCore.Qt.EditRole):
|
||||
if index.column() == 1:
|
||||
index = self.index(index.row(), 0, index.parent())
|
||||
if role in (QtCore.Qt.DisplayRole, QtCore.Qt.EditRole):
|
||||
role = PROJECT_VERSION_ROLE
|
||||
return super(ProjectModel, self).setData(index, value, role)
|
||||
|
||||
def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole):
|
||||
if role == QtCore.Qt.DisplayRole:
|
||||
if section == 0:
|
||||
return "Project name"
|
||||
|
||||
elif section == 1:
|
||||
return "Used version"
|
||||
return ""
|
||||
return super(ProjectModel, self).headerData(
|
||||
section, orientation, role
|
||||
)
|
||||
|
||||
|
||||
class VersionAction(QtWidgets.QAction):
|
||||
version_triggered = QtCore.Signal(str)
|
||||
|
||||
def __init__(self, version, *args, **kwargs):
|
||||
super(VersionAction, self).__init__(version, *args, **kwargs)
|
||||
self._version = version
|
||||
self.triggered.connect(self._on_trigger)
|
||||
|
||||
def _on_trigger(self):
|
||||
self.version_triggered.emit(self._version)
|
||||
|
||||
|
||||
class ProjectView(QtWidgets.QTreeView):
|
||||
left_mouse_released_at = QtCore.Signal(QtCore.QModelIndex)
|
||||
right_mouse_released_at = QtCore.Signal(QtCore.QModelIndex)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(ProjectView, self).__init__(*args, **kwargs)
|
||||
self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
|
||||
self.setIndentation(0)
|
||||
|
||||
# Do not allow editing
|
||||
self.setEditTriggers(
|
||||
QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers
|
||||
)
|
||||
# Do not automatically handle selection
|
||||
self.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection)
|
||||
self.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
|
||||
|
||||
def mouseReleaseEvent(self, event):
|
||||
if event.button() == QtCore.Qt.LeftButton:
|
||||
index = self.indexAt(event.pos())
|
||||
self.left_mouse_released_at.emit(index)
|
||||
super(ProjectListView, self).mouseReleaseEvent(event)
|
||||
|
||||
elif event.button() == QtCore.Qt.RightButton:
|
||||
index = self.indexAt(event.pos())
|
||||
self.right_mouse_released_at.emit(index)
|
||||
|
||||
super(ProjectView, self).mouseReleaseEvent(event)
|
||||
|
||||
|
||||
class ProjectSortFilterProxy(QtCore.QSortFilterProxyModel):
|
||||
|
|
@ -846,18 +1000,21 @@ class ProjectSortFilterProxy(QtCore.QSortFilterProxyModel):
|
|||
|
||||
class ProjectListWidget(QtWidgets.QWidget):
|
||||
project_changed = QtCore.Signal()
|
||||
version_change_requested = QtCore.Signal(str)
|
||||
|
||||
def __init__(self, parent, only_active=False):
|
||||
self._parent = parent
|
||||
|
||||
self._entity = None
|
||||
self.current_project = None
|
||||
|
||||
super(ProjectListWidget, self).__init__(parent)
|
||||
self.setObjectName("ProjectListWidget")
|
||||
|
||||
label_widget = QtWidgets.QLabel("Projects")
|
||||
content_frame = QtWidgets.QFrame(self)
|
||||
content_frame.setObjectName("ProjectListContentWidget")
|
||||
|
||||
project_list = ProjectListView(self)
|
||||
project_list = ProjectView(content_frame)
|
||||
project_model = ProjectModel(only_active)
|
||||
project_proxy = ProjectSortFilterProxy()
|
||||
|
||||
|
|
@ -865,33 +1022,37 @@ class ProjectListWidget(QtWidgets.QWidget):
|
|||
project_proxy.setSourceModel(project_model)
|
||||
project_list.setModel(project_proxy)
|
||||
|
||||
# Do not allow editing
|
||||
project_list.setEditTriggers(
|
||||
QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers
|
||||
)
|
||||
# Do not automatically handle selection
|
||||
project_list.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection)
|
||||
content_layout = QtWidgets.QVBoxLayout(content_frame)
|
||||
content_layout.setContentsMargins(0, 0, 0, 0)
|
||||
content_layout.setSpacing(0)
|
||||
content_layout.addWidget(project_list, 1)
|
||||
|
||||
layout = QtWidgets.QVBoxLayout(self)
|
||||
layout.setSpacing(3)
|
||||
layout.addWidget(label_widget, 0)
|
||||
layout.addWidget(project_list, 1)
|
||||
inactive_chk = None
|
||||
if not only_active:
|
||||
checkbox_wrapper = QtWidgets.QWidget(content_frame)
|
||||
checkbox_wrapper.setAttribute(QtCore.Qt.WA_TranslucentBackground)
|
||||
|
||||
if only_active:
|
||||
inactive_chk = None
|
||||
else:
|
||||
inactive_chk = QtWidgets.QCheckBox(" Show Inactive Projects ")
|
||||
inactive_chk = QtWidgets.QCheckBox(
|
||||
"Show Inactive Projects", checkbox_wrapper
|
||||
)
|
||||
inactive_chk.setChecked(not project_proxy.is_filter_enabled())
|
||||
|
||||
layout.addSpacing(5)
|
||||
layout.addWidget(inactive_chk, 0)
|
||||
layout.addSpacing(5)
|
||||
wrapper_layout = QtWidgets.QHBoxLayout(checkbox_wrapper)
|
||||
wrapper_layout.addWidget(inactive_chk, 1)
|
||||
|
||||
content_layout.addWidget(checkbox_wrapper, 0)
|
||||
|
||||
inactive_chk.stateChanged.connect(self.on_inactive_vis_changed)
|
||||
|
||||
project_list.left_mouse_released_at.connect(self.on_item_clicked)
|
||||
layout = QtWidgets.QVBoxLayout(self)
|
||||
# Margins '3' are matching to configurables widget scroll area on right
|
||||
layout.setContentsMargins(5, 3, 3, 3)
|
||||
layout.addWidget(content_frame, 1)
|
||||
|
||||
self._default_project_item = None
|
||||
project_list.left_mouse_released_at.connect(self.on_item_clicked)
|
||||
project_list.right_mouse_released_at.connect(
|
||||
self._on_item_right_clicked
|
||||
)
|
||||
|
||||
self.project_list = project_list
|
||||
self.project_proxy = project_proxy
|
||||
|
|
@ -900,10 +1061,46 @@ class ProjectListWidget(QtWidgets.QWidget):
|
|||
|
||||
self.dbcon = None
|
||||
|
||||
def on_item_clicked(self, new_index):
|
||||
new_project_name = new_index.data(QtCore.Qt.DisplayRole)
|
||||
if new_project_name is None:
|
||||
def set_entity(self, entity):
|
||||
self._entity = entity
|
||||
|
||||
def _on_item_right_clicked(self, index):
|
||||
if not index.isValid():
|
||||
return
|
||||
project_name = index.data(PROJECT_NAME_ROLE)
|
||||
if project_name is None:
|
||||
project_name = DEFAULT_PROJECT_LABEL
|
||||
|
||||
if self.current_project != project_name:
|
||||
self.on_item_clicked(index)
|
||||
|
||||
if self.current_project != project_name:
|
||||
return
|
||||
|
||||
if not self._entity:
|
||||
return
|
||||
|
||||
versions = self._entity.get_available_source_versions(sorted=True)
|
||||
if not versions:
|
||||
return
|
||||
|
||||
menu = QtWidgets.QMenu(self)
|
||||
submenu = QtWidgets.QMenu("Use settings from version", menu)
|
||||
for version in reversed(versions):
|
||||
action = VersionAction(version, submenu)
|
||||
action.version_triggered.connect(
|
||||
self.version_change_requested
|
||||
)
|
||||
submenu.addAction(action)
|
||||
menu.addMenu(submenu)
|
||||
menu.exec_(QtGui.QCursor.pos())
|
||||
|
||||
def on_item_clicked(self, new_index):
|
||||
if not new_index.isValid():
|
||||
return
|
||||
new_project_name = new_index.data(PROJECT_NAME_ROLE)
|
||||
if new_project_name is None:
|
||||
new_project_name = DEFAULT_PROJECT_LABEL
|
||||
|
||||
if self.current_project == new_project_name:
|
||||
return
|
||||
|
|
@ -963,12 +1160,30 @@ class ProjectListWidget(QtWidgets.QWidget):
|
|||
index = model.indexFromItem(found_items[0])
|
||||
model.setData(index, True, PROJECT_IS_SELECTED_ROLE)
|
||||
|
||||
index = proxy.mapFromSource(index)
|
||||
src_indexes = []
|
||||
col_count = model.columnCount()
|
||||
if col_count > 1:
|
||||
for col in range(col_count):
|
||||
src_indexes.append(
|
||||
model.index(index.row(), col, index.parent())
|
||||
)
|
||||
dst_indexes = []
|
||||
for index in src_indexes:
|
||||
dst_indexes.append(proxy.mapFromSource(index))
|
||||
|
||||
self.project_list.selectionModel().clear()
|
||||
self.project_list.selectionModel().setCurrentIndex(
|
||||
index, QtCore.QItemSelectionModel.SelectionFlag.SelectCurrent
|
||||
)
|
||||
selection_model = self.project_list.selectionModel()
|
||||
selection_model.clear()
|
||||
|
||||
first = True
|
||||
for index in dst_indexes:
|
||||
if first:
|
||||
selection_model.setCurrentIndex(
|
||||
index,
|
||||
QtCore.QItemSelectionModel.SelectionFlag.SelectCurrent
|
||||
)
|
||||
first = False
|
||||
continue
|
||||
selection_model.select(index, QtCore.QItemSelectionModel.Select)
|
||||
|
||||
def get_project_names(self):
|
||||
output = []
|
||||
|
|
@ -980,7 +1195,7 @@ class ProjectListWidget(QtWidgets.QWidget):
|
|||
def refresh(self):
|
||||
selected_project = None
|
||||
for index in self.project_list.selectedIndexes():
|
||||
selected_project = index.data(QtCore.Qt.DisplayRole)
|
||||
selected_project = index.data(PROJECT_NAME_ROLE)
|
||||
break
|
||||
|
||||
mongo_url = os.environ["OPENPYPE_MONGO"]
|
||||
|
|
@ -1008,5 +1223,6 @@ class ProjectListWidget(QtWidgets.QWidget):
|
|||
self.select_project(selected_project)
|
||||
|
||||
self.current_project = self.project_list.currentIndex().data(
|
||||
QtCore.Qt.DisplayRole
|
||||
PROJECT_NAME_ROLE
|
||||
)
|
||||
self.project_list.resizeColumnToContents(0)
|
||||
|
|
|
|||
|
|
@ -4,7 +4,11 @@ from .categories import (
|
|||
SystemWidget,
|
||||
ProjectWidget
|
||||
)
|
||||
from .widgets import ShadowWidget, RestartDialog
|
||||
from .widgets import (
|
||||
ShadowWidget,
|
||||
RestartDialog,
|
||||
SettingsTabWidget
|
||||
)
|
||||
from openpype import style
|
||||
|
||||
from openpype.lib import is_admin_password_required
|
||||
|
|
@ -34,7 +38,7 @@ class MainWidget(QtWidgets.QWidget):
|
|||
self.setStyleSheet(stylesheet)
|
||||
self.setWindowIcon(QtGui.QIcon(style.app_icon_path()))
|
||||
|
||||
header_tab_widget = QtWidgets.QTabWidget(parent=self)
|
||||
header_tab_widget = SettingsTabWidget(parent=self)
|
||||
|
||||
studio_widget = SystemWidget(user_role, header_tab_widget)
|
||||
project_widget = ProjectWidget(user_role, header_tab_widget)
|
||||
|
|
@ -65,6 +69,10 @@ class MainWidget(QtWidgets.QWidget):
|
|||
)
|
||||
tab_widget.full_path_requested.connect(self._on_full_path_request)
|
||||
|
||||
header_tab_widget.context_menu_requested.connect(
|
||||
self._on_context_menu_request
|
||||
)
|
||||
|
||||
self._header_tab_widget = header_tab_widget
|
||||
self.tab_widgets = tab_widgets
|
||||
|
||||
|
|
@ -100,6 +108,18 @@ class MainWidget(QtWidgets.QWidget):
|
|||
tab_widget.set_category_path(category, path)
|
||||
break
|
||||
|
||||
def _on_context_menu_request(self, tab_idx):
|
||||
widget = self._header_tab_widget.widget(tab_idx)
|
||||
if not widget:
|
||||
return
|
||||
|
||||
menu = QtWidgets.QMenu(self)
|
||||
widget.add_context_actions(menu)
|
||||
if menu.actions():
|
||||
result = menu.exec_(QtGui.QCursor.pos())
|
||||
if result is not None:
|
||||
self._header_tab_widget.setCurrentIndex(tab_idx)
|
||||
|
||||
def showEvent(self, event):
|
||||
super(MainWidget, self).showEvent(event)
|
||||
if self._reset_on_show:
|
||||
|
|
|
|||
|
|
@ -33,7 +33,8 @@ from openpype.settings import (
|
|||
)
|
||||
from openpype.tools.utils import (
|
||||
WrappedCallbackItem,
|
||||
paint_image_with_color
|
||||
paint_image_with_color,
|
||||
get_warning_pixmap
|
||||
)
|
||||
|
||||
from .pype_info_widget import PypeInfoWidget
|
||||
|
|
@ -76,7 +77,7 @@ class PixmapLabel(QtWidgets.QLabel):
|
|||
super(PixmapLabel, self).resizeEvent(event)
|
||||
|
||||
|
||||
class VersionDialog(QtWidgets.QDialog):
|
||||
class VersionUpdateDialog(QtWidgets.QDialog):
|
||||
restart_requested = QtCore.Signal()
|
||||
ignore_requested = QtCore.Signal()
|
||||
|
||||
|
|
@ -84,7 +85,7 @@ class VersionDialog(QtWidgets.QDialog):
|
|||
_min_height = 130
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super(VersionDialog, self).__init__(parent)
|
||||
super(VersionUpdateDialog, self).__init__(parent)
|
||||
|
||||
icon = QtGui.QIcon(resources.get_openpype_icon_filepath())
|
||||
self.setWindowIcon(icon)
|
||||
|
|
@ -152,11 +153,11 @@ class VersionDialog(QtWidgets.QDialog):
|
|||
)
|
||||
|
||||
def showEvent(self, event):
|
||||
super().showEvent(event)
|
||||
super(VersionUpdateDialog, self).showEvent(event)
|
||||
self._restart_accepted = False
|
||||
|
||||
def closeEvent(self, event):
|
||||
super().closeEvent(event)
|
||||
super(VersionUpdateDialog, self).closeEvent(event)
|
||||
if self._restart_accepted or self._current_is_higher:
|
||||
return
|
||||
# Trigger ignore requested only if restart was not clicked and current
|
||||
|
|
@ -202,6 +203,63 @@ class VersionDialog(QtWidgets.QDialog):
|
|||
self.accept()
|
||||
|
||||
|
||||
class BuildVersionDialog(QtWidgets.QDialog):
|
||||
"""Build/Installation version is too low for current OpenPype version.
|
||||
|
||||
This dialog tells to user that it's build OpenPype is too old.
|
||||
"""
|
||||
def __init__(self, parent=None):
|
||||
super(BuildVersionDialog, self).__init__(parent)
|
||||
|
||||
icon = QtGui.QIcon(resources.get_openpype_icon_filepath())
|
||||
self.setWindowIcon(icon)
|
||||
self.setWindowTitle("Outdated OpenPype installation")
|
||||
self.setWindowFlags(
|
||||
self.windowFlags()
|
||||
| QtCore.Qt.WindowStaysOnTopHint
|
||||
)
|
||||
|
||||
top_widget = QtWidgets.QWidget(self)
|
||||
|
||||
warning_pixmap = get_warning_pixmap()
|
||||
warning_icon_label = PixmapLabel(warning_pixmap, top_widget)
|
||||
|
||||
message = (
|
||||
"Your installation of OpenPype <b>does not match minimum"
|
||||
" requirements</b>.<br/><br/>Please update OpenPype installation"
|
||||
" to newer version."
|
||||
)
|
||||
content_label = QtWidgets.QLabel(message, self)
|
||||
|
||||
top_layout = QtWidgets.QHBoxLayout(top_widget)
|
||||
top_layout.setContentsMargins(0, 0, 0, 0)
|
||||
top_layout.addWidget(
|
||||
warning_icon_label, 0,
|
||||
QtCore.Qt.AlignTop | QtCore.Qt.AlignHCenter
|
||||
)
|
||||
top_layout.addWidget(content_label, 1)
|
||||
|
||||
footer_widget = QtWidgets.QWidget(self)
|
||||
ok_btn = QtWidgets.QPushButton("I understand", footer_widget)
|
||||
|
||||
footer_layout = QtWidgets.QHBoxLayout(footer_widget)
|
||||
footer_layout.setContentsMargins(0, 0, 0, 0)
|
||||
footer_layout.addStretch(1)
|
||||
footer_layout.addWidget(ok_btn)
|
||||
|
||||
main_layout = QtWidgets.QVBoxLayout(self)
|
||||
main_layout.addWidget(top_widget, 0)
|
||||
main_layout.addStretch(1)
|
||||
main_layout.addWidget(footer_widget, 0)
|
||||
|
||||
self.setStyleSheet(style.load_stylesheet())
|
||||
|
||||
ok_btn.clicked.connect(self._on_ok_clicked)
|
||||
|
||||
def _on_ok_clicked(self):
|
||||
self.close()
|
||||
|
||||
|
||||
class TrayManager:
|
||||
"""Cares about context of application.
|
||||
|
||||
|
|
@ -272,7 +330,7 @@ class TrayManager:
|
|||
return
|
||||
|
||||
if self._version_dialog is None:
|
||||
self._version_dialog = VersionDialog()
|
||||
self._version_dialog = VersionUpdateDialog()
|
||||
self._version_dialog.restart_requested.connect(
|
||||
self._restart_and_install
|
||||
)
|
||||
|
|
@ -383,6 +441,10 @@ class TrayManager:
|
|||
|
||||
self._validate_settings_defaults()
|
||||
|
||||
if not op_version_control_available():
|
||||
dialog = BuildVersionDialog()
|
||||
dialog.exec_()
|
||||
|
||||
def _validate_settings_defaults(self):
|
||||
valid = True
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -10,7 +10,10 @@ from .widgets import (
|
|||
from .error_dialog import ErrorMessageBox
|
||||
from .lib import (
|
||||
WrappedCallbackItem,
|
||||
paint_image_with_color
|
||||
paint_image_with_color,
|
||||
get_warning_pixmap,
|
||||
set_style_property,
|
||||
DynamicQThread,
|
||||
)
|
||||
|
||||
from .models import (
|
||||
|
|
@ -29,6 +32,9 @@ __all__ = (
|
|||
|
||||
"WrappedCallbackItem",
|
||||
"paint_image_with_color",
|
||||
"get_warning_pixmap",
|
||||
"set_style_property",
|
||||
"DynamicQThread",
|
||||
|
||||
"RecursiveSortFilterProxyModel",
|
||||
)
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import Qt
|
|||
from Qt import QtWidgets, QtGui, QtCore
|
||||
|
||||
from avalon.lib import HeroVersionType
|
||||
from openpype.style import get_objected_colors
|
||||
from .models import TreeModel
|
||||
from . import lib
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ from openpype.api import (
|
|||
Logger
|
||||
)
|
||||
from openpype.lib import filter_profiles
|
||||
from openpype.style import get_objected_colors
|
||||
from openpype.resources import get_image_path
|
||||
|
||||
|
||||
def center_window(window):
|
||||
|
|
@ -28,6 +30,18 @@ def center_window(window):
|
|||
window.move(geo.topLeft())
|
||||
|
||||
|
||||
def set_style_property(widget, property_name, property_value):
|
||||
"""Set widget's property that may affect style.
|
||||
|
||||
If current property value is different then style of widget is polished.
|
||||
"""
|
||||
cur_value = widget.property(property_name)
|
||||
if cur_value == property_value:
|
||||
return
|
||||
widget.setProperty(property_name, property_value)
|
||||
widget.style().polish(widget)
|
||||
|
||||
|
||||
def paint_image_with_color(image, color):
|
||||
"""Redraw image with single color using it's alpha.
|
||||
|
||||
|
|
@ -670,3 +684,19 @@ class WrappedCallbackItem:
|
|||
|
||||
finally:
|
||||
self._done = True
|
||||
|
||||
|
||||
def get_warning_pixmap(color=None):
|
||||
"""Warning icon as QPixmap.
|
||||
|
||||
Args:
|
||||
color(QtGui.QColor): Color that will be used to paint warning icon.
|
||||
"""
|
||||
src_image_path = get_image_path("warning.png")
|
||||
src_image = QtGui.QImage(src_image_path)
|
||||
if color is None:
|
||||
colors = get_objected_colors()
|
||||
color_value = colors["delete-btn-bg"]
|
||||
color = color_value.get_qcolor()
|
||||
|
||||
return paint_image_with_color(src_image, color)
|
||||
|
|
|
|||
|
|
@ -3,9 +3,6 @@ import logging
|
|||
|
||||
import Qt
|
||||
from Qt import QtCore, QtGui
|
||||
from avalon.vendor import qtawesome
|
||||
from avalon import style, io
|
||||
from . import lib
|
||||
from .constants import (
|
||||
PROJECT_IS_ACTIVE_ROLE,
|
||||
PROJECT_NAME_ROLE,
|
||||
|
|
|
|||
|
|
@ -21,14 +21,13 @@ from openpype.tools.utils.tasks_widget import TasksWidget
|
|||
from openpype.tools.utils.delegates import PrettyTimeDelegate
|
||||
from openpype.lib import (
|
||||
Anatomy,
|
||||
get_workdir,
|
||||
get_workfile_doc,
|
||||
create_workfile_doc,
|
||||
save_workfile_data_to_doc,
|
||||
get_workfile_template_key,
|
||||
create_workdir_extra_folders
|
||||
create_workdir_extra_folders,
|
||||
get_system_general_anatomy_data
|
||||
)
|
||||
|
||||
from .model import FilesModel
|
||||
from .view import FilesView
|
||||
|
||||
|
|
@ -110,6 +109,10 @@ class NameWindow(QtWidgets.QDialog):
|
|||
"ext": None
|
||||
}
|
||||
|
||||
# add system general settings anatomy data
|
||||
system_general_data = get_system_general_anatomy_data()
|
||||
self.data.update(system_general_data)
|
||||
|
||||
# Store project anatomy
|
||||
self.anatomy = anatomy
|
||||
self.template = anatomy.templates[template_key]["file"]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue