From 912ad165d52df7825f2ca573a8b7c5117b99d090 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 16 Nov 2021 19:15:36 +0100 Subject: [PATCH 1/9] added new button with menu --- openpype/style/style.css | 19 ++++++++++++++ openpype/tools/sceneinventory/widgets.py | 33 ++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/openpype/style/style.css b/openpype/style/style.css index 89458fd117f..2b819050168 100644 --- a/openpype/style/style.css +++ b/openpype/style/style.css @@ -771,6 +771,25 @@ QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { border: 1px solid #ff0000; } +/* Scene Inventory*/ +#ButtonWithMenu { + padding-right: 16px; + border: 1px solid #4A4949; + border-radius: 2px; +} +#ButtonWithMenu::menu-button { + border: 1px solid #4A4949; + width: 12px; + border-top-left-radius: 0px; + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; + border-bottom-left-radius: 0px; +} + +#ButtonWithMenu[state="1"], #ButtonWithMenu[state="1"]::menu-button, #ButtonWithMenu[state="1"]::menu-button:hover { + border-color: green; +} + /* Python console interpreter */ #PythonInterpreterOutput, #PythonCodeEditor { font-family: "Roboto Mono"; diff --git a/openpype/tools/sceneinventory/widgets.py b/openpype/tools/sceneinventory/widgets.py index 6bb74d2d1ba..587f443b821 100644 --- a/openpype/tools/sceneinventory/widgets.py +++ b/openpype/tools/sceneinventory/widgets.py @@ -1,6 +1,39 @@ from Qt import QtWidgets, QtCore +class ButtonWithMenu(QtWidgets.QToolButton): + def __init__(self, parent=None): + super(ButtonWithMenu, self).__init__(parent) + + self.setObjectName("ButtonWithMenu") + + self.setPopupMode(self.MenuButtonPopup) + menu = QtWidgets.QMenu(self) + + self.setMenu(menu) + + self._menu = menu + self._actions = [] + + def menu(self): + return self._menu + + def clear_actions(self): + if self._menu is not None: + self._menu.clear() + self._actions = [] + + def add_action(self, action): + self._actions.append(action) + self._menu.addAction(action) + + def _on_action_trigger(self): + action = self.sender() + if action not in self._actions: + return + action.trigger() + + class SearchComboBox(QtWidgets.QComboBox): """Searchable ComboBox with empty placeholder value as first value""" From 3ee5e3ec40a679a11ccc77070201ed8b6bbb9655 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 16 Nov 2021 19:15:51 +0100 Subject: [PATCH 2/9] moved modification from avalon PR --- .../tools/sceneinventory/switch_dialog.py | 397 ++++++++++++++++-- 1 file changed, 371 insertions(+), 26 deletions(-) diff --git a/openpype/tools/sceneinventory/switch_dialog.py b/openpype/tools/sceneinventory/switch_dialog.py index ecad8eac0a3..a7b586da3e5 100644 --- a/openpype/tools/sceneinventory/switch_dialog.py +++ b/openpype/tools/sceneinventory/switch_dialog.py @@ -2,10 +2,13 @@ import logging from Qt import QtWidgets, QtCore -from avalon import io, api +from avalon import io, api, pipeline from avalon.vendor import qtawesome -from .widgets import SearchComboBox +from .widgets import ( + ButtonWithMenu, + SearchComboBox +) log = logging.getLogger("SwitchAssetDialog") @@ -55,7 +58,7 @@ def __init__(self, parent=None, items=None): current_asset_btn = QtWidgets.QPushButton("Use current asset") accept_icon = qtawesome.icon("fa.check", color="white") - accept_btn = QtWidgets.QPushButton(self) + accept_btn = ButtonWithMenu(self) accept_btn.setIcon(accept_icon) main_layout = QtWidgets.QGridLayout(self) @@ -100,6 +103,24 @@ def __init__(self, parent=None, items=None): self._accept_btn = accept_btn + self.content_loaders = set() + self.content_assets = {} + self.content_subsets = {} + self.content_versions = {} + self.content_repres = {} + + self.hero_version_ids = set() + + self.missing_assets = [] + self.missing_versions = [] + self.missing_subsets = [] + self.missing_repres = [] + self.missing_docs = False + + self.archived_assets = [] + self.archived_subsets = [] + self.archived_repres = [] + self._init_asset_name = None self._init_subset_name = None self._init_repre_name = None @@ -117,13 +138,15 @@ def __init__(self, parent=None, items=None): accept_btn.setFocus() def _prepare_content_data(self): - repre_ids = [ - io.ObjectId(item["representation"]) - for item in self._items - ] + repre_ids = set() + content_loaders = set() + for item in self._items: + repre_ids.add(io.ObjectId(item["representation"])) + content_loaders.add(item["loader"]) + repres = list(io.find({ "type": {"$in": ["representation", "archived_representation"]}, - "_id": {"$in": repre_ids} + "_id": {"$in": list(repre_ids)} })) repres_by_id = {repre["_id"]: repre for repre in repres} @@ -207,6 +230,7 @@ def _prepare_content_data(self): else: content_assets[asset_id] = assets_by_id[asset_id] + self.content_loaders = content_loaders self.content_assets = content_assets self.content_subsets = content_subsets self.content_versions = content_versions @@ -260,8 +284,11 @@ def refresh(self, init_refresh=False): # Fill comboboxes with values self.set_labels() + self.apply_validations(validation_state) + self._build_loaders_menu() + 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) @@ -269,23 +296,89 @@ def refresh(self, init_refresh=False): self._fill_check = True - def _get_loaders(self, representations): - if not representations: + def _build_loaders_menu(self): + repre_ids = self._get_current_output_repre_ids() + loaders = self._get_loaders(repre_ids) + # Get and destroy the action group + self._accept_btn.clear_actions() + + if not loaders: + return + + # Build new action group + group = QtWidgets.QActionGroup(self._accept_btn) + + for loader in loaders: + # Label + label = getattr(loader, "label", None) + if label is None: + label = loader.__name__ + + action = group.addAction(label) + # action = QtWidgets.QAction(label) + action.setData(loader) + + # Support font-awesome icons using the `.icon` and `.color` + # attributes on plug-ins. + icon = getattr(loader, "icon", None) + if icon is not None: + try: + key = "fa.{0}".format(icon) + color = getattr(loader, "color", "white") + action.setIcon(qtawesome.icon(key, color=color)) + + except Exception as exc: + print("Unable to set icon for loader {}: {}".format( + loader, str(exc) + )) + + self._accept_btn.add_action(action) + + group.triggered.connect(self._on_action_clicked) + + def _on_action_clicked(self, action): + loader_plugin = action.data() + self._trigger_switch(loader_plugin) + + def _get_loaders(self, repre_ids): + repre_contexts = None + if repre_ids: + repre_contexts = pipeline.get_repres_contexts(repre_ids) + + if not repre_contexts: return list() - available_loaders = filter( - lambda l: not (hasattr(l, "is_utility") and l.is_utility), - api.discover(api.Loader) - ) + available_loaders = [] + for loader_plugin in api.discover(api.Loader): + # Skip loaders without switch method + if not hasattr(loader_plugin, "switch"): + continue - loaders = set() + # Skip utility loaders + if ( + hasattr(loader_plugin, "is_utility") + and loader_plugin.is_utility + ): + continue + available_loaders.append(loader_plugin) - for representation in representations: - for loader in api.loaders_from_representation( - available_loaders, - representation - ): - loaders.add(loader) + loaders = None + for repre_context in repre_contexts.values(): + _loaders = set(pipeline.loaders_from_repre_context( + available_loaders, repre_context + )) + if loaders is None: + loaders = _loaders + else: + loaders = _loaders.intersection(loaders) + + if not loaders: + break + + if loaders is None: + loaders = [] + else: + loaders = list(loaders) return loaders @@ -325,12 +418,11 @@ def set_labels(self): 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 + accept_state = "" if validation_state.asset_ok is False: asset_sheet = error_sheet self._asset_label.setText(error_msg) @@ -342,14 +434,264 @@ def apply_validations(self, validation_state): self._repre_label.setText(error_msg) if validation_state.all_ok: - accept_sheet = success_sheet + accept_state = "1" 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 "") + self._set_style_property(self._accept_btn, "state", accept_state) + + def _set_style_property(self, widget, name, value): + cur_value = widget.property(name) + if cur_value == value: + return + widget.setProperty(name, value) + widget.style().polish(widget) + + def _get_current_output_repre_ids(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() + selected_repre = self._representations_box.currentText() + + # Nothing is selected + # [ ] [ ] [ ] + if not selected_asset and not selected_subset and not selected_repre: + return list(self.content_repres.keys()) + + # Prepare asset document if asset is selcted + if selected_asset: + asset_doc = io.find_one( + {"type": "asset", "name": selected_asset}, + {"_id": True} + ) + if not asset_doc: + return [] + + # Everything is selected + # [x] [x] [x] + if selected_asset and selected_subset and selected_repre: + subset_doc = io.find_one( + { + "type": "subset", + "name": selected_subset, + "parent": asset_doc["_id"] + }, + {"_id": True} + ) + 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) + if not version_doc: + return [] + + repre_docs = io.find( + { + "type": "representation", + "parent": version_doc["_id"], + "name": selected_repre + }, + {"_id": True} + ) + return [repre_doc["_id"] for repre_doc in repre_docs] + + # [x] [x] [ ] + # If asset and subset is selected + if selected_asset and selected_subset: + subset_doc = io.find_one( + { + "type": "subset", + "parent": asset_doc["_id"], + "name": selected_subset + }, + {"_id": True} + ) + if not subset_doc: + return [] + + repre_names = set() + for repre_doc in self.content_repres.values(): + repre_names.add(repre_doc["name"]) + + repre_docs = io.find( + { + "type": "rerpesentation", + "parent": subset_doc["_id"], + "name": {"$in": list(repre_names)} + }, + {"_id": True} + ) + return [repre_doc["_id"] for repre_doc in repre_docs] + + # [x] [ ] [x] + # If asset and repre is selected + if selected_asset and selected_repre: + susbet_names = set() + for subset_doc in self.content_subsets.values(): + susbet_names.add(subset_doc["name"]) + + subset_docs = io.find( + { + "type": "subset", + "name": {"$in": list(susbet_names)} + }, + {"_id": True} + ) + subset_ids = [subset_doc["_id"] for subset_doc in subset_docs] + repre_docs = io.find( + { + "type": "representation", + "parent": {"$in": subset_ids}, + "name": selected_repre + }, + {"_id": True} + ) + return [repre_doc["_id"] for repre_doc in repre_docs] + + # [x] [ ] [ ] + # If asset and subset is selected + if selected_asset: + repres_by_subset_name = collections.defaultdict(set) + for repre_doc in self.content_repres.values(): + repre_name = repre_doc["name"] + version_doc = self.content_versions[repre_doc["parent"]] + subset_doc = self.content_subsets[version_doc["parent"]] + subset_name = subset_doc["name"] + repres_by_subset_name[subset_name].add(repre_name) + + asset_doc = io.find_one( + {"type": "asset", "name": selected_asset}, + {"_id": True} + ) + subset_docs = list(io.find( + { + "type": "subset", + "parent": asset_doc["_id"], + "name": {"$in": list(repres_by_subset_name.keys())} + }, + {"_id": True, "name": True} + )) + subset_name_by_id = { + subset_doc["_id"]: subset_doc["name"] + for subset_doc in subset_docs + } + subset_ids = list(subset_name_by_id.keys()) + last_versions_by_subset_id = self.find_last_versions(subset_ids) + last_version_id_by_subset_name = {} + for subset_id, last_version in last_versions_by_subset_id.items(): + subset_name = subset_name_by_id[subset_id] + last_version_id_by_subset_name[subset_name] = ( + last_version["_id"] + ) + + repre_or_query = [] + for subset_name, repre_names in repres_by_subset_name.items(): + version_id = last_version_id_by_subset_name.get(subset_name) + # This should not happen but why to crash? + if version_id is None: + continue + repre_or_query.append({ + "parent": version_id, + "name": {"$in": list(repre_names)} + }) + repre_docs = io.find( + {"$or": repre_or_query}, + {"_id": True} + ) + return [repre_doc["_id"] for repre_doc in repre_docs] + + # [ ] [x] [x] + if selected_subset and selected_repre: + subset_docs = list(io.find({ + "type": "subset", + "parent": {"$in": list(self.content_assets.keys())}, + "name": selected_subset + })) + subset_ids = [subset_doc["_id"] for subset_doc in subset_docs] + last_versions_by_subset_id = self.find_last_versions(subset_ids) + last_version_ids = [ + last_version["_id"] + for last_version in last_versions_by_subset_id.values() + ] + repre_docs = io.find({ + "type": "representation", + "parent": {"$in": last_version_ids}, + "name": selected_repre + }) + + return [repre_doc["_id"] for repre_doc in repre_docs] + + # [ ] [x] [ ] + if selected_subset: + subset_docs = list(io.find( + { + "type": "subset", + "parent": {"$in": list(self.content_assets.keys())}, + "name": selected_subset + }, + {"_id": True, "parent": True} + )) + 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_names_by_asset_id = collections.defaultdict(set) + 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_doc = self.content_assets[subset_doc["parent"]] + repre_name = repre_doc["name"] + asset_id = asset_doc["_id"] + repre_names_by_asset_id[asset_id].add(repre_name) + + repre_or_query = [] + for last_version_id, subset_id in subset_id_by_version_id.items(): + subset_doc = subset_docs_by_id[subset_id] + asset_id = subset_doc["parent"] + repre_names = repre_names_by_asset_id.get(asset_id) + if not repre_names: + continue + repre_or_query.append({ + "parent": last_version_id, + "name": {"$in": list(repre_names)} + }) + repre_docs = io.find( + { + "type": "representation", + "$or": repre_or_query + }, + {"_id": True} + ) + + return [repre_doc["_id"] for repre_doc in repre_docs] + + # [ ] [ ] [x] + repre_docs = io.find( + { + "name": selected_repre, + "parent": {"$in": list(self.content_versions.keys())} + }, + {"_id": True} + ) + return [repre_doc["_id"] for repre_doc in repre_docs] def _get_asset_box_values(self): asset_docs = io.find( @@ -852,6 +1194,9 @@ def _on_current_asset(self): self._assets_box.setCurrentIndex(index) def _on_accept(self): + self._trigger_switch() + + def _trigger_switch(self, loader=None): # 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() @@ -974,7 +1319,7 @@ def _on_accept(self): repre_doc = repres_by_name[container_repre_name] try: - api.switch(container, repre_doc) + api.switch(container, repre_doc, loader) except Exception: msg = ( "Couldn't switch asset." From 449d296d57f3ffdd0dfab516492f849affdb5486 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 18 Nov 2021 09:53:42 +0100 Subject: [PATCH 3/9] split _get_current_output_repre_ids into more submethods --- .../tools/sceneinventory/switch_dialog.py | 387 ++++++++++-------- 1 file changed, 210 insertions(+), 177 deletions(-) diff --git a/openpype/tools/sceneinventory/switch_dialog.py b/openpype/tools/sceneinventory/switch_dialog.py index a7b586da3e5..3faa6a7cbe7 100644 --- a/openpype/tools/sceneinventory/switch_dialog.py +++ b/openpype/tools/sceneinventory/switch_dialog.py @@ -462,7 +462,8 @@ def _get_current_output_repre_ids(self): if not selected_asset and not selected_subset and not selected_repre: return list(self.content_repres.keys()) - # Prepare asset document if asset is selcted + # Prepare asset document if asset is selected + asset_doc = None if selected_asset: asset_doc = io.find_one( {"type": "asset", "name": selected_asset}, @@ -474,215 +475,247 @@ def _get_current_output_repre_ids(self): # Everything is selected # [x] [x] [x] if selected_asset and selected_subset and selected_repre: - subset_doc = io.find_one( - { - "type": "subset", - "name": selected_subset, - "parent": asset_doc["_id"] - }, - {"_id": True} + return self._get_current_output_repre_ids_xxx( + asset_doc, selected_subset, selected_repre ) - 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) - if not version_doc: - return [] - - repre_docs = io.find( - { - "type": "representation", - "parent": version_doc["_id"], - "name": selected_repre - }, - {"_id": True} - ) - return [repre_doc["_id"] for repre_doc in repre_docs] # [x] [x] [ ] # If asset and subset is selected if selected_asset and selected_subset: - subset_doc = io.find_one( - { - "type": "subset", - "parent": asset_doc["_id"], - "name": selected_subset - }, - {"_id": True} - ) - if not subset_doc: - return [] - - repre_names = set() - for repre_doc in self.content_repres.values(): - repre_names.add(repre_doc["name"]) - - repre_docs = io.find( - { - "type": "rerpesentation", - "parent": subset_doc["_id"], - "name": {"$in": list(repre_names)} - }, - {"_id": True} + return self._get_current_output_repre_ids_xxo( + asset_doc, selected_subset ) - return [repre_doc["_id"] for repre_doc in repre_docs] # [x] [ ] [x] # If asset and repre is selected if selected_asset and selected_repre: - susbet_names = set() - for subset_doc in self.content_subsets.values(): - susbet_names.add(subset_doc["name"]) - - subset_docs = io.find( - { - "type": "subset", - "name": {"$in": list(susbet_names)} - }, - {"_id": True} + return self._get_current_output_repre_ids_xox( + asset_doc, selected_repre ) - subset_ids = [subset_doc["_id"] for subset_doc in subset_docs] - repre_docs = io.find( - { - "type": "representation", - "parent": {"$in": subset_ids}, - "name": selected_repre - }, - {"_id": True} - ) - return [repre_doc["_id"] for repre_doc in repre_docs] # [x] [ ] [ ] # If asset and subset is selected if selected_asset: - repres_by_subset_name = collections.defaultdict(set) - for repre_doc in self.content_repres.values(): - repre_name = repre_doc["name"] - version_doc = self.content_versions[repre_doc["parent"]] - subset_doc = self.content_subsets[version_doc["parent"]] - subset_name = subset_doc["name"] - repres_by_subset_name[subset_name].add(repre_name) + return self._get_current_output_repre_ids_xoo(asset_doc) - asset_doc = io.find_one( - {"type": "asset", "name": selected_asset}, - {"_id": True} + # [ ] [x] [x] + if selected_subset and selected_repre: + return self._get_current_output_repre_ids_oxx( + selected_subset, selected_repre ) - subset_docs = list(io.find( - { - "type": "subset", - "parent": asset_doc["_id"], - "name": {"$in": list(repres_by_subset_name.keys())} - }, - {"_id": True, "name": True} - )) - subset_name_by_id = { - subset_doc["_id"]: subset_doc["name"] - for subset_doc in subset_docs - } - subset_ids = list(subset_name_by_id.keys()) - last_versions_by_subset_id = self.find_last_versions(subset_ids) - last_version_id_by_subset_name = {} - for subset_id, last_version in last_versions_by_subset_id.items(): - subset_name = subset_name_by_id[subset_id] - last_version_id_by_subset_name[subset_name] = ( - last_version["_id"] - ) - repre_or_query = [] - for subset_name, repre_names in repres_by_subset_name.items(): - version_id = last_version_id_by_subset_name.get(subset_name) - # This should not happen but why to crash? - if version_id is None: - continue - repre_or_query.append({ - "parent": version_id, - "name": {"$in": list(repre_names)} - }) - repre_docs = io.find( - {"$or": repre_or_query}, - {"_id": True} + # [ ] [x] [ ] + if selected_subset: + return self._get_current_output_repre_ids_oxo( + selected_subset ) - return [repre_doc["_id"] for repre_doc in repre_docs] - # [ ] [x] [x] - if selected_subset and selected_repre: - subset_docs = list(io.find({ + return self._get_current_output_repre_ids_oox(selected_repre) + + def _get_current_output_repre_ids_xxx( + self, asset_doc, selected_subset, selected_repre + ): + subset_doc = io.find_one( + { "type": "subset", - "parent": {"$in": list(self.content_assets.keys())}, + "name": selected_subset, + "parent": asset_doc["_id"] + }, + {"_id": True} + ) + 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) + if not version_doc: + return [] + + repre_docs = io.find( + { + "type": "representation", + "parent": version_doc["_id"], + "name": selected_repre + }, + {"_id": True} + ) + return [repre_doc["_id"] for repre_doc in repre_docs] + + def _get_current_output_repre_ids_xxo(self, asset_doc, selected_subset): + subset_doc = io.find_one( + { + "type": "subset", + "parent": asset_doc["_id"], "name": selected_subset - })) - subset_ids = [subset_doc["_id"] for subset_doc in subset_docs] - last_versions_by_subset_id = self.find_last_versions(subset_ids) - last_version_ids = [ - last_version["_id"] - for last_version in last_versions_by_subset_id.values() - ] - repre_docs = io.find({ + }, + {"_id": True} + ) + if not subset_doc: + return [] + + repre_names = set() + for repre_doc in self.content_repres.values(): + repre_names.add(repre_doc["name"]) + + repre_docs = io.find( + { + "type": "rerpesentation", + "parent": subset_doc["_id"], + "name": {"$in": list(repre_names)} + }, + {"_id": True} + ) + return [repre_doc["_id"] for repre_doc in repre_docs] + + def _get_current_output_repre_ids_xox(self, asset_doc, selected_repre): + susbet_names = set() + for subset_doc in self.content_subsets.values(): + susbet_names.add(subset_doc["name"]) + + subset_docs = io.find( + { + "type": "subset", + "name": {"$in": list(susbet_names)}, + "parent": asset_doc["_id"] + }, + {"_id": True} + ) + subset_ids = [subset_doc["_id"] for subset_doc in subset_docs] + repre_docs = io.find( + { "type": "representation", - "parent": {"$in": last_version_ids}, + "parent": {"$in": subset_ids}, "name": selected_repre + }, + {"_id": True} + ) + return [repre_doc["_id"] for repre_doc in repre_docs] + + def _get_current_output_repre_ids_xoo(self, asset_doc): + repres_by_subset_name = collections.defaultdict(set) + for repre_doc in self.content_repres.values(): + repre_name = repre_doc["name"] + version_doc = self.content_versions[repre_doc["parent"]] + subset_doc = self.content_subsets[version_doc["parent"]] + subset_name = subset_doc["name"] + repres_by_subset_name[subset_name].add(repre_name) + + subset_docs = list(io.find( + { + "type": "subset", + "parent": asset_doc["_id"], + "name": {"$in": list(repres_by_subset_name.keys())} + }, + {"_id": True, "name": True} + )) + subset_name_by_id = { + subset_doc["_id"]: subset_doc["name"] + for subset_doc in subset_docs + } + subset_ids = list(subset_name_by_id.keys()) + last_versions_by_subset_id = self.find_last_versions(subset_ids) + last_version_id_by_subset_name = {} + for subset_id, last_version in last_versions_by_subset_id.items(): + subset_name = subset_name_by_id[subset_id] + last_version_id_by_subset_name[subset_name] = ( + last_version["_id"] + ) + + repre_or_query = [] + for subset_name, repre_names in repres_by_subset_name.items(): + version_id = last_version_id_by_subset_name.get(subset_name) + # This should not happen but why to crash? + if version_id is None: + continue + repre_or_query.append({ + "parent": version_id, + "name": {"$in": list(repre_names)} }) + repre_docs = io.find( + {"$or": repre_or_query}, + {"_id": True} + ) + return [repre_doc["_id"] for repre_doc in repre_docs] - return [repre_doc["_id"] for repre_doc in repre_docs] + def _get_current_output_repre_ids_oxx( + self, selected_subset, selected_repre + ): + subset_docs = list(io.find({ + "type": "subset", + "parent": {"$in": list(self.content_assets.keys())}, + "name": selected_subset + })) + subset_ids = [subset_doc["_id"] for subset_doc in subset_docs] + last_versions_by_subset_id = self.find_last_versions(subset_ids) + last_version_ids = [ + last_version["_id"] + for last_version in last_versions_by_subset_id.values() + ] + repre_docs = io.find({ + "type": "representation", + "parent": {"$in": last_version_ids}, + "name": selected_repre + }) - # [ ] [x] [ ] - if selected_subset: - subset_docs = list(io.find( - { - "type": "subset", - "parent": {"$in": list(self.content_assets.keys())}, - "name": selected_subset - }, - {"_id": True, "parent": True} - )) - if not subset_docs: - return list() + return [repre_doc["_id"] for repre_doc in repre_docs] - 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() - ) + def _get_current_output_repre_ids_oxo(self, selected_subset): + subset_docs = list(io.find( + { + "type": "subset", + "parent": {"$in": list(self.content_assets.keys())}, + "name": selected_subset + }, + {"_id": True, "parent": True} + )) + if not subset_docs: + return list() - 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 + 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() + ) - if not subset_id_by_version_id: - return list() + 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_names_by_asset_id = collections.defaultdict(set) - 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_doc = self.content_assets[subset_doc["parent"]] - repre_name = repre_doc["name"] - asset_id = asset_doc["_id"] - repre_names_by_asset_id[asset_id].add(repre_name) - - repre_or_query = [] - for last_version_id, subset_id in subset_id_by_version_id.items(): - subset_doc = subset_docs_by_id[subset_id] - asset_id = subset_doc["parent"] - repre_names = repre_names_by_asset_id.get(asset_id) - if not repre_names: - continue - repre_or_query.append({ - "parent": last_version_id, - "name": {"$in": list(repre_names)} - }) - repre_docs = io.find( - { - "type": "representation", - "$or": repre_or_query - }, - {"_id": True} - ) + if not subset_id_by_version_id: + return list() + + repre_names_by_asset_id = collections.defaultdict(set) + 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_doc = self.content_assets[subset_doc["parent"]] + repre_name = repre_doc["name"] + asset_id = asset_doc["_id"] + repre_names_by_asset_id[asset_id].add(repre_name) + + repre_or_query = [] + for last_version_id, subset_id in subset_id_by_version_id.items(): + subset_doc = subset_docs_by_id[subset_id] + asset_id = subset_doc["parent"] + repre_names = repre_names_by_asset_id.get(asset_id) + if not repre_names: + continue + repre_or_query.append({ + "parent": last_version_id, + "name": {"$in": list(repre_names)} + }) + repre_docs = io.find( + { + "type": "representation", + "$or": repre_or_query + }, + {"_id": True} + ) - return [repre_doc["_id"] for repre_doc in repre_docs] + return [repre_doc["_id"] for repre_doc in repre_docs] + def _get_current_output_repre_ids_oox(self, selected_repre): # [ ] [ ] [x] repre_docs = io.find( { From 46ded83a97174047f7c070cc48a7cb7aae86d61c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 18 Nov 2021 10:22:06 +0100 Subject: [PATCH 4/9] modified completer to look like combobox menu --- openpype/style/style.css | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/openpype/style/style.css b/openpype/style/style.css index 2b819050168..b681a94c220 100644 --- a/openpype/style/style.css +++ b/openpype/style/style.css @@ -722,14 +722,13 @@ QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { } #CompleterView::item { - padding: 2px 4px 2px 4px; - border-left: 3px solid {color:bg-view}; + background: {color:bg-view-hover}; + color: {color:font}; + padding-left: 0px; } - +/*#CompleterView::item:selected:hover {*/ #CompleterView::item:hover { - border-left-color: {palette:blue-base}; - background: {color:bg-view-selection}; - color: {color:font}; + background: {color:bg-view-hover}; } /* Launcher specific stylesheets */ From 469adb56ad9fa1811fd29852ad3f863421b84b4b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 18 Nov 2021 10:24:11 +0100 Subject: [PATCH 5/9] set style to SearchCombobox --- openpype/tools/sceneinventory/widgets.py | 27 ++++++++++++++++-------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/openpype/tools/sceneinventory/widgets.py b/openpype/tools/sceneinventory/widgets.py index 587f443b821..4c4aafad3a0 100644 --- a/openpype/tools/sceneinventory/widgets.py +++ b/openpype/tools/sceneinventory/widgets.py @@ -1,4 +1,5 @@ from Qt import QtWidgets, QtCore +from openpype import style class ButtonWithMenu(QtWidgets.QToolButton): @@ -37,23 +38,31 @@ def _on_action_trigger(self): class SearchComboBox(QtWidgets.QComboBox): """Searchable ComboBox with empty placeholder value as first value""" - def __init__(self, parent=None): + def __init__(self, parent): super(SearchComboBox, self).__init__(parent) self.setEditable(True) self.setInsertPolicy(self.NoInsert) - # Apply completer settings + combobox_delegate = QtWidgets.QStyledItemDelegate(self) + self.setItemDelegate(combobox_delegate) + completer = self.completer() - completer.setCompletionMode(completer.PopupCompletion) + completer.setCompletionMode( + QtWidgets.QCompleter.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()) + completer_view = completer.popup() + completer_view.setObjectName("CompleterView") + completer_delegate = QtWidgets.QStyledItemDelegate(completer_view) + completer_view.setItemDelegate(completer_delegate) + completer_view.setStyleSheet(style.load_stylesheet()) + + self._combobox_delegate = combobox_delegate + + self._completer_delegate = completer_delegate + self._completer = completer def set_placeholder(self, placeholder): self.lineEdit().setPlaceholderText(placeholder) From 5c4693394ab97960da45a319f971a7ea07ed8f5e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 18 Nov 2021 10:24:22 +0100 Subject: [PATCH 6/9] moved ui logic earlier --- openpype/tools/sceneinventory/switch_dialog.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/openpype/tools/sceneinventory/switch_dialog.py b/openpype/tools/sceneinventory/switch_dialog.py index 3faa6a7cbe7..7c9f7ef5c0e 100644 --- a/openpype/tools/sceneinventory/switch_dialog.py +++ b/openpype/tools/sceneinventory/switch_dialog.py @@ -103,6 +103,12 @@ def __init__(self, parent=None, items=None): self._accept_btn = accept_btn + 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() + self.content_loaders = set() self.content_assets = {} self.content_subsets = {} @@ -131,12 +137,6 @@ def __init__(self, parent=None, items=None): 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 = set() content_loaders = set() From 5a2dcd9016800f0be72ee60b228500ad25db57db Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 18 Nov 2021 10:27:16 +0100 Subject: [PATCH 7/9] removed commented line --- openpype/style/style.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/style/style.css b/openpype/style/style.css index b681a94c220..02ac1d7505b 100644 --- a/openpype/style/style.css +++ b/openpype/style/style.css @@ -726,7 +726,7 @@ QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { color: {color:font}; padding-left: 0px; } -/*#CompleterView::item:selected:hover {*/ + #CompleterView::item:hover { background: {color:bg-view-hover}; } From 74d7dea47ba0ad40d225bef2532c74abc8a92ad0 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 18 Nov 2021 10:29:00 +0100 Subject: [PATCH 8/9] move comment --- openpype/tools/sceneinventory/switch_dialog.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/tools/sceneinventory/switch_dialog.py b/openpype/tools/sceneinventory/switch_dialog.py index 7c9f7ef5c0e..c0886747b22 100644 --- a/openpype/tools/sceneinventory/switch_dialog.py +++ b/openpype/tools/sceneinventory/switch_dialog.py @@ -510,6 +510,7 @@ def _get_current_output_repre_ids(self): selected_subset ) + # [ ] [ ] [x] return self._get_current_output_repre_ids_oox(selected_repre) def _get_current_output_repre_ids_xxx( @@ -716,7 +717,6 @@ def _get_current_output_repre_ids_oxo(self, selected_subset): return [repre_doc["_id"] for repre_doc in repre_docs] def _get_current_output_repre_ids_oox(self, selected_repre): - # [ ] [ ] [x] repre_docs = io.find( { "name": selected_repre, From 9dfa2b732a376873ea43a62e998ca196f0264a67 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 18 Nov 2021 10:31:39 +0100 Subject: [PATCH 9/9] fix indentation --- openpype/tools/sceneinventory/switch_dialog.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/tools/sceneinventory/switch_dialog.py b/openpype/tools/sceneinventory/switch_dialog.py index c0886747b22..75e2b6be40a 100644 --- a/openpype/tools/sceneinventory/switch_dialog.py +++ b/openpype/tools/sceneinventory/switch_dialog.py @@ -358,7 +358,7 @@ def _get_loaders(self, repre_ids): if ( hasattr(loader_plugin, "is_utility") and loader_plugin.is_utility - ): + ): continue available_loaders.append(loader_plugin)