mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-26 13:52:15 +01:00
Merge pull request #2304 from pypeclub/feature/tools_cleanup
Tools: Cleanup of unused classes
This commit is contained in:
commit
b372eeef0e
12 changed files with 89 additions and 996 deletions
|
|
@ -3,9 +3,10 @@
|
|||
import contextlib
|
||||
|
||||
import logging
|
||||
from Qt import QtCore, QtGui
|
||||
from openpype.tools.utils.widgets import AssetWidget
|
||||
from avalon import style, io
|
||||
from Qt import QtWidgets, QtCore, QtGui
|
||||
from avalon import io
|
||||
from openpype import style
|
||||
from openpype.tools.utils.assets_widget import SingleSelectAssetsWidget
|
||||
|
||||
from pxr import Sdf
|
||||
|
||||
|
|
@ -13,6 +14,60 @@ from pxr import Sdf
|
|||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SelectAssetDialog(QtWidgets.QWidget):
|
||||
"""Frameless assets dialog to select asset with double click.
|
||||
|
||||
Args:
|
||||
parm: Parameter where selected asset name is set.
|
||||
"""
|
||||
def __init__(self, parm):
|
||||
self.setWindowTitle("Pick Asset")
|
||||
self.setWindowFlags(QtCore.Qt.FramelessWindowHint | QtCore.Qt.Popup)
|
||||
|
||||
assets_widget = SingleSelectAssetsWidget(io, parent=self)
|
||||
|
||||
layout = QtWidgets.QHBoxLayout(self)
|
||||
layout.addWidget(assets_widget)
|
||||
|
||||
assets_widget.double_clicked.connect(self._set_parameter)
|
||||
self._assets_widget = assets_widget
|
||||
self._parm = parm
|
||||
|
||||
def _set_parameter(self):
|
||||
name = self._assets_widget.get_selected_asset_name()
|
||||
self._parm.set(name)
|
||||
self.close()
|
||||
|
||||
def _on_show(self):
|
||||
pos = QtGui.QCursor.pos()
|
||||
# Select the current asset if there is any
|
||||
select_id = None
|
||||
name = self._parm.eval()
|
||||
if name:
|
||||
db_asset = io.find_one(
|
||||
{"name": name, "type": "asset"},
|
||||
{"_id": True}
|
||||
)
|
||||
if db_asset:
|
||||
select_id = db_asset["_id"]
|
||||
|
||||
# Set stylesheet
|
||||
self.setStyleSheet(style.load_stylesheet())
|
||||
# Refresh assets (is threaded)
|
||||
self._assets_widget.refresh()
|
||||
# Select asset - must be done after refresh
|
||||
if select_id is not None:
|
||||
self._assets_widget.select_asset(select_id)
|
||||
|
||||
# Show cursor (top right of window) near cursor
|
||||
self.resize(250, 400)
|
||||
self.move(self.mapFromGlobal(pos) - QtCore.QPoint(self.width(), 0))
|
||||
|
||||
def showEvent(self, event):
|
||||
super(SelectAssetDialog, self).showEvent(event)
|
||||
self._on_show()
|
||||
|
||||
|
||||
def pick_asset(node):
|
||||
"""Show a user interface to select an Asset in the project
|
||||
|
||||
|
|
@ -21,43 +76,15 @@ def pick_asset(node):
|
|||
|
||||
"""
|
||||
|
||||
pos = QtGui.QCursor.pos()
|
||||
|
||||
parm = node.parm("asset_name")
|
||||
if not parm:
|
||||
log.error("Node has no 'asset' parameter: %s", node)
|
||||
return
|
||||
|
||||
# Construct the AssetWidget as a frameless popup so it automatically
|
||||
# Construct a frameless popup so it automatically
|
||||
# closes when clicked outside of it.
|
||||
global tool
|
||||
tool = AssetWidget(io)
|
||||
tool.setContentsMargins(5, 5, 5, 5)
|
||||
tool.setWindowTitle("Pick Asset")
|
||||
tool.setStyleSheet(style.load_stylesheet())
|
||||
tool.setWindowFlags(QtCore.Qt.FramelessWindowHint | QtCore.Qt.Popup)
|
||||
tool.refresh()
|
||||
|
||||
# Select the current asset if there is any
|
||||
name = parm.eval()
|
||||
if name:
|
||||
db_asset = io.find_one({"name": name, "type": "asset"})
|
||||
if db_asset:
|
||||
silo = db_asset.get("silo")
|
||||
if silo:
|
||||
tool.set_silo(silo)
|
||||
tool.select_assets([name], expand=True)
|
||||
|
||||
# Show cursor (top right of window) near cursor
|
||||
tool.resize(250, 400)
|
||||
tool.move(tool.mapFromGlobal(pos) - QtCore.QPoint(tool.width(), 0))
|
||||
|
||||
def set_parameter_callback(index):
|
||||
name = index.data(tool.model.DocumentRole)["name"]
|
||||
parm.set(name)
|
||||
tool.close()
|
||||
|
||||
tool.view.doubleClicked.connect(set_parameter_callback)
|
||||
tool = SelectAssetDialog(parm)
|
||||
tool.show()
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +1,12 @@
|
|||
import os
|
||||
import sys
|
||||
import json
|
||||
from subprocess import Popen
|
||||
try:
|
||||
import ftrack_api_old as ftrack_api
|
||||
except Exception:
|
||||
import ftrack_api
|
||||
|
||||
import ftrack_api
|
||||
from Qt import QtWidgets, QtCore
|
||||
from openpype.api import get_current_project_settings
|
||||
from openpype import lib as pypelib
|
||||
from avalon.vendor.Qt import QtWidgets, QtCore
|
||||
from openpype.tools.utils.lib import qt_app_context
|
||||
from avalon import io, api, style, schema
|
||||
from avalon.tools import lib as parentlib
|
||||
from . import widget, model
|
||||
|
||||
module = sys.modules[__name__]
|
||||
|
|
@ -630,7 +626,7 @@ def show(parent=None, debug=False, context=None):
|
|||
if debug is True:
|
||||
io.install()
|
||||
|
||||
with parentlib.application():
|
||||
with qt_app_context():
|
||||
window = Window(parent, context)
|
||||
window.setStyleSheet(style.load_stylesheet())
|
||||
window.show()
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ class LibraryLoaderWindow(QtWidgets.QDialog):
|
|||
message_timeout = 5000
|
||||
|
||||
def __init__(
|
||||
self, parent=None, icon=None, show_projects=False, show_libraries=True
|
||||
self, parent=None, show_projects=False, show_libraries=True
|
||||
):
|
||||
super(LibraryLoaderWindow, self).__init__(parent)
|
||||
|
||||
|
|
@ -517,10 +517,7 @@ class LibraryLoaderWindow(QtWidgets.QDialog):
|
|||
return super(LibraryLoaderWindow, self).closeEvent(event)
|
||||
|
||||
|
||||
def show(
|
||||
debug=False, parent=None, icon=None,
|
||||
show_projects=False, show_libraries=True
|
||||
):
|
||||
def show(debug=False, parent=None, show_projects=False, show_libraries=True):
|
||||
"""Display Loader GUI
|
||||
|
||||
Arguments:
|
||||
|
|
@ -555,9 +552,9 @@ def show(
|
|||
import traceback
|
||||
sys.excepthook = lambda typ, val, tb: traceback.print_last()
|
||||
|
||||
with tools_lib.application():
|
||||
with tools_lib.qt_app_context():
|
||||
window = LibraryLoaderWindow(
|
||||
parent, icon, show_projects, show_libraries
|
||||
parent, show_projects, show_libraries
|
||||
)
|
||||
window.show()
|
||||
|
||||
|
|
|
|||
|
|
@ -631,7 +631,7 @@ def show(debug=False, parent=None, use_context=False):
|
|||
api.Session["AVALON_PROJECT"] = any_project["name"]
|
||||
module.project = any_project["name"]
|
||||
|
||||
with lib.application():
|
||||
with lib.qt_app_context():
|
||||
window = LoaderWindow(parent)
|
||||
window.show()
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,10 @@ from openpype.tools.utils.delegates import (
|
|||
VersionDelegate,
|
||||
PrettyTimeDelegate
|
||||
)
|
||||
from openpype.tools.utils.widgets import OptionalMenu
|
||||
from openpype.tools.utils.widgets import (
|
||||
OptionalMenu,
|
||||
PlaceholderLineEdit
|
||||
)
|
||||
from openpype.tools.utils.views import (
|
||||
TreeViewSpinner,
|
||||
DeselectableTreeView
|
||||
|
|
@ -175,7 +178,7 @@ class SubsetWidget(QtWidgets.QWidget):
|
|||
family_proxy = FamiliesFilterProxyModel()
|
||||
family_proxy.setSourceModel(proxy)
|
||||
|
||||
subset_filter = QtWidgets.QLineEdit(self)
|
||||
subset_filter = PlaceholderLineEdit(self)
|
||||
subset_filter.setPlaceholderText("Filter subsets..")
|
||||
|
||||
group_checkbox = QtWidgets.QCheckBox("Enable Grouping", self)
|
||||
|
|
@ -810,8 +813,9 @@ class ThumbnailWidget(QtWidgets.QLabel):
|
|||
{"_id": doc_id},
|
||||
{"data.thumbnail_id"}
|
||||
)
|
||||
|
||||
thumbnail_id = doc.get("data", {}).get("thumbnail_id")
|
||||
thumbnail_id = None
|
||||
if doc:
|
||||
thumbnail_id = doc.get("data", {}).get("thumbnail_id")
|
||||
if thumbnail_id == self.current_thumb_id:
|
||||
if self.current_thumbnail is None:
|
||||
self.set_pixmap()
|
||||
|
|
|
|||
|
|
@ -564,6 +564,8 @@ class AssetsWidget(QtWidgets.QWidget):
|
|||
refreshed = QtCore.Signal()
|
||||
# on view selection change
|
||||
selection_changed = QtCore.Signal()
|
||||
# It was double clicked on view
|
||||
double_clicked = QtCore.Signal()
|
||||
|
||||
def __init__(self, dbcon, parent=None):
|
||||
super(AssetsWidget, self).__init__(parent=parent)
|
||||
|
|
@ -618,6 +620,7 @@ class AssetsWidget(QtWidgets.QWidget):
|
|||
refresh_btn.clicked.connect(self.refresh)
|
||||
current_asset_btn.clicked.connect(self.set_current_session_asset)
|
||||
model.refreshed.connect(self._on_model_refresh)
|
||||
view.doubleClicked.connect(self.double_clicked)
|
||||
|
||||
self._current_asset_btn = current_asset_btn
|
||||
self._model = model
|
||||
|
|
|
|||
|
|
@ -5,10 +5,6 @@ DEFAULT_PROJECT_LABEL = "< Default >"
|
|||
PROJECT_NAME_ROLE = QtCore.Qt.UserRole + 101
|
||||
PROJECT_IS_ACTIVE_ROLE = QtCore.Qt.UserRole + 102
|
||||
|
||||
TASK_NAME_ROLE = QtCore.Qt.UserRole + 301
|
||||
TASK_TYPE_ROLE = QtCore.Qt.UserRole + 302
|
||||
TASK_ORDER_ROLE = QtCore.Qt.UserRole + 303
|
||||
|
||||
LOCAL_PROVIDER_ROLE = QtCore.Qt.UserRole + 500 # provider of active site
|
||||
REMOTE_PROVIDER_ROLE = QtCore.Qt.UserRole + 501 # provider of remote site
|
||||
LOCAL_PROGRESS_ROLE = QtCore.Qt.UserRole + 502 # percentage downld on active
|
||||
|
|
|
|||
|
|
@ -8,10 +8,7 @@ from Qt import QtWidgets, QtGui, QtCore
|
|||
|
||||
from avalon.lib import HeroVersionType
|
||||
from openpype.style import get_objected_colors
|
||||
from .models import (
|
||||
AssetModel,
|
||||
TreeModel
|
||||
)
|
||||
from .models import TreeModel
|
||||
from . import lib
|
||||
|
||||
if Qt.__binding__ == "PySide":
|
||||
|
|
@ -22,173 +19,6 @@ elif Qt.__binding__ == "PyQt4":
|
|||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AssetDelegate(QtWidgets.QItemDelegate):
|
||||
bar_height = 3
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(AssetDelegate, self).__init__(*args, **kwargs)
|
||||
asset_view_colors = get_objected_colors()["loader"]["asset-view"]
|
||||
self._selected_color = (
|
||||
asset_view_colors["selected"].get_qcolor()
|
||||
)
|
||||
self._hover_color = (
|
||||
asset_view_colors["hover"].get_qcolor()
|
||||
)
|
||||
self._selected_hover_color = (
|
||||
asset_view_colors["selected-hover"].get_qcolor()
|
||||
)
|
||||
|
||||
def sizeHint(self, option, index):
|
||||
result = super(AssetDelegate, self).sizeHint(option, index)
|
||||
height = result.height()
|
||||
result.setHeight(height + self.bar_height)
|
||||
|
||||
return result
|
||||
|
||||
def paint(self, painter, option, index):
|
||||
# Qt4 compat
|
||||
if Qt.__binding__ in ("PySide", "PyQt4"):
|
||||
option = QStyleOptionViewItemV4(option)
|
||||
|
||||
painter.save()
|
||||
|
||||
item_rect = QtCore.QRect(option.rect)
|
||||
item_rect.setHeight(option.rect.height() - self.bar_height)
|
||||
|
||||
subset_colors = index.data(AssetModel.subsetColorsRole)
|
||||
subset_colors_width = 0
|
||||
if subset_colors:
|
||||
subset_colors_width = option.rect.width() / len(subset_colors)
|
||||
|
||||
subset_rects = []
|
||||
counter = 0
|
||||
for subset_c in subset_colors:
|
||||
new_color = None
|
||||
new_rect = None
|
||||
if subset_c:
|
||||
new_color = QtGui.QColor(*subset_c)
|
||||
|
||||
new_rect = QtCore.QRect(
|
||||
option.rect.left() + (counter * subset_colors_width),
|
||||
option.rect.top() + (
|
||||
option.rect.height() - self.bar_height
|
||||
),
|
||||
subset_colors_width,
|
||||
self.bar_height
|
||||
)
|
||||
subset_rects.append((new_color, new_rect))
|
||||
counter += 1
|
||||
|
||||
# Background
|
||||
if option.state & QtWidgets.QStyle.State_Selected:
|
||||
if len(subset_colors) == 0:
|
||||
item_rect.setTop(item_rect.top() + (self.bar_height / 2))
|
||||
|
||||
if option.state & QtWidgets.QStyle.State_MouseOver:
|
||||
bg_color = self._selected_hover_color
|
||||
else:
|
||||
bg_color = self._selected_color
|
||||
else:
|
||||
item_rect.setTop(item_rect.top() + (self.bar_height / 2))
|
||||
if option.state & QtWidgets.QStyle.State_MouseOver:
|
||||
bg_color = self._hover_color
|
||||
else:
|
||||
bg_color = QtGui.QColor()
|
||||
bg_color.setAlpha(0)
|
||||
|
||||
# When not needed to do a rounded corners (easier and without
|
||||
# painter restore):
|
||||
# painter.fillRect(
|
||||
# item_rect,
|
||||
# QtGui.QBrush(bg_color)
|
||||
# )
|
||||
pen = painter.pen()
|
||||
pen.setStyle(QtCore.Qt.NoPen)
|
||||
pen.setWidth(0)
|
||||
painter.setPen(pen)
|
||||
painter.setBrush(QtGui.QBrush(bg_color))
|
||||
painter.drawRoundedRect(option.rect, 3, 3)
|
||||
|
||||
if option.state & QtWidgets.QStyle.State_Selected:
|
||||
for color, subset_rect in subset_rects:
|
||||
if not color or not subset_rect:
|
||||
continue
|
||||
painter.fillRect(subset_rect, QtGui.QBrush(color))
|
||||
|
||||
painter.restore()
|
||||
painter.save()
|
||||
|
||||
# Icon
|
||||
icon_index = index.model().index(
|
||||
index.row(), index.column(), index.parent()
|
||||
)
|
||||
# - Default icon_rect if not icon
|
||||
icon_rect = QtCore.QRect(
|
||||
item_rect.left(),
|
||||
item_rect.top(),
|
||||
# To make sure it's same size all the time
|
||||
option.rect.height() - self.bar_height,
|
||||
option.rect.height() - self.bar_height
|
||||
)
|
||||
icon = index.model().data(icon_index, QtCore.Qt.DecorationRole)
|
||||
|
||||
if icon:
|
||||
mode = QtGui.QIcon.Normal
|
||||
if not (option.state & QtWidgets.QStyle.State_Enabled):
|
||||
mode = QtGui.QIcon.Disabled
|
||||
elif option.state & QtWidgets.QStyle.State_Selected:
|
||||
mode = QtGui.QIcon.Selected
|
||||
|
||||
if isinstance(icon, QtGui.QPixmap):
|
||||
icon = QtGui.QIcon(icon)
|
||||
option.decorationSize = icon.size() / icon.devicePixelRatio()
|
||||
|
||||
elif isinstance(icon, QtGui.QColor):
|
||||
pixmap = QtGui.QPixmap(option.decorationSize)
|
||||
pixmap.fill(icon)
|
||||
icon = QtGui.QIcon(pixmap)
|
||||
|
||||
elif isinstance(icon, QtGui.QImage):
|
||||
icon = QtGui.QIcon(QtGui.QPixmap.fromImage(icon))
|
||||
option.decorationSize = icon.size() / icon.devicePixelRatio()
|
||||
|
||||
elif isinstance(icon, QtGui.QIcon):
|
||||
state = QtGui.QIcon.Off
|
||||
if option.state & QtWidgets.QStyle.State_Open:
|
||||
state = QtGui.QIcon.On
|
||||
actualSize = option.icon.actualSize(
|
||||
option.decorationSize, mode, state
|
||||
)
|
||||
option.decorationSize = QtCore.QSize(
|
||||
min(option.decorationSize.width(), actualSize.width()),
|
||||
min(option.decorationSize.height(), actualSize.height())
|
||||
)
|
||||
|
||||
state = QtGui.QIcon.Off
|
||||
if option.state & QtWidgets.QStyle.State_Open:
|
||||
state = QtGui.QIcon.On
|
||||
|
||||
icon.paint(
|
||||
painter, icon_rect,
|
||||
QtCore.Qt.AlignLeft, mode, state
|
||||
)
|
||||
|
||||
# Text
|
||||
text_rect = QtCore.QRect(
|
||||
icon_rect.left() + icon_rect.width() + 2,
|
||||
item_rect.top(),
|
||||
item_rect.width(),
|
||||
item_rect.height()
|
||||
)
|
||||
|
||||
painter.drawText(
|
||||
text_rect, QtCore.Qt.AlignVCenter,
|
||||
index.data(QtCore.Qt.DisplayRole)
|
||||
)
|
||||
|
||||
painter.restore()
|
||||
|
||||
|
||||
class VersionDelegate(QtWidgets.QStyledItemDelegate):
|
||||
"""A delegate that display version integer formatted as version string."""
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
import re
|
||||
import time
|
||||
import logging
|
||||
import collections
|
||||
|
||||
import Qt
|
||||
from Qt import QtCore, QtGui
|
||||
|
|
@ -11,10 +9,7 @@ from . import lib
|
|||
from .constants import (
|
||||
PROJECT_IS_ACTIVE_ROLE,
|
||||
PROJECT_NAME_ROLE,
|
||||
DEFAULT_PROJECT_LABEL,
|
||||
TASK_ORDER_ROLE,
|
||||
TASK_TYPE_ROLE,
|
||||
TASK_NAME_ROLE
|
||||
DEFAULT_PROJECT_LABEL
|
||||
)
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
|
@ -203,283 +198,6 @@ class Item(dict):
|
|||
self._children.append(child)
|
||||
|
||||
|
||||
class AssetModel(TreeModel):
|
||||
"""A model listing assets in the silo in the active project.
|
||||
|
||||
The assets are displayed in a treeview, they are visually parented by
|
||||
a `visualParent` field in the database containing an `_id` to a parent
|
||||
asset.
|
||||
|
||||
"""
|
||||
|
||||
Columns = ["label"]
|
||||
Name = 0
|
||||
Deprecated = 2
|
||||
ObjectId = 3
|
||||
|
||||
DocumentRole = QtCore.Qt.UserRole + 2
|
||||
ObjectIdRole = QtCore.Qt.UserRole + 3
|
||||
subsetColorsRole = QtCore.Qt.UserRole + 4
|
||||
|
||||
doc_fetched = QtCore.Signal(bool)
|
||||
refreshed = QtCore.Signal(bool)
|
||||
|
||||
# Asset document projection
|
||||
asset_projection = {
|
||||
"type": 1,
|
||||
"schema": 1,
|
||||
"name": 1,
|
||||
"silo": 1,
|
||||
"data.visualParent": 1,
|
||||
"data.label": 1,
|
||||
"data.tags": 1,
|
||||
"data.icon": 1,
|
||||
"data.color": 1,
|
||||
"data.deprecated": 1
|
||||
}
|
||||
|
||||
def __init__(self, dbcon=None, parent=None, asset_projection=None):
|
||||
super(AssetModel, self).__init__(parent=parent)
|
||||
if dbcon is None:
|
||||
dbcon = io
|
||||
self.dbcon = dbcon
|
||||
self.asset_colors = {}
|
||||
|
||||
# Projections for Mongo queries
|
||||
# - let ability to modify them if used in tools that require more than
|
||||
# defaults
|
||||
if asset_projection:
|
||||
self.asset_projection = asset_projection
|
||||
|
||||
self.asset_projection = asset_projection
|
||||
|
||||
self._doc_fetching_thread = None
|
||||
self._doc_fetching_stop = False
|
||||
self._doc_payload = {}
|
||||
|
||||
self.doc_fetched.connect(self.on_doc_fetched)
|
||||
|
||||
self.refresh()
|
||||
|
||||
def _add_hierarchy(self, assets, parent=None, silos=None):
|
||||
"""Add the assets that are related to the parent as children items.
|
||||
|
||||
This method does *not* query the database. These instead are queried
|
||||
in a single batch upfront as an optimization to reduce database
|
||||
queries. Resulting in up to 10x speed increase.
|
||||
|
||||
Args:
|
||||
assets (dict): All assets in the currently active silo stored
|
||||
by key/value
|
||||
|
||||
Returns:
|
||||
None
|
||||
|
||||
"""
|
||||
# Reset colors
|
||||
self.asset_colors = {}
|
||||
|
||||
if silos:
|
||||
# WARNING: Silo item "_id" is set to silo value
|
||||
# mainly because GUI issue with perserve selection and expanded row
|
||||
# and because of easier hierarchy parenting (in "assets")
|
||||
for silo in silos:
|
||||
item = Item({
|
||||
"_id": silo,
|
||||
"name": silo,
|
||||
"label": silo,
|
||||
"type": "silo"
|
||||
})
|
||||
self.add_child(item, parent=parent)
|
||||
self._add_hierarchy(assets, parent=item)
|
||||
|
||||
parent_id = parent["_id"] if parent else None
|
||||
current_assets = assets.get(parent_id, list())
|
||||
|
||||
for asset in current_assets:
|
||||
# get label from data, otherwise use name
|
||||
data = asset.get("data", {})
|
||||
label = data.get("label", asset["name"])
|
||||
tags = data.get("tags", [])
|
||||
|
||||
# store for the asset for optimization
|
||||
deprecated = "deprecated" in tags
|
||||
|
||||
item = Item({
|
||||
"_id": asset["_id"],
|
||||
"name": asset["name"],
|
||||
"label": label,
|
||||
"type": asset["type"],
|
||||
"tags": ", ".join(tags),
|
||||
"deprecated": deprecated,
|
||||
"_document": asset
|
||||
})
|
||||
self.add_child(item, parent=parent)
|
||||
|
||||
# Add asset's children recursively if it has children
|
||||
if asset["_id"] in assets:
|
||||
self._add_hierarchy(assets, parent=item)
|
||||
|
||||
self.asset_colors[asset["_id"]] = []
|
||||
|
||||
def on_doc_fetched(self, was_stopped):
|
||||
if was_stopped:
|
||||
self.stop_fetch_thread()
|
||||
return
|
||||
|
||||
self.beginResetModel()
|
||||
|
||||
assets_by_parent = self._doc_payload.get("assets_by_parent")
|
||||
silos = self._doc_payload.get("silos")
|
||||
if assets_by_parent is not None:
|
||||
# Build the hierarchical tree items recursively
|
||||
self._add_hierarchy(
|
||||
assets_by_parent,
|
||||
parent=None,
|
||||
silos=silos
|
||||
)
|
||||
|
||||
self.endResetModel()
|
||||
|
||||
has_content = bool(assets_by_parent) or bool(silos)
|
||||
self.refreshed.emit(has_content)
|
||||
|
||||
self.stop_fetch_thread()
|
||||
|
||||
def fetch(self):
|
||||
self._doc_payload = self._fetch() or {}
|
||||
# Emit doc fetched only if was not stopped
|
||||
self.doc_fetched.emit(self._doc_fetching_stop)
|
||||
|
||||
def _fetch(self):
|
||||
if not self.dbcon.Session.get("AVALON_PROJECT"):
|
||||
return
|
||||
|
||||
project_doc = self.dbcon.find_one(
|
||||
{"type": "project"},
|
||||
{"_id": True}
|
||||
)
|
||||
if not project_doc:
|
||||
return
|
||||
|
||||
# Get all assets sorted by name
|
||||
db_assets = self.dbcon.find(
|
||||
{"type": "asset"},
|
||||
self.asset_projection
|
||||
).sort("name", 1)
|
||||
|
||||
# Group the assets by their visual parent's id
|
||||
assets_by_parent = collections.defaultdict(list)
|
||||
for asset in db_assets:
|
||||
if self._doc_fetching_stop:
|
||||
return
|
||||
parent_id = asset.get("data", {}).get("visualParent")
|
||||
assets_by_parent[parent_id].append(asset)
|
||||
|
||||
return {
|
||||
"assets_by_parent": assets_by_parent,
|
||||
"silos": None
|
||||
}
|
||||
|
||||
def stop_fetch_thread(self):
|
||||
if self._doc_fetching_thread is not None:
|
||||
self._doc_fetching_stop = True
|
||||
while self._doc_fetching_thread.isRunning():
|
||||
time.sleep(0.001)
|
||||
self._doc_fetching_thread = None
|
||||
|
||||
def refresh(self, force=False):
|
||||
"""Refresh the data for the model."""
|
||||
# Skip fetch if there is already other thread fetching documents
|
||||
if self._doc_fetching_thread is not None:
|
||||
if not force:
|
||||
return
|
||||
self.stop_fetch_thread()
|
||||
|
||||
# Clear model items
|
||||
self.clear()
|
||||
|
||||
# Fetch documents from mongo
|
||||
# Restart payload
|
||||
self._doc_payload = {}
|
||||
self._doc_fetching_stop = False
|
||||
self._doc_fetching_thread = lib.create_qthread(self.fetch)
|
||||
self._doc_fetching_thread.start()
|
||||
|
||||
def flags(self, index):
|
||||
return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable
|
||||
|
||||
def setData(self, index, value, role=QtCore.Qt.EditRole):
|
||||
if not index.isValid():
|
||||
return False
|
||||
|
||||
if role == self.subsetColorsRole:
|
||||
asset_id = index.data(self.ObjectIdRole)
|
||||
self.asset_colors[asset_id] = value
|
||||
|
||||
if Qt.__binding__ in ("PyQt4", "PySide"):
|
||||
self.dataChanged.emit(index, index)
|
||||
else:
|
||||
self.dataChanged.emit(index, index, [role])
|
||||
|
||||
return True
|
||||
|
||||
return super(AssetModel, self).setData(index, value, role)
|
||||
|
||||
def data(self, index, role):
|
||||
if not index.isValid():
|
||||
return
|
||||
|
||||
item = index.internalPointer()
|
||||
if role == QtCore.Qt.DecorationRole:
|
||||
column = index.column()
|
||||
if column == self.Name:
|
||||
# Allow a custom icon and custom icon color to be defined
|
||||
data = item.get("_document", {}).get("data", {})
|
||||
icon = data.get("icon", None)
|
||||
if icon is None and item.get("type") == "silo":
|
||||
icon = "database"
|
||||
color = data.get("color", style.colors.default)
|
||||
|
||||
if icon is None:
|
||||
# Use default icons if no custom one is specified.
|
||||
# If it has children show a full folder, otherwise
|
||||
# show an open folder
|
||||
has_children = self.rowCount(index) > 0
|
||||
icon = "folder" if has_children else "folder-o"
|
||||
|
||||
# Make the color darker when the asset is deprecated
|
||||
if item.get("deprecated", False):
|
||||
color = QtGui.QColor(color).darker(250)
|
||||
|
||||
try:
|
||||
key = "fa.{0}".format(icon) # font-awesome key
|
||||
icon = qtawesome.icon(key, color=color)
|
||||
return icon
|
||||
except Exception as exception:
|
||||
# Log an error message instead of erroring out completely
|
||||
# when the icon couldn't be created (e.g. invalid name)
|
||||
log.error(exception)
|
||||
|
||||
return
|
||||
|
||||
if role == QtCore.Qt.ForegroundRole: # font color
|
||||
if "deprecated" in item.get("tags", []):
|
||||
return QtGui.QColor(style.colors.light).darker(250)
|
||||
|
||||
if role == self.ObjectIdRole:
|
||||
return item.get("_id", None)
|
||||
|
||||
if role == self.DocumentRole:
|
||||
return item.get("_document", None)
|
||||
|
||||
if role == self.subsetColorsRole:
|
||||
asset_id = item.get("_id", None)
|
||||
return self.asset_colors.get(asset_id) or []
|
||||
|
||||
return super(AssetModel, self).data(index, role)
|
||||
|
||||
|
||||
class RecursiveSortFilterProxyModel(QtCore.QSortFilterProxyModel):
|
||||
"""Filters to the regex if any of the children matches allow parent"""
|
||||
def filterAcceptsRow(self, row, parent):
|
||||
|
|
@ -654,163 +372,3 @@ class ProjectSortFilterProxy(QtCore.QSortFilterProxyModel):
|
|||
def set_filter_enabled(self, value):
|
||||
self._filter_enabled = value
|
||||
self.invalidateFilter()
|
||||
|
||||
|
||||
class TasksModel(QtGui.QStandardItemModel):
|
||||
"""A model listing the tasks combined for a list of assets"""
|
||||
def __init__(self, dbcon, parent=None):
|
||||
super(TasksModel, self).__init__(parent=parent)
|
||||
self.dbcon = dbcon
|
||||
self._default_icon = qtawesome.icon(
|
||||
"fa.male",
|
||||
color=style.colors.default
|
||||
)
|
||||
self._no_tasks_icon = qtawesome.icon(
|
||||
"fa.exclamation-circle",
|
||||
color=style.colors.mid
|
||||
)
|
||||
self._cached_icons = {}
|
||||
self._project_task_types = {}
|
||||
|
||||
self._last_asset_id = None
|
||||
|
||||
self.refresh()
|
||||
|
||||
def refresh(self):
|
||||
if self.dbcon.Session.get("AVALON_PROJECT"):
|
||||
self._refresh_task_types()
|
||||
self.set_asset_id(self._last_asset_id)
|
||||
else:
|
||||
self.clear()
|
||||
|
||||
def _refresh_task_types(self):
|
||||
# Get the project configured icons from database
|
||||
project = self.dbcon.find_one(
|
||||
{"type": "project"},
|
||||
{"config.tasks"}
|
||||
)
|
||||
tasks = project["config"].get("tasks") or {}
|
||||
self._project_task_types = tasks
|
||||
|
||||
def _try_get_awesome_icon(self, icon_name):
|
||||
icon = None
|
||||
if icon_name:
|
||||
try:
|
||||
icon = qtawesome.icon(
|
||||
"fa.{}".format(icon_name),
|
||||
color=style.colors.default
|
||||
)
|
||||
|
||||
except Exception:
|
||||
pass
|
||||
return icon
|
||||
|
||||
def headerData(self, section, orientation, role):
|
||||
# Show nice labels in the header
|
||||
if (
|
||||
role == QtCore.Qt.DisplayRole
|
||||
and orientation == QtCore.Qt.Horizontal
|
||||
):
|
||||
if section == 0:
|
||||
return "Tasks"
|
||||
|
||||
return super(TasksModel, self).headerData(section, orientation, role)
|
||||
|
||||
def _get_icon(self, task_icon, task_type_icon):
|
||||
if task_icon in self._cached_icons:
|
||||
return self._cached_icons[task_icon]
|
||||
|
||||
icon = self._try_get_awesome_icon(task_icon)
|
||||
if icon is not None:
|
||||
self._cached_icons[task_icon] = icon
|
||||
return icon
|
||||
|
||||
if task_type_icon in self._cached_icons:
|
||||
icon = self._cached_icons[task_type_icon]
|
||||
self._cached_icons[task_icon] = icon
|
||||
return icon
|
||||
|
||||
icon = self._try_get_awesome_icon(task_type_icon)
|
||||
if icon is None:
|
||||
icon = self._default_icon
|
||||
|
||||
self._cached_icons[task_icon] = icon
|
||||
self._cached_icons[task_type_icon] = icon
|
||||
|
||||
return icon
|
||||
|
||||
def set_asset_id(self, asset_id):
|
||||
asset_doc = None
|
||||
if asset_id:
|
||||
asset_doc = self.dbcon.find_one(
|
||||
{"_id": asset_id},
|
||||
{"data.tasks": True}
|
||||
)
|
||||
self.set_asset(asset_doc)
|
||||
|
||||
def set_asset(self, asset_doc):
|
||||
"""Set assets to track by their database id
|
||||
|
||||
Arguments:
|
||||
asset_doc (dict): Asset document from MongoDB.
|
||||
"""
|
||||
self.clear()
|
||||
|
||||
if not asset_doc:
|
||||
self._last_asset_id = None
|
||||
return
|
||||
|
||||
self._last_asset_id = asset_doc["_id"]
|
||||
|
||||
asset_tasks = asset_doc.get("data", {}).get("tasks") or {}
|
||||
items = []
|
||||
for task_name, task_info in asset_tasks.items():
|
||||
task_icon = task_info.get("icon")
|
||||
task_type = task_info.get("type")
|
||||
task_order = task_info.get("order")
|
||||
task_type_info = self._project_task_types.get(task_type) or {}
|
||||
task_type_icon = task_type_info.get("icon")
|
||||
icon = self._get_icon(task_icon, task_type_icon)
|
||||
|
||||
label = "{} ({})".format(task_name, task_type or "type N/A")
|
||||
item = QtGui.QStandardItem(label)
|
||||
item.setData(task_name, TASK_NAME_ROLE)
|
||||
item.setData(task_type, TASK_TYPE_ROLE)
|
||||
item.setData(task_order, TASK_ORDER_ROLE)
|
||||
item.setData(icon, QtCore.Qt.DecorationRole)
|
||||
item.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable)
|
||||
items.append(item)
|
||||
|
||||
if not items:
|
||||
item = QtGui.QStandardItem("No task")
|
||||
item.setData(self._no_tasks_icon, QtCore.Qt.DecorationRole)
|
||||
item.setFlags(QtCore.Qt.NoItemFlags)
|
||||
items.append(item)
|
||||
|
||||
self.invisibleRootItem().appendRows(items)
|
||||
|
||||
|
||||
class TasksProxyModel(QtCore.QSortFilterProxyModel):
|
||||
def lessThan(self, x_index, y_index):
|
||||
x_order = x_index.data(TASK_ORDER_ROLE)
|
||||
y_order = y_index.data(TASK_ORDER_ROLE)
|
||||
if x_order is not None and y_order is not None:
|
||||
if x_order < y_order:
|
||||
return True
|
||||
if x_order > y_order:
|
||||
return False
|
||||
|
||||
elif x_order is None and y_order is not None:
|
||||
return True
|
||||
|
||||
elif y_order is None and x_order is not None:
|
||||
return False
|
||||
|
||||
x_name = x_index.data(QtCore.Qt.DisplayRole)
|
||||
y_name = y_index.data(QtCore.Qt.DisplayRole)
|
||||
if x_name == y_name:
|
||||
return True
|
||||
|
||||
if x_name == tuple(sorted((x_name, y_name)))[0]:
|
||||
return True
|
||||
return False
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@ from avalon import style
|
|||
from avalon.vendor import qtawesome
|
||||
|
||||
from .views import DeselectableTreeView
|
||||
from .constants import (
|
||||
TASK_ORDER_ROLE,
|
||||
TASK_TYPE_ROLE,
|
||||
TASK_NAME_ROLE
|
||||
)
|
||||
|
||||
|
||||
TASK_NAME_ROLE = QtCore.Qt.UserRole + 1
|
||||
TASK_TYPE_ROLE = QtCore.Qt.UserRole + 2
|
||||
TASK_ORDER_ROLE = QtCore.Qt.UserRole + 3
|
||||
|
||||
|
||||
class TasksModel(QtGui.QStandardItemModel):
|
||||
|
|
|
|||
|
|
@ -61,26 +61,3 @@ class TreeViewSpinner(QtWidgets.QTreeView):
|
|||
self.paint_empty(event)
|
||||
else:
|
||||
super(TreeViewSpinner, self).paintEvent(event)
|
||||
|
||||
|
||||
class AssetsView(TreeViewSpinner, DeselectableTreeView):
|
||||
"""Item view.
|
||||
This implements a context menu.
|
||||
"""
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super(AssetsView, self).__init__(parent)
|
||||
self.setIndentation(15)
|
||||
self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
|
||||
self.setHeaderHidden(True)
|
||||
|
||||
def mousePressEvent(self, event):
|
||||
index = self.indexAt(event.pos())
|
||||
if not index.isValid():
|
||||
modifiers = QtWidgets.QApplication.keyboardModifiers()
|
||||
if modifiers == QtCore.Qt.ShiftModifier:
|
||||
return
|
||||
elif modifiers == QtCore.Qt.ControlModifier:
|
||||
return
|
||||
|
||||
super(AssetsView, self).mousePressEvent(event)
|
||||
|
|
|
|||
|
|
@ -1,18 +1,10 @@
|
|||
import logging
|
||||
import time
|
||||
|
||||
from . import lib
|
||||
|
||||
from Qt import QtWidgets, QtCore, QtGui
|
||||
|
||||
from avalon.vendor import qtawesome, qargparse
|
||||
|
||||
from avalon import style
|
||||
from openpype.style import get_objected_colors
|
||||
|
||||
from .models import AssetModel, RecursiveSortFilterProxyModel
|
||||
from .views import AssetsView
|
||||
from .delegates import AssetDelegate
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
|
@ -38,293 +30,6 @@ class PlaceholderLineEdit(QtWidgets.QLineEdit):
|
|||
self.setPalette(filter_palette)
|
||||
|
||||
|
||||
class AssetWidget(QtWidgets.QWidget):
|
||||
"""A Widget to display a tree of assets with filter
|
||||
|
||||
To list the assets of the active project:
|
||||
>>> # widget = AssetWidget()
|
||||
>>> # widget.refresh()
|
||||
>>> # widget.show()
|
||||
|
||||
"""
|
||||
|
||||
refresh_triggered = QtCore.Signal() # on model refresh
|
||||
refreshed = QtCore.Signal()
|
||||
selection_changed = QtCore.Signal() # on view selection change
|
||||
current_changed = QtCore.Signal() # on view current index change
|
||||
|
||||
def __init__(self, dbcon, multiselection=False, parent=None):
|
||||
super(AssetWidget, self).__init__(parent=parent)
|
||||
|
||||
self.dbcon = dbcon
|
||||
|
||||
# Tree View
|
||||
model = AssetModel(dbcon=self.dbcon, parent=self)
|
||||
proxy = RecursiveSortFilterProxyModel()
|
||||
proxy.setSourceModel(model)
|
||||
proxy.setFilterCaseSensitivity(QtCore.Qt.CaseInsensitive)
|
||||
|
||||
view = AssetsView(self)
|
||||
view.setModel(proxy)
|
||||
if multiselection:
|
||||
asset_delegate = AssetDelegate()
|
||||
view.setSelectionMode(view.ExtendedSelection)
|
||||
view.setItemDelegate(asset_delegate)
|
||||
|
||||
icon = qtawesome.icon("fa.arrow-down", color=style.colors.light)
|
||||
set_current_asset_btn = QtWidgets.QPushButton(icon, "")
|
||||
set_current_asset_btn.setToolTip("Go to Asset from current Session")
|
||||
# Hide by default
|
||||
set_current_asset_btn.setVisible(False)
|
||||
|
||||
icon = qtawesome.icon("fa.refresh", color=style.colors.light)
|
||||
refresh = QtWidgets.QPushButton(icon, "", parent=self)
|
||||
refresh.setToolTip("Refresh items")
|
||||
|
||||
filter_input = QtWidgets.QLineEdit(self)
|
||||
filter_input.setPlaceholderText("Filter assets..")
|
||||
|
||||
# Header
|
||||
header_layout = QtWidgets.QHBoxLayout()
|
||||
header_layout.addWidget(filter_input)
|
||||
header_layout.addWidget(set_current_asset_btn)
|
||||
header_layout.addWidget(refresh)
|
||||
|
||||
# Layout
|
||||
layout = QtWidgets.QVBoxLayout(self)
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
layout.setSpacing(4)
|
||||
layout.addLayout(header_layout)
|
||||
layout.addWidget(view)
|
||||
|
||||
# Signals/Slots
|
||||
filter_input.textChanged.connect(proxy.setFilterFixedString)
|
||||
|
||||
selection = view.selectionModel()
|
||||
selection.selectionChanged.connect(self.selection_changed)
|
||||
selection.currentChanged.connect(self.current_changed)
|
||||
refresh.clicked.connect(self.refresh)
|
||||
set_current_asset_btn.clicked.connect(self.set_current_session_asset)
|
||||
|
||||
self.set_current_asset_btn = set_current_asset_btn
|
||||
self.model = model
|
||||
self.proxy = proxy
|
||||
self.view = view
|
||||
|
||||
self.model_selection = {}
|
||||
|
||||
def set_current_asset_btn_visibility(self, visible=None):
|
||||
"""Hide set current asset button.
|
||||
|
||||
Not all tools support using of current context asset.
|
||||
"""
|
||||
if visible is None:
|
||||
visible = not self.set_current_asset_btn.isVisible()
|
||||
self.set_current_asset_btn.setVisible(visible)
|
||||
|
||||
def _refresh_model(self):
|
||||
# Store selection
|
||||
self._store_model_selection()
|
||||
time_start = time.time()
|
||||
|
||||
self.set_loading_state(
|
||||
loading=True,
|
||||
empty=True
|
||||
)
|
||||
|
||||
def on_refreshed(has_item):
|
||||
self.set_loading_state(loading=False, empty=not has_item)
|
||||
self._restore_model_selection()
|
||||
self.model.refreshed.disconnect()
|
||||
self.refreshed.emit()
|
||||
print("Duration: %.3fs" % (time.time() - time_start))
|
||||
|
||||
# Connect to signal
|
||||
self.model.refreshed.connect(on_refreshed)
|
||||
# Trigger signal before refresh is called
|
||||
self.refresh_triggered.emit()
|
||||
# Refresh model
|
||||
self.model.refresh()
|
||||
|
||||
def refresh(self):
|
||||
self._refresh_model()
|
||||
|
||||
def get_active_asset(self):
|
||||
"""Return the asset item of the current selection."""
|
||||
current = self.view.currentIndex()
|
||||
return current.data(self.model.ItemRole)
|
||||
|
||||
def get_active_asset_document(self):
|
||||
"""Return the asset document of the current selection."""
|
||||
current = self.view.currentIndex()
|
||||
return current.data(self.model.DocumentRole)
|
||||
|
||||
def get_active_index(self):
|
||||
return self.view.currentIndex()
|
||||
|
||||
def get_selected_assets(self):
|
||||
"""Return the documents of selected assets."""
|
||||
selection = self.view.selectionModel()
|
||||
rows = selection.selectedRows()
|
||||
assets = [row.data(self.model.DocumentRole) for row in rows]
|
||||
|
||||
# NOTE: skip None object assumed they are silo (backwards comp.)
|
||||
return [asset for asset in assets if asset]
|
||||
|
||||
def select_assets(self, assets, expand=True, key="name"):
|
||||
"""Select assets by item key.
|
||||
|
||||
Args:
|
||||
assets (list): List of asset values that can be found under
|
||||
specified `key`
|
||||
expand (bool): Whether to also expand to the asset in the view
|
||||
key (string): Key that specifies where to look for `assets` values
|
||||
|
||||
Returns:
|
||||
None
|
||||
|
||||
Default `key` is "name" in that case `assets` should contain single
|
||||
asset name or list of asset names. (It is good idea to use "_id" key
|
||||
instead of name in that case `assets` must contain `ObjectId` object/s)
|
||||
It is expected that each value in `assets` will be found only once.
|
||||
If the filters according to the `key` and `assets` correspond to
|
||||
the more asset, only the first found will be selected.
|
||||
|
||||
"""
|
||||
|
||||
if not isinstance(assets, (tuple, list)):
|
||||
assets = [assets]
|
||||
|
||||
# convert to list - tuple cant be modified
|
||||
assets = set(assets)
|
||||
|
||||
# Clear selection
|
||||
selection_model = self.view.selectionModel()
|
||||
selection_model.clearSelection()
|
||||
|
||||
# Select
|
||||
mode = selection_model.Select | selection_model.Rows
|
||||
for index in lib.iter_model_rows(
|
||||
self.proxy, column=0, include_root=False
|
||||
):
|
||||
# stop iteration if there are no assets to process
|
||||
if not assets:
|
||||
break
|
||||
|
||||
value = index.data(self.model.ItemRole).get(key)
|
||||
if value not in assets:
|
||||
continue
|
||||
|
||||
# Remove processed asset
|
||||
assets.discard(value)
|
||||
|
||||
selection_model.select(index, mode)
|
||||
if expand:
|
||||
# Expand parent index
|
||||
self.view.expand(self.proxy.parent(index))
|
||||
|
||||
# Set the currently active index
|
||||
self.view.setCurrentIndex(index)
|
||||
|
||||
def set_loading_state(self, loading, empty):
|
||||
if self.view.is_loading != loading:
|
||||
if loading:
|
||||
self.view.spinner.repaintNeeded.connect(
|
||||
self.view.viewport().update
|
||||
)
|
||||
else:
|
||||
self.view.spinner.repaintNeeded.disconnect()
|
||||
|
||||
self.view.is_loading = loading
|
||||
self.view.is_empty = empty
|
||||
|
||||
def _store_model_selection(self):
|
||||
index = self.view.currentIndex()
|
||||
current = None
|
||||
if index and index.isValid():
|
||||
current = index.data(self.model.ObjectIdRole)
|
||||
|
||||
expanded = set()
|
||||
model = self.view.model()
|
||||
for index in lib.iter_model_rows(
|
||||
model, column=0, include_root=False
|
||||
):
|
||||
if self.view.isExpanded(index):
|
||||
value = index.data(self.model.ObjectIdRole)
|
||||
expanded.add(value)
|
||||
|
||||
selection_model = self.view.selectionModel()
|
||||
|
||||
selected = None
|
||||
selected_rows = selection_model.selectedRows()
|
||||
if selected_rows:
|
||||
selected = set(
|
||||
row.data(self.model.ObjectIdRole)
|
||||
for row in selected_rows
|
||||
)
|
||||
|
||||
self.model_selection = {
|
||||
"expanded": expanded,
|
||||
"selected": selected,
|
||||
"current": current
|
||||
}
|
||||
|
||||
def _restore_model_selection(self):
|
||||
model = self.view.model()
|
||||
not_set = object()
|
||||
expanded = self.model_selection.pop("expanded", not_set)
|
||||
selected = self.model_selection.pop("selected", not_set)
|
||||
current = self.model_selection.pop("current", not_set)
|
||||
|
||||
if (
|
||||
expanded is not_set
|
||||
or selected is not_set
|
||||
or current is not_set
|
||||
):
|
||||
return
|
||||
|
||||
if expanded:
|
||||
for index in lib.iter_model_rows(
|
||||
model, column=0, include_root=False
|
||||
):
|
||||
is_expanded = index.data(self.model.ObjectIdRole) in expanded
|
||||
self.view.setExpanded(index, is_expanded)
|
||||
|
||||
if not selected and not current:
|
||||
self.set_current_session_asset()
|
||||
return
|
||||
|
||||
current_index = None
|
||||
selected_indexes = []
|
||||
# Go through all indices, select the ones with similar data
|
||||
for index in lib.iter_model_rows(
|
||||
model, column=0, include_root=False
|
||||
):
|
||||
object_id = index.data(self.model.ObjectIdRole)
|
||||
if object_id in selected:
|
||||
selected_indexes.append(index)
|
||||
|
||||
if not current_index and object_id == current:
|
||||
current_index = index
|
||||
|
||||
if current_index:
|
||||
self.view.setCurrentIndex(current_index)
|
||||
|
||||
if not selected_indexes:
|
||||
return
|
||||
selection_model = self.view.selectionModel()
|
||||
flags = selection_model.Select | selection_model.Rows
|
||||
for index in selected_indexes:
|
||||
# Ensure item is visible
|
||||
self.view.scrollTo(index)
|
||||
selection_model.select(index, flags)
|
||||
|
||||
def set_current_session_asset(self):
|
||||
asset_name = self.dbcon.Session.get("AVALON_ASSET")
|
||||
if asset_name:
|
||||
self.select_assets([asset_name])
|
||||
|
||||
|
||||
class OptionalMenu(QtWidgets.QMenu):
|
||||
"""A subclass of `QtWidgets.QMenu` to work with `OptionalAction`
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue