mirror of
https://github.com/ynput/ayon-core.git
synced 2026-01-02 00:44:52 +01:00
moved create dialog to separated file
This commit is contained in:
parent
107b8841b5
commit
163f88b553
3 changed files with 450 additions and 443 deletions
|
|
@ -2,7 +2,9 @@ from .widgets import (
|
|||
PublishOverlayFrame,
|
||||
SubsetAttributesWidget,
|
||||
InstanceCardView,
|
||||
InstanceListView,
|
||||
InstanceListView
|
||||
)
|
||||
from .create_dialog import (
|
||||
CreateDialog
|
||||
)
|
||||
|
||||
|
|
@ -12,5 +14,6 @@ __all__ = (
|
|||
"SubsetAttributesWidget",
|
||||
"InstanceCardView",
|
||||
"InstanceListView",
|
||||
|
||||
"CreateDialog"
|
||||
)
|
||||
|
|
|
|||
446
openpype/tools/new_publisher/widgets/create_dialog.py
Normal file
446
openpype/tools/new_publisher/widgets/create_dialog.py
Normal file
|
|
@ -0,0 +1,446 @@
|
|||
import sys
|
||||
import re
|
||||
import traceback
|
||||
import copy
|
||||
|
||||
from Qt import QtWidgets, QtCore, QtGui
|
||||
|
||||
from openpype.pipeline.create import CreatorError
|
||||
|
||||
SEPARATORS = ("---separator---", "---")
|
||||
|
||||
|
||||
class CreateErrorMessageBox(QtWidgets.QDialog):
|
||||
def __init__(
|
||||
self,
|
||||
family,
|
||||
subset_name,
|
||||
asset_name,
|
||||
exc_msg,
|
||||
formatted_traceback,
|
||||
parent=None
|
||||
):
|
||||
super(CreateErrorMessageBox, self).__init__(parent)
|
||||
self.setWindowTitle("Creation failed")
|
||||
self.setFocusPolicy(QtCore.Qt.StrongFocus)
|
||||
if not parent:
|
||||
self.setWindowFlags(
|
||||
self.windowFlags() | QtCore.Qt.WindowStaysOnTopHint
|
||||
)
|
||||
|
||||
body_layout = QtWidgets.QVBoxLayout(self)
|
||||
|
||||
main_label = (
|
||||
"<span style='font-size:18pt;'>Failed to create</span>"
|
||||
)
|
||||
main_label_widget = QtWidgets.QLabel(main_label, self)
|
||||
body_layout.addWidget(main_label_widget)
|
||||
|
||||
item_name_template = (
|
||||
"<span style='font-weight:bold;'>Family:</span> {}<br>"
|
||||
"<span style='font-weight:bold;'>Subset:</span> {}<br>"
|
||||
"<span style='font-weight:bold;'>Asset:</span> {}<br>"
|
||||
)
|
||||
exc_msg_template = "<span style='font-weight:bold'>{}</span>"
|
||||
|
||||
line = self._create_line()
|
||||
body_layout.addWidget(line)
|
||||
|
||||
item_name = item_name_template.format(family, subset_name, asset_name)
|
||||
item_name_widget = QtWidgets.QLabel(
|
||||
item_name.replace("\n", "<br>"), self
|
||||
)
|
||||
body_layout.addWidget(item_name_widget)
|
||||
|
||||
exc_msg = exc_msg_template.format(exc_msg.replace("\n", "<br>"))
|
||||
message_label_widget = QtWidgets.QLabel(exc_msg, self)
|
||||
body_layout.addWidget(message_label_widget)
|
||||
|
||||
if formatted_traceback:
|
||||
tb_widget = QtWidgets.QLabel(
|
||||
formatted_traceback.replace("\n", "<br>"), self
|
||||
)
|
||||
tb_widget.setTextInteractionFlags(
|
||||
QtCore.Qt.TextBrowserInteraction
|
||||
)
|
||||
body_layout.addWidget(tb_widget)
|
||||
|
||||
footer_widget = QtWidgets.QWidget(self)
|
||||
footer_layout = QtWidgets.QHBoxLayout(footer_widget)
|
||||
button_box = QtWidgets.QDialogButtonBox(QtCore.Qt.Vertical)
|
||||
button_box.setStandardButtons(
|
||||
QtWidgets.QDialogButtonBox.StandardButton.Ok
|
||||
)
|
||||
button_box.accepted.connect(self._on_accept)
|
||||
footer_layout.addWidget(button_box, alignment=QtCore.Qt.AlignRight)
|
||||
body_layout.addWidget(footer_widget)
|
||||
|
||||
def _on_accept(self):
|
||||
self.close()
|
||||
|
||||
def _create_line(self):
|
||||
line = QtWidgets.QFrame(self)
|
||||
line.setFixedHeight(2)
|
||||
line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||
return line
|
||||
|
||||
|
||||
class CreateDialog(QtWidgets.QDialog):
|
||||
def __init__(self, controller, parent=None):
|
||||
super(CreateDialog, self).__init__(parent)
|
||||
|
||||
self.controller = controller
|
||||
|
||||
self._last_pos = None
|
||||
self._asset_doc = None
|
||||
self._subset_names = None
|
||||
self._selected_creator = None
|
||||
|
||||
self._prereq_available = False
|
||||
|
||||
self.message_dialog = None
|
||||
|
||||
family_view = QtWidgets.QListView(self)
|
||||
family_model = QtGui.QStandardItemModel()
|
||||
family_view.setModel(family_model)
|
||||
|
||||
variant_input = QtWidgets.QLineEdit(self)
|
||||
variant_input.setObjectName("VariantInput")
|
||||
|
||||
variant_hints_btn = QtWidgets.QPushButton(self)
|
||||
variant_hints_btn.setFixedWidth(18)
|
||||
|
||||
variant_hints_menu = QtWidgets.QMenu(variant_hints_btn)
|
||||
variant_hints_group = QtWidgets.QActionGroup(variant_hints_menu)
|
||||
variant_hints_btn.setMenu(variant_hints_menu)
|
||||
|
||||
variant_layout = QtWidgets.QHBoxLayout()
|
||||
variant_layout.setContentsMargins(0, 0, 0, 0)
|
||||
variant_layout.setSpacing(0)
|
||||
variant_layout.addWidget(variant_input, 1)
|
||||
variant_layout.addWidget(variant_hints_btn, 0)
|
||||
|
||||
asset_name_input = QtWidgets.QLineEdit(self)
|
||||
asset_name_input.setEnabled(False)
|
||||
|
||||
subset_name_input = QtWidgets.QLineEdit(self)
|
||||
subset_name_input.setEnabled(False)
|
||||
|
||||
checkbox_inputs = QtWidgets.QWidget(self)
|
||||
auto_close_checkbox = QtWidgets.QCheckBox(
|
||||
"Auto-close", checkbox_inputs
|
||||
)
|
||||
use_selection_checkbox = QtWidgets.QCheckBox(
|
||||
"Use selection", checkbox_inputs
|
||||
)
|
||||
|
||||
checkbox_layout = QtWidgets.QHBoxLayout(checkbox_inputs)
|
||||
checkbox_layout.setContentsMargins(0, 0, 0, 0)
|
||||
checkbox_layout.addWidget(auto_close_checkbox)
|
||||
checkbox_layout.addWidget(use_selection_checkbox)
|
||||
|
||||
create_btn = QtWidgets.QPushButton("Create", self)
|
||||
create_btn.setEnabled(False)
|
||||
|
||||
layout = QtWidgets.QVBoxLayout(self)
|
||||
layout.addWidget(QtWidgets.QLabel("Family:", self))
|
||||
layout.addWidget(family_view, 1)
|
||||
layout.addWidget(QtWidgets.QLabel("Asset:", self))
|
||||
layout.addWidget(asset_name_input, 0)
|
||||
layout.addWidget(QtWidgets.QLabel("Name:", self))
|
||||
layout.addLayout(variant_layout, 0)
|
||||
layout.addWidget(QtWidgets.QLabel("Subset:", self))
|
||||
layout.addWidget(subset_name_input, 0)
|
||||
layout.addWidget(checkbox_inputs, 0)
|
||||
layout.addWidget(create_btn, 0)
|
||||
|
||||
create_btn.clicked.connect(self._on_create)
|
||||
variant_input.returnPressed.connect(self._on_create)
|
||||
variant_input.textChanged.connect(self._on_variant_change)
|
||||
family_view.selectionModel().currentChanged.connect(
|
||||
self._on_family_change
|
||||
)
|
||||
variant_hints_menu.triggered.connect(self._on_variant_action)
|
||||
|
||||
controller.add_plugins_refresh_callback(self._on_plugins_refresh)
|
||||
|
||||
self.asset_name_input = asset_name_input
|
||||
self.subset_name_input = subset_name_input
|
||||
|
||||
self.variant_input = variant_input
|
||||
self.variant_hints_btn = variant_hints_btn
|
||||
self.variant_hints_menu = variant_hints_menu
|
||||
self.variant_hints_group = variant_hints_group
|
||||
|
||||
self.family_model = family_model
|
||||
self.family_view = family_view
|
||||
self.auto_close_checkbox = auto_close_checkbox
|
||||
self.use_selection_checkbox = auto_close_checkbox
|
||||
self.create_btn = create_btn
|
||||
|
||||
@property
|
||||
def dbcon(self):
|
||||
return self.controller.dbcon
|
||||
|
||||
def refresh(self):
|
||||
self._prereq_available = True
|
||||
|
||||
# Refresh data before update of creators
|
||||
self._refresh_asset()
|
||||
# Then refresh creators which may trigger callbacks using refreshed
|
||||
# data
|
||||
self._refresh_creators()
|
||||
|
||||
if self._asset_doc is None:
|
||||
self.asset_name_input.setText("< Asset is not set >")
|
||||
self._prereq_available = False
|
||||
|
||||
if self.family_model.rowCount() < 1:
|
||||
self._prereq_available = False
|
||||
|
||||
self.create_btn.setEnabled(self._prereq_available)
|
||||
self.family_view.setEnabled(self._prereq_available)
|
||||
self.variant_input.setEnabled(self._prereq_available)
|
||||
self.variant_hints_btn.setEnabled(self._prereq_available)
|
||||
|
||||
def _refresh_asset(self):
|
||||
asset_name = self.dbcon.Session.get("AVALON_ASSET")
|
||||
|
||||
# Skip if asset did not change
|
||||
if self._asset_doc and self._asset_doc["name"] == asset_name:
|
||||
return
|
||||
|
||||
# Make sure `_asset_doc` and `_subset_names` variables are reset
|
||||
self._asset_doc = None
|
||||
self._subset_names = None
|
||||
if asset_name is None:
|
||||
return
|
||||
|
||||
asset_doc = self.dbcon.find_one({
|
||||
"type": "asset",
|
||||
"name": asset_name
|
||||
})
|
||||
self._asset_doc = asset_doc
|
||||
|
||||
if asset_doc:
|
||||
self.asset_name_input.setText(asset_doc["name"])
|
||||
subset_docs = self.dbcon.find(
|
||||
{
|
||||
"type": "subset",
|
||||
"parent": asset_doc["_id"]
|
||||
},
|
||||
{"name": 1}
|
||||
)
|
||||
self._subset_names = set(subset_docs.distinct("name"))
|
||||
|
||||
def _refresh_creators(self):
|
||||
# Refresh creators and add their families to list
|
||||
existing_items = {}
|
||||
old_families = set()
|
||||
for row in range(self.family_model.rowCount()):
|
||||
item = self.family_model.item(row, 0)
|
||||
family = item.data(QtCore.Qt.DisplayRole)
|
||||
existing_items[family] = item
|
||||
old_families.add(family)
|
||||
|
||||
# Add new families
|
||||
new_families = set()
|
||||
for family, creator in self.controller.creators.items():
|
||||
# TODO add details about creator
|
||||
new_families.add(family)
|
||||
if family not in existing_items:
|
||||
item = QtGui.QStandardItem(family)
|
||||
self.family_model.appendRow(item)
|
||||
|
||||
# Remove families that are no more available
|
||||
for family in (old_families - new_families):
|
||||
item = existing_items[family]
|
||||
self.family_model.takeRow(item.row())
|
||||
|
||||
if self.family_model.rowCount() < 1:
|
||||
return
|
||||
|
||||
# Make sure there is a selection
|
||||
indexes = self.family_view.selectedIndexes()
|
||||
if not indexes:
|
||||
index = self.family_model.index(0, 0)
|
||||
self.family_view.setCurrentIndex(index)
|
||||
|
||||
def _on_plugins_refresh(self):
|
||||
# Trigger refresh only if is visible
|
||||
if self.isVisible():
|
||||
self.refresh()
|
||||
|
||||
def _on_family_change(self, new_index, _old_index):
|
||||
family = None
|
||||
if new_index.isValid():
|
||||
family = new_index.data(QtCore.Qt.DisplayRole)
|
||||
|
||||
creator = self.controller.creators.get(family)
|
||||
self._selected_creator = creator
|
||||
if not creator:
|
||||
return
|
||||
|
||||
default_variants = creator.get_default_variants()
|
||||
if not default_variants:
|
||||
default_variants = ["Main"]
|
||||
|
||||
default_variant = creator.get_default_variant()
|
||||
if not default_variant:
|
||||
default_variant = default_variants[0]
|
||||
|
||||
for action in tuple(self.variant_hints_menu.actions()):
|
||||
self.variant_hints_menu.removeAction(action)
|
||||
action.deleteLater()
|
||||
|
||||
for variant in default_variants:
|
||||
if variant in SEPARATORS:
|
||||
self.variant_hints_menu.addSeparator()
|
||||
elif variant:
|
||||
self.variant_hints_menu.addAction(variant)
|
||||
|
||||
self.variant_input.setText(default_variant or "Main")
|
||||
|
||||
def _on_variant_action(self, action):
|
||||
value = action.text()
|
||||
if self.variant_input.text() != value:
|
||||
self.variant_input.setText(value)
|
||||
|
||||
def _on_variant_change(self, variant_value):
|
||||
if not self._prereq_available or not self._selected_creator:
|
||||
if self.subset_name_input.text():
|
||||
self.subset_name_input.setText("")
|
||||
return
|
||||
|
||||
project_name = self.dbcon.Session["AVALON_PROJECT"]
|
||||
task_name = self.dbcon.Session.get("AVALON_TASK")
|
||||
|
||||
asset_doc = copy.deepcopy(self._asset_doc)
|
||||
# Calculate subset name with Creator plugin
|
||||
subset_name = self._selected_creator.get_subset_name(
|
||||
variant_value, task_name, asset_doc, project_name
|
||||
)
|
||||
self.subset_name_input.setText(subset_name)
|
||||
|
||||
self._validate_subset_name(subset_name, variant_value)
|
||||
|
||||
def _validate_subset_name(self, subset_name, variant_value):
|
||||
# Get all subsets of the current asset
|
||||
if self._subset_names:
|
||||
existing_subset_names = set(self._subset_names)
|
||||
else:
|
||||
existing_subset_names = set()
|
||||
existing_subset_names_low = set(
|
||||
_name.lower()
|
||||
for _name in existing_subset_names
|
||||
)
|
||||
|
||||
# Replace
|
||||
compare_regex = re.compile(re.sub(
|
||||
variant_value, "(.+)", subset_name, flags=re.IGNORECASE
|
||||
))
|
||||
variant_hints = set()
|
||||
if variant_value:
|
||||
for _name in existing_subset_names:
|
||||
_result = compare_regex.search(_name)
|
||||
if _result:
|
||||
variant_hints |= set(_result.groups())
|
||||
|
||||
# Remove previous hints from menu
|
||||
for action in tuple(self.variant_hints_group.actions()):
|
||||
self.variant_hints_group.removeAction(action)
|
||||
self.variant_hints_menu.removeAction(action)
|
||||
action.deleteLater()
|
||||
|
||||
# Add separator if there are hints and menu already has actions
|
||||
if variant_hints and self.variant_hints_menu.actions():
|
||||
self.variant_hints_menu.addSeparator()
|
||||
|
||||
# Add hints to actions
|
||||
for variant_hint in variant_hints:
|
||||
action = self.variant_hints_menu.addAction(variant_hint)
|
||||
self.variant_hints_group.addAction(action)
|
||||
|
||||
# Indicate subset existence
|
||||
if not variant_value:
|
||||
property_value = "empty"
|
||||
|
||||
elif subset_name.lower() in existing_subset_names_low:
|
||||
# validate existence of subset name with lowered text
|
||||
# - "renderMain" vs. "rendermain" mean same path item for
|
||||
# windows
|
||||
property_value = "exists"
|
||||
else:
|
||||
property_value = "new"
|
||||
|
||||
current_value = self.variant_input.property("state")
|
||||
if current_value != property_value:
|
||||
self.variant_input.setProperty("state", property_value)
|
||||
self.variant_input.style().polish(self.variant_input)
|
||||
|
||||
variant_is_valid = variant_value.strip() != ""
|
||||
if variant_is_valid != self.create_btn.isEnabled():
|
||||
self.create_btn.setEnabled(variant_is_valid)
|
||||
|
||||
def moveEvent(self, event):
|
||||
super(CreateDialog, self).moveEvent(event)
|
||||
self._last_pos = self.pos()
|
||||
|
||||
def showEvent(self, event):
|
||||
super(CreateDialog, self).showEvent(event)
|
||||
if self._last_pos is not None:
|
||||
self.move(self._last_pos)
|
||||
|
||||
self.refresh()
|
||||
|
||||
def _on_create(self):
|
||||
indexes = self.family_view.selectedIndexes()
|
||||
if not indexes or len(indexes) > 1:
|
||||
return
|
||||
|
||||
if not self.create_btn.isEnabled():
|
||||
return
|
||||
|
||||
index = indexes[0]
|
||||
family = index.data(QtCore.Qt.DisplayRole)
|
||||
subset_name = self.subset_name_input.text()
|
||||
variant = self.variant_input.text()
|
||||
asset_name = self._asset_doc["name"]
|
||||
task_name = self.dbcon.Session.get("AVALON_TASK")
|
||||
options = {
|
||||
"useSelection": self.use_selection_checkbox.isChecked()
|
||||
}
|
||||
# Where to define these data?
|
||||
# - what data show be stored?
|
||||
instance_data = {
|
||||
"asset": asset_name,
|
||||
"task": task_name,
|
||||
"variant": variant,
|
||||
"family": family
|
||||
}
|
||||
|
||||
error_info = None
|
||||
try:
|
||||
self.controller.create(family, subset_name, instance_data, options)
|
||||
|
||||
except CreatorError as exc:
|
||||
error_info = (str(exc), None)
|
||||
|
||||
except Exception as exc:
|
||||
exc_type, exc_value, exc_traceback = sys.exc_info()
|
||||
formatted_traceback = "".join(traceback.format_exception(
|
||||
exc_type, exc_value, exc_traceback
|
||||
))
|
||||
error_info = (str(exc), formatted_traceback)
|
||||
|
||||
if error_info:
|
||||
box = CreateErrorMessageBox(
|
||||
family, subset_name, asset_name, *error_info
|
||||
)
|
||||
box.show()
|
||||
# Store dialog so is not garbage collected before is shown
|
||||
self.message_dialog = box
|
||||
|
||||
if self.auto_close_checkbox.isChecked():
|
||||
self.hide()
|
||||
|
|
@ -1,12 +1,8 @@
|
|||
import os
|
||||
import sys
|
||||
import re
|
||||
import copy
|
||||
import collections
|
||||
import traceback
|
||||
from Qt import QtWidgets, QtCore, QtGui
|
||||
|
||||
from openpype.pipeline.create import CreatorError
|
||||
from openpype.widgets.attribute_defs import create_widget_for_attr_def
|
||||
from constants import (
|
||||
INSTANCE_ID_ROLE,
|
||||
|
|
@ -15,8 +11,6 @@ from constants import (
|
|||
|
||||
from openpype.tools.flickcharm import FlickCharm
|
||||
|
||||
SEPARATORS = ("---separator---", "---")
|
||||
|
||||
|
||||
def get_default_thumbnail_image_path():
|
||||
dirpath = os.path.dirname(os.path.abspath(__file__))
|
||||
|
|
@ -847,366 +841,6 @@ class ThumbnailWidget(QtWidgets.QWidget):
|
|||
self.current_pix = None
|
||||
|
||||
|
||||
class CreateDialog(QtWidgets.QDialog):
|
||||
def __init__(self, controller, parent=None):
|
||||
super(CreateDialog, self).__init__(parent)
|
||||
|
||||
self.controller = controller
|
||||
|
||||
self._last_pos = None
|
||||
self._asset_doc = None
|
||||
self._subset_names = None
|
||||
self._selected_creator = None
|
||||
|
||||
self._prereq_available = False
|
||||
|
||||
self.message_dialog = None
|
||||
|
||||
family_view = QtWidgets.QListView(self)
|
||||
family_model = QtGui.QStandardItemModel()
|
||||
family_view.setModel(family_model)
|
||||
|
||||
variant_input = QtWidgets.QLineEdit(self)
|
||||
variant_input.setObjectName("VariantInput")
|
||||
|
||||
variant_hints_btn = QtWidgets.QPushButton(self)
|
||||
variant_hints_btn.setFixedWidth(18)
|
||||
|
||||
variant_hints_menu = QtWidgets.QMenu(variant_hints_btn)
|
||||
variant_hints_group = QtWidgets.QActionGroup(variant_hints_menu)
|
||||
variant_hints_btn.setMenu(variant_hints_menu)
|
||||
|
||||
variant_layout = QtWidgets.QHBoxLayout()
|
||||
variant_layout.setContentsMargins(0, 0, 0, 0)
|
||||
variant_layout.setSpacing(0)
|
||||
variant_layout.addWidget(variant_input, 1)
|
||||
variant_layout.addWidget(variant_hints_btn, 0)
|
||||
|
||||
asset_name_input = QtWidgets.QLineEdit(self)
|
||||
asset_name_input.setEnabled(False)
|
||||
|
||||
subset_name_input = QtWidgets.QLineEdit(self)
|
||||
subset_name_input.setEnabled(False)
|
||||
|
||||
checkbox_inputs = QtWidgets.QWidget(self)
|
||||
auto_close_checkbox = QtWidgets.QCheckBox(
|
||||
"Auto-close", checkbox_inputs
|
||||
)
|
||||
use_selection_checkbox = QtWidgets.QCheckBox(
|
||||
"Use selection", checkbox_inputs
|
||||
)
|
||||
|
||||
checkbox_layout = QtWidgets.QHBoxLayout(checkbox_inputs)
|
||||
checkbox_layout.setContentsMargins(0, 0, 0, 0)
|
||||
checkbox_layout.addWidget(auto_close_checkbox)
|
||||
checkbox_layout.addWidget(use_selection_checkbox)
|
||||
|
||||
create_btn = QtWidgets.QPushButton("Create", self)
|
||||
create_btn.setEnabled(False)
|
||||
|
||||
layout = QtWidgets.QVBoxLayout(self)
|
||||
layout.addWidget(QtWidgets.QLabel("Family:", self))
|
||||
layout.addWidget(family_view, 1)
|
||||
layout.addWidget(QtWidgets.QLabel("Asset:", self))
|
||||
layout.addWidget(asset_name_input, 0)
|
||||
layout.addWidget(QtWidgets.QLabel("Name:", self))
|
||||
layout.addLayout(variant_layout, 0)
|
||||
layout.addWidget(QtWidgets.QLabel("Subset:", self))
|
||||
layout.addWidget(subset_name_input, 0)
|
||||
layout.addWidget(checkbox_inputs, 0)
|
||||
layout.addWidget(create_btn, 0)
|
||||
|
||||
create_btn.clicked.connect(self._on_create)
|
||||
variant_input.returnPressed.connect(self._on_create)
|
||||
variant_input.textChanged.connect(self._on_variant_change)
|
||||
family_view.selectionModel().currentChanged.connect(
|
||||
self._on_family_change
|
||||
)
|
||||
variant_hints_menu.triggered.connect(self._on_variant_action)
|
||||
|
||||
controller.add_plugins_refresh_callback(self._on_plugins_refresh)
|
||||
|
||||
self.asset_name_input = asset_name_input
|
||||
self.subset_name_input = subset_name_input
|
||||
|
||||
self.variant_input = variant_input
|
||||
self.variant_hints_btn = variant_hints_btn
|
||||
self.variant_hints_menu = variant_hints_menu
|
||||
self.variant_hints_group = variant_hints_group
|
||||
|
||||
self.family_model = family_model
|
||||
self.family_view = family_view
|
||||
self.auto_close_checkbox = auto_close_checkbox
|
||||
self.use_selection_checkbox = auto_close_checkbox
|
||||
self.create_btn = create_btn
|
||||
|
||||
@property
|
||||
def dbcon(self):
|
||||
return self.controller.dbcon
|
||||
|
||||
def refresh(self):
|
||||
self._prereq_available = True
|
||||
|
||||
# Refresh data before update of creators
|
||||
self._refresh_asset()
|
||||
# Then refresh creators which may trigger callbacks using refreshed
|
||||
# data
|
||||
self._refresh_creators()
|
||||
|
||||
if self._asset_doc is None:
|
||||
self.asset_name_input.setText("< Asset is not set >")
|
||||
self._prereq_available = False
|
||||
|
||||
if self.family_model.rowCount() < 1:
|
||||
self._prereq_available = False
|
||||
|
||||
self.create_btn.setEnabled(self._prereq_available)
|
||||
self.family_view.setEnabled(self._prereq_available)
|
||||
self.variant_input.setEnabled(self._prereq_available)
|
||||
self.variant_hints_btn.setEnabled(self._prereq_available)
|
||||
|
||||
def _refresh_asset(self):
|
||||
asset_name = self.dbcon.Session.get("AVALON_ASSET")
|
||||
|
||||
# Skip if asset did not change
|
||||
if self._asset_doc and self._asset_doc["name"] == asset_name:
|
||||
return
|
||||
|
||||
# Make sure `_asset_doc` and `_subset_names` variables are reset
|
||||
self._asset_doc = None
|
||||
self._subset_names = None
|
||||
if asset_name is None:
|
||||
return
|
||||
|
||||
asset_doc = self.dbcon.find_one({
|
||||
"type": "asset",
|
||||
"name": asset_name
|
||||
})
|
||||
self._asset_doc = asset_doc
|
||||
|
||||
if asset_doc:
|
||||
self.asset_name_input.setText(asset_doc["name"])
|
||||
subset_docs = self.dbcon.find(
|
||||
{
|
||||
"type": "subset",
|
||||
"parent": asset_doc["_id"]
|
||||
},
|
||||
{"name": 1}
|
||||
)
|
||||
self._subset_names = set(subset_docs.distinct("name"))
|
||||
|
||||
def _refresh_creators(self):
|
||||
# Refresh creators and add their families to list
|
||||
existing_items = {}
|
||||
old_families = set()
|
||||
for row in range(self.family_model.rowCount()):
|
||||
item = self.family_model.item(row, 0)
|
||||
family = item.data(QtCore.Qt.DisplayRole)
|
||||
existing_items[family] = item
|
||||
old_families.add(family)
|
||||
|
||||
# Add new families
|
||||
new_families = set()
|
||||
for family, creator in self.controller.creators.items():
|
||||
# TODO add details about creator
|
||||
new_families.add(family)
|
||||
if family not in existing_items:
|
||||
item = QtGui.QStandardItem(family)
|
||||
self.family_model.appendRow(item)
|
||||
|
||||
# Remove families that are no more available
|
||||
for family in (old_families - new_families):
|
||||
item = existing_items[family]
|
||||
self.family_model.takeRow(item.row())
|
||||
|
||||
if self.family_model.rowCount() < 1:
|
||||
return
|
||||
|
||||
# Make sure there is a selection
|
||||
indexes = self.family_view.selectedIndexes()
|
||||
if not indexes:
|
||||
index = self.family_model.index(0, 0)
|
||||
self.family_view.setCurrentIndex(index)
|
||||
|
||||
def _on_plugins_refresh(self):
|
||||
# Trigger refresh only if is visible
|
||||
if self.isVisible():
|
||||
self.refresh()
|
||||
|
||||
def _on_family_change(self, new_index, _old_index):
|
||||
family = None
|
||||
if new_index.isValid():
|
||||
family = new_index.data(QtCore.Qt.DisplayRole)
|
||||
|
||||
creator = self.controller.creators.get(family)
|
||||
self._selected_creator = creator
|
||||
if not creator:
|
||||
return
|
||||
|
||||
default_variants = creator.get_default_variants()
|
||||
if not default_variants:
|
||||
default_variants = ["Main"]
|
||||
|
||||
default_variant = creator.get_default_variant()
|
||||
if not default_variant:
|
||||
default_variant = default_variants[0]
|
||||
|
||||
for action in tuple(self.variant_hints_menu.actions()):
|
||||
self.variant_hints_menu.removeAction(action)
|
||||
action.deleteLater()
|
||||
|
||||
for variant in default_variants:
|
||||
if variant in SEPARATORS:
|
||||
self.variant_hints_menu.addSeparator()
|
||||
elif variant:
|
||||
self.variant_hints_menu.addAction(variant)
|
||||
|
||||
self.variant_input.setText(default_variant or "Main")
|
||||
|
||||
def _on_variant_action(self, action):
|
||||
value = action.text()
|
||||
if self.variant_input.text() != value:
|
||||
self.variant_input.setText(value)
|
||||
|
||||
def _on_variant_change(self, variant_value):
|
||||
if not self._prereq_available or not self._selected_creator:
|
||||
if self.subset_name_input.text():
|
||||
self.subset_name_input.setText("")
|
||||
return
|
||||
|
||||
project_name = self.dbcon.Session["AVALON_PROJECT"]
|
||||
task_name = self.dbcon.Session.get("AVALON_TASK")
|
||||
|
||||
asset_doc = copy.deepcopy(self._asset_doc)
|
||||
# Calculate subset name with Creator plugin
|
||||
subset_name = self._selected_creator.get_subset_name(
|
||||
variant_value, task_name, asset_doc, project_name
|
||||
)
|
||||
self.subset_name_input.setText(subset_name)
|
||||
|
||||
self._validate_subset_name(subset_name, variant_value)
|
||||
|
||||
def _validate_subset_name(self, subset_name, variant_value):
|
||||
# Get all subsets of the current asset
|
||||
if self._subset_names:
|
||||
existing_subset_names = set(self._subset_names)
|
||||
else:
|
||||
existing_subset_names = set()
|
||||
existing_subset_names_low = set(
|
||||
_name.lower()
|
||||
for _name in existing_subset_names
|
||||
)
|
||||
|
||||
# Replace
|
||||
compare_regex = re.compile(re.sub(
|
||||
variant_value, "(.+)", subset_name, flags=re.IGNORECASE
|
||||
))
|
||||
variant_hints = set()
|
||||
if variant_value:
|
||||
for _name in existing_subset_names:
|
||||
_result = compare_regex.search(_name)
|
||||
if _result:
|
||||
variant_hints |= set(_result.groups())
|
||||
|
||||
# Remove previous hints from menu
|
||||
for action in tuple(self.variant_hints_group.actions()):
|
||||
self.variant_hints_group.removeAction(action)
|
||||
self.variant_hints_menu.removeAction(action)
|
||||
action.deleteLater()
|
||||
|
||||
# Add separator if there are hints and menu already has actions
|
||||
if variant_hints and self.variant_hints_menu.actions():
|
||||
self.variant_hints_menu.addSeparator()
|
||||
|
||||
# Add hints to actions
|
||||
for variant_hint in variant_hints:
|
||||
action = self.variant_hints_menu.addAction(variant_hint)
|
||||
self.variant_hints_group.addAction(action)
|
||||
|
||||
# Indicate subset existence
|
||||
if not variant_value:
|
||||
property_value = "empty"
|
||||
|
||||
elif subset_name.lower() in existing_subset_names_low:
|
||||
# validate existence of subset name with lowered text
|
||||
# - "renderMain" vs. "rendermain" mean same path item for
|
||||
# windows
|
||||
property_value = "exists"
|
||||
else:
|
||||
property_value = "new"
|
||||
|
||||
current_value = self.variant_input.property("state")
|
||||
if current_value != property_value:
|
||||
self.variant_input.setProperty("state", property_value)
|
||||
self.variant_input.style().polish(self.variant_input)
|
||||
|
||||
variant_is_valid = variant_value.strip() != ""
|
||||
if variant_is_valid != self.create_btn.isEnabled():
|
||||
self.create_btn.setEnabled(variant_is_valid)
|
||||
|
||||
def moveEvent(self, event):
|
||||
super(CreateDialog, self).moveEvent(event)
|
||||
self._last_pos = self.pos()
|
||||
|
||||
def showEvent(self, event):
|
||||
super(CreateDialog, self).showEvent(event)
|
||||
if self._last_pos is not None:
|
||||
self.move(self._last_pos)
|
||||
|
||||
self.refresh()
|
||||
|
||||
def _on_create(self):
|
||||
indexes = self.family_view.selectedIndexes()
|
||||
if not indexes or len(indexes) > 1:
|
||||
return
|
||||
|
||||
if not self.create_btn.isEnabled():
|
||||
return
|
||||
|
||||
index = indexes[0]
|
||||
family = index.data(QtCore.Qt.DisplayRole)
|
||||
subset_name = self.subset_name_input.text()
|
||||
variant = self.variant_input.text()
|
||||
asset_name = self._asset_doc["name"]
|
||||
task_name = self.dbcon.Session.get("AVALON_TASK")
|
||||
options = {
|
||||
"useSelection": self.use_selection_checkbox.isChecked()
|
||||
}
|
||||
# Where to define these data?
|
||||
# - what data show be stored?
|
||||
instance_data = {
|
||||
"asset": asset_name,
|
||||
"task": task_name,
|
||||
"variant": variant,
|
||||
"family": family
|
||||
}
|
||||
|
||||
error_info = None
|
||||
try:
|
||||
self.controller.create(family, subset_name, instance_data, options)
|
||||
|
||||
except CreatorError as exc:
|
||||
error_info = (str(exc), None)
|
||||
|
||||
except Exception as exc:
|
||||
exc_type, exc_value, exc_traceback = sys.exc_info()
|
||||
formatted_traceback = "".join(traceback.format_exception(
|
||||
exc_type, exc_value, exc_traceback
|
||||
))
|
||||
error_info = (str(exc), formatted_traceback)
|
||||
|
||||
if error_info:
|
||||
box = CreateErrorMessageBox(
|
||||
family, subset_name, asset_name, *error_info
|
||||
)
|
||||
box.show()
|
||||
# Store dialog so is not garbage collected before is shown
|
||||
self.message_dialog = box
|
||||
|
||||
if self.auto_close_checkbox.isChecked():
|
||||
self.hide()
|
||||
|
||||
|
||||
class InstanceCardWidget(QtWidgets.QWidget):
|
||||
active_changed = QtCore.Signal(str, bool)
|
||||
|
||||
|
|
@ -1861,79 +1495,3 @@ class PublishOverlayFrame(QtWidgets.QFrame):
|
|||
|
||||
def set_progress(self, value):
|
||||
self.progress_widget.setValue(value)
|
||||
|
||||
|
||||
class CreateErrorMessageBox(QtWidgets.QDialog):
|
||||
def __init__(
|
||||
self,
|
||||
family,
|
||||
subset_name,
|
||||
asset_name,
|
||||
exc_msg,
|
||||
formatted_traceback,
|
||||
parent=None
|
||||
):
|
||||
super(CreateErrorMessageBox, self).__init__(parent)
|
||||
self.setWindowTitle("Creation failed")
|
||||
self.setFocusPolicy(QtCore.Qt.StrongFocus)
|
||||
if not parent:
|
||||
self.setWindowFlags(
|
||||
self.windowFlags() | QtCore.Qt.WindowStaysOnTopHint
|
||||
)
|
||||
|
||||
body_layout = QtWidgets.QVBoxLayout(self)
|
||||
|
||||
main_label = (
|
||||
"<span style='font-size:18pt;'>Failed to create</span>"
|
||||
)
|
||||
main_label_widget = QtWidgets.QLabel(main_label, self)
|
||||
body_layout.addWidget(main_label_widget)
|
||||
|
||||
item_name_template = (
|
||||
"<span style='font-weight:bold;'>Family:</span> {}<br>"
|
||||
"<span style='font-weight:bold;'>Subset:</span> {}<br>"
|
||||
"<span style='font-weight:bold;'>Asset:</span> {}<br>"
|
||||
)
|
||||
exc_msg_template = "<span style='font-weight:bold'>{}</span>"
|
||||
|
||||
line = self._create_line()
|
||||
body_layout.addWidget(line)
|
||||
|
||||
item_name = item_name_template.format(family, subset_name, asset_name)
|
||||
item_name_widget = QtWidgets.QLabel(
|
||||
item_name.replace("\n", "<br>"), self
|
||||
)
|
||||
body_layout.addWidget(item_name_widget)
|
||||
|
||||
exc_msg = exc_msg_template.format(exc_msg.replace("\n", "<br>"))
|
||||
message_label_widget = QtWidgets.QLabel(exc_msg, self)
|
||||
body_layout.addWidget(message_label_widget)
|
||||
|
||||
if formatted_traceback:
|
||||
tb_widget = QtWidgets.QLabel(
|
||||
formatted_traceback.replace("\n", "<br>"), self
|
||||
)
|
||||
tb_widget.setTextInteractionFlags(
|
||||
QtCore.Qt.TextBrowserInteraction
|
||||
)
|
||||
body_layout.addWidget(tb_widget)
|
||||
|
||||
footer_widget = QtWidgets.QWidget(self)
|
||||
footer_layout = QtWidgets.QHBoxLayout(footer_widget)
|
||||
button_box = QtWidgets.QDialogButtonBox(QtCore.Qt.Vertical)
|
||||
button_box.setStandardButtons(
|
||||
QtWidgets.QDialogButtonBox.StandardButton.Ok
|
||||
)
|
||||
button_box.accepted.connect(self._on_accept)
|
||||
footer_layout.addWidget(button_box, alignment=QtCore.Qt.AlignRight)
|
||||
body_layout.addWidget(footer_widget)
|
||||
|
||||
def _on_accept(self):
|
||||
self.close()
|
||||
|
||||
def _create_line(self):
|
||||
line = QtWidgets.QFrame(self)
|
||||
line.setFixedHeight(2)
|
||||
line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||
return line
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue