mirror of
https://github.com/ynput/ayon-core.git
synced 2026-01-01 08:24:53 +01:00
Merge branch 'develop' into feature/envs-in-roots
This commit is contained in:
commit
f450942ccd
12 changed files with 239 additions and 39 deletions
|
|
@ -39,6 +39,7 @@ class CollectAudio(pyblish.api.ContextPlugin):
|
||||||
"blender",
|
"blender",
|
||||||
"houdini",
|
"houdini",
|
||||||
"max",
|
"max",
|
||||||
|
"circuit",
|
||||||
]
|
]
|
||||||
|
|
||||||
audio_product_name = "audioMain"
|
audio_product_name = "audioMain"
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,8 @@ class ExtractBurnin(publish.Extractor):
|
||||||
"houdini",
|
"houdini",
|
||||||
"max",
|
"max",
|
||||||
"blender",
|
"blender",
|
||||||
"unreal"
|
"unreal",
|
||||||
|
"circuit",
|
||||||
]
|
]
|
||||||
|
|
||||||
optional = True
|
optional = True
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,8 @@ class ExtractReview(pyblish.api.InstancePlugin):
|
||||||
"webpublisher",
|
"webpublisher",
|
||||||
"aftereffects",
|
"aftereffects",
|
||||||
"flame",
|
"flame",
|
||||||
"unreal"
|
"unreal",
|
||||||
|
"circuit",
|
||||||
]
|
]
|
||||||
|
|
||||||
# Supported extensions
|
# Supported extensions
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,8 @@ class ExtractThumbnail(pyblish.api.InstancePlugin):
|
||||||
"nuke",
|
"nuke",
|
||||||
"aftereffects",
|
"aftereffects",
|
||||||
"unreal",
|
"unreal",
|
||||||
"houdini"
|
"houdini",
|
||||||
|
"circuit",
|
||||||
]
|
]
|
||||||
enabled = False
|
enabled = False
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -227,6 +227,9 @@ class HierarchyModel(object):
|
||||||
self._tasks_by_id = NestedCacheItem(
|
self._tasks_by_id = NestedCacheItem(
|
||||||
levels=2, default_factory=dict, lifetime=self.lifetime)
|
levels=2, default_factory=dict, lifetime=self.lifetime)
|
||||||
|
|
||||||
|
self._entity_ids_by_assignee = NestedCacheItem(
|
||||||
|
levels=2, default_factory=dict, lifetime=self.lifetime)
|
||||||
|
|
||||||
self._folders_refreshing = set()
|
self._folders_refreshing = set()
|
||||||
self._tasks_refreshing = set()
|
self._tasks_refreshing = set()
|
||||||
self._controller = controller
|
self._controller = controller
|
||||||
|
|
@ -238,6 +241,8 @@ class HierarchyModel(object):
|
||||||
self._task_items.reset()
|
self._task_items.reset()
|
||||||
self._tasks_by_id.reset()
|
self._tasks_by_id.reset()
|
||||||
|
|
||||||
|
self._entity_ids_by_assignee.reset()
|
||||||
|
|
||||||
def refresh_project(self, project_name):
|
def refresh_project(self, project_name):
|
||||||
"""Force to refresh folder items for a project.
|
"""Force to refresh folder items for a project.
|
||||||
|
|
||||||
|
|
@ -461,6 +466,54 @@ class HierarchyModel(object):
|
||||||
output = self.get_task_entities(project_name, {task_id})
|
output = self.get_task_entities(project_name, {task_id})
|
||||||
return output[task_id]
|
return output[task_id]
|
||||||
|
|
||||||
|
def get_entity_ids_for_assignees(
|
||||||
|
self, project_name: str, assignees: list[str]
|
||||||
|
):
|
||||||
|
folder_ids = set()
|
||||||
|
task_ids = set()
|
||||||
|
output = {
|
||||||
|
"folder_ids": folder_ids,
|
||||||
|
"task_ids": task_ids,
|
||||||
|
}
|
||||||
|
assignees = set(assignees)
|
||||||
|
for assignee in tuple(assignees):
|
||||||
|
cache = self._entity_ids_by_assignee[project_name][assignee]
|
||||||
|
if cache.is_valid:
|
||||||
|
assignees.discard(assignee)
|
||||||
|
assignee_data = cache.get_data()
|
||||||
|
folder_ids.update(assignee_data["folder_ids"])
|
||||||
|
task_ids.update(assignee_data["task_ids"])
|
||||||
|
|
||||||
|
if not assignees:
|
||||||
|
return output
|
||||||
|
|
||||||
|
tasks = ayon_api.get_tasks(
|
||||||
|
project_name,
|
||||||
|
assignees_all=assignees,
|
||||||
|
fields={"id", "folderId", "assignees"},
|
||||||
|
)
|
||||||
|
tasks_assignee = {}
|
||||||
|
for task in tasks:
|
||||||
|
folder_ids.add(task["folderId"])
|
||||||
|
task_ids.add(task["id"])
|
||||||
|
for assignee in task["assignees"]:
|
||||||
|
tasks_assignee.setdefault(assignee, []).append(task)
|
||||||
|
|
||||||
|
for assignee, tasks in tasks_assignee.items():
|
||||||
|
cache = self._entity_ids_by_assignee[project_name][assignee]
|
||||||
|
assignee_folder_ids = set()
|
||||||
|
assignee_task_ids = set()
|
||||||
|
assignee_data = {
|
||||||
|
"folder_ids": assignee_folder_ids,
|
||||||
|
"task_ids": assignee_task_ids,
|
||||||
|
}
|
||||||
|
for task in tasks:
|
||||||
|
assignee_folder_ids.add(task["folderId"])
|
||||||
|
assignee_task_ids.add(task["id"])
|
||||||
|
cache.update_data(assignee_data)
|
||||||
|
|
||||||
|
return output
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def _folder_refresh_event_manager(self, project_name, sender):
|
def _folder_refresh_event_manager(self, project_name, sender):
|
||||||
self._folders_refreshing.add(project_name)
|
self._folders_refreshing.add(project_name)
|
||||||
|
|
|
||||||
|
|
@ -160,8 +160,8 @@ class AbstractLauncherFrontEnd(AbstractLauncherCommon):
|
||||||
Returns:
|
Returns:
|
||||||
list[FolderItem]: Minimum possible information needed
|
list[FolderItem]: Minimum possible information needed
|
||||||
for visualisation of folder hierarchy.
|
for visualisation of folder hierarchy.
|
||||||
"""
|
|
||||||
|
|
||||||
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
|
|
@ -180,8 +180,8 @@ class AbstractLauncherFrontEnd(AbstractLauncherCommon):
|
||||||
Returns:
|
Returns:
|
||||||
list[TaskItem]: Minimum possible information needed
|
list[TaskItem]: Minimum possible information needed
|
||||||
for visualisation of tasks.
|
for visualisation of tasks.
|
||||||
"""
|
|
||||||
|
|
||||||
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
|
|
@ -190,8 +190,8 @@ class AbstractLauncherFrontEnd(AbstractLauncherCommon):
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Union[str, None]: Selected project name.
|
Union[str, None]: Selected project name.
|
||||||
"""
|
|
||||||
|
|
||||||
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
|
|
@ -200,8 +200,8 @@ class AbstractLauncherFrontEnd(AbstractLauncherCommon):
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Union[str, None]: Selected folder id.
|
Union[str, None]: Selected folder id.
|
||||||
"""
|
|
||||||
|
|
||||||
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
|
|
@ -210,8 +210,8 @@ class AbstractLauncherFrontEnd(AbstractLauncherCommon):
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Union[str, None]: Selected task id.
|
Union[str, None]: Selected task id.
|
||||||
"""
|
|
||||||
|
|
||||||
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
|
|
@ -220,8 +220,8 @@ class AbstractLauncherFrontEnd(AbstractLauncherCommon):
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Union[str, None]: Selected task name.
|
Union[str, None]: Selected task name.
|
||||||
"""
|
|
||||||
|
|
||||||
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
|
|
@ -238,8 +238,8 @@ class AbstractLauncherFrontEnd(AbstractLauncherCommon):
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict[str, Union[str, None]]: Selected context.
|
dict[str, Union[str, None]]: Selected context.
|
||||||
"""
|
|
||||||
|
|
||||||
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
|
|
@ -249,8 +249,8 @@ class AbstractLauncherFrontEnd(AbstractLauncherCommon):
|
||||||
Args:
|
Args:
|
||||||
project_name (Union[str, None]): Project nameor None if no project
|
project_name (Union[str, None]): Project nameor None if no project
|
||||||
is selected.
|
is selected.
|
||||||
"""
|
|
||||||
|
|
||||||
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
|
|
@ -260,8 +260,8 @@ class AbstractLauncherFrontEnd(AbstractLauncherCommon):
|
||||||
Args:
|
Args:
|
||||||
folder_id (Union[str, None]): Folder id or None if no folder
|
folder_id (Union[str, None]): Folder id or None if no folder
|
||||||
is selected.
|
is selected.
|
||||||
"""
|
|
||||||
|
|
||||||
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
|
|
@ -273,8 +273,8 @@ class AbstractLauncherFrontEnd(AbstractLauncherCommon):
|
||||||
is selected.
|
is selected.
|
||||||
task_name (Union[str, None]): Task name or None if no task
|
task_name (Union[str, None]): Task name or None if no task
|
||||||
is selected.
|
is selected.
|
||||||
"""
|
|
||||||
|
|
||||||
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Actions
|
# Actions
|
||||||
|
|
@ -290,8 +290,8 @@ class AbstractLauncherFrontEnd(AbstractLauncherCommon):
|
||||||
Returns:
|
Returns:
|
||||||
list[ActionItem]: List of action items that should be shown
|
list[ActionItem]: List of action items that should be shown
|
||||||
for given context.
|
for given context.
|
||||||
"""
|
|
||||||
|
|
||||||
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
|
|
@ -303,8 +303,8 @@ class AbstractLauncherFrontEnd(AbstractLauncherCommon):
|
||||||
folder_id (Union[str, None]): Folder id.
|
folder_id (Union[str, None]): Folder id.
|
||||||
task_id (Union[str, None]): Task id.
|
task_id (Union[str, None]): Task id.
|
||||||
action_id (str): Action identifier.
|
action_id (str): Action identifier.
|
||||||
"""
|
|
||||||
|
|
||||||
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
|
|
@ -317,10 +317,10 @@ class AbstractLauncherFrontEnd(AbstractLauncherCommon):
|
||||||
project_name (Union[str, None]): Project name.
|
project_name (Union[str, None]): Project name.
|
||||||
folder_id (Union[str, None]): Folder id.
|
folder_id (Union[str, None]): Folder id.
|
||||||
task_id (Union[str, None]): Task id.
|
task_id (Union[str, None]): Task id.
|
||||||
action_id (Iterable[str]): Action identifiers.
|
action_ids (Iterable[str]): Action identifiers.
|
||||||
enabled (bool): New value of force not open workfile.
|
enabled (bool): New value of force not open workfile.
|
||||||
"""
|
|
||||||
|
|
||||||
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
|
|
@ -340,5 +340,17 @@ class AbstractLauncherFrontEnd(AbstractLauncherCommon):
|
||||||
Triggers 'controller.refresh.actions.started' event at the beginning
|
Triggers 'controller.refresh.actions.started' event at the beginning
|
||||||
and 'controller.refresh.actions.finished' at the end.
|
and 'controller.refresh.actions.finished' at the end.
|
||||||
"""
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def get_my_tasks_entity_ids(self, project_name: str):
|
||||||
|
"""Get entity ids for my tasks.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
project_name (str): Project name.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict[str, Union[list[str]]]: Folder and task ids.
|
||||||
|
|
||||||
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
from ayon_core.lib import Logger
|
from ayon_core.lib import Logger, get_ayon_username
|
||||||
from ayon_core.lib.events import QueuedEventSystem
|
from ayon_core.lib.events import QueuedEventSystem
|
||||||
from ayon_core.settings import get_project_settings
|
from ayon_core.settings import get_project_settings
|
||||||
from ayon_core.tools.common_models import ProjectsModel, HierarchyModel
|
from ayon_core.tools.common_models import ProjectsModel, HierarchyModel
|
||||||
|
|
@ -6,6 +6,8 @@ from ayon_core.tools.common_models import ProjectsModel, HierarchyModel
|
||||||
from .abstract import AbstractLauncherFrontEnd, AbstractLauncherBackend
|
from .abstract import AbstractLauncherFrontEnd, AbstractLauncherBackend
|
||||||
from .models import LauncherSelectionModel, ActionsModel
|
from .models import LauncherSelectionModel, ActionsModel
|
||||||
|
|
||||||
|
NOT_SET = object()
|
||||||
|
|
||||||
|
|
||||||
class BaseLauncherController(
|
class BaseLauncherController(
|
||||||
AbstractLauncherFrontEnd, AbstractLauncherBackend
|
AbstractLauncherFrontEnd, AbstractLauncherBackend
|
||||||
|
|
@ -15,6 +17,8 @@ class BaseLauncherController(
|
||||||
self._event_system = None
|
self._event_system = None
|
||||||
self._log = None
|
self._log = None
|
||||||
|
|
||||||
|
self._username = NOT_SET
|
||||||
|
|
||||||
self._selection_model = LauncherSelectionModel(self)
|
self._selection_model = LauncherSelectionModel(self)
|
||||||
self._projects_model = ProjectsModel(self)
|
self._projects_model = ProjectsModel(self)
|
||||||
self._hierarchy_model = HierarchyModel(self)
|
self._hierarchy_model = HierarchyModel(self)
|
||||||
|
|
@ -168,5 +172,19 @@ class BaseLauncherController(
|
||||||
|
|
||||||
self._emit_event("controller.refresh.actions.finished")
|
self._emit_event("controller.refresh.actions.finished")
|
||||||
|
|
||||||
|
def get_my_tasks_entity_ids(self, project_name: str):
|
||||||
|
username = self._get_my_username()
|
||||||
|
assignees = []
|
||||||
|
if username:
|
||||||
|
assignees.append(username)
|
||||||
|
return self._hierarchy_model.get_entity_ids_for_assignees(
|
||||||
|
project_name, assignees
|
||||||
|
)
|
||||||
|
|
||||||
|
def _get_my_username(self):
|
||||||
|
if self._username is NOT_SET:
|
||||||
|
self._username = get_ayon_username()
|
||||||
|
return self._username
|
||||||
|
|
||||||
def _emit_event(self, topic, data=None):
|
def _emit_event(self, topic, data=None):
|
||||||
self.emit_event(topic, data, "controller")
|
self.emit_event(topic, data, "controller")
|
||||||
|
|
|
||||||
|
|
@ -5,17 +5,17 @@ from ayon_core.tools.utils import (
|
||||||
PlaceholderLineEdit,
|
PlaceholderLineEdit,
|
||||||
SquareButton,
|
SquareButton,
|
||||||
RefreshButton,
|
RefreshButton,
|
||||||
)
|
|
||||||
from ayon_core.tools.utils import (
|
|
||||||
ProjectsCombobox,
|
ProjectsCombobox,
|
||||||
FoldersWidget,
|
FoldersWidget,
|
||||||
TasksWidget,
|
TasksWidget,
|
||||||
|
NiceCheckbox,
|
||||||
)
|
)
|
||||||
|
from ayon_core.tools.utils.lib import checkstate_int_to_enum
|
||||||
|
|
||||||
|
|
||||||
class HierarchyPage(QtWidgets.QWidget):
|
class HierarchyPage(QtWidgets.QWidget):
|
||||||
def __init__(self, controller, parent):
|
def __init__(self, controller, parent):
|
||||||
super(HierarchyPage, self).__init__(parent)
|
super().__init__(parent)
|
||||||
|
|
||||||
# Header
|
# Header
|
||||||
header_widget = QtWidgets.QWidget(self)
|
header_widget = QtWidgets.QWidget(self)
|
||||||
|
|
@ -43,23 +43,36 @@ class HierarchyPage(QtWidgets.QWidget):
|
||||||
)
|
)
|
||||||
content_body.setOrientation(QtCore.Qt.Horizontal)
|
content_body.setOrientation(QtCore.Qt.Horizontal)
|
||||||
|
|
||||||
# - Folders widget with filter
|
# - filters
|
||||||
folders_wrapper = QtWidgets.QWidget(content_body)
|
filters_widget = QtWidgets.QWidget(self)
|
||||||
|
|
||||||
folders_filter_text = PlaceholderLineEdit(folders_wrapper)
|
folders_filter_text = PlaceholderLineEdit(filters_widget)
|
||||||
folders_filter_text.setPlaceholderText("Filter folders...")
|
folders_filter_text.setPlaceholderText("Filter folders...")
|
||||||
|
|
||||||
folders_widget = FoldersWidget(controller, folders_wrapper)
|
my_tasks_tooltip = (
|
||||||
|
"Filter folders and task to only those you are assigned to."
|
||||||
|
)
|
||||||
|
my_tasks_label = QtWidgets.QLabel("My tasks", filters_widget)
|
||||||
|
my_tasks_label.setToolTip(my_tasks_tooltip)
|
||||||
|
|
||||||
folders_wrapper_layout = QtWidgets.QVBoxLayout(folders_wrapper)
|
my_tasks_checkbox = NiceCheckbox(filters_widget)
|
||||||
folders_wrapper_layout.setContentsMargins(0, 0, 0, 0)
|
my_tasks_checkbox.setChecked(False)
|
||||||
folders_wrapper_layout.addWidget(folders_filter_text, 0)
|
my_tasks_checkbox.setToolTip(my_tasks_tooltip)
|
||||||
folders_wrapper_layout.addWidget(folders_widget, 1)
|
|
||||||
|
filters_layout = QtWidgets.QHBoxLayout(filters_widget)
|
||||||
|
filters_layout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
filters_layout.addWidget(folders_filter_text, 1)
|
||||||
|
filters_layout.addWidget(my_tasks_label, 0)
|
||||||
|
filters_layout.addWidget(my_tasks_checkbox, 0)
|
||||||
|
|
||||||
|
# - Folders widget
|
||||||
|
folders_widget = FoldersWidget(controller, content_body)
|
||||||
|
folders_widget.set_header_visible(True)
|
||||||
|
|
||||||
# - Tasks widget
|
# - Tasks widget
|
||||||
tasks_widget = TasksWidget(controller, content_body)
|
tasks_widget = TasksWidget(controller, content_body)
|
||||||
|
|
||||||
content_body.addWidget(folders_wrapper)
|
content_body.addWidget(folders_widget)
|
||||||
content_body.addWidget(tasks_widget)
|
content_body.addWidget(tasks_widget)
|
||||||
content_body.setStretchFactor(0, 100)
|
content_body.setStretchFactor(0, 100)
|
||||||
content_body.setStretchFactor(1, 65)
|
content_body.setStretchFactor(1, 65)
|
||||||
|
|
@ -67,20 +80,27 @@ class HierarchyPage(QtWidgets.QWidget):
|
||||||
main_layout = QtWidgets.QVBoxLayout(self)
|
main_layout = QtWidgets.QVBoxLayout(self)
|
||||||
main_layout.setContentsMargins(0, 0, 0, 0)
|
main_layout.setContentsMargins(0, 0, 0, 0)
|
||||||
main_layout.addWidget(header_widget, 0)
|
main_layout.addWidget(header_widget, 0)
|
||||||
|
main_layout.addWidget(filters_widget, 0)
|
||||||
main_layout.addWidget(content_body, 1)
|
main_layout.addWidget(content_body, 1)
|
||||||
|
|
||||||
btn_back.clicked.connect(self._on_back_clicked)
|
btn_back.clicked.connect(self._on_back_clicked)
|
||||||
refresh_btn.clicked.connect(self._on_refresh_clicked)
|
refresh_btn.clicked.connect(self._on_refresh_clicked)
|
||||||
folders_filter_text.textChanged.connect(self._on_filter_text_changed)
|
folders_filter_text.textChanged.connect(self._on_filter_text_changed)
|
||||||
|
my_tasks_checkbox.stateChanged.connect(
|
||||||
|
self._on_my_tasks_checkbox_state_changed
|
||||||
|
)
|
||||||
|
|
||||||
self._is_visible = False
|
self._is_visible = False
|
||||||
self._controller = controller
|
self._controller = controller
|
||||||
|
|
||||||
self._btn_back = btn_back
|
self._btn_back = btn_back
|
||||||
self._projects_combobox = projects_combobox
|
self._projects_combobox = projects_combobox
|
||||||
|
self._my_tasks_checkbox = my_tasks_checkbox
|
||||||
self._folders_widget = folders_widget
|
self._folders_widget = folders_widget
|
||||||
self._tasks_widget = tasks_widget
|
self._tasks_widget = tasks_widget
|
||||||
|
|
||||||
|
self._project_name = None
|
||||||
|
|
||||||
# Post init
|
# Post init
|
||||||
projects_combobox.set_listen_to_selection_change(self._is_visible)
|
projects_combobox.set_listen_to_selection_change(self._is_visible)
|
||||||
|
|
||||||
|
|
@ -91,10 +111,14 @@ class HierarchyPage(QtWidgets.QWidget):
|
||||||
self._projects_combobox.set_listen_to_selection_change(visible)
|
self._projects_combobox.set_listen_to_selection_change(visible)
|
||||||
if visible and project_name:
|
if visible and project_name:
|
||||||
self._projects_combobox.set_selection(project_name)
|
self._projects_combobox.set_selection(project_name)
|
||||||
|
self._project_name = project_name
|
||||||
|
|
||||||
def refresh(self):
|
def refresh(self):
|
||||||
self._folders_widget.refresh()
|
self._folders_widget.refresh()
|
||||||
self._tasks_widget.refresh()
|
self._tasks_widget.refresh()
|
||||||
|
self._on_my_tasks_checkbox_state_changed(
|
||||||
|
self._my_tasks_checkbox.checkState()
|
||||||
|
)
|
||||||
|
|
||||||
def _on_back_clicked(self):
|
def _on_back_clicked(self):
|
||||||
self._controller.set_selected_project(None)
|
self._controller.set_selected_project(None)
|
||||||
|
|
@ -104,3 +128,16 @@ class HierarchyPage(QtWidgets.QWidget):
|
||||||
|
|
||||||
def _on_filter_text_changed(self, text):
|
def _on_filter_text_changed(self, text):
|
||||||
self._folders_widget.set_name_filter(text)
|
self._folders_widget.set_name_filter(text)
|
||||||
|
|
||||||
|
def _on_my_tasks_checkbox_state_changed(self, state):
|
||||||
|
folder_ids = None
|
||||||
|
task_ids = None
|
||||||
|
state = checkstate_int_to_enum(state)
|
||||||
|
if state == QtCore.Qt.Checked:
|
||||||
|
entity_ids = self._controller.get_my_tasks_entity_ids(
|
||||||
|
self._project_name
|
||||||
|
)
|
||||||
|
folder_ids = entity_ids["folder_ids"]
|
||||||
|
task_ids = entity_ids["task_ids"]
|
||||||
|
self._folders_widget.set_folder_ids_filter(folder_ids)
|
||||||
|
self._tasks_widget.set_task_ids_filter(task_ids)
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ class LauncherWindow(QtWidgets.QWidget):
|
||||||
page_side_anim_interval = 250
|
page_side_anim_interval = 250
|
||||||
|
|
||||||
def __init__(self, controller=None, parent=None):
|
def __init__(self, controller=None, parent=None):
|
||||||
super(LauncherWindow, self).__init__(parent)
|
super().__init__(parent)
|
||||||
|
|
||||||
if controller is None:
|
if controller is None:
|
||||||
controller = BaseLauncherController()
|
controller = BaseLauncherController()
|
||||||
|
|
@ -153,14 +153,14 @@ class LauncherWindow(QtWidgets.QWidget):
|
||||||
self.resize(520, 740)
|
self.resize(520, 740)
|
||||||
|
|
||||||
def showEvent(self, event):
|
def showEvent(self, event):
|
||||||
super(LauncherWindow, self).showEvent(event)
|
super().showEvent(event)
|
||||||
self._window_is_active = True
|
self._window_is_active = True
|
||||||
if not self._actions_refresh_timer.isActive():
|
if not self._actions_refresh_timer.isActive():
|
||||||
self._actions_refresh_timer.start()
|
self._actions_refresh_timer.start()
|
||||||
self._controller.refresh()
|
self._controller.refresh()
|
||||||
|
|
||||||
def closeEvent(self, event):
|
def closeEvent(self, event):
|
||||||
super(LauncherWindow, self).closeEvent(event)
|
super().closeEvent(event)
|
||||||
self._window_is_active = False
|
self._window_is_active = False
|
||||||
self._actions_refresh_timer.stop()
|
self._actions_refresh_timer.stop()
|
||||||
|
|
||||||
|
|
@ -176,7 +176,7 @@ class LauncherWindow(QtWidgets.QWidget):
|
||||||
self._on_actions_refresh_timeout()
|
self._on_actions_refresh_timeout()
|
||||||
self._actions_refresh_timer.start()
|
self._actions_refresh_timer.start()
|
||||||
|
|
||||||
super(LauncherWindow, self).changeEvent(event)
|
super().changeEvent(event)
|
||||||
|
|
||||||
def _on_actions_refresh_timeout(self):
|
def _on_actions_refresh_timeout(self):
|
||||||
# Stop timer if widget is not visible
|
# Stop timer if widget is not visible
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
from __future__ import annotations
|
||||||
from qtpy import QtGui, QtCore
|
from qtpy import QtGui, QtCore
|
||||||
|
|
||||||
from ._multicombobox import (
|
from ._multicombobox import (
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
|
from __future__ import annotations
|
||||||
import collections
|
import collections
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from qtpy import QtWidgets, QtGui, QtCore
|
from qtpy import QtWidgets, QtGui, QtCore
|
||||||
|
|
||||||
|
|
@ -33,7 +35,10 @@ class FoldersQtModel(QtGui.QStandardItemModel):
|
||||||
refreshed = QtCore.Signal()
|
refreshed = QtCore.Signal()
|
||||||
|
|
||||||
def __init__(self, controller):
|
def __init__(self, controller):
|
||||||
super(FoldersQtModel, self).__init__()
|
super().__init__()
|
||||||
|
|
||||||
|
self.setColumnCount(1)
|
||||||
|
self.setHeaderData(0, QtCore.Qt.Horizontal, "Folders")
|
||||||
|
|
||||||
self._controller = controller
|
self._controller = controller
|
||||||
self._items_by_id = {}
|
self._items_by_id = {}
|
||||||
|
|
@ -334,6 +339,29 @@ class FoldersQtModel(QtGui.QStandardItemModel):
|
||||||
self.refreshed.emit()
|
self.refreshed.emit()
|
||||||
|
|
||||||
|
|
||||||
|
class FoldersProxyModel(RecursiveSortFilterProxyModel):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self._folder_ids_filter = None
|
||||||
|
|
||||||
|
def set_folder_ids_filter(self, folder_ids: Optional[list[str]]):
|
||||||
|
if self._folder_ids_filter == folder_ids:
|
||||||
|
return
|
||||||
|
self._folder_ids_filter = folder_ids
|
||||||
|
self.invalidateFilter()
|
||||||
|
|
||||||
|
def filterAcceptsRow(self, row, parent_index):
|
||||||
|
if self._folder_ids_filter is not None:
|
||||||
|
if not self._folder_ids_filter:
|
||||||
|
return False
|
||||||
|
source_index = self.sourceModel().index(row, 0, parent_index)
|
||||||
|
folder_id = source_index.data(FOLDER_ID_ROLE)
|
||||||
|
if folder_id not in self._folder_ids_filter:
|
||||||
|
return False
|
||||||
|
return super().filterAcceptsRow(row, parent_index)
|
||||||
|
|
||||||
|
|
||||||
class FoldersWidget(QtWidgets.QWidget):
|
class FoldersWidget(QtWidgets.QWidget):
|
||||||
"""Folders widget.
|
"""Folders widget.
|
||||||
|
|
||||||
|
|
@ -369,13 +397,13 @@ class FoldersWidget(QtWidgets.QWidget):
|
||||||
refreshed = QtCore.Signal()
|
refreshed = QtCore.Signal()
|
||||||
|
|
||||||
def __init__(self, controller, parent, handle_expected_selection=False):
|
def __init__(self, controller, parent, handle_expected_selection=False):
|
||||||
super(FoldersWidget, self).__init__(parent)
|
super().__init__(parent)
|
||||||
|
|
||||||
folders_view = TreeView(self)
|
folders_view = TreeView(self)
|
||||||
folders_view.setHeaderHidden(True)
|
folders_view.setHeaderHidden(True)
|
||||||
|
|
||||||
folders_model = FoldersQtModel(controller)
|
folders_model = FoldersQtModel(controller)
|
||||||
folders_proxy_model = RecursiveSortFilterProxyModel()
|
folders_proxy_model = FoldersProxyModel()
|
||||||
folders_proxy_model.setSourceModel(folders_model)
|
folders_proxy_model.setSourceModel(folders_model)
|
||||||
folders_proxy_model.setSortCaseSensitivity(QtCore.Qt.CaseInsensitive)
|
folders_proxy_model.setSortCaseSensitivity(QtCore.Qt.CaseInsensitive)
|
||||||
|
|
||||||
|
|
@ -446,6 +474,18 @@ class FoldersWidget(QtWidgets.QWidget):
|
||||||
if name:
|
if name:
|
||||||
self._folders_view.expandAll()
|
self._folders_view.expandAll()
|
||||||
|
|
||||||
|
def set_folder_ids_filter(self, folder_ids: Optional[list[str]]):
|
||||||
|
"""Set filter of folder ids.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
folder_ids (list[str]): The list of folder ids.
|
||||||
|
|
||||||
|
"""
|
||||||
|
self._folders_proxy_model.set_folder_ids_filter(folder_ids)
|
||||||
|
|
||||||
|
def set_header_visible(self, visible: bool):
|
||||||
|
self._folders_view.setHeaderHidden(not visible)
|
||||||
|
|
||||||
def refresh(self):
|
def refresh(self):
|
||||||
"""Refresh folders model.
|
"""Refresh folders model.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from qtpy import QtWidgets, QtGui, QtCore
|
from qtpy import QtWidgets, QtGui, QtCore
|
||||||
|
|
||||||
from ayon_core.style import (
|
from ayon_core.style import (
|
||||||
|
|
@ -343,6 +346,29 @@ class TasksQtModel(QtGui.QStandardItemModel):
|
||||||
return self._has_content
|
return self._has_content
|
||||||
|
|
||||||
|
|
||||||
|
class TasksProxyModel(QtCore.QSortFilterProxyModel):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self._task_ids_filter: Optional[set[str]] = None
|
||||||
|
|
||||||
|
def set_task_ids_filter(self, task_ids: Optional[set[str]]):
|
||||||
|
if self._task_ids_filter == task_ids:
|
||||||
|
return
|
||||||
|
self._task_ids_filter = task_ids
|
||||||
|
self.invalidateFilter()
|
||||||
|
|
||||||
|
def filterAcceptsRow(self, row, parent_index):
|
||||||
|
if self._task_ids_filter is not None:
|
||||||
|
if not self._task_ids_filter:
|
||||||
|
return False
|
||||||
|
source_index = self.sourceModel().index(row, 0, parent_index)
|
||||||
|
task_id = source_index.data(ITEM_ID_ROLE)
|
||||||
|
if task_id is not None and task_id not in self._task_ids_filter:
|
||||||
|
return False
|
||||||
|
return super().filterAcceptsRow(row, parent_index)
|
||||||
|
|
||||||
|
|
||||||
class TasksWidget(QtWidgets.QWidget):
|
class TasksWidget(QtWidgets.QWidget):
|
||||||
"""Tasks widget.
|
"""Tasks widget.
|
||||||
|
|
||||||
|
|
@ -364,7 +390,7 @@ class TasksWidget(QtWidgets.QWidget):
|
||||||
tasks_view.setIndentation(0)
|
tasks_view.setIndentation(0)
|
||||||
|
|
||||||
tasks_model = TasksQtModel(controller)
|
tasks_model = TasksQtModel(controller)
|
||||||
tasks_proxy_model = QtCore.QSortFilterProxyModel()
|
tasks_proxy_model = TasksProxyModel()
|
||||||
tasks_proxy_model.setSourceModel(tasks_model)
|
tasks_proxy_model.setSourceModel(tasks_model)
|
||||||
tasks_proxy_model.setSortCaseSensitivity(QtCore.Qt.CaseInsensitive)
|
tasks_proxy_model.setSortCaseSensitivity(QtCore.Qt.CaseInsensitive)
|
||||||
|
|
||||||
|
|
@ -490,6 +516,15 @@ class TasksWidget(QtWidgets.QWidget):
|
||||||
)
|
)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def set_task_ids_filter(self, task_ids: Optional[list[str]]):
|
||||||
|
"""Set filter of folder ids.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
task_ids (list[str]): The list of folder ids.
|
||||||
|
|
||||||
|
"""
|
||||||
|
self._tasks_proxy_model.set_task_ids_filter(task_ids)
|
||||||
|
|
||||||
def _on_tasks_refresh_finished(self, event):
|
def _on_tasks_refresh_finished(self, event):
|
||||||
"""Tasks were refreshed in controller.
|
"""Tasks were refreshed in controller.
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue