Skip to content

Commit

Permalink
Support multiple hosts in Work Files tool (add to Houdini + Fusion)
Browse files Browse the repository at this point in the history
  • Loading branch information
BigRoy committed Jan 17, 2019
1 parent 9a70667 commit 241864f
Show file tree
Hide file tree
Showing 4 changed files with 309 additions and 88 deletions.
154 changes: 66 additions & 88 deletions avalon/tools/workfiles/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,24 @@


from ...vendor.Qt import QtWidgets, QtCore
from ... import style
from ... import io, api
from ... import style, io, api, pipeline
from .. import lib as parentlib


def determine_application():
# Determine executable
application = None
def current_host():
"""Return the compatible current host as implemented in host.py"""

basename = os.path.basename(sys.executable).lower()
from . import host

if "maya" in basename:
application = "maya"
for Host in pipeline.plugin_from_module(superclass=host.Host,
module=host):
if Host.compatible():
return Host()

if application is None:
raise ValueError(
"Could not determine application from executable:"
" \"{0}\"".format(sys.executable)
)

return application
raise ValueError(
"Could not determine Work Files host in executable:"
" \"{0}\"".format(sys.executable)
)


class NameWindow(QtWidgets.QDialog):
Expand Down Expand Up @@ -140,7 +138,16 @@ def get_work_file(self, template=None):
work_file = work_file.replace("<", "")
work_file = work_file.replace(">", "")

work_file = work_file + self.extensions[self.application]
# Define saving file extension
current_file = self.host.current_file()
if current_file:
# Match the extension of current file
_, extension = os.path.splitext(current_file)
else:
# Fall back to the first extension supported for this host.
extension = self.host.extensions()[0]

work_file = work_file + extension

return work_file

Expand All @@ -152,8 +159,8 @@ def refresh(self):
files = os.listdir(self.root)

# Fast match on extension
ext = self.extensions[self.application]
files = [f for f in files if f.endswith(ext)]
extensions = self.host.extensions()
files = [f for f in files if os.path.splitext(f)[1] in extensions]

# Build template without optionals, version to digits only regex
# and comment to any definable value.
Expand Down Expand Up @@ -204,7 +211,7 @@ def refresh(self):

def setup(self, root):
self.root = root
self.application = determine_application()
self.host = current_host()

# Get work file name
self.data = {
Expand All @@ -228,8 +235,6 @@ def setup(self, root):
if "workfile" in templates:
self.template = templates["workfile"]

self.extensions = {"maya": ".ma"}


class Window(QtWidgets.QDialog):
"""Work Files Window"""
Expand All @@ -243,11 +248,7 @@ def __init__(self, root=None):
if self.root is None:
self.root = os.getcwd()

filters = {
"maya": [".ma", ".mb"]
}
self.application = determine_application()
self.filter = filters[self.application]
self.host = current_host()

self.layout = QtWidgets.QVBoxLayout()
self.setLayout(self.layout)
Expand Down Expand Up @@ -285,7 +286,7 @@ def __init__(self, root=None):
self.layout.addWidget(separator)

current_file_label = QtWidgets.QLabel(
"Current File: " + self.current_file()
"Current File: " + (self.host.current_file() or "<unsaved>")
)
self.layout.addWidget(current_file_label)

Expand Down Expand Up @@ -313,35 +314,17 @@ def get_name(self):

return window.get_result()

def current_file(self):
func = {"maya": self.current_file_maya}
return func[self.application]()

def current_file_maya(self):
import os
from maya import cmds

current_file = cmds.file(sceneName=True, query=True)

# Maya returns forward-slashes by default
normalised = os.path.basename(os.path.normpath(current_file))

# Unsaved current file
if normalised == ".":
return "NOT SAVED"

return normalised

def refresh(self):
self.list.clear()

modified = []
extensions = set(self.host.extensions())
for f in sorted(os.listdir(self.root)):
path = os.path.join(self.root, f)
if os.path.isdir(path):
continue

if self.filter and os.path.splitext(f)[1] not in self.filter:
if extensions and os.path.splitext(f)[1] not in extensions:
continue

self.list.addItem(f)
Expand All @@ -361,11 +344,6 @@ def refresh(self):

self.list.setMinimumWidth(self.list.sizeHintForColumn(0) + 30)

def save_as_maya(self, file_path):
from maya import cmds
cmds.file(rename=file_path)
cmds.file(save=True, type="mayaAscii")

def save_changes_prompt(self):
messagebox = QtWidgets.QMessageBox()
messagebox.setWindowFlags(QtCore.Qt.FramelessWindowHint)
Expand All @@ -387,33 +365,25 @@ def save_changes_prompt(self):
else:
return None

def open_maya(self, file_path):
from maya import cmds
def open(self, filepath):

force = False
if cmds.file(q=True, modified=True):
host = self.host
if host.has_unsaved_changes():
result = self.save_changes_prompt()

if result is None:
# Cancel operation
return False

if result:
cmds.file(save=True, type="mayaAscii")
else:
force = True

cmds.file(file_path, open=True, force=force)

return True

def open(self, file_path):
func = {"maya": self.open_maya}
# Save current scene, continue to open file
host.save(host.current_file())

work_file = os.path.join(
self.root, self.list.selectedItems()[0].text()
)
else:
# Don't save, continue to open file
pass

return func[self.application](work_file)
return host.open(filepath)

def on_duplicate_pressed(self):
work_file = self.get_name()
Expand All @@ -432,18 +402,21 @@ def on_duplicate_pressed(self):
self.refresh()

def on_open_pressed(self):
work_file = os.path.join(
self.root, self.list.selectedItems()[0].text()
)

result = self.open(work_file)
selection = self.list.selectedItems()
if not selection:
print("No file selected to open..")
return

work_file = os.path.join(self.root, selection[0].text())

result = self.open(work_file)
if result:
self.close()

def on_browse_pressed(self):

filter = " *".join(self.filter)
filter = " *".join(self.host.extensions())
filter = "Work File (*{0})".format(filter)
work_file = QtWidgets.QFileDialog.getOpenFileName(
caption="Work Files",
Expand All @@ -465,22 +438,27 @@ def on_save_as_pressed(self):
if not work_file:
return

save_as = {"maya": self.save_as_maya}
application = determine_application()
if application not in save_as:
raise ValueError(
"Could not find a save as method for this application."
)

file_path = os.path.join(self.root, work_file)

save_as[application](file_path)
self.host.save(file_path)

self.close()


def show(root):
def show(root=None):
"""Show Work Files GUI"""
window = Window(root)
window.setStyleSheet(style.load_stylesheet())
window.exec_()

# Allow to use a Host's default root.
if root is None:
host = current_host()
root = host.root()
if not root:
raise ValueError("Root not given and no root returned by "
"default from current host %s" % host.__name__)

if not os.path.exists(root):
raise OSError("Root set for Work Files app does not exist: %s" % root)

with parentlib.application():
window = Window(root)
window.setStyleSheet(style.load_stylesheet())
window.exec_()
Loading

0 comments on commit 241864f

Please sign in to comment.