Merge pull request #5867 from ynput/bugfix/launcher-refresh-issues

This commit is contained in:
Milan Kolar 2023-11-06 08:22:30 +01:00 committed by GitHub
commit 18070ed7a1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 86 additions and 60 deletions

View file

@ -3,7 +3,7 @@ from qtpy import QtWidgets, QtCore
from openpype.tools.flickcharm import FlickCharm
from openpype.tools.utils import PlaceholderLineEdit, RefreshButton
from openpype.tools.ayon_utils.widgets import (
ProjectsModel,
ProjectsQtModel,
ProjectSortFilterProxy,
)
from openpype.tools.ayon_utils.models import PROJECTS_MODEL_SENDER
@ -95,7 +95,7 @@ class ProjectsWidget(QtWidgets.QWidget):
projects_view.setSelectionMode(QtWidgets.QListView.NoSelection)
flick = FlickCharm(parent=self)
flick.activateOn(projects_view)
projects_model = ProjectsModel(controller)
projects_model = ProjectsQtModel(controller)
projects_proxy_model = ProjectSortFilterProxy()
projects_proxy_model.setSourceModel(projects_model)
@ -133,9 +133,14 @@ class ProjectsWidget(QtWidgets.QWidget):
return self._projects_model.has_content()
def _on_view_clicked(self, index):
if index.isValid():
project_name = index.data(QtCore.Qt.DisplayRole)
self._controller.set_selected_project(project_name)
if not index.isValid():
return
model = index.model()
flags = model.flags(index)
if not flags & QtCore.Qt.ItemIsEnabled:
return
project_name = index.data(QtCore.Qt.DisplayRole)
self._controller.set_selected_project(project_name)
def _on_project_filter_change(self, text):
self._projects_proxy_model.setFilterFixedString(text)

View file

@ -8,7 +8,7 @@ from openpype.tools.utils import (
from openpype.style import get_objected_colors
from openpype.tools.ayon_utils.widgets import (
FoldersModel,
FoldersQtModel,
FOLDERS_MODEL_SENDER_NAME,
)
from openpype.tools.ayon_utils.widgets.folders_widget import FOLDER_ID_ROLE
@ -182,7 +182,7 @@ class UnderlinesFolderDelegate(QtWidgets.QItemDelegate):
painter.restore()
class LoaderFoldersModel(FoldersModel):
class LoaderFoldersModel(FoldersQtModel):
def __init__(self, *args, **kwargs):
super(LoaderFoldersModel, self).__init__(*args, **kwargs)

View file

@ -87,7 +87,7 @@ def _get_project_items_from_entitiy(projects):
class ProjectsModel(object):
def __init__(self, controller):
self._projects_cache = CacheItem(default_factory=dict)
self._projects_cache = CacheItem(default_factory=list)
self._project_items_by_name = {}
self._projects_by_name = {}
@ -103,8 +103,18 @@ class ProjectsModel(object):
self._refresh_projects_cache()
def get_project_items(self, sender):
"""
Args:
sender (str): Name of sender who asked for items.
Returns:
Union[list[ProjectItem], None]: List of project items, or None
if model is refreshing.
"""
if not self._projects_cache.is_valid:
self._refresh_projects_cache(sender)
return self._refresh_projects_cache(sender)
return self._projects_cache.get_data()
def get_project_entity(self, project_name):
@ -136,11 +146,12 @@ class ProjectsModel(object):
def _refresh_projects_cache(self, sender=None):
if self._is_refreshing:
return
return None
with self._project_refresh_event_manager(sender):
project_items = self._query_projects()
self._projects_cache.update_data(project_items)
return self._projects_cache.get_data()
def _query_projects(self):
projects = ayon_api.get_projects(fields=["name", "active", "library"])

View file

@ -1,19 +1,19 @@
from .projects_widget import (
# ProjectsWidget,
ProjectsCombobox,
ProjectsModel,
ProjectsQtModel,
ProjectSortFilterProxy,
)
from .folders_widget import (
FoldersWidget,
FoldersModel,
FoldersQtModel,
FOLDERS_MODEL_SENDER_NAME,
)
from .tasks_widget import (
TasksWidget,
TasksModel,
TasksQtModel,
TASKS_MODEL_SENDER_NAME,
)
from .utils import (
@ -25,15 +25,15 @@ from .utils import (
__all__ = (
# "ProjectsWidget",
"ProjectsCombobox",
"ProjectsModel",
"ProjectsQtModel",
"ProjectSortFilterProxy",
"FoldersWidget",
"FoldersModel",
"FoldersQtModel",
"FOLDERS_MODEL_SENDER_NAME",
"TasksWidget",
"TasksModel",
"TasksQtModel",
"TASKS_MODEL_SENDER_NAME",
"get_qt_icon",

View file

@ -16,7 +16,7 @@ FOLDER_PATH_ROLE = QtCore.Qt.UserRole + 3
FOLDER_TYPE_ROLE = QtCore.Qt.UserRole + 4
class FoldersModel(QtGui.QStandardItemModel):
class FoldersQtModel(QtGui.QStandardItemModel):
"""Folders model which cares about refresh of folders.
Args:
@ -26,7 +26,7 @@ class FoldersModel(QtGui.QStandardItemModel):
refreshed = QtCore.Signal()
def __init__(self, controller):
super(FoldersModel, self).__init__()
super(FoldersQtModel, self).__init__()
self._controller = controller
self._items_by_id = {}
@ -104,8 +104,8 @@ class FoldersModel(QtGui.QStandardItemModel):
if not project_name:
self._last_project_name = project_name
self._current_refresh_thread = None
self._fill_items({})
self._current_refresh_thread = None
return
self._is_refreshing = True
@ -152,6 +152,7 @@ class FoldersModel(QtGui.QStandardItemModel):
return
self._fill_items(thread.get_result())
self._current_refresh_thread = None
def _fill_item_data(self, item, folder_item):
"""
@ -281,7 +282,7 @@ class FoldersWidget(QtWidgets.QWidget):
folders_view = TreeView(self)
folders_view.setHeaderHidden(True)
folders_model = FoldersModel(controller)
folders_model = FoldersQtModel(controller)
folders_proxy_model = RecursiveSortFilterProxyModel()
folders_proxy_model.setSourceModel(folders_model)
folders_proxy_model.setSortCaseSensitivity(QtCore.Qt.CaseInsensitive)

View file

@ -10,11 +10,11 @@ PROJECT_IS_CURRENT_ROLE = QtCore.Qt.UserRole + 4
LIBRARY_PROJECT_SEPARATOR_ROLE = QtCore.Qt.UserRole + 5
class ProjectsModel(QtGui.QStandardItemModel):
class ProjectsQtModel(QtGui.QStandardItemModel):
refreshed = QtCore.Signal()
def __init__(self, controller):
super(ProjectsModel, self).__init__()
super(ProjectsQtModel, self).__init__()
self._controller = controller
self._project_items = {}
@ -35,12 +35,11 @@ class ProjectsModel(QtGui.QStandardItemModel):
self._selected_project = None
self._is_refreshing = False
self._refresh_thread = None
@property
def is_refreshing(self):
return self._is_refreshing
return self._refresh_thread is not None
def refresh(self):
self._refresh()
@ -169,28 +168,33 @@ class ProjectsModel(QtGui.QStandardItemModel):
return self._select_item
def _refresh(self):
if self._is_refreshing:
if self._refresh_thread is not None:
return
self._is_refreshing = True
refresh_thread = RefreshThread(
"projects", self._query_project_items
)
refresh_thread.refresh_finished.connect(self._refresh_finished)
refresh_thread.start()
self._refresh_thread = refresh_thread
refresh_thread.start()
def _query_project_items(self):
return self._controller.get_project_items()
return self._controller.get_project_items(
sender=PROJECTS_MODEL_SENDER
)
def _refresh_finished(self):
# TODO check if failed
result = self._refresh_thread.get_result()
if result is not None:
self._fill_items(result)
self._refresh_thread = None
self._fill_items(result)
self._is_refreshing = False
self.refreshed.emit()
if result is None:
self._refresh()
else:
self.refreshed.emit()
def _fill_items(self, project_items):
new_project_names = {
@ -403,7 +407,7 @@ class ProjectsCombobox(QtWidgets.QWidget):
projects_combobox = QtWidgets.QComboBox(self)
combobox_delegate = QtWidgets.QStyledItemDelegate(projects_combobox)
projects_combobox.setItemDelegate(combobox_delegate)
projects_model = ProjectsModel(controller)
projects_model = ProjectsQtModel(controller)
projects_proxy_model = ProjectSortFilterProxy()
projects_proxy_model.setSourceModel(projects_model)
projects_combobox.setModel(projects_proxy_model)

View file

@ -12,7 +12,7 @@ ITEM_NAME_ROLE = QtCore.Qt.UserRole + 3
TASK_TYPE_ROLE = QtCore.Qt.UserRole + 4
class TasksModel(QtGui.QStandardItemModel):
class TasksQtModel(QtGui.QStandardItemModel):
"""Tasks model which cares about refresh of tasks by folder id.
Args:
@ -22,7 +22,7 @@ class TasksModel(QtGui.QStandardItemModel):
refreshed = QtCore.Signal()
def __init__(self, controller):
super(TasksModel, self).__init__()
super(TasksQtModel, self).__init__()
self._controller = controller
@ -185,28 +185,7 @@ class TasksModel(QtGui.QStandardItemModel):
thread.refresh_finished.connect(self._on_refresh_thread)
thread.start()
def _on_refresh_thread(self, thread_id):
"""Callback when refresh thread is finished.
Technically can be running multiple refresh threads at the same time,
to avoid using values from wrong thread, we check if thread id is
current refresh thread id.
Tasks are stored by name, so if a folder has same task name as
previously selected folder it keeps the selection.
Args:
thread_id (str): Thread id.
"""
# Make sure to remove thread from '_refresh_threads' dict
thread = self._refresh_threads.pop(thread_id)
if (
self._current_refresh_thread is None
or thread_id != self._current_refresh_thread.id
):
return
def _fill_data_from_thread(self, thread):
task_items = thread.get_result()
# Task items are refreshed
if task_items is None:
@ -247,7 +226,33 @@ class TasksModel(QtGui.QStandardItemModel):
if new_items:
root_item.appendRows(new_items)
def _on_refresh_thread(self, thread_id):
"""Callback when refresh thread is finished.
Technically can be running multiple refresh threads at the same time,
to avoid using values from wrong thread, we check if thread id is
current refresh thread id.
Tasks are stored by name, so if a folder has same task name as
previously selected folder it keeps the selection.
Args:
thread_id (str): Thread id.
"""
# Make sure to remove thread from '_refresh_threads' dict
thread = self._refresh_threads.pop(thread_id)
if (
self._current_refresh_thread is None
or thread_id != self._current_refresh_thread.id
):
return
self._fill_data_from_thread(thread)
root_item = self.invisibleRootItem()
self._has_content = root_item.rowCount() > 0
self._current_refresh_thread = None
self._is_refreshing = False
self.refreshed.emit()
@ -280,7 +285,7 @@ class TasksModel(QtGui.QStandardItemModel):
if section == 0:
return "Tasks"
return super(TasksModel, self).headerData(
return super(TasksQtModel, self).headerData(
section, orientation, role
)
@ -305,7 +310,7 @@ class TasksWidget(QtWidgets.QWidget):
tasks_view = DeselectableTreeView(self)
tasks_view.setIndentation(0)
tasks_model = TasksModel(controller)
tasks_model = TasksQtModel(controller)
tasks_proxy_model = QtCore.QSortFilterProxyModel()
tasks_proxy_model.setSourceModel(tasks_model)
tasks_proxy_model.setSortCaseSensitivity(QtCore.Qt.CaseInsensitive)