mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-25 21:32:15 +01:00
separated switch dialog from window file
This commit is contained in:
parent
48005747cd
commit
0c8a517d07
3 changed files with 1041 additions and 1020 deletions
989
openpype/tools/sceneinventory/switch_dialog.py
Normal file
989
openpype/tools/sceneinventory/switch_dialog.py
Normal file
|
|
@ -0,0 +1,989 @@
|
|||
import collections
|
||||
from Qt import QtWidgets, QtCore
|
||||
|
||||
from avalon import io, api, style
|
||||
from avalon.vendor import qtawesome
|
||||
|
||||
from .widgets import SearchComboBox
|
||||
|
||||
|
||||
class ValidationState:
|
||||
def __init__(self):
|
||||
self.asset_ok = True
|
||||
self.subset_ok = True
|
||||
self.repre_ok = True
|
||||
|
||||
@property
|
||||
def all_ok(self):
|
||||
return (
|
||||
self.asset_ok
|
||||
and self.subset_ok
|
||||
and self.repre_ok
|
||||
)
|
||||
|
||||
|
||||
class SwitchAssetDialog(QtWidgets.QDialog):
|
||||
"""Widget to support asset switching"""
|
||||
|
||||
MIN_WIDTH = 550
|
||||
|
||||
switched = QtCore.Signal()
|
||||
|
||||
def __init__(self, parent=None, items=None):
|
||||
super(SwitchAssetDialog, self).__init__(parent)
|
||||
|
||||
self.setWindowTitle("Switch selected items ...")
|
||||
|
||||
# Force and keep focus dialog
|
||||
self.setModal(True)
|
||||
|
||||
assets_combox = SearchComboBox(self)
|
||||
subsets_combox = SearchComboBox(self)
|
||||
repres_combobox = SearchComboBox(self)
|
||||
|
||||
assets_combox.set_placeholder("<asset>")
|
||||
subsets_combox.set_placeholder("<subset>")
|
||||
repres_combobox.set_placeholder("<representation>")
|
||||
|
||||
asset_label = QtWidgets.QLabel(self)
|
||||
subset_label = QtWidgets.QLabel(self)
|
||||
repre_label = QtWidgets.QLabel(self)
|
||||
|
||||
current_asset_btn = QtWidgets.QPushButton("Use current asset")
|
||||
|
||||
accept_icon = qtawesome.icon("fa.check", color="white")
|
||||
accept_btn = QtWidgets.QPushButton(self)
|
||||
accept_btn.setIcon(accept_icon)
|
||||
|
||||
main_layout = QtWidgets.QGridLayout(self)
|
||||
# Asset column
|
||||
main_layout.addWidget(current_asset_btn, 0, 0)
|
||||
main_layout.addWidget(assets_combox, 1, 0)
|
||||
main_layout.addWidget(asset_label, 2, 0)
|
||||
# Subset column
|
||||
main_layout.addWidget(subsets_combox, 1, 1)
|
||||
main_layout.addWidget(subset_label, 2, 1)
|
||||
# Representation column
|
||||
main_layout.addWidget(repres_combobox, 1, 2)
|
||||
main_layout.addWidget(repre_label, 2, 2)
|
||||
# Btn column
|
||||
main_layout.addWidget(accept_btn, 1, 3)
|
||||
|
||||
assets_combox.currentIndexChanged.connect(
|
||||
self._combobox_value_changed
|
||||
)
|
||||
subsets_combox.currentIndexChanged.connect(
|
||||
self._combobox_value_changed
|
||||
)
|
||||
repres_combobox.currentIndexChanged.connect(
|
||||
self._combobox_value_changed
|
||||
)
|
||||
accept_btn.clicked.connect(self._on_accept)
|
||||
current_asset_btn.clicked.connect(self._on_current_asset)
|
||||
|
||||
self._current_asset_btn = current_asset_btn
|
||||
|
||||
self._assets_box = assets_combox
|
||||
self._subsets_box = subsets_combox
|
||||
self._representations_box = repres_combobox
|
||||
|
||||
self._asset_label = asset_label
|
||||
self._subset_label = subset_label
|
||||
self._repre_label = repre_label
|
||||
|
||||
self._accept_btn = accept_btn
|
||||
|
||||
self._init_asset_name = None
|
||||
self._init_subset_name = None
|
||||
self._init_repre_name = None
|
||||
|
||||
self._fill_check = False
|
||||
|
||||
self._items = items
|
||||
self._prepare_content_data()
|
||||
self.refresh(True)
|
||||
|
||||
self.setMinimumWidth(self.MIN_WIDTH)
|
||||
|
||||
# Set default focus to accept button so you don't directly type in
|
||||
# first asset field, this also allows to see the placeholder value.
|
||||
accept_btn.setFocus()
|
||||
|
||||
def _prepare_content_data(self):
|
||||
repre_ids = [
|
||||
io.ObjectId(item["representation"])
|
||||
for item in self._items
|
||||
]
|
||||
repres = list(io.find({
|
||||
"type": {"$in": ["representation", "archived_representation"]},
|
||||
"_id": {"$in": repre_ids}
|
||||
}))
|
||||
repres_by_id = {repre["_id"]: repre for repre in repres}
|
||||
|
||||
# stash context values, works only for single representation
|
||||
if len(repres) == 1:
|
||||
self._init_asset_name = repres[0]["context"]["asset"]
|
||||
self._init_subset_name = repres[0]["context"]["subset"]
|
||||
self._init_repre_name = repres[0]["context"]["representation"]
|
||||
|
||||
content_repres = {}
|
||||
archived_repres = []
|
||||
missing_repres = []
|
||||
version_ids = []
|
||||
for repre_id in repre_ids:
|
||||
if repre_id not in repres_by_id:
|
||||
missing_repres.append(repre_id)
|
||||
elif repres_by_id[repre_id]["type"] == "archived_representation":
|
||||
repre = repres_by_id[repre_id]
|
||||
archived_repres.append(repre)
|
||||
version_ids.append(repre["parent"])
|
||||
else:
|
||||
repre = repres_by_id[repre_id]
|
||||
content_repres[repre_id] = repres_by_id[repre_id]
|
||||
version_ids.append(repre["parent"])
|
||||
|
||||
versions = io.find({
|
||||
"type": {"$in": ["version", "hero_version"]},
|
||||
"_id": {"$in": list(set(version_ids))}
|
||||
})
|
||||
content_versions = {}
|
||||
hero_version_ids = set()
|
||||
for version in versions:
|
||||
content_versions[version["_id"]] = version
|
||||
if version["type"] == "hero_version":
|
||||
hero_version_ids.add(version["_id"])
|
||||
|
||||
missing_versions = []
|
||||
subset_ids = []
|
||||
for version_id in version_ids:
|
||||
if version_id not in content_versions:
|
||||
missing_versions.append(version_id)
|
||||
else:
|
||||
subset_ids.append(content_versions[version_id]["parent"])
|
||||
|
||||
subsets = io.find({
|
||||
"type": {"$in": ["subset", "archived_subset"]},
|
||||
"_id": {"$in": subset_ids}
|
||||
})
|
||||
subsets_by_id = {sub["_id"]: sub for sub in subsets}
|
||||
|
||||
asset_ids = []
|
||||
archived_subsets = []
|
||||
missing_subsets = []
|
||||
content_subsets = {}
|
||||
for subset_id in subset_ids:
|
||||
if subset_id not in subsets_by_id:
|
||||
missing_subsets.append(subset_id)
|
||||
elif subsets_by_id[subset_id]["type"] == "archived_subset":
|
||||
subset = subsets_by_id[subset_id]
|
||||
asset_ids.append(subset["parent"])
|
||||
archived_subsets.append(subset)
|
||||
else:
|
||||
subset = subsets_by_id[subset_id]
|
||||
asset_ids.append(subset["parent"])
|
||||
content_subsets[subset_id] = subset
|
||||
|
||||
assets = io.find({
|
||||
"type": {"$in": ["asset", "archived_asset"]},
|
||||
"_id": {"$in": list(asset_ids)}
|
||||
})
|
||||
assets_by_id = {asset["_id"]: asset for asset in assets}
|
||||
|
||||
missing_assets = []
|
||||
archived_assets = []
|
||||
content_assets = {}
|
||||
for asset_id in asset_ids:
|
||||
if asset_id not in assets_by_id:
|
||||
missing_assets.append(asset_id)
|
||||
elif assets_by_id[asset_id]["type"] == "archived_asset":
|
||||
archived_assets.append(assets_by_id[asset_id])
|
||||
else:
|
||||
content_assets[asset_id] = assets_by_id[asset_id]
|
||||
|
||||
self.content_assets = content_assets
|
||||
self.content_subsets = content_subsets
|
||||
self.content_versions = content_versions
|
||||
self.content_repres = content_repres
|
||||
|
||||
self.hero_version_ids = hero_version_ids
|
||||
|
||||
self.missing_assets = missing_assets
|
||||
self.missing_versions = missing_versions
|
||||
self.missing_subsets = missing_subsets
|
||||
self.missing_repres = missing_repres
|
||||
self.missing_docs = (
|
||||
bool(missing_assets)
|
||||
or bool(missing_versions)
|
||||
or bool(missing_subsets)
|
||||
or bool(missing_repres)
|
||||
)
|
||||
|
||||
self.archived_assets = archived_assets
|
||||
self.archived_subsets = archived_subsets
|
||||
self.archived_repres = archived_repres
|
||||
|
||||
def _combobox_value_changed(self, *args, **kwargs):
|
||||
self.refresh()
|
||||
|
||||
def refresh(self, init_refresh=False):
|
||||
"""Build the need comboboxes with content"""
|
||||
if not self._fill_check and not init_refresh:
|
||||
return
|
||||
|
||||
self._fill_check = False
|
||||
|
||||
if init_refresh:
|
||||
asset_values = self._get_asset_box_values()
|
||||
self._fill_combobox(asset_values, "asset")
|
||||
|
||||
validation_state = ValidationState()
|
||||
|
||||
# Set other comboboxes to empty if any document is missing or any asset
|
||||
# of loaded representations is archived.
|
||||
self._is_asset_ok(validation_state)
|
||||
if validation_state.asset_ok:
|
||||
subset_values = self._get_subset_box_values()
|
||||
self._fill_combobox(subset_values, "subset")
|
||||
self._is_subset_ok(validation_state)
|
||||
|
||||
if validation_state.asset_ok and validation_state.subset_ok:
|
||||
repre_values = sorted(self._representations_box_values())
|
||||
self._fill_combobox(repre_values, "repre")
|
||||
self._is_repre_ok(validation_state)
|
||||
|
||||
# Fill comboboxes with values
|
||||
self.set_labels()
|
||||
self.apply_validations(validation_state)
|
||||
|
||||
if init_refresh: # pre select context if possible
|
||||
self._assets_box.set_valid_value(self._init_asset_name)
|
||||
self._subsets_box.set_valid_value(self._init_subset_name)
|
||||
self._representations_box.set_valid_value(self._init_repre_name)
|
||||
|
||||
self._fill_check = True
|
||||
|
||||
def _get_loaders(self, representations):
|
||||
if not representations:
|
||||
return list()
|
||||
|
||||
available_loaders = filter(
|
||||
lambda l: not (hasattr(l, "is_utility") and l.is_utility),
|
||||
api.discover(api.Loader)
|
||||
)
|
||||
|
||||
loaders = set()
|
||||
|
||||
for representation in representations:
|
||||
for loader in api.loaders_from_representation(
|
||||
available_loaders,
|
||||
representation
|
||||
):
|
||||
loaders.add(loader)
|
||||
|
||||
return loaders
|
||||
|
||||
def _fill_combobox(self, values, combobox_type):
|
||||
if combobox_type == "asset":
|
||||
combobox_widget = self._assets_box
|
||||
elif combobox_type == "subset":
|
||||
combobox_widget = self._subsets_box
|
||||
elif combobox_type == "repre":
|
||||
combobox_widget = self._representations_box
|
||||
else:
|
||||
return
|
||||
selected_value = combobox_widget.get_valid_value()
|
||||
|
||||
# Fill combobox
|
||||
if values is not None:
|
||||
combobox_widget.populate(list(sorted(values)))
|
||||
if selected_value and selected_value in values:
|
||||
index = None
|
||||
for idx in range(combobox_widget.count()):
|
||||
if selected_value == str(combobox_widget.itemText(idx)):
|
||||
index = idx
|
||||
break
|
||||
if index is not None:
|
||||
combobox_widget.setCurrentIndex(index)
|
||||
|
||||
def set_labels(self):
|
||||
asset_label = self._assets_box.get_valid_value()
|
||||
subset_label = self._subsets_box.get_valid_value()
|
||||
repre_label = self._representations_box.get_valid_value()
|
||||
|
||||
default = "*No changes"
|
||||
self._asset_label.setText(asset_label or default)
|
||||
self._subset_label.setText(subset_label or default)
|
||||
self._repre_label.setText(repre_label or default)
|
||||
|
||||
def apply_validations(self, validation_state):
|
||||
error_msg = "*Please select"
|
||||
error_sheet = "border: 1px solid red;"
|
||||
success_sheet = "border: 1px solid green;"
|
||||
|
||||
asset_sheet = None
|
||||
subset_sheet = None
|
||||
repre_sheet = None
|
||||
accept_sheet = None
|
||||
if validation_state.asset_ok is False:
|
||||
asset_sheet = error_sheet
|
||||
self._asset_label.setText(error_msg)
|
||||
elif validation_state.subset_ok is False:
|
||||
subset_sheet = error_sheet
|
||||
self._subset_label.setText(error_msg)
|
||||
elif validation_state.repre_ok is False:
|
||||
repre_sheet = error_sheet
|
||||
self._repre_label.setText(error_msg)
|
||||
|
||||
if validation_state.all_ok:
|
||||
accept_sheet = success_sheet
|
||||
|
||||
self._assets_box.setStyleSheet(asset_sheet or "")
|
||||
self._subsets_box.setStyleSheet(subset_sheet or "")
|
||||
self._representations_box.setStyleSheet(repre_sheet or "")
|
||||
|
||||
self._accept_btn.setEnabled(validation_state.all_ok)
|
||||
self._accept_btn.setStyleSheet(accept_sheet or "")
|
||||
|
||||
def _get_asset_box_values(self):
|
||||
asset_docs = io.find(
|
||||
{"type": "asset"},
|
||||
{"_id": 1, "name": 1}
|
||||
)
|
||||
asset_names_by_id = {
|
||||
asset_doc["_id"]: asset_doc["name"]
|
||||
for asset_doc in asset_docs
|
||||
}
|
||||
subsets = io.find(
|
||||
{
|
||||
"type": "subset",
|
||||
"parent": {"$in": list(asset_names_by_id.keys())}
|
||||
},
|
||||
{
|
||||
"parent": 1
|
||||
}
|
||||
)
|
||||
|
||||
filtered_assets = []
|
||||
for subset in subsets:
|
||||
asset_name = asset_names_by_id[subset["parent"]]
|
||||
if asset_name not in filtered_assets:
|
||||
filtered_assets.append(asset_name)
|
||||
return sorted(filtered_assets)
|
||||
|
||||
def _get_subset_box_values(self):
|
||||
selected_asset = self._assets_box.get_valid_value()
|
||||
if selected_asset:
|
||||
asset_doc = io.find_one({"type": "asset", "name": selected_asset})
|
||||
asset_ids = [asset_doc["_id"]]
|
||||
else:
|
||||
asset_ids = list(self.content_assets.keys())
|
||||
|
||||
subsets = io.find(
|
||||
{
|
||||
"type": "subset",
|
||||
"parent": {"$in": asset_ids}
|
||||
},
|
||||
{
|
||||
"parent": 1,
|
||||
"name": 1
|
||||
}
|
||||
)
|
||||
|
||||
subset_names_by_parent_id = collections.defaultdict(set)
|
||||
for subset in subsets:
|
||||
subset_names_by_parent_id[subset["parent"]].add(subset["name"])
|
||||
|
||||
possible_subsets = None
|
||||
for subset_names in subset_names_by_parent_id.values():
|
||||
if possible_subsets is None:
|
||||
possible_subsets = subset_names
|
||||
else:
|
||||
possible_subsets = (possible_subsets & subset_names)
|
||||
|
||||
if not possible_subsets:
|
||||
break
|
||||
|
||||
return list(possible_subsets or list())
|
||||
|
||||
def _representations_box_values(self):
|
||||
# NOTE hero versions are not used because it is expected that
|
||||
# hero version has same representations as latests
|
||||
selected_asset = self._assets_box.currentText()
|
||||
selected_subset = self._subsets_box.currentText()
|
||||
|
||||
# If nothing is selected
|
||||
# [ ] [ ] [?]
|
||||
if not selected_asset and not selected_subset:
|
||||
# Find all representations of selection's subsets
|
||||
possible_repres = list(io.find(
|
||||
{
|
||||
"type": "representation",
|
||||
"parent": {"$in": list(self.content_versions.keys())}
|
||||
},
|
||||
{
|
||||
"parent": 1,
|
||||
"name": 1
|
||||
}
|
||||
))
|
||||
|
||||
possible_repres_by_parent = collections.defaultdict(set)
|
||||
for repre in possible_repres:
|
||||
possible_repres_by_parent[repre["parent"]].add(repre["name"])
|
||||
|
||||
output_repres = None
|
||||
for repre_names in possible_repres_by_parent.values():
|
||||
if output_repres is None:
|
||||
output_repres = repre_names
|
||||
else:
|
||||
output_repres = (output_repres & repre_names)
|
||||
|
||||
if not output_repres:
|
||||
break
|
||||
|
||||
return list(output_repres or list())
|
||||
|
||||
# [x] [x] [?]
|
||||
if selected_asset and selected_subset:
|
||||
asset_doc = io.find_one(
|
||||
{"type": "asset", "name": selected_asset},
|
||||
{"_id": 1}
|
||||
)
|
||||
subset_doc = io.find_one(
|
||||
{
|
||||
"type": "subset",
|
||||
"name": selected_subset,
|
||||
"parent": asset_doc["_id"]
|
||||
},
|
||||
{"_id": 1}
|
||||
)
|
||||
subset_id = subset_doc["_id"]
|
||||
last_versions_by_subset_id = self.find_last_versions([subset_id])
|
||||
version_doc = last_versions_by_subset_id.get(subset_id)
|
||||
repre_docs = io.find(
|
||||
{
|
||||
"type": "representation",
|
||||
"parent": version_doc["_id"]
|
||||
},
|
||||
{
|
||||
"name": 1
|
||||
}
|
||||
)
|
||||
return [
|
||||
repre_doc["name"]
|
||||
for repre_doc in repre_docs
|
||||
]
|
||||
|
||||
# [x] [ ] [?]
|
||||
# If asset only is selected
|
||||
if selected_asset:
|
||||
asset_doc = io.find_one(
|
||||
{"type": "asset", "name": selected_asset},
|
||||
{"_id": 1}
|
||||
)
|
||||
if not asset_doc:
|
||||
return list()
|
||||
|
||||
# Filter subsets by subset names from content
|
||||
subset_names = set()
|
||||
for subset_doc in self.content_subsets.values():
|
||||
subset_names.add(subset_doc["name"])
|
||||
subset_docs = io.find(
|
||||
{
|
||||
"type": "subset",
|
||||
"parent": asset_doc["_id"],
|
||||
"name": {"$in": list(subset_names)}
|
||||
},
|
||||
{"_id": 1}
|
||||
)
|
||||
subset_ids = [
|
||||
subset_doc["_id"]
|
||||
for subset_doc in subset_docs
|
||||
]
|
||||
if not subset_ids:
|
||||
return list()
|
||||
|
||||
last_versions_by_subset_id = self.find_last_versions(subset_ids)
|
||||
subset_id_by_version_id = {}
|
||||
for subset_id, last_version in last_versions_by_subset_id.items():
|
||||
version_id = last_version["_id"]
|
||||
subset_id_by_version_id[version_id] = subset_id
|
||||
|
||||
if not subset_id_by_version_id:
|
||||
return list()
|
||||
|
||||
repre_docs = list(io.find(
|
||||
{
|
||||
"type": "representation",
|
||||
"parent": {"$in": list(subset_id_by_version_id.keys())}
|
||||
},
|
||||
{
|
||||
"name": 1,
|
||||
"parent": 1
|
||||
}
|
||||
))
|
||||
if not repre_docs:
|
||||
return list()
|
||||
|
||||
repre_names_by_parent = collections.defaultdict(set)
|
||||
for repre_doc in repre_docs:
|
||||
repre_names_by_parent[repre_doc["parent"]].add(
|
||||
repre_doc["name"]
|
||||
)
|
||||
|
||||
available_repres = None
|
||||
for repre_names in repre_names_by_parent.values():
|
||||
if available_repres is None:
|
||||
available_repres = repre_names
|
||||
continue
|
||||
|
||||
available_repres = available_repres.intersection(repre_names)
|
||||
|
||||
return list(available_repres)
|
||||
|
||||
# [ ] [x] [?]
|
||||
subset_docs = list(io.find(
|
||||
{
|
||||
"type": "subset",
|
||||
"parent": {"$in": list(self.content_assets.keys())},
|
||||
"name": selected_subset
|
||||
},
|
||||
{"_id": 1, "parent": 1}
|
||||
))
|
||||
if not subset_docs:
|
||||
return list()
|
||||
|
||||
subset_docs_by_id = {
|
||||
subset_doc["_id"]: subset_doc
|
||||
for subset_doc in subset_docs
|
||||
}
|
||||
last_versions_by_subset_id = self.find_last_versions(
|
||||
subset_docs_by_id.keys()
|
||||
)
|
||||
|
||||
subset_id_by_version_id = {}
|
||||
for subset_id, last_version in last_versions_by_subset_id.items():
|
||||
version_id = last_version["_id"]
|
||||
subset_id_by_version_id[version_id] = subset_id
|
||||
|
||||
if not subset_id_by_version_id:
|
||||
return list()
|
||||
|
||||
repre_docs = list(io.find(
|
||||
{
|
||||
"type": "representation",
|
||||
"parent": {"$in": list(subset_id_by_version_id.keys())}
|
||||
},
|
||||
{
|
||||
"name": 1,
|
||||
"parent": 1
|
||||
}
|
||||
))
|
||||
if not repre_docs:
|
||||
return list()
|
||||
|
||||
repre_names_by_asset_id = {}
|
||||
for repre_doc in repre_docs:
|
||||
subset_id = subset_id_by_version_id[repre_doc["parent"]]
|
||||
asset_id = subset_docs_by_id[subset_id]["parent"]
|
||||
if asset_id not in repre_names_by_asset_id:
|
||||
repre_names_by_asset_id[asset_id] = set()
|
||||
repre_names_by_asset_id[asset_id].add(repre_doc["name"])
|
||||
|
||||
available_repres = None
|
||||
for repre_names in repre_names_by_asset_id.values():
|
||||
if available_repres is None:
|
||||
available_repres = repre_names
|
||||
continue
|
||||
|
||||
available_repres = available_repres.intersection(repre_names)
|
||||
|
||||
return list(available_repres)
|
||||
|
||||
def _is_asset_ok(self, validation_state):
|
||||
selected_asset = self._assets_box.get_valid_value()
|
||||
if (
|
||||
selected_asset is None
|
||||
and (self.missing_docs or self.archived_assets)
|
||||
):
|
||||
validation_state.asset_ok = False
|
||||
|
||||
def _is_subset_ok(self, validation_state):
|
||||
selected_asset = self._assets_box.get_valid_value()
|
||||
selected_subset = self._subsets_box.get_valid_value()
|
||||
|
||||
# [?] [x] [?]
|
||||
# If subset is selected then must be ok
|
||||
if selected_subset is not None:
|
||||
return
|
||||
|
||||
# [ ] [ ] [?]
|
||||
if selected_asset is None:
|
||||
# If there were archived subsets and asset is not selected
|
||||
if self.archived_subsets:
|
||||
validation_state.subset_ok = False
|
||||
return
|
||||
|
||||
# [x] [ ] [?]
|
||||
asset_doc = io.find_one(
|
||||
{"type": "asset", "name": selected_asset},
|
||||
{"_id": 1}
|
||||
)
|
||||
subset_docs = io.find(
|
||||
{"type": "subset", "parent": asset_doc["_id"]},
|
||||
{"name": 1}
|
||||
)
|
||||
subset_names = set(
|
||||
subset_doc["name"]
|
||||
for subset_doc in subset_docs
|
||||
)
|
||||
|
||||
for subset_doc in self.content_subsets.values():
|
||||
if subset_doc["name"] not in subset_names:
|
||||
validation_state.subset_ok = False
|
||||
break
|
||||
|
||||
def find_last_versions(self, subset_ids):
|
||||
_pipeline = [
|
||||
# Find all versions of those subsets
|
||||
{"$match": {
|
||||
"type": "version",
|
||||
"parent": {"$in": list(subset_ids)}
|
||||
}},
|
||||
# Sorting versions all together
|
||||
{"$sort": {"name": 1}},
|
||||
# Group them by "parent", but only take the last
|
||||
{"$group": {
|
||||
"_id": "$parent",
|
||||
"_version_id": {"$last": "$_id"},
|
||||
"type": {"$last": "$type"}
|
||||
}}
|
||||
]
|
||||
last_versions_by_subset_id = dict()
|
||||
for doc in io.aggregate(_pipeline):
|
||||
doc["parent"] = doc["_id"]
|
||||
doc["_id"] = doc.pop("_version_id")
|
||||
last_versions_by_subset_id[doc["parent"]] = doc
|
||||
return last_versions_by_subset_id
|
||||
|
||||
def _is_repre_ok(self, validation_state):
|
||||
selected_asset = self._assets_box.get_valid_value()
|
||||
selected_subset = self._subsets_box.get_valid_value()
|
||||
selected_repre = self._representations_box.get_valid_value()
|
||||
|
||||
# [?] [?] [x]
|
||||
# If subset is selected then must be ok
|
||||
if selected_repre is not None:
|
||||
return
|
||||
|
||||
# [ ] [ ] [ ]
|
||||
if selected_asset is None and selected_subset is None:
|
||||
if (
|
||||
self.archived_repres
|
||||
or self.missing_versions
|
||||
or self.missing_repres
|
||||
):
|
||||
validation_state.repre_ok = False
|
||||
return
|
||||
|
||||
# [x] [x] [ ]
|
||||
if selected_asset is not None and selected_subset is not None:
|
||||
asset_doc = io.find_one(
|
||||
{"type": "asset", "name": selected_asset},
|
||||
{"_id": 1}
|
||||
)
|
||||
subset_doc = io.find_one(
|
||||
{
|
||||
"type": "subset",
|
||||
"parent": asset_doc["_id"],
|
||||
"name": selected_subset
|
||||
},
|
||||
{"_id": 1}
|
||||
)
|
||||
last_versions_by_subset_id = self.find_last_versions(
|
||||
[subset_doc["_id"]]
|
||||
)
|
||||
last_version = last_versions_by_subset_id.get(subset_doc["_id"])
|
||||
if not last_version:
|
||||
validation_state.repre_ok = False
|
||||
return
|
||||
|
||||
repre_docs = io.find(
|
||||
{
|
||||
"type": "representation",
|
||||
"parent": last_version["_id"]
|
||||
},
|
||||
{"name": 1}
|
||||
)
|
||||
|
||||
repre_names = set(
|
||||
repre_doc["name"]
|
||||
for repre_doc in repre_docs
|
||||
)
|
||||
for repre_doc in self.content_repres.values():
|
||||
if repre_doc["name"] not in repre_names:
|
||||
validation_state.repre_ok = False
|
||||
break
|
||||
return
|
||||
|
||||
# [x] [ ] [ ]
|
||||
if selected_asset is not None:
|
||||
asset_doc = io.find_one(
|
||||
{"type": "asset", "name": selected_asset},
|
||||
{"_id": 1}
|
||||
)
|
||||
subset_docs = list(io.find(
|
||||
{
|
||||
"type": "subset",
|
||||
"parent": asset_doc["_id"]
|
||||
},
|
||||
{"_id": 1, "name": 1}
|
||||
))
|
||||
|
||||
subset_name_by_id = {}
|
||||
subset_ids = set()
|
||||
for subset_doc in subset_docs:
|
||||
subset_id = subset_doc["_id"]
|
||||
subset_ids.add(subset_id)
|
||||
subset_name_by_id[subset_id] = subset_doc["name"]
|
||||
|
||||
last_versions_by_subset_id = self.find_last_versions(subset_ids)
|
||||
|
||||
subset_id_by_version_id = {}
|
||||
for subset_id, last_version in last_versions_by_subset_id.items():
|
||||
version_id = last_version["_id"]
|
||||
subset_id_by_version_id[version_id] = subset_id
|
||||
|
||||
repre_docs = io.find(
|
||||
{
|
||||
"type": "representation",
|
||||
"parent": {"$in": list(subset_id_by_version_id.keys())}
|
||||
},
|
||||
{
|
||||
"name": 1,
|
||||
"parent": 1
|
||||
}
|
||||
)
|
||||
repres_by_subset_name = {}
|
||||
for repre_doc in repre_docs:
|
||||
subset_id = subset_id_by_version_id[repre_doc["parent"]]
|
||||
subset_name = subset_name_by_id[subset_id]
|
||||
if subset_name not in repres_by_subset_name:
|
||||
repres_by_subset_name[subset_name] = set()
|
||||
repres_by_subset_name[subset_name].add(repre_doc["name"])
|
||||
|
||||
for repre_doc in self.content_repres.values():
|
||||
version_doc = self.content_versions[repre_doc["parent"]]
|
||||
subset_doc = self.content_subsets[version_doc["parent"]]
|
||||
repre_names = (
|
||||
repres_by_subset_name.get(subset_doc["name"]) or []
|
||||
)
|
||||
if repre_doc["name"] not in repre_names:
|
||||
validation_state.repre_ok = False
|
||||
break
|
||||
return
|
||||
|
||||
# [ ] [x] [ ]
|
||||
# Subset documents
|
||||
subset_docs = io.find(
|
||||
{
|
||||
"type": "subset",
|
||||
"parent": {"$in": list(self.content_assets.keys())},
|
||||
"name": selected_subset
|
||||
},
|
||||
{"_id": 1, "name": 1, "parent": 1}
|
||||
)
|
||||
|
||||
subset_docs_by_id = {}
|
||||
for subset_doc in subset_docs:
|
||||
subset_docs_by_id[subset_doc["_id"]] = subset_doc
|
||||
|
||||
last_versions_by_subset_id = self.find_last_versions(
|
||||
subset_docs_by_id.keys()
|
||||
)
|
||||
subset_id_by_version_id = {}
|
||||
for subset_id, last_version in last_versions_by_subset_id.items():
|
||||
version_id = last_version["_id"]
|
||||
subset_id_by_version_id[version_id] = subset_id
|
||||
|
||||
repre_docs = io.find(
|
||||
{
|
||||
"type": "representation",
|
||||
"parent": {"$in": list(subset_id_by_version_id.keys())}
|
||||
},
|
||||
{
|
||||
"name": 1,
|
||||
"parent": 1
|
||||
}
|
||||
)
|
||||
repres_by_asset_id = {}
|
||||
for repre_doc in repre_docs:
|
||||
subset_id = subset_id_by_version_id[repre_doc["parent"]]
|
||||
asset_id = subset_docs_by_id[subset_id]["parent"]
|
||||
if asset_id not in repres_by_asset_id:
|
||||
repres_by_asset_id[asset_id] = set()
|
||||
repres_by_asset_id[asset_id].add(repre_doc["name"])
|
||||
|
||||
for repre_doc in self.content_repres.values():
|
||||
version_doc = self.content_versions[repre_doc["parent"]]
|
||||
subset_doc = self.content_subsets[version_doc["parent"]]
|
||||
asset_id = subset_doc["parent"]
|
||||
repre_names = (
|
||||
repres_by_asset_id.get(asset_id) or []
|
||||
)
|
||||
if repre_doc["name"] not in repre_names:
|
||||
validation_state.repre_ok = False
|
||||
break
|
||||
|
||||
def _on_current_asset(self):
|
||||
# Set initial asset as current.
|
||||
asset_name = io.Session["AVALON_ASSET"]
|
||||
index = self._assets_box.findText(
|
||||
asset_name, QtCore.Qt.MatchFixedString
|
||||
)
|
||||
if index >= 0:
|
||||
print("Setting asset to {}".format(asset_name))
|
||||
self._assets_box.setCurrentIndex(index)
|
||||
|
||||
def _on_accept(self):
|
||||
# Use None when not a valid value or when placeholder value
|
||||
selected_asset = self._assets_box.get_valid_value()
|
||||
selected_subset = self._subsets_box.get_valid_value()
|
||||
selected_representation = self._representations_box.get_valid_value()
|
||||
|
||||
if selected_asset:
|
||||
asset_doc = io.find_one({"type": "asset", "name": selected_asset})
|
||||
asset_docs_by_id = {asset_doc["_id"]: asset_doc}
|
||||
else:
|
||||
asset_docs_by_id = self.content_assets
|
||||
|
||||
asset_docs_by_name = {
|
||||
asset_doc["name"]: asset_doc
|
||||
for asset_doc in asset_docs_by_id.values()
|
||||
}
|
||||
|
||||
asset_ids = list(asset_docs_by_id.keys())
|
||||
|
||||
subset_query = {
|
||||
"type": "subset",
|
||||
"parent": {"$in": asset_ids}
|
||||
}
|
||||
if selected_subset:
|
||||
subset_query["name"] = selected_subset
|
||||
|
||||
subset_docs = list(io.find(subset_query))
|
||||
subset_ids = []
|
||||
subset_docs_by_parent_and_name = collections.defaultdict(dict)
|
||||
for subset in subset_docs:
|
||||
subset_ids.append(subset["_id"])
|
||||
parent_id = subset["parent"]
|
||||
name = subset["name"]
|
||||
subset_docs_by_parent_and_name[parent_id][name] = subset
|
||||
|
||||
# versions
|
||||
version_docs = list(io.find({
|
||||
"type": "version",
|
||||
"parent": {"$in": subset_ids}
|
||||
}, sort=[("name", -1)]))
|
||||
|
||||
hero_version_docs = list(io.find({
|
||||
"type": "hero_version",
|
||||
"parent": {"$in": subset_ids}
|
||||
}))
|
||||
|
||||
version_ids = list()
|
||||
|
||||
version_docs_by_parent_id = {}
|
||||
for version_doc in version_docs:
|
||||
parent_id = version_doc["parent"]
|
||||
if parent_id not in version_docs_by_parent_id:
|
||||
version_ids.append(version_doc["_id"])
|
||||
version_docs_by_parent_id[parent_id] = version_doc
|
||||
|
||||
hero_version_docs_by_parent_id = {}
|
||||
for hero_version_doc in hero_version_docs:
|
||||
version_ids.append(hero_version_doc["_id"])
|
||||
parent_id = hero_version_doc["parent"]
|
||||
hero_version_docs_by_parent_id[parent_id] = hero_version_doc
|
||||
|
||||
repre_docs = io.find({
|
||||
"type": "representation",
|
||||
"parent": {"$in": version_ids}
|
||||
})
|
||||
repre_docs_by_parent_id_by_name = collections.defaultdict(dict)
|
||||
for repre_doc in repre_docs:
|
||||
parent_id = repre_doc["parent"]
|
||||
name = repre_doc["name"]
|
||||
repre_docs_by_parent_id_by_name[parent_id][name] = repre_doc
|
||||
|
||||
for container in self._items:
|
||||
container_repre_id = io.ObjectId(container["representation"])
|
||||
container_repre = self.content_repres[container_repre_id]
|
||||
container_repre_name = container_repre["name"]
|
||||
|
||||
container_version_id = container_repre["parent"]
|
||||
container_version = self.content_versions[container_version_id]
|
||||
|
||||
container_subset_id = container_version["parent"]
|
||||
container_subset = self.content_subsets[container_subset_id]
|
||||
container_subset_name = container_subset["name"]
|
||||
|
||||
container_asset_id = container_subset["parent"]
|
||||
container_asset = self.content_assets[container_asset_id]
|
||||
container_asset_name = container_asset["name"]
|
||||
|
||||
if selected_asset:
|
||||
asset_doc = asset_docs_by_name[selected_asset]
|
||||
else:
|
||||
asset_doc = asset_docs_by_name[container_asset_name]
|
||||
|
||||
subsets_by_name = subset_docs_by_parent_and_name[asset_doc["_id"]]
|
||||
if selected_subset:
|
||||
subset_doc = subsets_by_name[selected_subset]
|
||||
else:
|
||||
subset_doc = subsets_by_name[container_subset_name]
|
||||
|
||||
repre_doc = None
|
||||
subset_id = subset_doc["_id"]
|
||||
if container_version["type"] == "hero_version":
|
||||
hero_version = hero_version_docs_by_parent_id.get(
|
||||
subset_id
|
||||
)
|
||||
if hero_version:
|
||||
_repres = repre_docs_by_parent_id_by_name.get(
|
||||
hero_version["_id"]
|
||||
)
|
||||
if selected_representation:
|
||||
repre_doc = _repres.get(selected_representation)
|
||||
else:
|
||||
repre_doc = _repres.get(container_repre_name)
|
||||
|
||||
if not repre_doc:
|
||||
version_doc = version_docs_by_parent_id[subset_id]
|
||||
version_id = version_doc["_id"]
|
||||
repres_by_name = repre_docs_by_parent_id_by_name[version_id]
|
||||
if selected_representation:
|
||||
repre_doc = repres_by_name[selected_representation]
|
||||
else:
|
||||
repre_doc = repres_by_name[container_repre_name]
|
||||
|
||||
try:
|
||||
api.switch(container, repre_doc)
|
||||
except Exception:
|
||||
log.warning(
|
||||
(
|
||||
"Couldn't switch asset."
|
||||
"See traceback for more information."
|
||||
),
|
||||
exc_info=True
|
||||
)
|
||||
dialog = QtWidgets.QMessageBox()
|
||||
dialog.setStyleSheet(style.load_stylesheet())
|
||||
dialog.setWindowTitle("Switch asset failed")
|
||||
msg = "Switch asset failed. "\
|
||||
"Search console log for more details"
|
||||
dialog.setText(msg)
|
||||
dialog.exec_()
|
||||
|
||||
self.switched.emit()
|
||||
|
||||
self.close()
|
||||
51
openpype/tools/sceneinventory/widgets.py
Normal file
51
openpype/tools/sceneinventory/widgets.py
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
from Qt import QtWidgets, QtCore
|
||||
|
||||
|
||||
class SearchComboBox(QtWidgets.QComboBox):
|
||||
"""Searchable ComboBox with empty placeholder value as first value"""
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super(SearchComboBox, self).__init__(parent)
|
||||
|
||||
self.setEditable(True)
|
||||
self.setInsertPolicy(self.NoInsert)
|
||||
|
||||
# Apply completer settings
|
||||
completer = self.completer()
|
||||
completer.setCompletionMode(completer.PopupCompletion)
|
||||
completer.setCaseSensitivity(QtCore.Qt.CaseInsensitive)
|
||||
|
||||
# Force style sheet on popup menu
|
||||
# It won't take the parent stylesheet for some reason
|
||||
# todo: better fix for completer popup stylesheet
|
||||
# if module.window:
|
||||
# popup = completer.popup()
|
||||
# popup.setStyleSheet(module.window.styleSheet())
|
||||
|
||||
def set_placeholder(self, placeholder):
|
||||
self.lineEdit().setPlaceholderText(placeholder)
|
||||
|
||||
def populate(self, items):
|
||||
self.clear()
|
||||
self.addItems([""]) # ensure first item is placeholder
|
||||
self.addItems(items)
|
||||
|
||||
def get_valid_value(self):
|
||||
"""Return the current text if it's a valid value else None
|
||||
|
||||
Note: The empty placeholder value is valid and returns as ""
|
||||
|
||||
"""
|
||||
|
||||
text = self.currentText()
|
||||
lookup = set(self.itemText(i) for i in range(self.count()))
|
||||
if text not in lookup:
|
||||
return None
|
||||
|
||||
return text or None
|
||||
|
||||
def set_valid_value(self, value):
|
||||
"""Try to locate 'value' and pre-select it in dropdown."""
|
||||
index = self.findText(value)
|
||||
if index > -1:
|
||||
self.setCurrentIndex(index)
|
||||
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue