diff --git a/avalon/tools/cbsceneinventory/app.py b/avalon/tools/cbsceneinventory/app.py index ae9adac32..bad2b9dc7 100644 --- a/avalon/tools/cbsceneinventory/app.py +++ b/avalon/tools/cbsceneinventory/app.py @@ -481,7 +481,15 @@ def __init__(self, parent=None, items=None): self._representations_box = SearchComboBox( placeholder="") - input_layout = QtWidgets.QHBoxLayout() + self._asset_label = QtWidgets.QLabel('') + self._subset_label = QtWidgets.QLabel('') + self._repre_label = QtWidgets.QLabel('') + + main_layout = QtWidgets.QVBoxLayout() + context_layout = QtWidgets.QHBoxLayout() + asset_layout = QtWidgets.QVBoxLayout() + subset_layout = QtWidgets.QVBoxLayout() + repre_layout = QtWidgets.QVBoxLayout() accept_icon = qta.icon("fa.check", color="white") accept_btn = QtWidgets.QPushButton() @@ -489,15 +497,28 @@ def __init__(self, parent=None, items=None): accept_btn.setFixedWidth(24) accept_btn.setFixedHeight(24) - input_layout.addWidget(self._assets_box) - input_layout.addWidget(self._subsets_box) - input_layout.addWidget(self._representations_box) - input_layout.addWidget(accept_btn) + asset_layout.addWidget(self._assets_box) + asset_layout.addWidget(self._asset_label) + subset_layout.addWidget(self._subsets_box) + subset_layout.addWidget(self._subset_label) + repre_layout.addWidget(self._representations_box) + repre_layout.addWidget(self._repre_label) + + context_layout.addLayout(asset_layout) + context_layout.addLayout(subset_layout) + context_layout.addLayout(repre_layout) + context_layout.addWidget(accept_btn) - self._input_layout = input_layout self._accept_btn = accept_btn - self.setLayout(input_layout) + self._assets_box.currentIndexChanged.connect(self.on_assets_change) + self._subsets_box.currentIndexChanged.connect(self.on_subset_change) + self._representations_box.currentIndexChanged.connect( + self.on_repre_change + ) + + main_layout.addLayout(context_layout) + self.setLayout(main_layout) self.setWindowTitle("Switch selected items ...") self.connections() @@ -513,32 +534,266 @@ def __init__(self, parent=None, items=None): def connections(self): self._accept_btn.clicked.connect(self._on_accept) - def refresh(self): - """Build the need comboboxes with content""" + def on_assets_change(self): + self.refresh(1) - assets = sorted(self._get_assets()) - self._assets_box.populate(assets) + def on_subset_change(self): + self.refresh(2) - subsets = sorted(self._get_subsets()) - self._subsets_box.populate(subsets) + def on_repre_change(self): + self.refresh(3) + + def refresh(self, refresh_type=0): + """Build the need comboboxes with content""" + if refresh_type < 1: + assets = sorted(self._get_assets()) + self._assets_box.populate(assets) + + if refresh_type < 2: + last_subset = self._subsets_box.currentText() + + subsets = sorted(self._get_subsets()) + self._subsets_box.populate(subsets) + + if (last_subset != "" and last_subset in list(subsets)): + index = None + for i in range(self._subsets_box.count()): + if last_subset == str(self._subsets_box.itemText(i)): + index = i + break + if index is not None: + self._subsets_box.setCurrentIndex(index) + + if refresh_type < 3: + last_repre = self._representations_box.currentText() + + representations = sorted(self._get_representations()) + self._representations_box.populate(representations) + + if (last_repre != "" and last_repre in list(representations)): + index = None + for i in range(self._representations_box.count()): + if last_repre == self._representations_box.itemText(i): + index = i + break + if index is not None: + self._representations_box.setCurrentIndex(index) + + self.set_labels() + self.validate() + + def set_labels(self): + default = "*No changes" + asset_label = default + subset_label = default + repre_label = default + + if self._assets_box.currentText() != '': + asset_label = self._assets_box.currentText() + if self._subsets_box.currentText() != '': + subset_label = self._subsets_box.currentText() + if self._representations_box.currentText() != '': + repre_label = self._representations_box.currentText() + + self._asset_label.setText(asset_label) + self._subset_label.setText(subset_label) + self._repre_label.setText(repre_label) + + def validate(self): + asset_name = self._assets_box.get_valid_value() or None + subset_name = self._subsets_box.get_valid_value() or None + repre_name = self._representations_box.get_valid_value() or None + + asset_ok = True + subset_ok = True + repre_ok = True + for item in self._items: + if any(not x for x in [asset_name, subset_name, repre_name]): + _id = io.ObjectId(item["representation"]) + representation = io.find_one({ + "type": "representation", + "_id": _id + }) + version, subset, asset, project = io.parenthood(representation) + + if asset_name is None: + asset_name = asset["name"] + + if subset_name is None: + subset_name = subset["name"] + + if repre_name is None: + repre_name = representation["name"] + + asset = io.find_one({"name": asset_name, "type": "asset"}) + if asset is None: + asset_ok = False + continue + subset = io.find_one({ + "name": subset_name, + "type": "subset", + "parent": asset["_id"] + }) + if subset is None: + subset_ok = False + continue + version = io.find_one( + { + "type": "version", + "parent": subset["_id"] + }, + sort=[('name', -1)] + ) + if version is None: + repre_ok = False + continue - representations = sorted(self._get_representations()) - self._representations_box.populate(representations) + repre = io.find_one({ + "name": repre_name, + "type": "representation", + "parent": version["_id"] + }) + if repre is None: + repre_ok = False + + asset_sheet = '' + subset_sheet = '' + repre_sheet = '' + accept_sheet = '' + error_msg = '*Please select' + if asset_ok is False: + asset_sheet = 'border: 1px solid red;' + self._asset_label.setText(error_msg) + if subset_ok is False: + subset_sheet = 'border: 1px solid red;' + self._subset_label.setText(error_msg) + if repre_ok is False: + repre_sheet = 'border: 1px solid red;' + self._repre_label.setText(error_msg) + if asset_ok and subset_ok and repre_ok: + accept_sheet = 'border: 1px solid green;' + + self._assets_box.setStyleSheet(asset_sheet) + self._subsets_box.setStyleSheet(subset_sheet) + self._representations_box.setStyleSheet(repre_sheet) + + self._accept_btn.setEnabled(asset_ok and subset_ok and repre_ok) + self._accept_btn.setStyleSheet(accept_sheet) def _get_assets(self): - return self._get_document_names("asset") + filtered_assets = [] + for asset in io.find({'type': 'asset'}): + subsets = io.find({ + 'type': 'subset', + 'parent': asset['_id'] + }) + for subs in subsets: + filtered_assets.append(asset['name']) + break + + return filtered_assets def _get_subsets(self): - return self._get_document_names("subset") + # Filter subsets by asset in dropdown + if self._assets_box.currentText() != "": + parents = [] + parents.append(io.find_one({ + 'type': 'asset', + 'name': self._assets_box.currentText() + })) + + return self._get_document_names("subset", parents) + # If any asset in dropdown is selected + # - filter subsets by selected assets in scene inventory + assets = [] + for item in self._items: + _id = io.ObjectId(item["representation"]) + representation = io.find_one( + {"type": "representation", "_id": _id} + ) + version, subset, asset, project = io.parenthood(representation) + assets.append(asset) + + possible_subsets = None + for asset in assets: + subsets = io.find({ + 'type': 'subset', + 'parent': asset['_id'] + }) + asset_subsets = set() + for subset in subsets: + asset_subsets.add(subset['name']) + + if possible_subsets is None: + possible_subsets = asset_subsets + else: + possible_subsets = (possible_subsets & asset_subsets) + + return list(possible_subsets) def _get_representations(self): - return self._get_document_names("representation") + if self._subsets_box.currentText() != "": + subsets = [] + parents = [] + subsets.append(self._subsets_box.currentText()) + + for subset in subsets: + entity = io.find_one({ + 'type': 'subset', + 'name': subset + }) + + entity = io.find_one( + { + 'type': 'version', + 'parent': entity['_id'] + }, + sort=[('name', -1)] + ) + if entity not in parents: + parents.append(entity) + + return self._get_document_names("representation", parents) + + versions = [] + for item in self._items: + _id = io.ObjectId(item["representation"]) + representation = io.find_one( + {"type": "representation", "_id": _id} + ) + version, subset, asset, project = io.parenthood(representation) + versions.append(version) + + possible_repres = None + for version in versions: + representations = io.find({ + 'type': 'representation', + 'parent': version['_id'] + }) + repres = set() + for repre in representations: + repres.add(repre['name']) + + if possible_repres is None: + possible_repres = repres + else: + possible_repres = (possible_repres & repres) + + return list(possible_repres) - def _get_document_names(self, document_type, parent=None): + def _get_document_names(self, document_type, parents=[]): query = {"type": document_type} - if parent: - query["parent"] = parent["_id"] + + if len(parents) == 1: + query["parent"] = parents[0]["_id"] + elif len(parents) > 1: + or_exprs = [] + for parent in parents: + expr = {"parent": parent["_id"]} + or_exprs.append(expr) + + query["$or"] = or_exprs return io.find(query).distinct("name")