Skip to content

Commit

Permalink
Release v3.0.3 (#173)
Browse files Browse the repository at this point in the history
* LMV translation updates and improve thumbnails (#167)
* Fix Alias startup failure on reading file. (#172) 
* Add tk-framework-lmv requirement (#178)
* Add action to SG panel to import a note attachment (#176)
* Improve error logging from Alias Python API. (#171)
* Add Upload 3D Version note references are not included (#175)
* Add extra validation for translator path and log messaging. (#177)
* Add hook to customize ShotGrid menu. (#174) 
* Open published file using SG Toolkit Action (#179)
* Include Version thumbnail in LMV package for ShotGrid (#181)
* Fix multiple ShotGrid menus showing in Alias after restart (#180)
* Update tk-framework-alias min version (#182)
  • Loading branch information
staceyoue authored Mar 8, 2024
2 parents 26f55fc + 188aec5 commit 1f469bd
Show file tree
Hide file tree
Showing 9 changed files with 370 additions and 185 deletions.
66 changes: 49 additions & 17 deletions engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,11 @@ def data_validator(self):
"""Get the AliasDataValidator object to help validate the Alias data."""
return self.__data_validator

@property
def executable_path(self):
"""Get the path to the currently running Alias executable."""
return self.alias_execpath

# -------------------------------------------------------------------------------------------------------
# Override base Engine class methods
# -------------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -241,7 +246,7 @@ def post_context_change(self, old_context, new_context):
self.logger.debug("%s: Post context change...", self)

# Rebuild the menu only if we change of context and if we're running Alias in interactive mode
if self.has_ui:
if self.has_ui and self.__menu_generator:
self.__menu_generator.build()

def destroy_engine(self):
Expand Down Expand Up @@ -358,14 +363,25 @@ def restart_process(self):
with Alias (e.g. OpenAlias mode).
"""

if self.__menu_generator:
self.__menu_generator.clean_menu()
self.logger.info("Restarting the Alias Engine...")

if self.__sio:
self.__sio.emit_threadsafe("restart")
else:
if not self.__sio:
raise NotImplementedError()

if self.__menu_generator:
status = self.__menu_generator.remove_menu()
if status == self.alias_py.AlStatusCode.Success.value:
self.logger.debug("Removed ShotGrid menu from Alias successfully.")
elif status == self.alias_py.AlStatusCode.Failure.value:
self.logger.error("Failed to remove ShotGrid menu from Alias")
else:
self.logger.warning(
f"Alias Python API menu.remove() returned non-success status code {status}"
)
self.__menu_generator = None

self.__sio.emit_threadsafe("restart")

def shutdown(self):
"""
Shutdown the application running the engine.
Expand All @@ -375,6 +391,8 @@ def shutdown(self):
on the engine itself).
"""

self.logger.info("Shutting down the Alias Engine...")

from sgtk.platform.qt import QtGui

qt_app = QtGui.QApplication.instance() or self.__qt_app
Expand Down Expand Up @@ -474,8 +492,16 @@ def post_qt_init(self):
# Check if there is a file set to open on startup
path = os.environ.get("SGTK_FILE_TO_OPEN", None)
if path:
self.open_file(path)
# clear the env var after loading so that it doesn't get reopened on an engine restart.
if self.__sio:
self.open_file(path)
else:
# Add a timer to delay opening the file for 5 seconds. This is a work around for
# Alias when running SG in the same process (<2024), which is not ready to open
# a file on engine startup. This is not a bullet proof solution, but it should
# work in most cases, and there is not a better alternative to support older
# versions of Alias.
QtCore.QTimer.singleShot(1000 * 5, lambda: self.open_file(path))
# Clear the env var after loading so that it doesn't get reopened on an engine restart.
del os.environ["SGTK_FILE_TO_OPEN"]

def save_context_for_stage(self, context=None):
Expand Down Expand Up @@ -509,9 +535,11 @@ def save_file(self):
"""

status = self.alias_py.save_file()
if status != self.alias_py.AlStatusCode.Success.value:
self.logger.error(
"Alias Python API Error: save_file returned non-success status code {}".format(
if status == self.alias_py.AlStatusCode.Failure.value:
self.logger.error("Alias Python API save_file failed")
elif status != self.alias_py.AlStatusCode.Success.value:
self.logger.warning(
"Alias Python API save_file returned non-success status code {}".format(
status
)
)
Expand All @@ -529,9 +557,11 @@ def save_file_as(self, path):
"""

status = self.alias_py.save_file_as(path)
if status != self.alias_py.AlStatusCode.Success.value:
self.logger.error(
"Alias Python API Error: save_file_as('{}') returned non-success status code {}".format(
if status == self.alias_py.AlStatusCode.Failure.value:
self.logger.error("Alias Python API save_file_as failed")
elif status != self.alias_py.AlStatusCode.Success.value:
self.logger.warning(
"Alias Python API save_file_as('{}') returned non-success status code {}".format(
path, status
)
)
Expand All @@ -549,9 +579,11 @@ def open_file(self, path):
"""

status = self.alias_py.open_file(path)
if status != self.alias_py.AlStatusCode.Success.value:
self.logger.error(
"Alias Python API Error: open_file('{}') returned non-success status code {}".format(
if status == self.alias_py.AlStatusCode.Failure.value:
self.logger.error("Alias Python API open_file failed")
elif status != self.alias_py.AlStatusCode.Success.value:
self.logger.warning(
"Alias Python API open_file('{}') returned non-success status code {}".format(
path, status
)
)
Expand Down
56 changes: 56 additions & 0 deletions hooks/menu_customization.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Copyright (c) 2023 Autodesk
#
# CONFIDENTIAL AND PROPRIETARY
#
# This work is provided "AS IS" and subject to the ShotGrid Pipeline Toolkit
# Source Code License included in this distribution package. See LICENSE.
# By accessing, using, copying or modifying this work you indicate your
# agreement to the ShotGrid Pipeline Toolkit Source Code License. All rights
# not expressly granted therein are reserved by Autodesk.

import sgtk

HookBaseClass = sgtk.get_hook_baseclass()


class MenuCustomization(HookBaseClass):
"""Hook to allow customizing the ShotGrid menu in Alias."""

def sorted_menu_commands(self, commands):
"""
Return the given commands as a list in the order they should be displayed in the menu.
The menu will display the commands in the order they are returned by this method. the
default implementation will sort the commands alphabetically by command's app name,
then the command name itself.
The engine commands should be retrieved from the engine `commands` property. Apply
any custom ordering to these commands.
The commands are returned as a list of tuples, where the first item corresponds to the
command dict entry key, and the second item is the command dict entry value.
:param commands: The commands to add to the menu.
:type commands: dict
:return: The list of commands in order they should be displayed in.
:rtype: List[tuple[str, dict]]
"""

# To display menu commands in the order that they are defined in the config settings,
# uncomment the line below. Note that this requirest Python >= 3.7 because it relies
# on the dictionary preserve their order of insertion.
# return list(commands.items())

# Sort by the command app name (if not a context menu command), then the command name.
return sorted(
commands.items(),
key=lambda command: (
command[1]["properties"]["app"].display_name
if command[1].get("properties", {}).get("app")
and command[1].get("properties", {}).get("type", "default")
!= "context_menu"
else "Other Items",
command[0],
),
)
45 changes: 43 additions & 2 deletions hooks/tk-multi-publish2/basic/collector.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@
# not expressly granted therein are reserved by Shotgun Software Inc.

import os
import tempfile

import sgtk
import alias_api
from sgtk.platform.qt import QtGui


HookBaseClass = sgtk.get_hook_baseclass()

Expand Down Expand Up @@ -46,6 +48,11 @@ def settings(self):

return collector_settings

@property
def alias_py(self):
"""Get the Alias api module."""
return self.parent.engine.alias_py

def process_current_session(self, settings, parent_item):
"""
Analyzes the current scene open in a DCC and parents a subtree of items
Expand All @@ -62,7 +69,7 @@ def process_current_session(self, settings, parent_item):
parent_item.properties["bg_processing"] = bg_processing.value

# get the path to the current file
path = alias_api.get_current_path()
path = self.alias_py.get_current_path()

# determine the display name for the item
if path:
Expand All @@ -80,6 +87,9 @@ def process_current_session(self, settings, parent_item):
icon_path = os.path.join(self.disk_location, os.pardir, "icons", "alias.png")
session_item.set_icon_from_path(icon_path)

# set the default thumbnail to the current Alias viewport
session_item.thumbnail = self._get_thumbnail_pixmap()

# add a new item for Alias translations to separate them from the main session item
translation_item = session_item.create_item(
"alias.session.translation", "Alias Translations", "All Alias Translations"
Expand Down Expand Up @@ -111,3 +121,34 @@ def process_current_session(self, settings, parent_item):
vred_item.set_icon_from_path(icon_path)

self.logger.info("Collected current Alias file")

def _get_thumbnail_pixmap(self):
"""
Generate a thumbnail from the current Alias viewport.
:return: A thumbnail of the current Alias viewport.
:rtype: QtGui.QPixmap
"""

pixmap = None
thumbnail_path = None

try:
thumbnail_path = tempfile.NamedTemporaryFile(
suffix=".jpg", prefix="sgtk_thumb", delete=False
).name
status = self.alias_py.store_current_window(thumbnail_path)
if not self.alias_py.py_utils.is_success(status):
self.logger.warning(
f"Alias API store_current_window returned non-success status code '{status}'"
)
pixmap = QtGui.QPixmap(thumbnail_path)
except Exception as e:
self.logger.error(f"Failed to set default thumbnail: {e}")
finally:
try:
os.remove(thumbnail_path)
except:
pass

return pixmap
13 changes: 11 additions & 2 deletions hooks/tk-multi-publish2/basic/publish_translation.py
Original file line number Diff line number Diff line change
Expand Up @@ -269,12 +269,21 @@ def validate(self, settings, item):

# if we don't have translator settings, we can't publish
if not translator.translation_type:
self.logger.warning("Couldn't find the translation type.")
self.logger.warning(
f"Couldn't find the translation type {translator.translator_type}."
)
return False

if not translator.translator_path:
self.logger.warning("Couldn't find translator path.")
self.logger.warning(f"Couldn't determine which translator to use.")
return False

if not os.path.exists(translator.translator_path):
self.logger.warning(
f"Translator path does not exist {translator.translator_path}."
)
return False
self.logger.info(f"Translator in use: {translator.translator_path}.")

# store the licensing information in the item properties so that the translation could be run in
# background mode
Expand Down
Loading

0 comments on commit 1f469bd

Please sign in to comment.