fixed few issues in publisher ui

This commit is contained in:
Jakub Trllo 2022-02-21 16:58:01 +01:00
parent f69091bd8c
commit ae4c7a3ab4
6 changed files with 162 additions and 47 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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