mirror of
https://github.com/ynput/ayon-core.git
synced 2026-01-01 16:34:53 +01:00
fixed few issues in publisher ui
This commit is contained in:
parent
f69091bd8c
commit
ae4c7a3ab4
6 changed files with 162 additions and 47 deletions
|
|
@ -42,18 +42,23 @@ class MainThreadProcess(QtCore.QObject):
|
|||
This approach gives ability to update UI meanwhile plugin is in progress.
|
||||
"""
|
||||
|
||||
timer_interval = 3
|
||||
count_timeout = 2
|
||||
|
||||
def __init__(self):
|
||||
super(MainThreadProcess, self).__init__()
|
||||
self._items_to_process = collections.deque()
|
||||
|
||||
timer = QtCore.QTimer()
|
||||
timer.setInterval(self.timer_interval)
|
||||
timer.setInterval(0)
|
||||
|
||||
timer.timeout.connect(self._execute)
|
||||
|
||||
self._timer = timer
|
||||
self._switch_counter = self.count_timeout
|
||||
|
||||
def process(self, func, *args, **kwargs):
|
||||
item = MainThreadItem(func, *args, **kwargs)
|
||||
self.add_item(item)
|
||||
|
||||
def add_item(self, item):
|
||||
self._items_to_process.append(item)
|
||||
|
|
@ -62,6 +67,12 @@ class MainThreadProcess(QtCore.QObject):
|
|||
if not self._items_to_process:
|
||||
return
|
||||
|
||||
if self._switch_counter > 0:
|
||||
self._switch_counter -= 1
|
||||
return
|
||||
|
||||
self._switch_counter = self.count_timeout
|
||||
|
||||
item = self._items_to_process.popleft()
|
||||
item.process()
|
||||
|
||||
|
|
|
|||
|
|
@ -174,6 +174,8 @@ class CreatorDescriptionWidget(QtWidgets.QWidget):
|
|||
|
||||
|
||||
class CreateDialog(QtWidgets.QDialog):
|
||||
default_size = (900, 500)
|
||||
|
||||
def __init__(
|
||||
self, controller, asset_name=None, task_name=None, parent=None
|
||||
):
|
||||
|
|
@ -262,11 +264,16 @@ class CreateDialog(QtWidgets.QDialog):
|
|||
mid_layout.addLayout(form_layout, 0)
|
||||
mid_layout.addWidget(create_btn, 0)
|
||||
|
||||
splitter_widget = QtWidgets.QSplitter(self)
|
||||
splitter_widget.addWidget(context_widget)
|
||||
splitter_widget.addWidget(mid_widget)
|
||||
splitter_widget.addWidget(pre_create_widget)
|
||||
splitter_widget.setStretchFactor(0, 1)
|
||||
splitter_widget.setStretchFactor(1, 1)
|
||||
splitter_widget.setStretchFactor(2, 1)
|
||||
|
||||
layout = QtWidgets.QHBoxLayout(self)
|
||||
layout.setSpacing(10)
|
||||
layout.addWidget(context_widget, 1)
|
||||
layout.addWidget(mid_widget, 1)
|
||||
layout.addWidget(pre_create_widget, 1)
|
||||
layout.addWidget(splitter_widget, 1)
|
||||
|
||||
prereq_timer = QtCore.QTimer()
|
||||
prereq_timer.setInterval(50)
|
||||
|
|
@ -289,6 +296,8 @@ class CreateDialog(QtWidgets.QDialog):
|
|||
|
||||
controller.add_plugins_refresh_callback(self._on_plugins_refresh)
|
||||
|
||||
self._splitter_widget = splitter_widget
|
||||
|
||||
self._pre_create_widget = pre_create_widget
|
||||
|
||||
self._context_widget = context_widget
|
||||
|
|
@ -308,6 +317,7 @@ class CreateDialog(QtWidgets.QDialog):
|
|||
self.create_btn = create_btn
|
||||
|
||||
self._prereq_timer = prereq_timer
|
||||
self._first_show = True
|
||||
|
||||
def _context_change_is_enabled(self):
|
||||
return self._context_widget.isEnabled()
|
||||
|
|
@ -643,6 +653,16 @@ class CreateDialog(QtWidgets.QDialog):
|
|||
|
||||
def showEvent(self, event):
|
||||
super(CreateDialog, self).showEvent(event)
|
||||
if self._first_show:
|
||||
self._first_show = False
|
||||
width, height = self.default_size
|
||||
self.resize(width, height)
|
||||
|
||||
third_size = int(width / 3)
|
||||
self._splitter_widget.setSizes(
|
||||
[third_size, third_size, width - (2 * third_size)]
|
||||
)
|
||||
|
||||
if self._last_pos is not None:
|
||||
self.move(self._last_pos)
|
||||
|
||||
|
|
|
|||
|
|
@ -213,7 +213,6 @@ class PublishFrame(QtWidgets.QFrame):
|
|||
close_report_btn.setIcon(close_report_icon)
|
||||
|
||||
details_layout = QtWidgets.QVBoxLayout(details_widget)
|
||||
details_layout.setContentsMargins(0, 0, 0, 0)
|
||||
details_layout.addWidget(report_view)
|
||||
details_layout.addWidget(close_report_btn)
|
||||
|
||||
|
|
@ -495,10 +494,11 @@ class PublishFrame(QtWidgets.QFrame):
|
|||
def _on_show_details(self):
|
||||
self._change_bg_property(2)
|
||||
self._main_layout.setCurrentWidget(self._details_widget)
|
||||
logs = self.controller.get_publish_report()
|
||||
self._report_view.set_report(logs)
|
||||
report_data = self.controller.get_publish_report()
|
||||
self._report_view.set_report_data(report_data)
|
||||
|
||||
def _on_close_report_clicked(self):
|
||||
self._report_view.close_details_popup()
|
||||
if self.controller.get_publish_crash_error():
|
||||
self._change_bg_property()
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,9 @@ from openpype.tools.utils import BaseClickableFrame
|
|||
from .widgets import (
|
||||
IconValuePixmapLabel
|
||||
)
|
||||
from ..constants import (
|
||||
INSTANCE_ID_ROLE
|
||||
)
|
||||
|
||||
|
||||
class ValidationErrorInstanceList(QtWidgets.QListView):
|
||||
|
|
@ -22,19 +25,20 @@ class ValidationErrorInstanceList(QtWidgets.QListView):
|
|||
|
||||
self.setObjectName("ValidationErrorInstanceList")
|
||||
|
||||
self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
|
||||
self.setSelectionMode(QtWidgets.QListView.ExtendedSelection)
|
||||
|
||||
def minimumSizeHint(self):
|
||||
result = super(ValidationErrorInstanceList, self).minimumSizeHint()
|
||||
result.setHeight(self.sizeHint().height())
|
||||
return result
|
||||
return self.sizeHint()
|
||||
|
||||
def sizeHint(self):
|
||||
result = super(ValidationErrorInstanceList, self).sizeHint()
|
||||
row_count = self.model().rowCount()
|
||||
height = 0
|
||||
if row_count > 0:
|
||||
height = self.sizeHintForRow(0) * row_count
|
||||
return QtCore.QSize(self.width(), height)
|
||||
result.setHeight(height)
|
||||
return result
|
||||
|
||||
|
||||
class ValidationErrorTitleWidget(QtWidgets.QWidget):
|
||||
|
|
@ -47,6 +51,7 @@ class ValidationErrorTitleWidget(QtWidgets.QWidget):
|
|||
if there is a list (Valdation error may happen on context).
|
||||
"""
|
||||
selected = QtCore.Signal(int)
|
||||
instance_changed = QtCore.Signal(int)
|
||||
|
||||
def __init__(self, index, error_info, parent):
|
||||
super(ValidationErrorTitleWidget, self).__init__(parent)
|
||||
|
|
@ -64,32 +69,38 @@ class ValidationErrorTitleWidget(QtWidgets.QWidget):
|
|||
toggle_instance_btn.setArrowType(QtCore.Qt.RightArrow)
|
||||
toggle_instance_btn.setMaximumWidth(14)
|
||||
|
||||
exception = error_info["exception"]
|
||||
label_widget = QtWidgets.QLabel(exception.title, title_frame)
|
||||
label_widget = QtWidgets.QLabel(error_info["title"], title_frame)
|
||||
|
||||
title_frame_layout = QtWidgets.QHBoxLayout(title_frame)
|
||||
title_frame_layout.addWidget(toggle_instance_btn)
|
||||
title_frame_layout.addWidget(label_widget)
|
||||
|
||||
instances_model = QtGui.QStandardItemModel()
|
||||
instances = error_info["instances"]
|
||||
error_info = error_info["error_info"]
|
||||
|
||||
help_text_by_instance_id = {}
|
||||
context_validation = False
|
||||
if (
|
||||
not instances
|
||||
or (len(instances) == 1 and instances[0] is None)
|
||||
not error_info
|
||||
or (len(error_info) == 1 and error_info[0][0] is None)
|
||||
):
|
||||
context_validation = True
|
||||
toggle_instance_btn.setArrowType(QtCore.Qt.NoArrow)
|
||||
description = self._prepare_description(error_info[0][1])
|
||||
help_text_by_instance_id[None] = description
|
||||
else:
|
||||
items = []
|
||||
for instance in instances:
|
||||
for instance, exception in error_info:
|
||||
label = instance.data.get("label") or instance.data.get("name")
|
||||
item = QtGui.QStandardItem(label)
|
||||
item.setFlags(
|
||||
QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable
|
||||
)
|
||||
item.setData(instance.id)
|
||||
item.setData(label, QtCore.Qt.ToolTipRole)
|
||||
item.setData(instance.id, INSTANCE_ID_ROLE)
|
||||
items.append(item)
|
||||
description = self._prepare_description(exception)
|
||||
help_text_by_instance_id[instance.id] = description
|
||||
|
||||
instances_model.invisibleRootItem().appendRows(items)
|
||||
|
||||
|
|
@ -114,17 +125,64 @@ class ValidationErrorTitleWidget(QtWidgets.QWidget):
|
|||
if not context_validation:
|
||||
toggle_instance_btn.clicked.connect(self._on_toggle_btn_click)
|
||||
|
||||
instances_view.selectionModel().selectionChanged.connect(
|
||||
self._on_seleciton_change
|
||||
)
|
||||
|
||||
self._title_frame = title_frame
|
||||
|
||||
self._toggle_instance_btn = toggle_instance_btn
|
||||
|
||||
self._view_layout = view_layout
|
||||
|
||||
self._instances_model = instances_model
|
||||
self._instances_view = instances_view
|
||||
|
||||
self._context_validation = context_validation
|
||||
self._help_text_by_instance_id = help_text_by_instance_id
|
||||
|
||||
def sizeHint(self):
|
||||
result = super().sizeHint()
|
||||
expected_width = 0
|
||||
for idx in range(self._view_layout.count()):
|
||||
expected_width += self._view_layout.itemAt(idx).sizeHint().width()
|
||||
|
||||
if expected_width < 200:
|
||||
expected_width = 200
|
||||
|
||||
if result.width() < expected_width:
|
||||
result.setWidth(expected_width)
|
||||
return result
|
||||
|
||||
def minimumSizeHint(self):
|
||||
return self.sizeHint()
|
||||
|
||||
def _prepare_description(self, exception):
|
||||
dsc = exception.description
|
||||
detail = exception.detail
|
||||
if detail:
|
||||
dsc += "<br/><br/>{}".format(detail)
|
||||
|
||||
description = dsc
|
||||
if commonmark:
|
||||
description = commonmark.commonmark(dsc)
|
||||
return description
|
||||
|
||||
def _mouse_release_callback(self):
|
||||
"""Mark this widget as selected on click."""
|
||||
self.set_selected(True)
|
||||
|
||||
def current_desctiption_text(self):
|
||||
if self._context_validation:
|
||||
return self._help_text_by_instance_id[None]
|
||||
index = self._instances_view.currentIndex()
|
||||
# TODO make sure instance is selected
|
||||
if not index.isValid():
|
||||
index = self._instances_model.index(0, 0)
|
||||
|
||||
indence_id = index.data(INSTANCE_ID_ROLE)
|
||||
return self._help_text_by_instance_id[indence_id]
|
||||
|
||||
@property
|
||||
def is_selected(self):
|
||||
"""Is widget marked a selected"""
|
||||
|
|
@ -167,6 +225,9 @@ class ValidationErrorTitleWidget(QtWidgets.QWidget):
|
|||
else:
|
||||
self._toggle_instance_btn.setArrowType(QtCore.Qt.RightArrow)
|
||||
|
||||
def _on_seleciton_change(self):
|
||||
self.instance_changed.emit(self._index)
|
||||
|
||||
|
||||
class ActionButton(BaseClickableFrame):
|
||||
"""Plugin's action callback button.
|
||||
|
|
@ -185,13 +246,15 @@ class ActionButton(BaseClickableFrame):
|
|||
action_label = action.label or action.__name__
|
||||
action_icon = getattr(action, "icon", None)
|
||||
label_widget = QtWidgets.QLabel(action_label, self)
|
||||
icon_label = None
|
||||
if action_icon:
|
||||
icon_label = IconValuePixmapLabel(action_icon, self)
|
||||
|
||||
layout = QtWidgets.QHBoxLayout(self)
|
||||
layout.setContentsMargins(5, 0, 5, 0)
|
||||
layout.addWidget(label_widget, 1)
|
||||
layout.addWidget(icon_label, 0)
|
||||
if icon_label:
|
||||
layout.addWidget(icon_label, 0)
|
||||
|
||||
self.setSizePolicy(
|
||||
QtWidgets.QSizePolicy.Minimum,
|
||||
|
|
@ -231,6 +294,7 @@ class ValidateActionsWidget(QtWidgets.QFrame):
|
|||
item = self._content_layout.takeAt(0)
|
||||
widget = item.widget()
|
||||
if widget:
|
||||
widget.setVisible(False)
|
||||
widget.deleteLater()
|
||||
self._actions_mapping = {}
|
||||
|
||||
|
|
@ -363,24 +427,23 @@ class ValidationsWidget(QtWidgets.QWidget):
|
|||
errors_scroll.setWidgetResizable(True)
|
||||
|
||||
errors_widget = QtWidgets.QWidget(errors_scroll)
|
||||
errors_widget.setFixedWidth(200)
|
||||
errors_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground)
|
||||
errors_layout = QtWidgets.QVBoxLayout(errors_widget)
|
||||
errors_layout.setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
errors_scroll.setWidget(errors_widget)
|
||||
|
||||
error_details_widget = QtWidgets.QWidget(self)
|
||||
error_details_input = QtWidgets.QTextEdit(error_details_widget)
|
||||
error_details_frame = QtWidgets.QFrame(self)
|
||||
error_details_input = QtWidgets.QTextEdit(error_details_frame)
|
||||
error_details_input.setObjectName("InfoText")
|
||||
error_details_input.setTextInteractionFlags(
|
||||
QtCore.Qt.TextBrowserInteraction
|
||||
)
|
||||
|
||||
actions_widget = ValidateActionsWidget(controller, self)
|
||||
actions_widget.setFixedWidth(140)
|
||||
actions_widget.setMinimumWidth(140)
|
||||
|
||||
error_details_layout = QtWidgets.QHBoxLayout(error_details_widget)
|
||||
error_details_layout = QtWidgets.QHBoxLayout(error_details_frame)
|
||||
error_details_layout.addWidget(error_details_input, 1)
|
||||
error_details_layout.addWidget(actions_widget, 0)
|
||||
|
||||
|
|
@ -389,7 +452,7 @@ class ValidationsWidget(QtWidgets.QWidget):
|
|||
content_layout.setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
content_layout.addWidget(errors_scroll, 0)
|
||||
content_layout.addWidget(error_details_widget, 1)
|
||||
content_layout.addWidget(error_details_frame, 1)
|
||||
|
||||
top_label = QtWidgets.QLabel("Publish validation report", self)
|
||||
top_label.setObjectName("PublishInfoMainLabel")
|
||||
|
|
@ -403,7 +466,7 @@ class ValidationsWidget(QtWidgets.QWidget):
|
|||
self._top_label = top_label
|
||||
self._errors_widget = errors_widget
|
||||
self._errors_layout = errors_layout
|
||||
self._error_details_widget = error_details_widget
|
||||
self._error_details_frame = error_details_frame
|
||||
self._error_details_input = error_details_input
|
||||
self._actions_widget = actions_widget
|
||||
|
||||
|
|
@ -423,7 +486,7 @@ class ValidationsWidget(QtWidgets.QWidget):
|
|||
widget.deleteLater()
|
||||
|
||||
self._top_label.setVisible(False)
|
||||
self._error_details_widget.setVisible(False)
|
||||
self._error_details_frame.setVisible(False)
|
||||
self._errors_widget.setVisible(False)
|
||||
self._actions_widget.setVisible(False)
|
||||
|
||||
|
|
@ -434,34 +497,35 @@ class ValidationsWidget(QtWidgets.QWidget):
|
|||
return
|
||||
|
||||
self._top_label.setVisible(True)
|
||||
self._error_details_widget.setVisible(True)
|
||||
self._error_details_frame.setVisible(True)
|
||||
self._errors_widget.setVisible(True)
|
||||
|
||||
errors_by_title = []
|
||||
for plugin_info in errors:
|
||||
titles = []
|
||||
exception_by_title = {}
|
||||
instances_by_title = {}
|
||||
error_info_by_title = {}
|
||||
|
||||
for error_info in plugin_info["errors"]:
|
||||
exception = error_info["exception"]
|
||||
title = exception.title
|
||||
if title not in titles:
|
||||
titles.append(title)
|
||||
instances_by_title[title] = []
|
||||
exception_by_title[title] = exception
|
||||
instances_by_title[title].append(error_info["instance"])
|
||||
error_info_by_title[title] = []
|
||||
error_info_by_title[title].append(
|
||||
(error_info["instance"], exception)
|
||||
)
|
||||
|
||||
for title in titles:
|
||||
errors_by_title.append({
|
||||
"plugin": plugin_info["plugin"],
|
||||
"exception": exception_by_title[title],
|
||||
"instances": instances_by_title[title]
|
||||
"error_info": error_info_by_title[title],
|
||||
"title": title
|
||||
})
|
||||
|
||||
for idx, item in enumerate(errors_by_title):
|
||||
widget = ValidationErrorTitleWidget(idx, item, self)
|
||||
widget.selected.connect(self._on_select)
|
||||
widget.instance_changed.connect(self._on_instance_change)
|
||||
self._errors_layout.addWidget(widget)
|
||||
self._title_widgets[idx] = widget
|
||||
self._error_info[idx] = item
|
||||
|
|
@ -471,6 +535,8 @@ class ValidationsWidget(QtWidgets.QWidget):
|
|||
if self._title_widgets:
|
||||
self._title_widgets[0].set_selected(True)
|
||||
|
||||
self.updateGeometry()
|
||||
|
||||
def _on_select(self, index):
|
||||
if self._previous_select:
|
||||
if self._previous_select.index == index:
|
||||
|
|
@ -481,10 +547,19 @@ class ValidationsWidget(QtWidgets.QWidget):
|
|||
|
||||
error_item = self._error_info[index]
|
||||
|
||||
dsc = error_item["exception"].description
|
||||
self._actions_widget.set_plugin(error_item["plugin"])
|
||||
|
||||
self._update_description()
|
||||
|
||||
def _on_instance_change(self, index):
|
||||
if self._previous_select and self._previous_select.index != index:
|
||||
return
|
||||
self._update_description()
|
||||
|
||||
def _update_description(self):
|
||||
description = self._previous_select.current_desctiption_text()
|
||||
if commonmark:
|
||||
html = commonmark.commonmark(dsc)
|
||||
html = commonmark.commonmark(description)
|
||||
self._error_details_input.setHtml(html)
|
||||
else:
|
||||
self._error_details_input.setMarkdown(dsc)
|
||||
self._actions_widget.set_plugin(error_item["plugin"])
|
||||
self._error_details_input.setMarkdown(description)
|
||||
|
|
|
|||
|
|
@ -535,6 +535,7 @@ class TasksCombobox(QtWidgets.QComboBox):
|
|||
return
|
||||
|
||||
self._text = text
|
||||
self.repaint()
|
||||
|
||||
def paintEvent(self, event):
|
||||
"""Paint custom text without using QLineEdit.
|
||||
|
|
@ -548,6 +549,7 @@ class TasksCombobox(QtWidgets.QComboBox):
|
|||
self.initStyleOption(opt)
|
||||
if self._text is not None:
|
||||
opt.currentText = self._text
|
||||
|
||||
style = self.style()
|
||||
style.drawComplexControl(
|
||||
QtWidgets.QStyle.CC_ComboBox, opt, painter, self
|
||||
|
|
@ -609,11 +611,15 @@ class TasksCombobox(QtWidgets.QComboBox):
|
|||
if self._selected_items:
|
||||
is_valid = True
|
||||
|
||||
valid_task_names = []
|
||||
for task_name in self._selected_items:
|
||||
is_valid = self._model.is_task_name_valid(asset_name, task_name)
|
||||
if not is_valid:
|
||||
break
|
||||
_is_valid = self._model.is_task_name_valid(asset_name, task_name)
|
||||
if _is_valid:
|
||||
valid_task_names.append(task_name)
|
||||
else:
|
||||
is_valid = _is_valid
|
||||
|
||||
self._selected_items = valid_task_names
|
||||
if len(self._selected_items) == 0:
|
||||
self.set_selected_item("")
|
||||
|
||||
|
|
@ -625,6 +631,7 @@ class TasksCombobox(QtWidgets.QComboBox):
|
|||
if multiselection_text is None:
|
||||
multiselection_text = "|".join(self._selected_items)
|
||||
self.set_selected_item(multiselection_text)
|
||||
|
||||
self._set_is_valid(is_valid)
|
||||
|
||||
def set_selected_items(self, asset_task_combinations=None):
|
||||
|
|
@ -708,8 +715,7 @@ class TasksCombobox(QtWidgets.QComboBox):
|
|||
idx = self.findText(item_name)
|
||||
# Set current index (must be set to -1 if is invalid)
|
||||
self.setCurrentIndex(idx)
|
||||
if idx < 0:
|
||||
self.set_text(item_name)
|
||||
self.set_text(item_name)
|
||||
|
||||
def reset_to_origin(self):
|
||||
"""Change to task names set with last `set_selected_items` call."""
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ class PublisherWindow(QtWidgets.QDialog):
|
|||
|
||||
# Content
|
||||
# Subset widget
|
||||
subset_frame = QtWidgets.QWidget(self)
|
||||
subset_frame = QtWidgets.QFrame(self)
|
||||
|
||||
subset_views_widget = BorderedLabelWidget(
|
||||
"Subsets to publish", subset_frame
|
||||
|
|
@ -225,6 +225,9 @@ class PublisherWindow(QtWidgets.QDialog):
|
|||
controller.add_publish_validated_callback(self._on_publish_validated)
|
||||
controller.add_publish_stopped_callback(self._on_publish_stop)
|
||||
|
||||
# Store header for TrayPublisher
|
||||
self._header_layout = header_layout
|
||||
|
||||
self.content_stacked_layout = content_stacked_layout
|
||||
self.publish_frame = publish_frame
|
||||
self.subset_frame = subset_frame
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue