diff --git a/openpype/tools/launcher/models.py b/openpype/tools/launcher/models.py index 25b6dcdbf03..846a07e081e 100644 --- a/openpype/tools/launcher/models.py +++ b/openpype/tools/launcher/models.py @@ -325,19 +325,59 @@ def __init__(self, dbcon, parent=None): self.hide_invisible = False self.project_icon = qtawesome.icon("fa.map", color="white") + self._project_names = set() def refresh(self): - self.clear() - self.beginResetModel() - + project_names = set() for project_doc in self.get_projects(): - item = QtGui.QStandardItem(self.project_icon, project_doc["name"]) - self.appendRow(item) + project_names.add(project_doc["name"]) + + origin_project_names = set(self._project_names) + self._project_names = project_names + + project_names_to_remove = origin_project_names - project_names + if project_names_to_remove: + row_counts = {} + continuous = None + for row in range(self.rowCount()): + index = self.index(row, 0) + index_name = index.data(QtCore.Qt.DisplayRole) + if index_name in project_names_to_remove: + if continuous is None: + continuous = row + row_counts[continuous] = 0 + row_counts[continuous] += 1 + else: + continuous = None + + for row in reversed(sorted(row_counts.keys())): + count = row_counts[row] + self.removeRows(row, count) + + continuous = None + row_counts = {} + for idx, project_name in enumerate(sorted(project_names)): + if project_name in origin_project_names: + continuous = None + continue - self.endResetModel() + if continuous is None: + continuous = idx + row_counts[continuous] = [] + + row_counts[continuous].append(project_name) + + for row in reversed(sorted(row_counts.keys())): + items = [] + for project_name in row_counts[row]: + item = QtGui.QStandardItem(self.project_icon, project_name) + items.append(item) + + self.invisibleRootItem().insertRows(row, items) def get_projects(self): project_docs = [] + for project_doc in sorted( self.dbcon.projects(), key=lambda x: x["name"] ): diff --git a/openpype/tools/launcher/widgets.py b/openpype/tools/launcher/widgets.py index 22b08d7d153..0e8caeb278a 100644 --- a/openpype/tools/launcher/widgets.py +++ b/openpype/tools/launcher/widgets.py @@ -22,6 +22,9 @@ class ProjectBar(QtWidgets.QWidget): project_changed = QtCore.Signal(int) + # Project list will be refreshed each 10000 msecs + refresh_interval = 10000 + def __init__(self, dbcon, parent=None): super(ProjectBar, self).__init__(parent) @@ -47,14 +50,16 @@ def __init__(self, dbcon, parent=None): QtWidgets.QSizePolicy.Maximum ) + refresh_timer = QtCore.QTimer() + refresh_timer.setInterval(self.refresh_interval) + self.model = model self.project_delegate = project_delegate self.project_combobox = project_combobox - - # Initialize - self.refresh() + self.refresh_timer = refresh_timer # Signals + refresh_timer.timeout.connect(self._on_refresh_timeout) self.project_combobox.currentIndexChanged.connect(self.project_changed) # Set current project by default if it's set. @@ -62,6 +67,20 @@ def __init__(self, dbcon, parent=None): if project_name: self.set_project(project_name) + def showEvent(self, event): + if not self.refresh_timer.isActive(): + self.refresh_timer.start() + super(ProjectBar, self).showEvent(event) + + def _on_refresh_timeout(self): + if not self.isVisible(): + # Stop timer if widget is not visible + self.refresh_timer.stop() + + elif self.isActiveWindow(): + # Refresh projects if window is active + self.model.refresh() + def get_current_project(self): return self.project_combobox.currentText() @@ -69,27 +88,14 @@ def set_project(self, project_name): index = self.project_combobox.findText(project_name) if index < 0: # Try refresh combobox model - self.project_combobox.blockSignals(True) - self.model.refresh() - self.project_combobox.blockSignals(False) - + self.refresh() index = self.project_combobox.findText(project_name) if index >= 0: self.project_combobox.setCurrentIndex(index) def refresh(self): - prev_project_name = self.get_current_project() - - # Refresh without signals - self.project_combobox.blockSignals(True) - self.model.refresh() - self.set_project(prev_project_name) - - self.project_combobox.blockSignals(False) - - self.project_changed.emit(self.project_combobox.currentIndex()) class ActionBar(QtWidgets.QWidget): diff --git a/openpype/tools/launcher/window.py b/openpype/tools/launcher/window.py index af749814b76..a6d34bbe9da 100644 --- a/openpype/tools/launcher/window.py +++ b/openpype/tools/launcher/window.py @@ -91,6 +91,8 @@ class ProjectsPanel(QtWidgets.QWidget): """Projects Page""" project_clicked = QtCore.Signal(str) + # Refresh projects each 10000 msecs + refresh_interval = 10000 def __init__(self, dbcon, parent=None): super(ProjectsPanel, self).__init__(parent=parent) @@ -106,21 +108,40 @@ def __init__(self, dbcon, parent=None): flick.activateOn(view) model = ProjectModel(self.dbcon) model.hide_invisible = True - model.refresh() view.setModel(model) layout.addWidget(view) + refresh_timer = QtCore.QTimer() + refresh_timer.setInterval(self.refresh_interval) + + refresh_timer.timeout.connect(self._on_refresh_timeout) view.clicked.connect(self.on_clicked) self.model = model self.view = view + self.refresh_timer = refresh_timer def on_clicked(self, index): if index.isValid(): project_name = index.data(QtCore.Qt.DisplayRole) self.project_clicked.emit(project_name) + def showEvent(self, event): + self.model.refresh() + if not self.refresh_timer.isActive(): + self.refresh_timer.start() + super(ProjectsPanel, self).showEvent(event) + + def _on_refresh_timeout(self): + if not self.isVisible(): + # Stop timer if widget is not visible + self.refresh_timer.stop() + + elif self.isActiveWindow(): + # Refresh projects if window is active + self.model.refresh() + class AssetsPanel(QtWidgets.QWidget): """Assets page""" @@ -276,6 +297,8 @@ def on_task_change(self): class LauncherWindow(QtWidgets.QDialog): """Launcher interface""" + # Refresh actions each 10000msecs + actions_refresh_timeout = 10000 def __init__(self, parent=None): super(LauncherWindow, self).__init__(parent) @@ -344,6 +367,10 @@ def __init__(self, parent=None): layout.setSpacing(0) layout.setContentsMargins(0, 0, 0, 0) + actions_refresh_timer = QtCore.QTimer() + actions_refresh_timer.setInterval(self.actions_refresh_timeout) + + self.actions_refresh_timer = actions_refresh_timer self.message_label = message_label self.project_panel = project_panel self.asset_panel = asset_panel @@ -353,6 +380,7 @@ def __init__(self, parent=None): self._page = 0 # signals + actions_refresh_timer.timeout.connect(self._on_action_timer) actions_bar.action_clicked.connect(self.on_action_clicked) action_history.trigger_history.connect(self.on_history_action) project_panel.project_clicked.connect(self.on_project_clicked) @@ -367,9 +395,11 @@ def __init__(self, parent=None): self.resize(520, 740) def showEvent(self, event): - super().showEvent(event) - # TODO implement refresh/reset which will trigger updating - self.discover_actions() + if not self.actions_refresh_timer.isActive(): + self.actions_refresh_timer.start() + self.discover_actions() + + super(LauncherWindow, self).showEvent(event) def set_page(self, page): current = self.page_slider.currentIndex() @@ -402,6 +432,15 @@ def discover_actions(self): def filter_actions(self): self.actions_bar.filter_actions() + def _on_action_timer(self): + if not self.isVisible(): + # Stop timer if widget is not visible + self.actions_refresh_timer.stop() + + elif self.isActiveWindow(): + # Refresh projects if window is active + self.discover_actions() + def on_project_clicked(self, project_name): self.dbcon.Session["AVALON_PROJECT"] = project_name # Refresh projects @@ -412,7 +451,6 @@ def on_project_clicked(self, project_name): def on_back_clicked(self): self.dbcon.Session["AVALON_PROJECT"] = None self.set_page(0) - self.project_panel.model.refresh() # Refresh projects self.discover_actions() def on_action_clicked(self, action):