From 85a298e4f5867a7bbd7598679496735dd1200f2b Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Tue, 23 Jun 2020 12:30:20 +0100 Subject: [PATCH] Flag Outdated containers - on startup as message box appears, and outdated containers are coloured red. - on publish the "Validate Containers" errors. - loaded image containers are coloured green. --- pype/hosts/harmony/__init__.py | 100 +++++++++++- .../global/publish/validate_containers.py | 2 +- .../harmony/load/load_imagesequence.py | 145 ++++++++++++++---- 3 files changed, 216 insertions(+), 31 deletions(-) diff --git a/pype/hosts/harmony/__init__.py b/pype/hosts/harmony/__init__.py index 169786204e3..628397e777b 100644 --- a/pype/hosts/harmony/__init__.py +++ b/pype/hosts/harmony/__init__.py @@ -1,8 +1,9 @@ import os import sys -from avalon import api, harmony +from avalon import api, io, harmony from avalon.vendor import Qt +import avalon.tools.sceneinventory import pyblish.api from pype import lib @@ -92,6 +93,101 @@ def ensure_scene_settings(): set_scene_settings(valid_settings) +def check_inventory(): + if not lib.any_outdated(): + return + + host = avalon.api.registered_host() + outdated_containers = [] + for container in host.ls(): + representation = container['representation'] + representation_doc = io.find_one( + { + "_id": io.ObjectId(representation), + "type": "representation" + }, + projection={"parent": True} + ) + if representation_doc and not lib.is_latest(representation_doc): + outdated_containers.append(container) + + # Colour nodes. + func = """function func(args){ + for( var i =0; i <= args[0].length - 1; ++i) + { + var red_color = new ColorRGBA(255, 0, 0, 255); + node.setColor(args[0][i], red_color); + } + } + func + """ + outdated_nodes = [x["node"] for x in outdated_containers] + harmony.send({"function": func, "args": [outdated_nodes]}) + + # Warn about outdated containers. + print("Starting new QApplication..") + app = Qt.QtWidgets.QApplication(sys.argv) + + message_box = Qt.QtWidgets.QMessageBox() + message_box.setIcon(Qt.QtWidgets.QMessageBox.Warning) + msg = "There are outdated containers in the scene." + message_box.setText(msg) + message_box.exec_() + + # Garbage collect QApplication. + del app + + +def application_launch(): + ensure_scene_settings() + check_inventory() + + +def export_template(backdrops, nodes, filepath): + func = """function func(args) + { + // Add an extra node just so a new group can be created. + var temp_node = node.add("Top", "temp_note", "NOTE", 0, 0, 0); + var template_group = node.createGroup(temp_node, "temp_group"); + node.deleteNode( template_group + "/temp_note" ); + + // This will make Node View to focus on the new group. + selection.clearSelection(); + selection.addNodeToSelection(template_group); + Action.perform("onActionEnterGroup()", "Node View"); + + // Recreate backdrops in group. + for (var i = 0 ; i < args[0].length; i++) + { + Backdrop.addBackdrop(template_group, args[0][i]); + }; + + // Copy-paste the selected nodes into the new group. + var drag_object = copyPaste.copy(args[1], 1, frame.numberOf, ""); + copyPaste.pasteNewNodes(drag_object, template_group, ""); + + // Select all nodes within group and export as template. + Action.perform( "selectAll()", "Node View" ); + copyPaste.createTemplateFromSelection(args[2], args[3]); + + // Unfocus the group in Node view, delete all nodes and backdrops + // created during the process. + Action.perform("onActionUpToParent()", "Node View"); + node.deleteNode(template_group, true, true); + } + func + """ + harmony.send({ + "function": func, + "args": [ + backdrops, + nodes, + os.path.basename(filepath), + os.path.dirname(filepath) + ] + }) + + def install(): print("Installing Pype config...") @@ -116,7 +212,7 @@ def install(): "instanceToggled", on_pyblish_instance_toggled ) - api.on("application.launched", ensure_scene_settings) + api.on("application.launched", application_launch) def on_pyblish_instance_toggled(instance, old_value, new_value): diff --git a/pype/plugins/global/publish/validate_containers.py b/pype/plugins/global/publish/validate_containers.py index 44cb5def3ce..2c7b763f7ad 100644 --- a/pype/plugins/global/publish/validate_containers.py +++ b/pype/plugins/global/publish/validate_containers.py @@ -19,7 +19,7 @@ class ValidateContainers(pyblish.api.ContextPlugin): label = "Validate Containers" order = pyblish.api.ValidatorOrder - hosts = ["maya", "houdini", "nuke"] + hosts = ["maya", "houdini", "nuke", "harmony"] optional = True actions = [ShowInventory] diff --git a/pype/plugins/harmony/load/load_imagesequence.py b/pype/plugins/harmony/load/load_imagesequence.py index 7862e027af6..b56dba03d42 100644 --- a/pype/plugins/harmony/load/load_imagesequence.py +++ b/pype/plugins/harmony/load/load_imagesequence.py @@ -98,33 +98,63 @@ transparencyModeAttr.setValue(SGITransparencyMode); if (extension == "psd") transparencyModeAttr.setValue(FlatPSDTransparencyMode); + if (extension == "jpg") + transparencyModeAttr.setValue(LayeredPSDTransparencyMode); node.linkAttr(read, "DRAWING.ELEMENT", uniqueColumnName); - // Create a drawing for each file. - for( var i =0; i <= files.length - 1; ++i) + if (files.length == 1) { - timing = start_frame + i // Create a drawing drawing, 'true' indicate that the file exists. - Drawing.create(elemId, timing, true); + Drawing.create(elemId, 1, true); // Get the actual path, in tmp folder. - var drawingFilePath = Drawing.filename(elemId, timing.toString()); - copyFile( files[i], drawingFilePath ); - - column.setEntry(uniqueColumnName, 1, timing, timing.toString()); + var drawingFilePath = Drawing.filename(elemId, "1"); + copyFile(files[0], drawingFilePath); + // Expose the image for the entire frame range. + for( var i =0; i <= frame.numberOf() - 1; ++i) + { + timing = start_frame + i + column.setEntry(uniqueColumnName, 1, timing, "1"); + } + } else { + // Create a drawing for each file. + for( var i =0; i <= files.length - 1; ++i) + { + timing = start_frame + i + // Create a drawing drawing, 'true' indicate that the file exists. + Drawing.create(elemId, timing, true); + // Get the actual path, in tmp folder. + var drawingFilePath = Drawing.filename(elemId, timing.toString()); + copyFile( files[i], drawingFilePath ); + + column.setEntry(uniqueColumnName, 1, timing, timing.toString()); + } } + + var green_color = new ColorRGBA(0, 255, 0, 255); + node.setColor(read, green_color); + return read; } import_files """ -replace_files = """function replace_files(args) +replace_files = """var PNGTransparencyMode = 0; //Premultiplied wih Black +var TGATransparencyMode = 0; //Premultiplied wih Black +var SGITransparencyMode = 0; //Premultiplied wih Black +var LayeredPSDTransparencyMode = 1; //Straight +var FlatPSDTransparencyMode = 2; //Premultiplied wih White + +function replace_files(args) { var files = args[0]; + MessageLog.trace(files); + MessageLog.trace(files.length); var _node = args[1]; var start_frame = args[2]; var _column = node.linkedColumn(_node, "DRAWING.ELEMENT"); + var elemId = column.getElementIdOfDrawing(_column); // Delete existing drawings. var timings = column.getDrawingTimings(_column); @@ -133,20 +163,62 @@ column.deleteDrawingAt(_column, parseInt(timings[i])); } - // Create new drawings. - for( var i =0; i <= files.length - 1; ++i) + + var filename = files[0]; + var pos = filename.lastIndexOf("."); + if( pos < 0 ) + return null; + var extension = filename.substr(pos+1).toLowerCase(); + + if(extension == "jpeg") + extension = "jpg"; + + var transparencyModeAttr = node.getAttr( + _node, frame.current(), "applyMatteToColor" + ); + if (extension == "png") + transparencyModeAttr.setValue(PNGTransparencyMode); + if (extension == "tga") + transparencyModeAttr.setValue(TGATransparencyMode); + if (extension == "sgi") + transparencyModeAttr.setValue(SGITransparencyMode); + if (extension == "psd") + transparencyModeAttr.setValue(FlatPSDTransparencyMode); + if (extension == "jpg") + transparencyModeAttr.setValue(LayeredPSDTransparencyMode); + + if (files.length == 1) { - timing = start_frame + i // Create a drawing drawing, 'true' indicate that the file exists. - Drawing.create(node.getElementId(_node), timing, true); + Drawing.create(elemId, 1, true); // Get the actual path, in tmp folder. - var drawingFilePath = Drawing.filename( - node.getElementId(_node), timing.toString() - ); - copyFile( files[i], drawingFilePath ); - - column.setEntry(_column, 1, timing, timing.toString()); + var drawingFilePath = Drawing.filename(elemId, "1"); + copyFile(files[0], drawingFilePath); + MessageLog.trace(files[0]); + MessageLog.trace(drawingFilePath); + // Expose the image for the entire frame range. + for( var i =0; i <= frame.numberOf() - 1; ++i) + { + timing = start_frame + i + column.setEntry(_column, 1, timing, "1"); + } + } else { + // Create a drawing for each file. + for( var i =0; i <= files.length - 1; ++i) + { + timing = start_frame + i + // Create a drawing drawing, 'true' indicate that the file exists. + Drawing.create(elemId, timing, true); + // Get the actual path, in tmp folder. + var drawingFilePath = Drawing.filename(elemId, timing.toString()); + copyFile( files[i], drawingFilePath ); + + column.setEntry(_column, 1, timing, timing.toString()); + } } + + var green_color = new ColorRGBA(0, 255, 0, 255); + node.setColor(_node, green_color); } replace_files """ @@ -156,8 +228,8 @@ class ImageSequenceLoader(api.Loader): """Load images Stores the imported asset in a container named after the asset. """ - families = ["shot", "render"] - representations = ["jpeg", "png"] + families = ["shot", "render", "image"] + representations = ["jpeg", "png", "jpg"] def load(self, context, name=None, namespace=None, data=None): @@ -165,9 +237,18 @@ def load(self, context, name=None, namespace=None, data=None): os.listdir(os.path.dirname(self.fname)) ) files = [] - for f in list(collections[0]): + if collections: + for f in list(collections[0]): + files.append( + os.path.join( + os.path.dirname(self.fname), f + ).replace("\\", "/") + ) + else: files.append( - os.path.join(os.path.dirname(self.fname), f).replace("\\", "/") + os.path.join( + os.path.dirname(self.fname), remainder[0] + ).replace("\\", "/") ) read_node = harmony.send( @@ -190,15 +271,23 @@ def load(self, context, name=None, namespace=None, data=None): def update(self, container, representation): node = container.pop("node") + path = api.get_representation_path(representation) collections, remainder = clique.assemble( - os.listdir( - os.path.dirname(api.get_representation_path(representation)) - ) + os.listdir(os.path.dirname(path)) ) files = [] - for f in list(collections[0]): + if collections: + for f in list(collections[0]): + files.append( + os.path.join( + os.path.dirname(path), f + ).replace("\\", "/") + ) + else: files.append( - os.path.join(os.path.dirname(self.fname), f).replace("\\", "/") + os.path.join( + os.path.dirname(path), remainder[0] + ).replace("\\", "/") ) harmony.send(