diff --git a/client/ayon_core/tools/ayon_utils/widgets/__init__.py b/client/ayon_core/tools/ayon_utils/widgets/__init__.py index b1b7dd7527..a62bab6751 100644 --- a/client/ayon_core/tools/ayon_utils/widgets/__init__.py +++ b/client/ayon_core/tools/ayon_utils/widgets/__init__.py @@ -3,6 +3,10 @@ from .projects_widget import ( ProjectsCombobox, ProjectsQtModel, ProjectSortFilterProxy, + PROJECT_NAME_ROLE, + PROJECT_IS_CURRENT_ROLE, + PROJECT_IS_ACTIVE_ROLE, + PROJECT_IS_LIBRARY_ROLE, ) from .folders_widget import ( @@ -28,6 +32,10 @@ __all__ = ( "ProjectsCombobox", "ProjectsQtModel", "ProjectSortFilterProxy", + "PROJECT_NAME_ROLE", + "PROJECT_IS_CURRENT_ROLE", + "PROJECT_IS_ACTIVE_ROLE", + "PROJECT_IS_LIBRARY_ROLE", "FoldersWidget", "FoldersQtModel", diff --git a/client/ayon_core/tools/ayon_utils/widgets/projects_widget.py b/client/ayon_core/tools/ayon_utils/widgets/projects_widget.py index d3bebecfd6..79ffc77640 100644 --- a/client/ayon_core/tools/ayon_utils/widgets/projects_widget.py +++ b/client/ayon_core/tools/ayon_utils/widgets/projects_widget.py @@ -47,6 +47,22 @@ class ProjectsQtModel(QtGui.QStandardItemModel): def has_content(self): return len(self._project_items) > 0 + def get_index_by_project_name(self, project_name): + """Get index of project by name. + + Args: + project_name (str): Project name. + + Returns: + QtCore.QModelIndex: Index of project item. Index is not valid + if project is not found. + + """ + item = self._project_items.get(project_name) + if item is None: + return QtCore.QModelIndex() + return self.indexFromItem(item) + def set_select_item_visible(self, visible): if self._select_item_visible is visible: return diff --git a/client/ayon_core/tools/traypublisher/window.py b/client/ayon_core/tools/traypublisher/window.py index 78517b4185..210e77f0fa 100644 --- a/client/ayon_core/tools/traypublisher/window.py +++ b/client/ayon_core/tools/traypublisher/window.py @@ -10,22 +10,31 @@ import platform from qtpy import QtWidgets, QtCore import qtawesome -import appdirs -from ayon_core.lib import JSONSettingRegistry, is_running_from_build +from ayon_core.lib import AYONSettingsRegistry, is_running_from_build from ayon_core.pipeline import install_host from ayon_core.hosts.traypublisher.api import TrayPublisherHost from ayon_core.tools.publisher.control_qt import QtPublisherController from ayon_core.tools.publisher.window import PublisherWindow from ayon_core.tools.utils import PlaceholderLineEdit, get_ayon_qt_app -from ayon_core.tools.utils.constants import PROJECT_NAME_ROLE -from ayon_core.tools.utils.models import ( - ProjectModel, - ProjectSortFilterProxy +from ayon_core.tools.ayon_utils.models import ProjectsModel +from ayon_core.tools.ayon_utils.widgets import ( + ProjectsQtModel, + ProjectSortFilterProxy, + PROJECT_NAME_ROLE, ) +class TrayPublisherRegistry(AYONSettingsRegistry): + def __init__(self): + super(TrayPublisherRegistry, self).__init__("traypublisher") + + class TrayPublisherController(QtPublisherController): + def __init__(self, *args, **kwargs): + super(TrayPublisherController, self).__init__(*args, **kwargs) + self._projects_model = ProjectsModel(self) + @property def host(self): return self._host @@ -34,28 +43,14 @@ class TrayPublisherController(QtPublisherController): self._hierarchy_model.reset() self._asset_docs_cache.reset() - -class TrayPublisherRegistry(JSONSettingRegistry): - """Class handling AYON general settings registry. - - Attributes: - vendor (str): Name used for path construction. - product (str): Additional name used for path construction. - - """ - - def __init__(self): - self.vendor = "pypeclub" - self.product = "openpype" - name = "tray_publisher" - path = appdirs.user_data_dir(self.product, self.vendor) - super(TrayPublisherRegistry, self).__init__(name, path) + def get_project_items(self, sender=None): + return self._projects_model.get_project_items(sender) class StandaloneOverlayWidget(QtWidgets.QFrame): project_selected = QtCore.Signal(str) - def __init__(self, publisher_window): + def __init__(self, controller, publisher_window): super(StandaloneOverlayWidget, self).__init__(publisher_window) self.setObjectName("OverlayFrame") @@ -67,7 +62,7 @@ class StandaloneOverlayWidget(QtWidgets.QFrame): header_label = QtWidgets.QLabel("Choose project", content_widget) header_label.setObjectName("ChooseProjectLabel") # Create project models and view - projects_model = ProjectModel() + projects_model = ProjectsQtModel(controller) projects_proxy = ProjectSortFilterProxy() projects_proxy.setSourceModel(projects_model) projects_proxy.setFilterKeyColumn(0) @@ -138,12 +133,11 @@ class StandaloneOverlayWidget(QtWidgets.QFrame): project_name = None if project_name: - index = None - src_index = self._projects_model.find_project(project_name) - if src_index is not None: - index = self._projects_proxy.mapFromSource(src_index) - - if index is not None: + src_index = self._projects_model.get_index_by_project_name( + project_name + ) + index = self._projects_proxy.mapFromSource(src_index) + if index.isValid(): selection_model = self._projects_view.selectionModel() selection_model.select( index, @@ -202,7 +196,7 @@ class TrayPublishWindow(PublisherWindow): self.setWindowFlags(flags) - overlay_widget = StandaloneOverlayWidget(self) + overlay_widget = StandaloneOverlayWidget(controller, self) btns_widget = self._header_extra_widget diff --git a/client/ayon_core/tools/utils/models.py b/client/ayon_core/tools/utils/models.py index e60d85b4e4..a4b6ad7885 100644 --- a/client/ayon_core/tools/utils/models.py +++ b/client/ayon_core/tools/utils/models.py @@ -243,160 +243,3 @@ class RecursiveSortFilterProxyModel(QtCore.QSortFilterProxyModel): return super(RecursiveSortFilterProxyModel, self).filterAcceptsRow( row, parent_index ) - - -# TODO remove 'ProjectModel' and 'ProjectSortFilterProxy' classes -# - replace their usage with current 'ayon_utils' models -class ProjectModel(QtGui.QStandardItemModel): - def __init__( - self, only_active=True, add_default_project=False, *args, **kwargs - ): - super(ProjectModel, self).__init__(*args, **kwargs) - - self._only_active = only_active - self._add_default_project = add_default_project - - self._default_item = None - self._items_by_name = {} - self._refreshed = False - - def set_default_project_available(self, available=True): - if available is None: - available = not self._add_default_project - - if self._add_default_project == available: - return - - self._add_default_project = available - if not available and self._default_item is not None: - root_item = self.invisibleRootItem() - root_item.removeRow(self._default_item.row()) - self._default_item = None - - def set_only_active(self, only_active=True): - if only_active is None: - only_active = not self._only_active - - if self._only_active == only_active: - return - - self._only_active = only_active - - if self._refreshed: - self.refresh() - - def project_name_is_available(self, project_name): - """Check availability of project name in current items.""" - return project_name in self._items_by_name - - def refresh(self): - # Change '_refreshed' state - self._refreshed = True - new_items = [] - # Add default item to model if should - if self._add_default_project and self._default_item is None: - item = QtGui.QStandardItem(DEFAULT_PROJECT_LABEL) - item.setData(None, PROJECT_NAME_ROLE) - item.setData(True, PROJECT_IS_ACTIVE_ROLE) - new_items.append(item) - self._default_item = item - - project_names = set() - project_docs = get_projects( - inactive=not self._only_active, - fields=["name", "data.active"] - ) - for project_doc in project_docs: - project_name = project_doc["name"] - project_names.add(project_name) - if project_name in self._items_by_name: - item = self._items_by_name[project_name] - else: - item = QtGui.QStandardItem(project_name) - - self._items_by_name[project_name] = item - new_items.append(item) - - is_active = project_doc.get("data", {}).get("active", True) - item.setData(project_name, PROJECT_NAME_ROLE) - item.setData(is_active, PROJECT_IS_ACTIVE_ROLE) - - if not is_active: - font = item.font() - font.setItalic(True) - item.setFont(font) - - root_item = self.invisibleRootItem() - for project_name in tuple(self._items_by_name.keys()): - if project_name not in project_names: - item = self._items_by_name.pop(project_name) - root_item.removeRow(item.row()) - - if new_items: - root_item.appendRows(new_items) - - def find_project(self, project_name): - """ - Get index of 'project_name' value. - - Args: - project_name (str): - Returns: - (QModelIndex) - """ - val = self._items_by_name.get(project_name) - if val: - return self.indexFromItem(val) - - -class ProjectSortFilterProxy(QtCore.QSortFilterProxyModel): - def __init__(self, *args, **kwargs): - super(ProjectSortFilterProxy, self).__init__(*args, **kwargs) - self._filter_enabled = True - # Disable case sensitivity - self.setSortCaseSensitivity(QtCore.Qt.CaseInsensitive) - - def lessThan(self, left_index, right_index): - if left_index.data(PROJECT_NAME_ROLE) is None: - return True - - if right_index.data(PROJECT_NAME_ROLE) is None: - return False - - left_is_active = left_index.data(PROJECT_IS_ACTIVE_ROLE) - right_is_active = right_index.data(PROJECT_IS_ACTIVE_ROLE) - if right_is_active == left_is_active: - return super(ProjectSortFilterProxy, self).lessThan( - left_index, right_index - ) - - if left_is_active: - return True - return False - - def filterAcceptsRow(self, source_row, source_parent): - index = self.sourceModel().index(source_row, 0, source_parent) - string_pattern = self.filterRegularExpression().pattern() - if self._filter_enabled: - result = self._custom_index_filter(index) - if result is not None: - project_name = index.data(PROJECT_NAME_ROLE) - if project_name is None: - return result - return string_pattern.lower() in project_name.lower() - - return super(ProjectSortFilterProxy, self).filterAcceptsRow( - source_row, source_parent - ) - - def _custom_index_filter(self, index): - is_active = bool(index.data(PROJECT_IS_ACTIVE_ROLE)) - - return is_active - - def is_filter_enabled(self): - return self._filter_enabled - - def set_filter_enabled(self, value): - self._filter_enabled = value - self.invalidateFilter()