Create model for whole launcher tool

This commit is contained in:
iLLiCiTiT 2021-12-16 21:42:55 +01:00
parent c19f216128
commit 06396fa038

View file

@ -3,6 +3,10 @@ import copy
import logging
import collections
from Qt import QtCore, QtGui
from openpype.lib import ApplicationManager
from openpype.tools.utils.lib import DynamicQThread
from . import lib
from .constants import (
ACTION_ROLE,
@ -11,10 +15,8 @@ from .constants import (
ACTION_ID_ROLE
)
from .actions import ApplicationAction
from Qt import QtCore, QtGui
from avalon.vendor import qtawesome
from avalon import style, api
from openpype.lib import ApplicationManager
log = logging.getLogger(__name__)
@ -223,6 +225,305 @@ class ActionModel(QtGui.QStandardItemModel):
)
class LauncherModel(QtCore.QObject):
# Refresh interval of projects
refresh_interval = 10000
# Signals
# Current project has changed
project_changed = QtCore.Signal(str)
# Filters has changed (any)
filters_changed = QtCore.Signal()
# Projects were refreshed
projects_refreshed = QtCore.Signal()
# Signals ONLY for assets model!
# - other objects should listen to asset model signals
# Asset refresh started
assets_refresh_started = QtCore.Signal()
# Assets refresh finished
assets_refreshed = QtCore.Signal()
# Refresh timer timeout
# - give ability to tell parent window that this timer still runs
timer_timeout = QtCore.Signal()
# Duplication from AssetsModel with "data.tasks"
_asset_projection = {
"name": 1,
"parent": 1,
"data.visualParent": 1,
"data.label": 1,
"data.icon": 1,
"data.color": 1,
"data.tasks": 1
}
def __init__(self, dbcon):
super(LauncherModel, self).__init__()
# Refresh timer
# - should affect only projects
refresh_timer = QtCore.QTimer()
refresh_timer.setInterval(self.refresh_interval)
refresh_timer.timeout.connect(self._on_timeout)
self._refresh_timer = refresh_timer
# Launcher is active
self._active = False
# Global data
self._dbcon = dbcon
# Available project names
self._project_names = set()
# Context data
self._asset_docs = []
self._asset_docs_by_id = {}
self._asset_filter_data_by_id = {}
self._assignees = set()
self._task_types = set()
# Filters
self._asset_name_filter = ""
self._assignee_filters = set()
self._task_type_filters = set()
# Last project for which were assets queried
self._last_project_name = None
# Asset refresh thread is running
self._refreshing_assets = False
# Asset refresh thread
self._asset_refresh_thread = None
def _on_timeout(self):
"""Refresh timer timeout."""
if self._active:
self.timer_timeout.emit()
self.refresh_projects()
def set_active(self, active):
"""Window change active state."""
self._active = active
def start_refresh_timer(self, trigger=False):
"""Start refresh timer."""
self._refresh_timer.start()
if trigger:
self._on_timeout()
def stop_refresh_timer(self):
"""Stop refresh timer."""
self._refresh_timer.stop()
@property
def project_name(self):
"""Current project name."""
return self._dbcon.Session.get("AVALON_PROJECT")
@property
def refreshing_assets(self):
"""Refreshing thread is running."""
return self._refreshing_assets
@property
def asset_docs(self):
"""Access to asset docs."""
return self._asset_docs
@property
def project_names(self):
"""Available project names."""
return self._project_names
@property
def asset_filter_data_by_id(self):
"""Prepared filter data by asset id."""
return self._asset_filter_data_by_id
@property
def assignees(self):
"""All assignees for all assets in current project."""
return self._assignees
@property
def task_types(self):
"""All task types for all assets in current project.
TODO: This could be maybe taken from project document where are all
task types...
"""
return self._task_types
@property
def task_type_filters(self):
"""Currently set task type filters."""
return self._task_type_filters
@property
def assignee_filters(self):
"""Currently set assignee filters."""
return self._assignee_filters
@property
def asset_name_filter(self):
"""Asset name filter (can be used as regex filter)."""
return self._asset_name_filter
def get_asset_doc(self, asset_id):
"""Get single asset document by id."""
return self._asset_docs_by_id.get(asset_id)
def set_project_name(self, project_name):
"""Change project name and refresh asset documents."""
if project_name == self.project_name:
return
self._dbcon.Session["AVALON_PROJECT"] = project_name
self.project_changed.emit(project_name)
self.refresh_assets(force=True)
def refresh(self):
"""Trigger refresh of whole model."""
self.refresh_projects()
self.refresh_assets(force=False)
def refresh_projects(self):
"""Refresh projects."""
current_project = self.project_name
project_names = set()
for project_doc in self._dbcon.projects(only_active=True):
project_names.add(project_doc["name"])
self._project_names = project_names
self.projects_refreshed.emit()
if (
current_project is not None
and current_project not in project_names
):
self.set_project_name(None)
def _set_asset_docs(self, asset_docs=None):
"""Set asset documents and all related data.
Method extract and prepare data needed for assets and tasks widget and
prepare filtering data.
"""
if asset_docs is None:
asset_docs = []
all_task_types = set()
all_assignees = set()
asset_docs_by_id = {}
asset_filter_data_by_id = {}
for asset_doc in asset_docs:
task_types = set()
assignees = set()
asset_id = asset_doc["_id"]
asset_docs_by_id[asset_id] = asset_doc
asset_tasks = asset_doc.get("data", {}).get("tasks")
asset_filter_data_by_id[asset_id] = {
"assignees": assignees,
"task_types": task_types
}
if not asset_tasks:
continue
for task_data in asset_tasks.values():
task_assignees = set()
_task_assignees = task_data.get("assignees")
if _task_assignees:
for assignee in _task_assignees:
task_assignees.add(assignee["username"])
task_type = task_data.get("type")
if task_assignees:
assignees |= set(task_assignees)
if task_type:
task_types.add(task_type)
all_task_types |= task_types
all_assignees |= assignees
self._asset_docs_by_id = asset_docs_by_id
self._asset_docs = asset_docs
self._asset_filter_data_by_id = asset_filter_data_by_id
self._assignees = all_assignees
self._task_types = all_task_types
self.assets_refreshed.emit()
def set_task_type_filter(self, task_types):
"""Change task type filter.
Args:
task_types (set): Set of task types that should be visible.
Pass empty set to turn filter off.
"""
self._task_type_filters = task_types
self.filters_changed.emit()
def set_assignee_filter(self, assignees):
"""Change assignees filter.
Args:
assignees (set): Set of assignees that should be visible.
Pass empty set to turn filter off.
"""
self._assignee_filters = assignees
self.filters_changed.emit()
def set_asset_name_filter(self, text_filter):
"""Change asset name filter.
Args:
text_filter (str): Asset name filter. Pass empty string to
turn filter off.
"""
self._asset_name_filter = text_filter
self.filters_changed.emit()
def refresh_assets(self, force=True):
"""Refresh assets."""
self.assets_refresh_started.emit()
if self.project_name is None:
self._set_asset_docs()
return
if (
not force
and self._last_project_name == self.project_name
):
return
self._stop_fetch_thread()
self._refreshing_assets = True
self._last_project_name = self.project_name
self._asset_refresh_thread = DynamicQThread(self._refresh_assets)
self._asset_refresh_thread.start()
def _stop_fetch_thread(self):
self._refreshing_assets = False
if self._asset_refresh_thread is not None:
while self._asset_refresh_thread.isRunning():
time.sleep(0.01)
self._asset_refresh_thread = None
def _refresh_assets(self):
asset_docs = list(self._dbcon.find(
{"type": "asset"},
self._asset_projection
))
time.sleep(5)
if not self._refreshing_assets:
return
self._refreshing_assets = False
self._set_asset_docs(asset_docs)
class ProjectModel(QtGui.QStandardItemModel):
"""List of projects"""