mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 21:04:40 +01:00
Merge pull request #2536 from pypeclub/feature/OP-1117_Disable-workfile-autoload-in-Launcher
Launcher: Added context menu to to skip opening last workfile
This commit is contained in:
commit
ad0abfbdd0
9 changed files with 192 additions and 10 deletions
|
|
@ -6,6 +6,8 @@ class AddLastWorkfileToLaunchArgs(PreLaunchHook):
|
|||
"""Add last workfile path to launch arguments.
|
||||
|
||||
This is not possible to do for all applications the same way.
|
||||
Checks 'start_last_workfile', if set to False, it will not open last
|
||||
workfile. This property is set explicitly in Launcher.
|
||||
"""
|
||||
|
||||
# Execute after workfile template copy
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ class GlobalHostDataHook(PreLaunchHook):
|
|||
|
||||
"env": self.launch_context.env,
|
||||
|
||||
"start_last_workfile": self.data.get("start_last_workfile"),
|
||||
"last_workfile_path": self.data.get("last_workfile_path"),
|
||||
|
||||
"log": self.log
|
||||
|
|
|
|||
|
|
@ -40,7 +40,10 @@ class NonPythonHostHook(PreLaunchHook):
|
|||
)
|
||||
# Add workfile path if exists
|
||||
workfile_path = self.data["last_workfile_path"]
|
||||
if os.path.exists(workfile_path):
|
||||
if (
|
||||
self.data.get("start_last_workfile")
|
||||
and workfile_path
|
||||
and os.path.exists(workfile_path)):
|
||||
new_launch_args.append(workfile_path)
|
||||
|
||||
# Append as whole list as these areguments should not be separated
|
||||
|
|
|
|||
|
|
@ -1490,6 +1490,7 @@ def _prepare_last_workfile(data, workdir):
|
|||
import avalon.api
|
||||
|
||||
log = data["log"]
|
||||
|
||||
_workdir_data = data.get("workdir_data")
|
||||
if not _workdir_data:
|
||||
log.info(
|
||||
|
|
@ -1503,9 +1504,15 @@ def _prepare_last_workfile(data, workdir):
|
|||
project_name = data["project_name"]
|
||||
task_name = data["task_name"]
|
||||
task_type = data["task_type"]
|
||||
start_last_workfile = should_start_last_workfile(
|
||||
project_name, app.host_name, task_name, task_type
|
||||
)
|
||||
|
||||
start_last_workfile = data.get("start_last_workfile")
|
||||
if start_last_workfile is None:
|
||||
start_last_workfile = should_start_last_workfile(
|
||||
project_name, app.host_name, task_name, task_type
|
||||
)
|
||||
else:
|
||||
log.info("Opening of last workfile was disabled by user")
|
||||
|
||||
data["start_last_workfile"] = start_last_workfile
|
||||
|
||||
workfile_startup = should_workfile_tool_start(
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ class ApplicationAction(api.Action):
|
|||
icon = None
|
||||
color = None
|
||||
order = 0
|
||||
data = {}
|
||||
|
||||
_log = None
|
||||
required_session_keys = (
|
||||
|
|
@ -103,7 +104,8 @@ class ApplicationAction(api.Action):
|
|||
self.application.launch(
|
||||
project_name=project_name,
|
||||
asset_name=asset_name,
|
||||
task_name=task_name
|
||||
task_name=task_name,
|
||||
**self.data
|
||||
)
|
||||
|
||||
except ApplictionExecutableNotFound as exc:
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ VARIANT_GROUP_ROLE = QtCore.Qt.UserRole + 2
|
|||
ACTION_ID_ROLE = QtCore.Qt.UserRole + 3
|
||||
ANIMATION_START_ROLE = QtCore.Qt.UserRole + 4
|
||||
ANIMATION_STATE_ROLE = QtCore.Qt.UserRole + 5
|
||||
FORCE_NOT_OPEN_WORKFILE_ROLE = QtCore.Qt.UserRole + 6
|
||||
ACTION_TOOLTIP_ROLE = QtCore.Qt.UserRole + 7
|
||||
|
||||
# Animation length in seconds
|
||||
ANIMATION_LEN = 7
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@ import time
|
|||
from Qt import QtCore, QtWidgets, QtGui
|
||||
from .constants import (
|
||||
ANIMATION_START_ROLE,
|
||||
ANIMATION_STATE_ROLE
|
||||
ANIMATION_STATE_ROLE,
|
||||
FORCE_NOT_OPEN_WORKFILE_ROLE
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -69,6 +70,16 @@ class ActionDelegate(QtWidgets.QStyledItemDelegate):
|
|||
self._draw_animation(painter, option, index)
|
||||
|
||||
super(ActionDelegate, self).paint(painter, option, index)
|
||||
|
||||
if index.data(FORCE_NOT_OPEN_WORKFILE_ROLE):
|
||||
rect = QtCore.QRectF(option.rect.x(), option.rect.height(),
|
||||
5, 5)
|
||||
painter.setPen(QtCore.Qt.transparent)
|
||||
painter.setBrush(QtGui.QColor(200, 0, 0))
|
||||
painter.drawEllipse(rect)
|
||||
|
||||
painter.setBrush(self.extender_bg_brush)
|
||||
|
||||
is_group = False
|
||||
for group_role in self.group_roles:
|
||||
is_group = index.data(group_role)
|
||||
|
|
|
|||
|
|
@ -2,19 +2,21 @@ import uuid
|
|||
import copy
|
||||
import logging
|
||||
import collections
|
||||
import appdirs
|
||||
|
||||
from . import lib
|
||||
from .constants import (
|
||||
ACTION_ROLE,
|
||||
GROUP_ROLE,
|
||||
VARIANT_GROUP_ROLE,
|
||||
ACTION_ID_ROLE
|
||||
ACTION_ID_ROLE,
|
||||
FORCE_NOT_OPEN_WORKFILE_ROLE
|
||||
)
|
||||
from .actions import ApplicationAction
|
||||
from Qt import QtCore, QtGui
|
||||
from avalon.vendor import qtawesome
|
||||
from avalon import style, api
|
||||
from openpype.lib import ApplicationManager
|
||||
from openpype.lib import ApplicationManager, JSONSettingRegistry
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -30,6 +32,13 @@ class ActionModel(QtGui.QStandardItemModel):
|
|||
# Cache of available actions
|
||||
self._registered_actions = list()
|
||||
self.items_by_id = {}
|
||||
path = appdirs.user_data_dir("openpype", "pypeclub")
|
||||
self.launcher_registry = JSONSettingRegistry("launcher", path)
|
||||
|
||||
try:
|
||||
_ = self.launcher_registry.get_item("force_not_open_workfile")
|
||||
except ValueError:
|
||||
self.launcher_registry.set_item("force_not_open_workfile", [])
|
||||
|
||||
def discover(self):
|
||||
"""Set up Actions cache. Run this for each new project."""
|
||||
|
|
@ -75,7 +84,8 @@ class ActionModel(QtGui.QStandardItemModel):
|
|||
"group": None,
|
||||
"icon": app.icon,
|
||||
"color": getattr(app, "color", None),
|
||||
"order": getattr(app, "order", None) or 0
|
||||
"order": getattr(app, "order", None) or 0,
|
||||
"data": {}
|
||||
}
|
||||
)
|
||||
|
||||
|
|
@ -179,11 +189,17 @@ class ActionModel(QtGui.QStandardItemModel):
|
|||
|
||||
self.beginResetModel()
|
||||
|
||||
stored = self.launcher_registry.get_item("force_not_open_workfile")
|
||||
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)
|
||||
|
||||
if self.is_force_not_open_workfile(item,
|
||||
stored):
|
||||
self.change_action_item(item, True)
|
||||
|
||||
self.items_by_id[item_id] = item
|
||||
items.append(item)
|
||||
|
||||
|
|
@ -222,6 +238,90 @@ class ActionModel(QtGui.QStandardItemModel):
|
|||
key=lambda action: (action.order, action.name)
|
||||
)
|
||||
|
||||
def update_force_not_open_workfile_settings(self, is_checked, action_id):
|
||||
"""Store/remove config for forcing to skip opening last workfile.
|
||||
|
||||
Args:
|
||||
is_checked (bool): True to add, False to remove
|
||||
action_id (str)
|
||||
"""
|
||||
action_item = self.items_by_id.get(action_id)
|
||||
if not action_item:
|
||||
return
|
||||
|
||||
action = action_item.data(ACTION_ROLE)
|
||||
actual_data = self._prepare_compare_data(action)
|
||||
|
||||
stored = self.launcher_registry.get_item("force_not_open_workfile")
|
||||
if is_checked:
|
||||
stored.append(actual_data)
|
||||
else:
|
||||
final_values = []
|
||||
for config in stored:
|
||||
if config != actual_data:
|
||||
final_values.append(config)
|
||||
stored = final_values
|
||||
|
||||
self.launcher_registry.set_item("force_not_open_workfile", stored)
|
||||
self.launcher_registry._get_item.cache_clear()
|
||||
self.change_action_item(action_item, is_checked)
|
||||
|
||||
def change_action_item(self, item, checked):
|
||||
"""Modifies tooltip and sets if opening of last workfile forbidden"""
|
||||
tooltip = item.data(QtCore.Qt.ToolTipRole)
|
||||
if checked:
|
||||
tooltip += " (Not opening last workfile)"
|
||||
|
||||
item.setData(tooltip, QtCore.Qt.ToolTipRole)
|
||||
item.setData(checked, FORCE_NOT_OPEN_WORKFILE_ROLE)
|
||||
|
||||
def is_application_action(self, action):
|
||||
"""Checks if item is of a ApplicationAction type
|
||||
|
||||
Args:
|
||||
action (action)
|
||||
"""
|
||||
if isinstance(action, list) and action:
|
||||
action = action[0]
|
||||
|
||||
return ApplicationAction in action.__bases__
|
||||
|
||||
def is_force_not_open_workfile(self, item, stored):
|
||||
"""Checks if application for task is marked to not open workfile
|
||||
|
||||
There might be specific tasks where is unwanted to open workfile right
|
||||
always (broken file, low performance). This allows artist to mark to
|
||||
skip opening for combination (project, asset, task_name, app)
|
||||
|
||||
Args:
|
||||
item (QStandardItem)
|
||||
stored (list) of dict
|
||||
"""
|
||||
action = item.data(ACTION_ROLE)
|
||||
if not self.is_application_action(action):
|
||||
return False
|
||||
|
||||
actual_data = self._prepare_compare_data(action)
|
||||
for config in stored:
|
||||
if config == actual_data:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def _prepare_compare_data(self, action):
|
||||
if isinstance(action, list) and action:
|
||||
action = action[0]
|
||||
|
||||
compare_data = {}
|
||||
if action:
|
||||
compare_data = {
|
||||
"app_label": action.label.lower(),
|
||||
"project_name": self.dbcon.Session["AVALON_PROJECT"],
|
||||
"asset": self.dbcon.Session["AVALON_ASSET"],
|
||||
"task_name": self.dbcon.Session["AVALON_TASK"]
|
||||
}
|
||||
return compare_data
|
||||
|
||||
|
||||
class ProjectModel(QtGui.QStandardItemModel):
|
||||
"""List of projects"""
|
||||
|
|
|
|||
|
|
@ -15,7 +15,8 @@ from .constants import (
|
|||
ACTION_ID_ROLE,
|
||||
ANIMATION_START_ROLE,
|
||||
ANIMATION_STATE_ROLE,
|
||||
ANIMATION_LEN
|
||||
ANIMATION_LEN,
|
||||
FORCE_NOT_OPEN_WORKFILE_ROLE
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -96,6 +97,7 @@ class ActionBar(QtWidgets.QWidget):
|
|||
view.setViewMode(QtWidgets.QListView.IconMode)
|
||||
view.setResizeMode(QtWidgets.QListView.Adjust)
|
||||
view.setSelectionMode(QtWidgets.QListView.NoSelection)
|
||||
view.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
|
||||
view.setEditTriggers(QtWidgets.QListView.NoEditTriggers)
|
||||
view.setWrapping(True)
|
||||
view.setGridSize(QtCore.QSize(70, 75))
|
||||
|
|
@ -135,8 +137,16 @@ class ActionBar(QtWidgets.QWidget):
|
|||
|
||||
project_handler.projects_refreshed.connect(self._on_projects_refresh)
|
||||
view.clicked.connect(self.on_clicked)
|
||||
view.customContextMenuRequested.connect(self.on_context_menu)
|
||||
|
||||
self._context_menu = None
|
||||
self._discover_on_menu = False
|
||||
|
||||
def discover_actions(self):
|
||||
if self._context_menu is not None:
|
||||
self._discover_on_menu = True
|
||||
return
|
||||
|
||||
if self._animation_timer.isActive():
|
||||
self._animation_timer.stop()
|
||||
self.model.discover()
|
||||
|
|
@ -181,6 +191,46 @@ class ActionBar(QtWidgets.QWidget):
|
|||
self._animated_items.add(action_id)
|
||||
self._animation_timer.start()
|
||||
|
||||
def on_context_menu(self, point):
|
||||
"""Creates menu to force skip opening last workfile."""
|
||||
index = self.view.indexAt(point)
|
||||
if not index.isValid():
|
||||
return
|
||||
|
||||
action_item = index.data(ACTION_ROLE)
|
||||
if not self.model.is_application_action(action_item):
|
||||
return
|
||||
|
||||
menu = QtWidgets.QMenu(self.view)
|
||||
checkbox = QtWidgets.QCheckBox("Skip opening last workfile.",
|
||||
menu)
|
||||
if index.data(FORCE_NOT_OPEN_WORKFILE_ROLE):
|
||||
checkbox.setChecked(True)
|
||||
|
||||
action_id = index.data(ACTION_ID_ROLE)
|
||||
checkbox.stateChanged.connect(
|
||||
lambda: self.on_checkbox_changed(checkbox.isChecked(),
|
||||
action_id))
|
||||
action = QtWidgets.QWidgetAction(menu)
|
||||
action.setDefaultWidget(checkbox)
|
||||
|
||||
menu.addAction(action)
|
||||
|
||||
self._context_menu = menu
|
||||
global_point = self.mapToGlobal(point)
|
||||
menu.exec_(global_point)
|
||||
self._context_menu = None
|
||||
if self._discover_on_menu:
|
||||
self._discover_on_menu = False
|
||||
self.discover_actions()
|
||||
|
||||
def on_checkbox_changed(self, is_checked, action_id):
|
||||
self.model.update_force_not_open_workfile_settings(is_checked,
|
||||
action_id)
|
||||
self.view.update()
|
||||
if self._context_menu is not None:
|
||||
self._context_menu.close()
|
||||
|
||||
def on_clicked(self, index):
|
||||
if not index or not index.isValid():
|
||||
return
|
||||
|
|
@ -189,6 +239,10 @@ class ActionBar(QtWidgets.QWidget):
|
|||
is_variant_group = index.data(VARIANT_GROUP_ROLE)
|
||||
if not is_group and not is_variant_group:
|
||||
action = index.data(ACTION_ROLE)
|
||||
if index.data(FORCE_NOT_OPEN_WORKFILE_ROLE):
|
||||
action.data["start_last_workfile"] = False
|
||||
else:
|
||||
action.data.pop("start_last_workfile", None)
|
||||
self._start_animation(index)
|
||||
self.action_clicked.emit(action)
|
||||
return
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue