mirror of
https://github.com/ynput/ayon-core.git
synced 2026-01-01 16:34:53 +01:00
General: Navigation to Folder from Launcher (#5404)
* Basic implementation of navigation to folder from launcher * Allow the action to appear without a task selected * Added multiplatform support * Improved code to open file browser in different platforms Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> * Fixed missing import * Improved implementation to get path Co-authored-by: Roy Nieterau <roy_nieterau@hotmail.com> * Hound fixes * Use qtpy instead of Qt * Changed icon and label * Fix navigation not navigating to task folder * Implemented suggestions Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> * Add comment for clarity * change behavior to strictly use task of asset path without finding first available path * require asset name * raise exceptions to show a message to user --------- Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Co-authored-by: Roy Nieterau <roy_nieterau@hotmail.com> Co-authored-by: Jakub Trllo <jakub.trllo@gmail.com>
This commit is contained in:
parent
80114b24fa
commit
a2a35e8252
1 changed files with 125 additions and 0 deletions
125
openpype/plugins/actions/open_file_explorer.py
Normal file
125
openpype/plugins/actions/open_file_explorer.py
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
import os
|
||||
import platform
|
||||
import subprocess
|
||||
|
||||
from string import Formatter
|
||||
from openpype.client import (
|
||||
get_project,
|
||||
get_asset_by_name,
|
||||
)
|
||||
from openpype.pipeline import (
|
||||
Anatomy,
|
||||
LauncherAction,
|
||||
)
|
||||
from openpype.pipeline.template_data import get_template_data
|
||||
|
||||
|
||||
class OpenTaskPath(LauncherAction):
|
||||
name = "open_task_path"
|
||||
label = "Explore here"
|
||||
icon = "folder-open"
|
||||
order = 500
|
||||
|
||||
def is_compatible(self, session):
|
||||
"""Return whether the action is compatible with the session"""
|
||||
return bool(session.get("AVALON_ASSET"))
|
||||
|
||||
def process(self, session, **kwargs):
|
||||
from qtpy import QtCore, QtWidgets
|
||||
|
||||
project_name = session["AVALON_PROJECT"]
|
||||
asset_name = session["AVALON_ASSET"]
|
||||
task_name = session.get("AVALON_TASK", None)
|
||||
|
||||
path = self._get_workdir(project_name, asset_name, task_name)
|
||||
if not path:
|
||||
return
|
||||
|
||||
app = QtWidgets.QApplication.instance()
|
||||
ctrl_pressed = QtCore.Qt.ControlModifier & app.keyboardModifiers()
|
||||
if ctrl_pressed:
|
||||
# Copy path to clipboard
|
||||
self.copy_path_to_clipboard(path)
|
||||
else:
|
||||
self.open_in_explorer(path)
|
||||
|
||||
def _find_first_filled_path(self, path):
|
||||
if not path:
|
||||
return ""
|
||||
|
||||
fields = set()
|
||||
for item in Formatter().parse(path):
|
||||
_, field_name, format_spec, conversion = item
|
||||
if not field_name:
|
||||
continue
|
||||
conversion = "!{}".format(conversion) if conversion else ""
|
||||
format_spec = ":{}".format(format_spec) if format_spec else ""
|
||||
orig_key = "{{{}{}{}}}".format(
|
||||
field_name, conversion, format_spec)
|
||||
fields.add(orig_key)
|
||||
|
||||
for field in fields:
|
||||
path = path.split(field, 1)[0]
|
||||
return path
|
||||
|
||||
def _get_workdir(self, project_name, asset_name, task_name):
|
||||
project = get_project(project_name)
|
||||
asset = get_asset_by_name(project_name, asset_name)
|
||||
|
||||
data = get_template_data(project, asset, task_name)
|
||||
|
||||
anatomy = Anatomy(project_name)
|
||||
workdir = anatomy.templates_obj["work"]["folder"].format(data)
|
||||
|
||||
# Remove any potential un-formatted parts of the path
|
||||
valid_workdir = self._find_first_filled_path(workdir)
|
||||
|
||||
# Path is not filled at all
|
||||
if not valid_workdir:
|
||||
raise AssertionError("Failed to calculate workdir.")
|
||||
|
||||
# Normalize
|
||||
valid_workdir = os.path.normpath(valid_workdir)
|
||||
if os.path.exists(valid_workdir):
|
||||
return valid_workdir
|
||||
|
||||
# If task was selected, try to find asset path only to asset
|
||||
if not task_name:
|
||||
raise AssertionError("Folder does not exist.")
|
||||
|
||||
data.pop("task", None)
|
||||
workdir = anatomy.templates_obj["work"]["folder"].format(data)
|
||||
valid_workdir = self._find_first_filled_path(workdir)
|
||||
if valid_workdir:
|
||||
# Normalize
|
||||
valid_workdir = os.path.normpath(valid_workdir)
|
||||
if os.path.exists(valid_workdir):
|
||||
return valid_workdir
|
||||
raise AssertionError("Folder does not exist.")
|
||||
|
||||
@staticmethod
|
||||
def open_in_explorer(path):
|
||||
platform_name = platform.system().lower()
|
||||
if platform_name == "windows":
|
||||
args = ["start", path]
|
||||
elif platform_name == "darwin":
|
||||
args = ["open", "-na", path]
|
||||
elif platform_name == "linux":
|
||||
args = ["xdg-open", path]
|
||||
else:
|
||||
raise RuntimeError(f"Unknown platform {platform.system()}")
|
||||
# Make sure path is converted correctly for 'os.system'
|
||||
os.system(subprocess.list2cmdline(args))
|
||||
|
||||
@staticmethod
|
||||
def copy_path_to_clipboard(path):
|
||||
from qtpy import QtWidgets
|
||||
|
||||
path = path.replace("\\", "/")
|
||||
print(f"Copied to clipboard: {path}")
|
||||
app = QtWidgets.QApplication.instance()
|
||||
assert app, "Must have running QApplication instance"
|
||||
|
||||
# Set to Clipboard
|
||||
clipboard = QtWidgets.QApplication.clipboard()
|
||||
clipboard.setText(os.path.normpath(path))
|
||||
Loading…
Add table
Add a link
Reference in a new issue