Skip to content
This repository has been archived by the owner on Sep 20, 2024. It is now read-only.

Launcher: Fix crashes on action click #1964

Merged
merged 8 commits into from
Aug 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions openpype/tools/launcher/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@
ANIMATION_START_ROLE = QtCore.Qt.UserRole + 4
ANIMATION_STATE_ROLE = QtCore.Qt.UserRole + 5


ANIMATION_LEN = 10
# Animation length in seconds
ANIMATION_LEN = 7
26 changes: 26 additions & 0 deletions openpype/tools/launcher/lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,41 @@ class ProjectHandler(QtCore.QObject):

# Signal emmited when project has changed
project_changed = QtCore.Signal(str)
projects_refreshed = QtCore.Signal()
timer_timeout = QtCore.Signal()

def __init__(self, dbcon, model):
super(ProjectHandler, self).__init__()
self._active = False
# Store project model for usage
self.model = model
# Store dbcon
self.dbcon = dbcon

self.current_project = dbcon.Session.get("AVALON_PROJECT")

refresh_timer = QtCore.QTimer()
refresh_timer.setInterval(self.refresh_interval)
refresh_timer.timeout.connect(self._on_timeout)

self.refresh_timer = refresh_timer

def _on_timeout(self):
if self._active:
self.timer_timeout.emit()
self.refresh_model()

def set_active(self, active):
self._active = active

def start_timer(self, trigger=False):
self.refresh_timer.start()
if trigger:
self._on_timeout()

def stop_timer(self):
self.refresh_timer.stop()

def set_project(self, project_name):
# Change current project of this handler
self.current_project = project_name
Expand All @@ -66,6 +91,7 @@ def set_project(self, project_name):

def refresh_model(self):
self.model.refresh()
self.projects_refreshed.emit()


def get_action_icon(action):
Expand Down
22 changes: 13 additions & 9 deletions openpype/tools/launcher/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,6 @@ def __init__(self, dbcon, parent=None):

self.application_manager = ApplicationManager()

self._groups = {}
self.default_icon = qtawesome.icon("fa.cube", color="white")
# Cache of available actions
self._registered_actions = list()
Expand All @@ -138,14 +137,18 @@ def discover(self):
actions.extend(app_actions)

self._registered_actions = actions
self.items_by_id.clear()

self.filter_actions()

def get_application_actions(self):
actions = []
if not self.dbcon.Session.get("AVALON_PROJECT"):
return actions

project_doc = self.dbcon.find_one({"type": "project"})
project_doc = self.dbcon.find_one(
{"type": "project"},
{"config.apps": True}
)
if not project_doc:
return actions

Expand Down Expand Up @@ -182,16 +185,12 @@ def get_icon(self, action, skip_default=False):
return icon

def filter_actions(self):
self.items_by_id.clear()
# Validate actions based on compatibility
self.clear()

self.items_by_id.clear()
self._groups.clear()

actions = self.filter_compatible_actions(self._registered_actions)

self.beginResetModel()

single_actions = []
varianted_actions = collections.defaultdict(list)
grouped_actions = collections.defaultdict(list)
Expand Down Expand Up @@ -274,12 +273,17 @@ def filter_actions(self):

items_by_order[order].append(item)

self.beginResetModel()

items = []
for order in sorted(items_by_order.keys()):
for item in items_by_order[order]:
item_id = str(uuid.uuid4())
item.setData(item_id, ACTION_ID_ROLE)
self.items_by_id[item_id] = item
self.appendRow(item)
items.append(item)

self.invisibleRootItem().appendRows(items)

self.endResetModel()

Expand Down
35 changes: 15 additions & 20 deletions openpype/tools/launcher/widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,11 @@ def __init__(self, project_handler, parent=None):
QtWidgets.QSizePolicy.Maximum
)

refresh_timer = QtCore.QTimer()
refresh_timer.setInterval(project_handler.refresh_interval)

self.project_handler = project_handler
self.project_delegate = project_delegate
self.project_combobox = project_combobox
self.refresh_timer = refresh_timer

# Signals
refresh_timer.timeout.connect(self._on_refresh_timeout)
self.project_combobox.currentIndexChanged.connect(self.on_index_change)
project_handler.project_changed.connect(self._on_project_change)

Expand All @@ -58,20 +53,6 @@ def __init__(self, project_handler, 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.project_handler.refresh_model()

def _on_project_change(self, project_name):
if self.get_current_project() == project_name:
return
Expand Down Expand Up @@ -103,9 +84,10 @@ class ActionBar(QtWidgets.QWidget):

action_clicked = QtCore.Signal(object)

def __init__(self, dbcon, parent=None):
def __init__(self, project_handler, dbcon, parent=None):
super(ActionBar, self).__init__(parent)

self.project_handler = project_handler
self.dbcon = dbcon

layout = QtWidgets.QHBoxLayout(self)
Expand Down Expand Up @@ -152,17 +134,25 @@ def __init__(self, dbcon, parent=None):

self.set_row_height(1)

project_handler.projects_refreshed.connect(self._on_projects_refresh)
view.clicked.connect(self.on_clicked)

def discover_actions(self):
if self._animation_timer.isActive():
self._animation_timer.stop()
self.model.discover()

def filter_actions(self):
if self._animation_timer.isActive():
self._animation_timer.stop()
self.model.filter_actions()

def set_row_height(self, rows):
self.setMinimumHeight(rows * 75)

def _on_projects_refresh(self):
self.discover_actions()

def _on_animation(self):
time_now = time.time()
for action_id in tuple(self._animated_items):
Expand All @@ -182,6 +172,8 @@ def _on_animation(self):
self.update()

def _start_animation(self, index):
# Offset refresh timout
self.project_handler.start_timer()
action_id = index.data(ACTION_ID_ROLE)
item = self.model.items_by_id.get(action_id)
if item:
Expand All @@ -202,6 +194,9 @@ def on_clicked(self, index):
self.action_clicked.emit(action)
return

# Offset refresh timout
self.project_handler.start_timer()

actions = index.data(ACTION_ROLE)

menu = QtWidgets.QMenu(self)
Expand Down
55 changes: 14 additions & 41 deletions openpype/tools/launcher/window.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,36 +103,16 @@ def __init__(self, project_handler, parent=None):

layout.addWidget(view)

refresh_timer = QtCore.QTimer()
refresh_timer.setInterval(project_handler.refresh_interval)

refresh_timer.timeout.connect(self._on_refresh_timeout)
view.clicked.connect(self.on_clicked)

self.view = view
self.refresh_timer = refresh_timer
self.project_handler = project_handler

def on_clicked(self, index):
if index.isValid():
project_name = index.data(QtCore.Qt.DisplayRole)
self.project_handler.set_project(project_name)

def showEvent(self, event):
self.project_handler.refresh_model()
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.project_handler.refresh_model()


class AssetsPanel(QtWidgets.QWidget):
"""Assets page"""
Expand Down Expand Up @@ -268,8 +248,6 @@ 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)
Expand Down Expand Up @@ -304,7 +282,7 @@ def __init__(self, parent=None):
page_slider.addWidget(asset_panel)

# actions
actions_bar = ActionBar(self.dbcon, self)
actions_bar = ActionBar(project_handler, self.dbcon, self)

# statusbar
statusbar = QtWidgets.QWidget()
Expand Down Expand Up @@ -342,10 +320,6 @@ 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.project_handler = project_handler

self.message_label = message_label
Expand All @@ -357,22 +331,31 @@ 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_handler.project_changed.connect(self.on_project_change)
project_handler.timer_timeout.connect(self._on_refresh_timeout)
asset_panel.back_clicked.connect(self.on_back_clicked)
asset_panel.session_changed.connect(self.on_session_changed)

self.resize(520, 740)

def showEvent(self, event):
if not self.actions_refresh_timer.isActive():
self.actions_refresh_timer.start()
self.discover_actions()
self.project_handler.set_active(True)
self.project_handler.start_timer(True)

super(LauncherWindow, self).showEvent(event)

def _on_refresh_timeout(self):
# Stop timer if widget is not visible
if not self.isVisible():
self.project_handler.stop_timer()

def changeEvent(self, event):
if event.type() == QtCore.QEvent.ActivationChange:
self.project_handler.set_active(self.isActiveWindow())
super(LauncherWindow, self).changeEvent(event)

def set_page(self, page):
current = self.page_slider.currentIndex()
if current == page and self._page == page:
Expand All @@ -392,20 +375,10 @@ def on_session_changed(self):

def discover_actions(self):
self.actions_bar.discover_actions()
self.filter_actions()

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_change(self, project_name):
# Update the Action plug-ins available for the current project
self.set_page(1)
Expand Down