mirror of
https://github.com/ynput/ayon-core.git
synced 2026-01-02 08:54:53 +01:00
changed select context dialog
This commit is contained in:
parent
5d4be57504
commit
4c43acde9d
2 changed files with 717 additions and 53 deletions
|
|
@ -1,17 +1,42 @@
|
|||
import re
|
||||
import collections
|
||||
from openpype.client import get_projects, get_assets
|
||||
|
||||
from openpype.client import (
|
||||
get_projects,
|
||||
get_assets,
|
||||
get_asset_by_id,
|
||||
get_subset_by_id,
|
||||
get_version_by_id,
|
||||
get_representations,
|
||||
)
|
||||
from openpype.settings import get_project_settings
|
||||
from openpype.lib import prepare_template_data
|
||||
from openpype.lib.events import EventSystem
|
||||
from openpype.pipeline.create import (
|
||||
SUBSET_NAME_ALLOWED_SYMBOLS,
|
||||
get_subset_name_template,
|
||||
)
|
||||
|
||||
|
||||
class AssetItem:
|
||||
def __init__(self, entity_id, name, icon, parent_id):
|
||||
def __init__(
|
||||
self,
|
||||
entity_id,
|
||||
name,
|
||||
icon_name,
|
||||
icon_color,
|
||||
parent_id,
|
||||
has_children
|
||||
):
|
||||
self.id = entity_id
|
||||
self.name = name
|
||||
self.icon = icon
|
||||
self.icon_name = icon_name
|
||||
self.icon_color = icon_color
|
||||
self.parent_id = parent_id
|
||||
self.has_children = has_children
|
||||
|
||||
@classmethod
|
||||
def from_doc(cls, asset_doc):
|
||||
def from_doc(cls, asset_doc, has_children=True):
|
||||
parent_id = asset_doc["data"].get("visualParent")
|
||||
if parent_id is not None:
|
||||
parent_id = str(parent_id)
|
||||
|
|
@ -19,7 +44,9 @@ class AssetItem:
|
|||
str(asset_doc["_id"]),
|
||||
asset_doc["name"],
|
||||
asset_doc["data"].get("icon"),
|
||||
parent_id
|
||||
asset_doc["data"].get("color"),
|
||||
parent_id,
|
||||
has_children
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -76,6 +103,9 @@ class EntitiesModel:
|
|||
self.refresh_assets(project_name)
|
||||
return dict(self._assets_by_project[project_name])
|
||||
|
||||
def get_asset_by_id(self, project_name, asset_id):
|
||||
return self._assets_by_project[project_name].get(asset_id)
|
||||
|
||||
def get_tasks(self, project_name, asset_id):
|
||||
if not project_name or not asset_id:
|
||||
return []
|
||||
|
|
@ -85,6 +115,8 @@ class EntitiesModel:
|
|||
|
||||
all_task_items = self._tasks_by_asset_id[project_name]
|
||||
asset_task_items = all_task_items.get(asset_id)
|
||||
if not asset_task_items:
|
||||
return []
|
||||
return list(asset_task_items)
|
||||
|
||||
def refresh_projects(self, force=False):
|
||||
|
|
@ -113,12 +145,25 @@ class EntitiesModel:
|
|||
return
|
||||
|
||||
project_doc = self._project_docs_by_name[project_name]
|
||||
asset_docs_by_parent_id = collections.defaultdict(list)
|
||||
for asset_doc in get_assets(project_name):
|
||||
asset_item = AssetItem.from_doc(asset_doc)
|
||||
parent_id = asset_doc["data"].get("visualParent")
|
||||
asset_docs_by_parent_id[parent_id].append(asset_doc)
|
||||
|
||||
hierarchy_queue = collections.deque()
|
||||
for asset_doc in asset_docs_by_parent_id[None]:
|
||||
hierarchy_queue.append(asset_doc)
|
||||
|
||||
while hierarchy_queue:
|
||||
asset_doc = hierarchy_queue.popleft()
|
||||
children = asset_docs_by_parent_id[asset_doc["_id"]]
|
||||
asset_item = AssetItem.from_doc(asset_doc, len(children) > 0)
|
||||
asset_items_by_id[asset_item.id] = asset_item
|
||||
task_items_by_asset_id[asset_item.id] = (
|
||||
TaskItem.from_asset_doc(asset_doc, project_doc)
|
||||
)
|
||||
for child in children:
|
||||
hierarchy_queue.append(child)
|
||||
|
||||
def refresh_assets(self, project_name, force=False):
|
||||
self._event_system.emit(
|
||||
|
|
@ -184,21 +229,330 @@ class SelectionModel:
|
|||
)
|
||||
|
||||
|
||||
class RepublisherDialogController:
|
||||
def __init__(self):
|
||||
class UserPublishValues:
|
||||
"""Helper object to validate values required for push to different project.
|
||||
|
||||
Args:
|
||||
event_system (EventSystem): Event system to catch and emit events.
|
||||
new_asset_name (str): Name of new asset name.
|
||||
variant (str): Variant for new subset name in new project.
|
||||
"""
|
||||
|
||||
asset_name_regex = re.compile("^[a-zA-Z0-9_.]+$")
|
||||
variant_regex = re.compile("^[{}]+$".format(SUBSET_NAME_ALLOWED_SYMBOLS))
|
||||
|
||||
def __init__(self, event_system):
|
||||
self._event_system = event_system
|
||||
self._new_asset_name = None
|
||||
self._variant = None
|
||||
self._comment = None
|
||||
self._is_variant_valid = False
|
||||
self._is_new_asset_name_valid = False
|
||||
|
||||
self.set_new_asset("")
|
||||
self.set_variant("")
|
||||
self.set_comment("")
|
||||
|
||||
@property
|
||||
def new_asset_name(self):
|
||||
return self._new_asset_name
|
||||
|
||||
@property
|
||||
def variant(self):
|
||||
return self._variant
|
||||
|
||||
@property
|
||||
def comment(self):
|
||||
return self._comment
|
||||
|
||||
@property
|
||||
def is_variant_valid(self):
|
||||
return self._is_variant_valid
|
||||
|
||||
@property
|
||||
def is_new_asset_name_valid(self):
|
||||
return self._is_new_asset_name_valid
|
||||
|
||||
@property
|
||||
def is_valid(self):
|
||||
return self.is_variant_valid and self.is_new_asset_name_valid
|
||||
|
||||
def set_variant(self, variant):
|
||||
if variant == self._variant:
|
||||
return
|
||||
|
||||
old_variant = self._variant
|
||||
old_is_valid = self._is_variant_valid
|
||||
|
||||
self._variant = variant
|
||||
is_valid = False
|
||||
if variant:
|
||||
is_valid = self.variant_regex.match(variant) is not None
|
||||
self._is_variant_valid = is_valid
|
||||
|
||||
changes = {
|
||||
key: {"new": new, "old": old}
|
||||
for key, old, new in (
|
||||
("variant", old_variant, variant),
|
||||
("is_valid", old_is_valid, is_valid)
|
||||
)
|
||||
}
|
||||
|
||||
self._event_system.emit(
|
||||
"variant.changed",
|
||||
{
|
||||
"variant": variant,
|
||||
"is_valid": self._is_variant_valid,
|
||||
"changes": changes
|
||||
},
|
||||
"user_values"
|
||||
)
|
||||
|
||||
def set_new_asset(self, asset_name):
|
||||
if self._new_asset_name == asset_name:
|
||||
return
|
||||
old_asset_name = self._new_asset_name
|
||||
old_is_valid = self._is_new_asset_name_valid
|
||||
self._new_asset_name = asset_name
|
||||
is_valid = True
|
||||
if asset_name:
|
||||
is_valid = (
|
||||
self.asset_name_regex.match(asset_name) is not None
|
||||
)
|
||||
self._is_new_asset_name_valid = is_valid
|
||||
changes = {
|
||||
key: {"new": new, "old": old}
|
||||
for key, old, new in (
|
||||
("new_asset_name", old_asset_name, asset_name),
|
||||
("is_valid", old_is_valid, is_valid)
|
||||
)
|
||||
}
|
||||
|
||||
self._event_system.emit(
|
||||
"new_asset_name.changed",
|
||||
{
|
||||
"new_asset_name": self._new_asset_name,
|
||||
"is_valid": self._is_new_asset_name_valid,
|
||||
"changes": changes
|
||||
},
|
||||
"user_values"
|
||||
)
|
||||
|
||||
def set_comment(self, comment):
|
||||
if comment == self._comment:
|
||||
return
|
||||
old_comment = self._comment
|
||||
self._comment = comment
|
||||
self._event_system.emit(
|
||||
"comment.changed",
|
||||
{
|
||||
"new_asset_name": comment,
|
||||
"changes": {
|
||||
"comment": {"new": comment, "old": old_comment}
|
||||
}
|
||||
},
|
||||
"user_values"
|
||||
)
|
||||
|
||||
|
||||
class PushToContextController:
|
||||
def __init__(self, project_name=None, version_id=None):
|
||||
self._src_project_name = None
|
||||
self._src_version_id = None
|
||||
self._src_asset_doc = None
|
||||
self._src_subset_doc = None
|
||||
self._src_version_doc = None
|
||||
|
||||
event_system = EventSystem()
|
||||
entities_model = EntitiesModel(event_system)
|
||||
selection_model = SelectionModel(event_system)
|
||||
user_values = UserPublishValues(event_system)
|
||||
|
||||
self._event_system = event_system
|
||||
self._entities_model = entities_model
|
||||
self._selection_model = selection_model
|
||||
|
||||
self.dst_project_name = None
|
||||
self.dst_asset_id = None
|
||||
self.dst_task_name = None
|
||||
self._user_values = user_values
|
||||
|
||||
event_system.add_callback("project.changed", self._on_project_change)
|
||||
event_system.add_callback("asset.changed", self._invalidate)
|
||||
event_system.add_callback("variant.changed", self._invalidate)
|
||||
event_system.add_callback("new_asset_name.changed", self._invalidate)
|
||||
|
||||
self._submission_enabled = False
|
||||
|
||||
self.set_source(project_name, version_id)
|
||||
|
||||
def _get_task_info_from_repre_docs(self, asset_doc, repre_docs):
|
||||
asset_tasks = asset_doc["data"].get("tasks") or {}
|
||||
found_comb = []
|
||||
for repre_doc in repre_docs:
|
||||
context = repre_doc["context"]
|
||||
task_info = context.get("task")
|
||||
if task_info is None:
|
||||
continue
|
||||
|
||||
task_name = None
|
||||
task_type = None
|
||||
if isinstance(task_info, str):
|
||||
task_name = task_info
|
||||
asset_task_info = asset_tasks.get(task_info) or {}
|
||||
task_type = asset_task_info.get("type")
|
||||
|
||||
elif isinstance(task_info, dict):
|
||||
task_name = task_info.get("name")
|
||||
task_type = task_info.get("type")
|
||||
|
||||
if task_name and task_type:
|
||||
return task_name, task_type
|
||||
|
||||
if task_name:
|
||||
found_comb.append((task_name, task_type))
|
||||
|
||||
for task_name, task_type in found_comb:
|
||||
return task_name, task_type
|
||||
return None, None
|
||||
|
||||
def _get_src_variant(self):
|
||||
project_name = self._src_project_name
|
||||
version_doc = self._src_version_doc
|
||||
asset_doc = self._src_asset_doc
|
||||
repre_docs = get_representations(
|
||||
project_name, version_ids=[version_doc["_id"]]
|
||||
)
|
||||
task_name, task_type = self._get_task_info_from_repre_docs(
|
||||
asset_doc, repre_docs
|
||||
)
|
||||
|
||||
project_settings = get_project_settings(project_name)
|
||||
subset_doc = self.src_subset_doc
|
||||
family = subset_doc["data"].get("family")
|
||||
if not family:
|
||||
family = subset_doc["data"]["families"][0]
|
||||
template = get_subset_name_template(
|
||||
self._src_project_name,
|
||||
family,
|
||||
task_name,
|
||||
task_type,
|
||||
None,
|
||||
project_settings=project_settings
|
||||
)
|
||||
template_low = template.lower()
|
||||
variant_placeholder = "{variant}"
|
||||
if (
|
||||
variant_placeholder not in template_low
|
||||
or (not task_name and "{task" in template_low)
|
||||
):
|
||||
return ""
|
||||
|
||||
idx = template_low.index(variant_placeholder)
|
||||
template_s = template[:idx]
|
||||
template_e = template[idx + len(variant_placeholder):]
|
||||
fill_data = prepare_template_data({
|
||||
"family": family,
|
||||
"task": task_name
|
||||
})
|
||||
try:
|
||||
subset_s = template_s.format(**fill_data)
|
||||
subset_e = template_e.format(**fill_data)
|
||||
except Exception as exc:
|
||||
print("Failed format", exc)
|
||||
return ""
|
||||
|
||||
subset_name = self.src_subset_doc["name"]
|
||||
if (
|
||||
(subset_s and not subset_name.startswith(subset_s))
|
||||
or (subset_e and not subset_name.endswith(subset_e))
|
||||
):
|
||||
return ""
|
||||
|
||||
if subset_s:
|
||||
subset_name = subset_name[len(subset_s):]
|
||||
if subset_e:
|
||||
subset_name = subset_name[:len(subset_e)]
|
||||
return subset_name
|
||||
|
||||
def set_source(self, project_name, version_id):
|
||||
if (
|
||||
project_name == self._src_project_name
|
||||
and version_id == self._src_version_id
|
||||
):
|
||||
return
|
||||
|
||||
self._src_project_name = project_name
|
||||
self._src_version_id = version_id
|
||||
asset_doc = None
|
||||
subset_doc = None
|
||||
version_doc = None
|
||||
if project_name and version_id:
|
||||
version_doc = get_version_by_id(project_name, version_id)
|
||||
|
||||
if version_doc:
|
||||
subset_doc = get_subset_by_id(project_name, version_doc["parent"])
|
||||
|
||||
if subset_doc:
|
||||
asset_doc = get_asset_by_id(project_name, subset_doc["parent"])
|
||||
|
||||
self._src_asset_doc = asset_doc
|
||||
self._src_subset_doc = subset_doc
|
||||
self._src_version_doc = version_doc
|
||||
if asset_doc:
|
||||
self.user_values.set_new_asset(asset_doc["name"])
|
||||
variant = self._get_src_variant()
|
||||
if variant:
|
||||
self.user_values.set_variant(variant)
|
||||
|
||||
comment = version_doc["data"].get("comment")
|
||||
if comment:
|
||||
self.user_values.set_comment(comment)
|
||||
|
||||
self._event_system.emit(
|
||||
"source.changed", {
|
||||
"project_name": project_name,
|
||||
"version_id": version_id
|
||||
},
|
||||
"controller"
|
||||
)
|
||||
|
||||
@property
|
||||
def src_project_name(self):
|
||||
return self._src_project_name
|
||||
|
||||
@property
|
||||
def src_version_id(self):
|
||||
return self._src_version_id
|
||||
|
||||
@property
|
||||
def src_label(self):
|
||||
if not self._src_project_name or not self._src_version_id:
|
||||
return "Source is not defined"
|
||||
|
||||
asset_doc = self.src_asset_doc
|
||||
if not asset_doc:
|
||||
return "Source is invalid"
|
||||
|
||||
asset_path_parts = list(asset_doc["data"]["parents"])
|
||||
asset_path_parts.append(asset_doc["name"])
|
||||
asset_path = "/".join(asset_path_parts)
|
||||
subset_doc = self.src_subset_doc
|
||||
version_doc = self.src_version_doc
|
||||
return "Source: {}/{}/{}/v{:0>3}".format(
|
||||
self._src_project_name,
|
||||
asset_path,
|
||||
subset_doc["name"],
|
||||
version_doc["name"]
|
||||
)
|
||||
|
||||
@property
|
||||
def src_version_doc(self):
|
||||
return self._src_version_doc
|
||||
|
||||
@property
|
||||
def src_subset_doc(self):
|
||||
return self._src_subset_doc
|
||||
|
||||
@property
|
||||
def src_asset_doc(self):
|
||||
return self._src_asset_doc
|
||||
|
||||
@property
|
||||
def event_system(self):
|
||||
|
|
@ -212,11 +566,60 @@ class RepublisherDialogController:
|
|||
def selection_model(self):
|
||||
return self._selection_model
|
||||
|
||||
@property
|
||||
def user_values(self):
|
||||
return self._user_values
|
||||
|
||||
@property
|
||||
def submission_enabled(self):
|
||||
return self._submission_enabled
|
||||
|
||||
def _on_project_change(self, event):
|
||||
project_name = event["project_name"]
|
||||
self.model.refresh_assets(project_name)
|
||||
self._invalidate()
|
||||
|
||||
def _invalidate(self):
|
||||
submission_enabled = self._check_submit_validations()
|
||||
if submission_enabled == self._submission_enabled:
|
||||
return
|
||||
self._submission_enabled = submission_enabled
|
||||
self._event_system.emit(
|
||||
"submission.enabled.changed",
|
||||
{"enabled": submission_enabled},
|
||||
"controller"
|
||||
)
|
||||
|
||||
def _check_submit_validations(self):
|
||||
if not self._user_values.is_valid:
|
||||
return False
|
||||
|
||||
if not self.selection_model.project_name:
|
||||
return False
|
||||
|
||||
if (
|
||||
not self._user_values.new_asset_name
|
||||
and not self.selection_model.asset_id
|
||||
):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def get_selected_asset_name(self):
|
||||
project_name = self._selection_model.project_name
|
||||
asset_id = self._selection_model.asset_id
|
||||
if not project_name or not asset_id:
|
||||
return None
|
||||
asset_item = self._entities_model.get_asset_by_id(
|
||||
project_name, asset_id
|
||||
)
|
||||
if asset_item:
|
||||
return asset_item.name
|
||||
return None
|
||||
|
||||
def submit(self):
|
||||
if not self.submission_enabled:
|
||||
return
|
||||
project_name = self.selection_model.project_name
|
||||
asset_id = self.selection_model.asset_id
|
||||
task_name = self.selection_model.task_name
|
||||
|
|
|
|||
|
|
@ -1,17 +1,23 @@
|
|||
import re
|
||||
import collections
|
||||
|
||||
from qtpy import QtWidgets, QtGui, QtCore
|
||||
|
||||
from openpype.style import load_stylesheet
|
||||
from openpype.style import load_stylesheet, get_app_icon_path
|
||||
from openpype.tools.utils import (
|
||||
PlaceholderLineEdit,
|
||||
SeparatorWidget,
|
||||
get_asset_icon_by_name,
|
||||
set_style_property,
|
||||
)
|
||||
|
||||
from .control import RepublisherDialogController
|
||||
from .control import PushToContextController
|
||||
|
||||
PROJECT_NAME_ROLE = QtCore.Qt.UserRole + 1
|
||||
ASSET_NAME_ROLE = QtCore.Qt.UserRole + 2
|
||||
ASSET_ICON_ROLE = QtCore.Qt.UserRole + 3
|
||||
ASSET_ID_ROLE = QtCore.Qt.UserRole + 4
|
||||
TASK_NAME_ROLE = QtCore.Qt.UserRole + 5
|
||||
TASK_TYPE_ROLE = QtCore.Qt.UserRole + 6
|
||||
ASSET_ID_ROLE = QtCore.Qt.UserRole + 3
|
||||
TASK_NAME_ROLE = QtCore.Qt.UserRole + 4
|
||||
TASK_TYPE_ROLE = QtCore.Qt.UserRole + 5
|
||||
|
||||
|
||||
class ProjectsModel(QtGui.QStandardItemModel):
|
||||
|
|
@ -19,6 +25,8 @@ class ProjectsModel(QtGui.QStandardItemModel):
|
|||
refreshing_text = "< Refreshing >"
|
||||
select_project_text = "< Select Project >"
|
||||
|
||||
refreshed = QtCore.Signal()
|
||||
|
||||
def __init__(self, controller):
|
||||
super(ProjectsModel, self).__init__()
|
||||
self._controller = controller
|
||||
|
|
@ -59,7 +67,7 @@ class ProjectsModel(QtGui.QStandardItemModel):
|
|||
if project_name is None:
|
||||
continue
|
||||
item = self._items.pop(project_name)
|
||||
root_item.removeRow(item.row())
|
||||
root_item.takeRow(item.row())
|
||||
|
||||
for project_name in project_names:
|
||||
if project_name in self._items:
|
||||
|
|
@ -70,6 +78,7 @@ class ProjectsModel(QtGui.QStandardItemModel):
|
|||
|
||||
if new_items:
|
||||
root_item.appendRows(new_items)
|
||||
self.refreshed.emit()
|
||||
|
||||
|
||||
class ProjectProxyModel(QtCore.QSortFilterProxyModel):
|
||||
|
|
@ -94,6 +103,7 @@ class ProjectProxyModel(QtCore.QSortFilterProxyModel):
|
|||
|
||||
|
||||
class AssetsModel(QtGui.QStandardItemModel):
|
||||
items_changed = QtCore.Signal()
|
||||
empty_text = "< Empty >"
|
||||
|
||||
def __init__(self, controller):
|
||||
|
|
@ -151,6 +161,7 @@ class AssetsModel(QtGui.QStandardItemModel):
|
|||
|
||||
self._last_project = project_name
|
||||
self._clear()
|
||||
self.items_changed.emit()
|
||||
|
||||
def _on_refresh_start(self, event):
|
||||
pass
|
||||
|
|
@ -165,11 +176,13 @@ class AssetsModel(QtGui.QStandardItemModel):
|
|||
if project_name is None:
|
||||
if None not in self._items:
|
||||
self._clear()
|
||||
self.items_changed.emit()
|
||||
return
|
||||
|
||||
asset_items_by_id = self._controller.model.get_assets(project_name)
|
||||
if not asset_items_by_id:
|
||||
self._clear()
|
||||
self.items_changed.emit()
|
||||
return
|
||||
|
||||
assets_by_parent_id = collections.defaultdict(list)
|
||||
|
|
@ -201,9 +214,12 @@ class AssetsModel(QtGui.QStandardItemModel):
|
|||
elif item.parent() is not parent_item:
|
||||
new_items.append(item)
|
||||
|
||||
icon = get_asset_icon_by_name(
|
||||
asset_item.icon_name, asset_item.icon_color
|
||||
)
|
||||
item.setData(asset_item.name, QtCore.Qt.DisplayRole)
|
||||
item.setData(icon, QtCore.Qt.DecorationRole)
|
||||
item.setData(asset_item.id, ASSET_ID_ROLE)
|
||||
item.setData(asset_item.icon, ASSET_ICON_ROLE)
|
||||
|
||||
hierarchy_queue.append((asset_item.id, item))
|
||||
|
||||
|
|
@ -216,10 +232,13 @@ class AssetsModel(QtGui.QStandardItemModel):
|
|||
continue
|
||||
parent = item.parent()
|
||||
if parent is not None:
|
||||
parent.removeRow(item.row())
|
||||
parent.takeRow(item.row())
|
||||
|
||||
self.items_changed.emit()
|
||||
|
||||
|
||||
class TasksModel(QtGui.QStandardItemModel):
|
||||
items_changed = QtCore.Signal()
|
||||
empty_text = "< Empty >"
|
||||
|
||||
def __init__(self, controller):
|
||||
|
|
@ -277,6 +296,7 @@ class TasksModel(QtGui.QStandardItemModel):
|
|||
|
||||
self._last_project = project_name
|
||||
self._clear()
|
||||
self.items_changed.emit()
|
||||
|
||||
def _on_asset_refresh_finish(self, event):
|
||||
self._refresh(event["project_name"])
|
||||
|
|
@ -293,6 +313,7 @@ class TasksModel(QtGui.QStandardItemModel):
|
|||
if project_name is None:
|
||||
if None not in self._items:
|
||||
self._clear()
|
||||
self.items_changed.emit()
|
||||
return
|
||||
|
||||
asset_id = self._controller.selection_model.asset_id
|
||||
|
|
@ -301,6 +322,7 @@ class TasksModel(QtGui.QStandardItemModel):
|
|||
)
|
||||
if not task_items:
|
||||
self._clear()
|
||||
self.items_changed.emit()
|
||||
return
|
||||
|
||||
root_item = self.invisibleRootItem()
|
||||
|
|
@ -338,74 +360,153 @@ class TasksModel(QtGui.QStandardItemModel):
|
|||
if parent is not None:
|
||||
parent.removeRow(item.row())
|
||||
|
||||
self.items_changed.emit()
|
||||
|
||||
class RepublisherDialogWindow(QtWidgets.QWidget):
|
||||
|
||||
class PushToContextSelectWindow(QtWidgets.QWidget):
|
||||
def __init__(self, controller=None):
|
||||
super(RepublisherDialogWindow, self).__init__()
|
||||
super(PushToContextSelectWindow, self).__init__()
|
||||
if controller is None:
|
||||
controller = RepublisherDialogController()
|
||||
controller = PushToContextController()
|
||||
self._controller = controller
|
||||
|
||||
main_splitter = QtWidgets.QSplitter(self)
|
||||
self.setWindowTitle("Push to project (select context)")
|
||||
self.setWindowIcon(QtGui.QIcon(get_app_icon_path()))
|
||||
|
||||
left_widget = QtWidgets.QWidget(main_splitter)
|
||||
header_widget = QtWidgets.QWidget(self)
|
||||
|
||||
project_combobox = QtWidgets.QComboBox(left_widget)
|
||||
header_label = QtWidgets.QLabel(controller.src_label, header_widget)
|
||||
|
||||
header_layout = QtWidgets.QHBoxLayout(header_widget)
|
||||
header_layout.setContentsMargins(0, 0, 0, 0)
|
||||
header_layout.addWidget(header_label)
|
||||
|
||||
main_splitter = QtWidgets.QSplitter(QtCore.Qt.Horizontal, self)
|
||||
|
||||
context_widget = QtWidgets.QWidget(main_splitter)
|
||||
|
||||
project_combobox = QtWidgets.QComboBox(context_widget)
|
||||
project_model = ProjectsModel(controller)
|
||||
project_proxy = ProjectProxyModel()
|
||||
project_proxy.setSourceModel(project_model)
|
||||
project_proxy.setDynamicSortFilter(True)
|
||||
project_delegate = QtWidgets.QStyledItemDelegate()
|
||||
project_combobox.setItemDelegate(project_delegate)
|
||||
project_combobox.setModel(project_proxy)
|
||||
|
||||
asset_view = QtWidgets.QTreeView(left_widget)
|
||||
asset_task_splitter = QtWidgets.QSplitter(
|
||||
QtCore.Qt.Vertical, context_widget
|
||||
)
|
||||
|
||||
asset_view = QtWidgets.QTreeView(asset_task_splitter)
|
||||
asset_view.setHeaderHidden(True)
|
||||
asset_model = AssetsModel(controller)
|
||||
asset_view.setModel(asset_model)
|
||||
asset_proxy = QtCore.QSortFilterProxyModel()
|
||||
asset_proxy.setSourceModel(asset_model)
|
||||
asset_proxy.setDynamicSortFilter(True)
|
||||
asset_view.setModel(asset_proxy)
|
||||
|
||||
left_layout = QtWidgets.QVBoxLayout(left_widget)
|
||||
left_layout.setContentsMargins(0, 0, 0, 0)
|
||||
left_layout.addWidget(project_combobox, 0)
|
||||
left_layout.addWidget(asset_view, 1)
|
||||
|
||||
right_widget = QtWidgets.QWidget(main_splitter)
|
||||
|
||||
task_view = QtWidgets.QListView(right_widget)
|
||||
task_view = QtWidgets.QListView(asset_task_splitter)
|
||||
task_proxy = QtCore.QSortFilterProxyModel()
|
||||
task_model = TasksModel(controller)
|
||||
task_proxy.setSourceModel(task_model)
|
||||
task_proxy.setDynamicSortFilter(True)
|
||||
task_view.setModel(task_proxy)
|
||||
|
||||
right_layout = QtWidgets.QVBoxLayout(right_widget)
|
||||
right_layout.setContentsMargins(0, 0, 0, 0)
|
||||
right_layout.addWidget(task_view, 1)
|
||||
asset_task_splitter.addWidget(asset_view)
|
||||
asset_task_splitter.addWidget(task_view)
|
||||
|
||||
main_splitter.addWidget(left_widget)
|
||||
main_splitter.addWidget(right_widget)
|
||||
context_layout = QtWidgets.QVBoxLayout(context_widget)
|
||||
context_layout.setContentsMargins(0, 0, 0, 0)
|
||||
context_layout.addWidget(project_combobox, 0)
|
||||
context_layout.addWidget(asset_task_splitter, 1)
|
||||
|
||||
# --- Inputs widget ---
|
||||
inputs_widget = QtWidgets.QWidget(main_splitter)
|
||||
|
||||
asset_name_input = PlaceholderLineEdit(inputs_widget)
|
||||
asset_name_input.setPlaceholderText("< Name of new asset >")
|
||||
asset_name_input.setObjectName("ValidatedLineEdit")
|
||||
|
||||
variant_input = PlaceholderLineEdit(inputs_widget)
|
||||
variant_input.setPlaceholderText("< Variant >")
|
||||
variant_input.setObjectName("ValidatedLineEdit")
|
||||
|
||||
comment_input = PlaceholderLineEdit(inputs_widget)
|
||||
comment_input.setPlaceholderText("< Publish comment >")
|
||||
|
||||
inputs_layout = QtWidgets.QFormLayout(inputs_widget)
|
||||
inputs_layout.setContentsMargins(0, 0, 0, 0)
|
||||
inputs_layout.addRow("New asset name", asset_name_input)
|
||||
inputs_layout.addRow("Variant", variant_input)
|
||||
inputs_layout.addRow("Comment", comment_input)
|
||||
|
||||
main_splitter.addWidget(context_widget)
|
||||
main_splitter.addWidget(inputs_widget)
|
||||
|
||||
# --- Buttons widget ---
|
||||
btns_widget = QtWidgets.QWidget(self)
|
||||
close_btn = QtWidgets.QPushButton("Close", btns_widget)
|
||||
select_btn = QtWidgets.QPushButton("Select", btns_widget)
|
||||
cancel_btn = QtWidgets.QPushButton("Cancel", btns_widget)
|
||||
publish_btn = QtWidgets.QPushButton("Publish", btns_widget)
|
||||
|
||||
btns_layout = QtWidgets.QHBoxLayout(btns_widget)
|
||||
btns_layout.setContentsMargins(0, 0, 0, 0)
|
||||
btns_layout.addStretch(1)
|
||||
btns_layout.addWidget(close_btn, 0)
|
||||
btns_layout.addWidget(select_btn, 0)
|
||||
btns_layout.addWidget(cancel_btn, 0)
|
||||
btns_layout.addWidget(publish_btn, 0)
|
||||
|
||||
main_layout = QtWidgets.QHBoxLayout(self)
|
||||
sep_1 = SeparatorWidget(parent=self)
|
||||
sep_2 = SeparatorWidget(parent=self)
|
||||
main_layout = QtWidgets.QVBoxLayout(self)
|
||||
main_layout.addWidget(header_widget, 0)
|
||||
main_layout.addWidget(sep_1, 0)
|
||||
main_layout.addWidget(main_splitter, 1)
|
||||
main_layout.addWidget(sep_2, 0)
|
||||
main_layout.addWidget(btns_widget, 0)
|
||||
|
||||
show_timer = QtCore.QTimer()
|
||||
show_timer.setInterval(1)
|
||||
|
||||
user_input_changed_timer = QtCore.QTimer()
|
||||
user_input_changed_timer.setInterval(200)
|
||||
user_input_changed_timer.setSingleShot(True)
|
||||
|
||||
show_timer.timeout.connect(self._on_show_timer)
|
||||
user_input_changed_timer.timeout.connect(self._on_user_input_timer)
|
||||
asset_name_input.textChanged.connect(self._on_new_asset_change)
|
||||
variant_input.textChanged.connect(self._on_variant_change)
|
||||
comment_input.textChanged.connect(self._on_comment_change)
|
||||
project_model.refreshed.connect(self._on_projects_refresh)
|
||||
project_combobox.currentIndexChanged.connect(self._on_project_change)
|
||||
asset_view.selectionModel().selectionChanged.connect(
|
||||
self._on_asset_change
|
||||
)
|
||||
asset_model.items_changed.connect(self._on_asset_model_change)
|
||||
task_view.selectionModel().selectionChanged.connect(
|
||||
self._on_task_change
|
||||
)
|
||||
select_btn.clicked.connect(self._on_select_click)
|
||||
close_btn.clicked.connect(self._on_close_click)
|
||||
task_model.items_changed.connect(self._on_task_model_change)
|
||||
publish_btn.clicked.connect(self._on_select_click)
|
||||
cancel_btn.clicked.connect(self._on_close_click)
|
||||
|
||||
controller.event_system.add_callback(
|
||||
"new_asset_name.changed", self._on_controller_new_asset_change
|
||||
)
|
||||
controller.event_system.add_callback(
|
||||
"variant.changed", self._on_controller_variant_change
|
||||
)
|
||||
controller.event_system.add_callback(
|
||||
"comment.changed", self._on_controller_comment_change
|
||||
)
|
||||
controller.event_system.add_callback(
|
||||
"submission.enabled.changed", self._on_submission_change
|
||||
)
|
||||
controller.event_system.add_callback(
|
||||
"source.changed", self._on_controller_source_change
|
||||
)
|
||||
|
||||
self._header_label = header_label
|
||||
self._main_splitter = main_splitter
|
||||
|
||||
self._project_combobox = project_combobox
|
||||
self._project_model = project_model
|
||||
|
|
@ -414,17 +515,153 @@ class RepublisherDialogWindow(QtWidgets.QWidget):
|
|||
|
||||
self._asset_view = asset_view
|
||||
self._asset_model = asset_model
|
||||
self._asset_proxy_model = asset_proxy
|
||||
|
||||
self._task_view = task_view
|
||||
self._task_proxy_model = task_proxy
|
||||
|
||||
self._variant_input = variant_input
|
||||
self._asset_name_input = asset_name_input
|
||||
self._comment_input = comment_input
|
||||
|
||||
self._publish_btn = publish_btn
|
||||
|
||||
self._user_input_changed_timer = user_input_changed_timer
|
||||
# Store current value on input text change
|
||||
# The value is unset when is passed to controller
|
||||
# The goal is to have controll over changes happened during user change
|
||||
# in UI and controller auto-changes
|
||||
self._variant_input_text = None
|
||||
self._new_asset_name_input_text = None
|
||||
self._comment_input_text = None
|
||||
self._show_timer = show_timer
|
||||
self._show_counter = 2
|
||||
self._first_show = True
|
||||
|
||||
publish_btn.setEnabled(False)
|
||||
|
||||
if controller.user_values.new_asset_name:
|
||||
asset_name_input.setText(controller.user_values.new_asset_name)
|
||||
if controller.user_values.variant:
|
||||
variant_input.setText(controller.user_values.variant)
|
||||
self._invalidate_variant()
|
||||
self._invalidate_new_asset_name()
|
||||
|
||||
@property
|
||||
def controller(self):
|
||||
return self._controller
|
||||
|
||||
def showEvent(self, event):
|
||||
super(RepublisherDialogWindow, self).showEvent(event)
|
||||
super(PushToContextSelectWindow, self).showEvent(event)
|
||||
if self._first_show:
|
||||
self._first_show = False
|
||||
self._controller.model.refresh_projects()
|
||||
self.setStyleSheet(load_stylesheet())
|
||||
self._invalidate_variant()
|
||||
self._show_timer.start()
|
||||
|
||||
def _on_show_timer(self):
|
||||
if self._show_counter == 0:
|
||||
self._show_timer.stop()
|
||||
return
|
||||
|
||||
self._show_counter -= 1
|
||||
if self._show_counter == 1:
|
||||
width = 740
|
||||
height = 640
|
||||
inputs_width = 360
|
||||
self.resize(width, height)
|
||||
self._main_splitter.setSizes([width - inputs_width, inputs_width])
|
||||
|
||||
if self._show_counter > 0:
|
||||
return
|
||||
|
||||
self._controller.model.refresh_projects()
|
||||
|
||||
def _on_new_asset_change(self, text):
|
||||
self._new_asset_name_input_text = text
|
||||
self._user_input_changed_timer.start()
|
||||
|
||||
def _on_variant_change(self, text):
|
||||
self._variant_input_text = text
|
||||
self._user_input_changed_timer.start()
|
||||
|
||||
def _on_comment_change(self, text):
|
||||
self._comment_input_text = text
|
||||
self._user_input_changed_timer.start()
|
||||
|
||||
def _on_user_input_timer(self):
|
||||
asset_name = self._new_asset_name_input_text
|
||||
if asset_name is not None:
|
||||
self._new_asset_name_input_text = None
|
||||
self._controller.user_values.set_new_asset(asset_name)
|
||||
|
||||
variant = self._variant_input_text
|
||||
if variant is not None:
|
||||
self._variant_input_text = None
|
||||
self._controller.user_values.set_variant(variant)
|
||||
|
||||
comment = self._comment_input_text
|
||||
if comment is not None:
|
||||
self._comment_input_text = None
|
||||
self._controller.user_values.set_comment(comment)
|
||||
|
||||
def _on_controller_new_asset_change(self, event):
|
||||
asset_name = event["changes"]["new_asset_name"]["new"]
|
||||
if (
|
||||
self._new_asset_name_input_text is None
|
||||
and asset_name != self._asset_name_input.text()
|
||||
):
|
||||
self._asset_name_input.setText(asset_name)
|
||||
|
||||
self._invalidate_new_asset_name()
|
||||
|
||||
def _on_controller_variant_change(self, event):
|
||||
is_valid_changes = event["changes"]["is_valid"]
|
||||
variant = event["changes"]["variant"]["new"]
|
||||
if (
|
||||
self._variant_input_text is None
|
||||
and variant != self._variant_input.text()
|
||||
):
|
||||
self._variant_input.setText(variant)
|
||||
|
||||
if is_valid_changes["old"] != is_valid_changes["new"]:
|
||||
self._invalidate_variant()
|
||||
|
||||
def _on_controller_comment_change(self, event):
|
||||
comment = event["comment"]
|
||||
if (
|
||||
self._comment_input_text is None
|
||||
and comment != self._comment_input.text()
|
||||
):
|
||||
self._comment_input.setText(comment)
|
||||
|
||||
def _on_controller_source_change(self):
|
||||
self._header_label.setText(self._controller.src_label)
|
||||
|
||||
def _invalidate_new_asset_name(self):
|
||||
asset_name = self._controller.user_values.new_asset_name
|
||||
self._task_view.setVisible(not asset_name)
|
||||
|
||||
valid = None
|
||||
if asset_name:
|
||||
valid = self._controller.user_values.is_new_asset_name_valid
|
||||
|
||||
state = ""
|
||||
if valid is True:
|
||||
state = "valid"
|
||||
elif valid is False:
|
||||
state = "invalid"
|
||||
set_style_property(self._asset_name_input, "state", state)
|
||||
|
||||
def _invalidate_variant(self):
|
||||
valid = self._controller.user_values.is_variant_valid
|
||||
state = "invalid"
|
||||
if valid is True:
|
||||
state = "valid"
|
||||
set_style_property(self._variant_input, "state", state)
|
||||
|
||||
def _on_projects_refresh(self):
|
||||
self._project_proxy.sort(0, QtCore.Qt.AscendingOrder)
|
||||
|
||||
def _on_project_change(self):
|
||||
idx = self._project_combobox.currentIndex()
|
||||
|
|
@ -445,6 +682,12 @@ class RepublisherDialogWindow(QtWidgets.QWidget):
|
|||
asset_id = model.data(index, ASSET_ID_ROLE)
|
||||
self._controller.selection_model.select_asset(asset_id)
|
||||
|
||||
def _on_asset_model_change(self):
|
||||
self._asset_proxy_model.sort(0, QtCore.Qt.AscendingOrder)
|
||||
|
||||
def _on_task_model_change(self):
|
||||
self._task_proxy_model.sort(0, QtCore.Qt.AscendingOrder)
|
||||
|
||||
def _on_task_change(self):
|
||||
indexes = self._task_view.selectedIndexes()
|
||||
index = next(iter(indexes), None)
|
||||
|
|
@ -454,6 +697,9 @@ class RepublisherDialogWindow(QtWidgets.QWidget):
|
|||
task_name = model.data(index, TASK_NAME_ROLE)
|
||||
self._controller.selection_model.select_task(task_name)
|
||||
|
||||
def _on_submission_change(self, event):
|
||||
self._publish_btn.setEnabled(event["enabled"])
|
||||
|
||||
def _on_close_click(self):
|
||||
self.close()
|
||||
|
||||
|
|
@ -464,14 +710,29 @@ class RepublisherDialogWindow(QtWidgets.QWidget):
|
|||
def main():
|
||||
app = QtWidgets.QApplication.instance()
|
||||
if not app:
|
||||
# 'AA_EnableHighDpiScaling' must be set before app instance creation
|
||||
high_dpi_scale_attr = getattr(
|
||||
QtCore.Qt, "AA_EnableHighDpiScaling", None
|
||||
)
|
||||
if high_dpi_scale_attr is not None:
|
||||
QtWidgets.QApplication.setAttribute(high_dpi_scale_attr)
|
||||
|
||||
app = QtWidgets.QApplication([])
|
||||
|
||||
for attr_name in (
|
||||
"AA_UseHighDpiPixmaps",
|
||||
):
|
||||
attr = getattr(QtCore.Qt, attr_name, None)
|
||||
if attr is not None:
|
||||
app.setAttribute(attr)
|
||||
|
||||
# TODO find way how to get these
|
||||
project_name = None
|
||||
representation_id = None
|
||||
version_id = None
|
||||
|
||||
# Show window dialog
|
||||
window = RepublisherDialogWindow()
|
||||
window = PushToContextSelectWindow()
|
||||
window.controller.set_source(project_name, version_id)
|
||||
window.show()
|
||||
|
||||
app.exec_()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue