Merge pull request #2731 from pypeclub/bugfix/OP-2643_Loader-multiple-asset-selection-error

Loader UI: Multiple asset selection and underline colors fixed
This commit is contained in:
Jakub Trllo 2022-02-16 13:42:30 +01:00 committed by GitHub
commit 8deb622ae6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 109 additions and 148 deletions

View file

@ -396,9 +396,7 @@ class LibraryLoaderWindow(QtWidgets.QDialog):
self._versionschanged()
return
selected_subsets = self._subsets_widget.selected_subsets(
_merged=True, _other=False
)
selected_subsets = self._subsets_widget.get_selected_merge_items()
asset_colors = {}
asset_ids = []
@ -423,35 +421,14 @@ class LibraryLoaderWindow(QtWidgets.QDialog):
self._versionschanged()
def _versionschanged(self):
selection = self._subsets_widget.view.selectionModel()
# Active must be in the selected rows otherwise we
# assume it's not actually an "active" current index.
version_docs = None
items = self._subsets_widget.get_selected_subsets()
version_doc = None
active = selection.currentIndex()
rows = selection.selectedRows(column=active.column())
if active and active in rows:
item = active.data(self._subsets_widget.model.ItemRole)
if (
item is not None
and not (item.get("isGroup") or item.get("isMerged"))
):
version_doc = item["version_document"]
if rows:
version_docs = []
for index in rows:
if not index or not index.isValid():
continue
item = index.data(self._subsets_widget.model.ItemRole)
if (
item is None
or item.get("isGroup")
or item.get("isMerged")
):
continue
version_docs.append(item["version_document"])
version_docs = []
for item in items:
doc = item["version_document"]
version_docs.append(doc)
if version_doc is None:
version_doc = doc
self._version_info_widget.set_version(version_doc)

View file

@ -287,9 +287,7 @@ class LoaderWindow(QtWidgets.QDialog):
on selection change so they match current selection.
"""
# TODO do not touch inner attributes of asset widget
last_asset_ids = self.data["state"]["assetIds"]
if last_asset_ids:
self._assets_widget.clear_underlines()
self._assets_widget.clear_underlines()
def _assetschanged(self):
"""Selected assets have changed"""
@ -328,12 +326,11 @@ class LoaderWindow(QtWidgets.QDialog):
asset_ids = self.data["state"]["assetIds"]
# Skip setting colors if not asset multiselection
if not asset_ids or len(asset_ids) < 2:
self.clear_assets_underlines()
self._versionschanged()
return
selected_subsets = self._subsets_widget.selected_subsets(
_merged=True, _other=False
)
selected_subsets = self._subsets_widget.get_selected_merge_items()
asset_colors = {}
asset_ids = []
@ -358,37 +355,16 @@ class LoaderWindow(QtWidgets.QDialog):
self._versionschanged()
def _versionschanged(self):
subsets = self._subsets_widget
selection = subsets.view.selectionModel()
# Active must be in the selected rows otherwise we
# assume it's not actually an "active" current index.
items = self._subsets_widget.get_selected_subsets()
version_doc = None
active = selection.currentIndex()
rows = selection.selectedRows(column=active.column())
if active:
if active in rows:
item = active.data(subsets.model.ItemRole)
if (
item is not None and
not (item.get("isGroup") or item.get("isMerged"))
):
version_doc = item["version_document"]
self._version_info_widget.set_version(version_doc)
version_docs = []
if rows:
for index in rows:
if not index or not index.isValid():
continue
item = index.data(subsets.model.ItemRole)
if item is None:
continue
if item.get("isGroup") or item.get("isMerged"):
for child in item.children():
version_docs.append(child["version_document"])
else:
version_docs.append(item["version_document"])
for item in items:
doc = item["version_document"]
version_docs.append(doc)
if version_doc is None:
version_doc = doc
self._version_info_widget.set_version(version_doc)
thumbnail_src_ids = [
version_doc["_id"]
@ -480,18 +456,7 @@ class LoaderWindow(QtWidgets.QDialog):
self.echo("Grouping not enabled.")
return
selected = []
merged_items = []
for item in subsets.selected_subsets(_merged=True):
if item.get("isMerged"):
merged_items.append(item)
else:
selected.append(item)
for merged_item in merged_items:
for child_item in merged_item.children():
selected.append(child_item)
selected = self._subsets_widget.get_selected_subsets()
if not selected:
self.echo("No selected subset.")
return

View file

@ -18,26 +18,6 @@ def change_visibility(model, view, column_name, visible):
view.setColumnHidden(index, not visible)
def get_selected_items(rows, item_role):
items = []
for row_index in rows:
item = row_index.data(item_role)
if item.get("isGroup"):
continue
elif item.get("isMerged"):
for idx in range(row_index.model().rowCount(row_index)):
child_index = row_index.child(idx, 0)
item = child_index.data(item_role)
if item not in items:
items.append(item)
else:
if item not in items:
items.append(item)
return items
def get_options(action, loader, parent, repre_contexts):
"""Provides dialog to select value from loader provided options.

View file

@ -1,6 +1,7 @@
import copy
import re
import math
from uuid import uuid4
from avalon import (
style,
@ -22,6 +23,8 @@ from openpype.tools.utils.constants import (
REMOTE_AVAILABILITY_ROLE
)
ITEM_ID_ROLE = QtCore.Qt.UserRole + 90
def is_filtering_recursible():
"""Does Qt binding support recursive filtering for QSortFilterProxyModel?
@ -179,6 +182,7 @@ class SubsetsModel(TreeModel, BaseRepresentationModel):
self._icons = {
"subset": qtawesome.icon("fa.file-o", color=style.colors.default)
}
self._items_by_id = {}
self._doc_fetching_thread = None
self._doc_fetching_stop = False
@ -188,6 +192,15 @@ class SubsetsModel(TreeModel, BaseRepresentationModel):
self.refresh()
def get_item_by_id(self, item_id):
return self._items_by_id.get(item_id)
def add_child(self, new_item, *args, **kwargs):
item_id = str(uuid4())
new_item["id"] = item_id
self._items_by_id[item_id] = new_item
super(SubsetsModel, self).add_child(new_item, *args, **kwargs)
def set_assets(self, asset_ids):
self._asset_ids = asset_ids
self.refresh()
@ -486,7 +499,7 @@ class SubsetsModel(TreeModel, BaseRepresentationModel):
def refresh(self):
self.stop_fetch_thread()
self.clear()
self._items_by_id = {}
self.reset_sync_server()
if not self._asset_ids:
@ -497,6 +510,7 @@ class SubsetsModel(TreeModel, BaseRepresentationModel):
def on_doc_fetched(self):
self.clear()
self._items_by_id = {}
self.beginResetModel()
asset_docs_by_id = self._doc_payload.get(
@ -524,9 +538,13 @@ class SubsetsModel(TreeModel, BaseRepresentationModel):
return
self._fill_subset_items(
asset_docs_by_id, subset_docs_by_id, last_versions_by_subset_id,
asset_docs_by_id,
subset_docs_by_id,
last_versions_by_subset_id,
repre_info_by_version_id
)
self.endResetModel()
self.refreshed.emit(True)
def create_multiasset_group(
self, subset_name, asset_ids, subset_counter, parent_item=None
@ -538,7 +556,6 @@ class SubsetsModel(TreeModel, BaseRepresentationModel):
merge_group.update({
"subset": "{} ({})".format(subset_name, len(asset_ids)),
"isMerged": True,
"childRow": 0,
"subsetColor": subset_color,
"assetIds": list(asset_ids),
"icon": qtawesome.icon(
@ -547,7 +564,6 @@ class SubsetsModel(TreeModel, BaseRepresentationModel):
)
})
subset_counter += 1
self.add_child(merge_group, parent_item)
return merge_group
@ -567,8 +583,7 @@ class SubsetsModel(TreeModel, BaseRepresentationModel):
group_item = Item()
group_item.update({
"subset": group_name,
"isGroup": True,
"childRow": 0
"isGroup": True
})
group_item.update(group_data)
@ -666,14 +681,14 @@ class SubsetsModel(TreeModel, BaseRepresentationModel):
index = self.index(item.row(), 0, parent_index)
self.set_version(index, last_version)
self.endResetModel()
self.refreshed.emit(True)
def data(self, index, role):
if not index.isValid():
return
item = index.internalPointer()
if role == ITEM_ID_ROLE:
return item["id"]
if role == self.SortDescendingRole:
if item.get("isGroup"):
# Ensure groups be on top when sorting by descending order
@ -1139,7 +1154,6 @@ class RepresentationModel(TreeModel, BaseRepresentationModel):
"_id": doc["_id"],
"name": doc["name"],
"isMerged": True,
"childRow": 0,
"active_site_name": self.active_site,
"remote_site_name": self.remote_site,
"icon": qtawesome.icon(

View file

@ -34,7 +34,8 @@ from .model import (
SubsetFilterProxyModel,
FamiliesFilterProxyModel,
RepresentationModel,
RepresentationSortProxyModel
RepresentationSortProxyModel,
ITEM_ID_ROLE
)
from . import lib
@ -351,6 +352,59 @@ class SubsetWidget(QtWidgets.QWidget):
lib.change_visibility(self.model, self.view, "repre_info", enabled)
def get_selected_items(self):
selection_model = self.view.selectionModel()
indexes = selection_model.selectedIndexes()
item_ids = set()
for index in indexes:
item_id = index.data(ITEM_ID_ROLE)
if item_id is not None:
item_ids.add(item_id)
output = []
for item_id in item_ids:
item = self.model.get_item_by_id(item_id)
if item is not None:
output.append(item)
return output
def get_selected_merge_items(self):
output = []
items = collections.deque(self.get_selected_items())
item_ids = set()
while items:
item = items.popleft()
if item.get("isGroup"):
for child in item.children():
items.appendleft(child)
elif item.get("isMerged"):
item_id = item["id"]
if item_id not in item_ids:
item_ids.add(item_id)
output.append(item)
return output
def get_selected_subsets(self):
output = []
items = collections.deque(self.get_selected_items())
item_ids = set()
while items:
item = items.popleft()
if item.get("isGroup") or item.get("isMerged"):
for child in item.children():
items.appendleft(child)
else:
item_id = item["id"]
if item_id not in item_ids:
item_ids.add(item_id)
output.append(item)
return output
def on_context_menu(self, point):
"""Shows menu with loader actions on Right-click.
@ -367,10 +421,7 @@ class SubsetWidget(QtWidgets.QWidget):
return
# Get selected subsets without groups
selection = self.view.selectionModel()
rows = selection.selectedRows(column=0)
items = lib.get_selected_items(rows, self.model.ItemRole)
items = self.get_selected_subsets()
# Get all representation->loader combinations available for the
# index under the cursor, so we can list the user the options.
@ -539,35 +590,6 @@ class SubsetWidget(QtWidgets.QWidget):
box = LoadErrorMessageBox(error_info, self)
box.show()
def selected_subsets(self, _groups=False, _merged=False, _other=True):
selection = self.view.selectionModel()
rows = selection.selectedRows(column=0)
subsets = list()
if not any([_groups, _merged, _other]):
self.echo((
"This is a BUG: Selected_subsets args must contain"
" at least one value set to True"
))
return subsets
for row in rows:
item = row.data(self.model.ItemRole)
if item.get("isGroup"):
if not _groups:
continue
elif item.get("isMerged"):
if not _merged:
continue
else:
if not _other:
continue
subsets.append(item)
return subsets
def group_subsets(self, name, asset_ids, items):
field = "data.subsetGroup"
@ -1279,7 +1301,7 @@ class RepresentationWidget(QtWidgets.QWidget):
selection = self.tree_view.selectionModel()
rows = selection.selectedRows(column=0)
items = lib.get_selected_items(rows, self.model.ItemRole)
items = self.get_selected_subsets()
selected_side = self._get_selected_side(point_index, rows)

View file

@ -303,7 +303,7 @@ class AssetModel(QtGui.QStandardItemModel):
self._doc_fetched.connect(self._on_docs_fetched)
self._items_with_color_by_id = {}
self._item_ids_with_color = set()
self._items_by_asset_id = {}
self._last_project_name = None
@ -382,9 +382,11 @@ class AssetModel(QtGui.QStandardItemModel):
self._stop_fetch_thread()
def clear_underlines(self):
for asset_id in tuple(self._items_with_color_by_id.keys()):
item = self._items_with_color_by_id.pop(asset_id)
item.setData(None, ASSET_UNDERLINE_COLORS_ROLE)
for asset_id in set(self._item_ids_with_color):
self._item_ids_with_color.remove(asset_id)
item = self._items_by_asset_id.get(asset_id)
if item is not None:
item.setData(None, ASSET_UNDERLINE_COLORS_ROLE)
def set_underline_colors(self, colors_by_asset_id):
self.clear_underlines()
@ -394,12 +396,13 @@ class AssetModel(QtGui.QStandardItemModel):
if item is None:
continue
item.setData(colors, ASSET_UNDERLINE_COLORS_ROLE)
self._item_ids_with_color.add(asset_id)
def _clear_items(self):
root_item = self.invisibleRootItem()
root_item.removeRows(0, root_item.rowCount())
self._items_by_asset_id = {}
self._items_with_color_by_id = {}
self._item_ids_with_color = set()
def _on_docs_fetched(self):
# Make sure refreshing did not change