Below is an example demonstrating how to read recorded settings for a save filter from a JSON file and use them to batch control saving from that save filter.
Note: This script is dependent on the Save Filter Template Apply sample residing in the same directory.
See Also:
// Define an anonymous function; // serves as our main loop, // limits the scope of variables (function(){ // Initialize 'static' variables that hold modifier key state var s_bShiftPressed = false; var s_bControlPressed = false; var s_bAltPressed = false; var s_bMetaPressed = false; // If the "Action" global transient is defined, and its the correct type if( typeof( Action ) != "undefined" && Action.inherits( "DzScriptAction" ) ){ // If the current key sequence for the action is not pressed if( !App.isKeySequenceDown( Action.shortcut ) ){ updateModifierKeyState(); } // If the "Action" global transient is not defined } else if( typeof( Action ) == "undefined" ) { updateModifierKeyState(); } /*********************************************************************/ // void : A function for updating the keyboard modifier state function updateModifierKeyState() { // Get the current modifier key state var nModifierState = App.modifierKeyState(); // Update variables that hold modifier key state s_bShiftPressed = (nModifierState & 0x02000000) != 0; s_bControlPressed = (nModifierState & 0x04000000) != 0; s_bAltPressed = (nModifierState & 0x08000000) != 0; s_bMetaPressed = (nModifierState & 0x10000000) != 0; }; /*********************************************************************/ // void : A function for printing only if debugging function debug() { // If we are not debugging if( !s_bAltPressed ){ // We are done... return; } // Convert the arguments object into an array var aArguments = [].slice.call( arguments ); // Print the array print( aArguments.join(" ") ); }; /*********************************************************************/ // String : A function for retrieving a translation if one exists function text( sText ) { // If the version of the application supports qsTr() if( typeof( qsTr ) != "undefined" ){ // Return the translated (if any) text return qsTr( sText ); } // Return the original text return sText; }; /*********************************************************************/ // Boolean : A function for testing whether or not a QObject instance // inherits one of a list of types function inheritsType( oObject, aTypeNames ) { // If the object does not define the 'inherits' function if( !oObject || typeof( oObject.inherits ) != "function" ){ // We are done... it is not a QObject return false; } // Iterate over the list of type names for( var i = 0, nTypes = aTypeNames.length; i < nTypes; i += 1 ){ // If the object does not inherit the 'current' type if( !oObject.inherits( aTypeNames[i] ) ){ // Next!! continue; } // Return the result return true; } // Return the result return false; }; /*********************************************************************/ // DzNode : A function for getting the root of a node function getRootNode( oNode ) { // If we have a node and it is a bone if( oNode && inheritsType( oNode, ["DzBone"] ) ){ // We want the skeleton return oNode.getSkeleton(); } // Return the original node return oNode; }; /*********************************************************************/ // Object : A function for getting the value of a named member function getObjectValue( oObject, sMember, sType ) { if( oObject.hasOwnProperty( sMember ) ){ return oObject[ sMember ]; } switch( sType ){ case "object": return {}; case "array": return []; case "number": return Number(); case "string": return ""; default: break; } }; /*********************************************************************/ // String : A function for getting the path of a script that resides next to this script function getAdjacentScriptPath( sName, bNotify ) { // Create a file info object for this file var oFileInfo = new DzFileInfo( getScriptFileName() ); // Define the base path of the script we will call; without the file extension var sBasePath = String( "%1/%2" ).arg( oFileInfo.path() ).arg( sName ); // Clean up; do not leak memory oFileInfo.deleteLater(); // Create a script object var oScript = new DzScript(); // Attempt to find our script; doing it this way, we can debug with an // ascii file and distribute a binary [encrypted] file with the same name... // without having to update the contents of the script or manually handle // the file extensions; requires 3.0.1.5 or newer var sScriptPath = oScript.getScriptFile( sBasePath ); // Clean up; do not leak memory oScript.deleteLater(); // If a script is not found if( sScriptPath.isEmpty() && bNotify ){ // Define message strings var sTitle = text( "File Not Found" ); var sMessage = text( "A '%1.ds(a|b|e)' file could not be found." ).arg( sBasePath ); var sButton = text( "&OK" ); // Inform the user MessageBox.information( sMessage, sTitle, sButton ); } // Return the result return sScriptPath; }; /*********************************************************************/ // Boolean : A function for executing a script that resides next to this script function executeAdjacentScript( sName, aArgs ) { // Initialize var bResult = true; // Get the path of our script var sScriptPath = getAdjacentScriptPath( sName, true ); // If a script is found if( !sScriptPath.isEmpty() ){ // Create a script object var oScript = new DzScript(); // If the script loads if( oScript.loadFromFile( sScriptPath ) ){ // Execute the script with our argument if( !oScript.execute( aArgs ) ){ // Update our variable bResult = false; } // If the script does not load } else { // Define message strings var sTitle = text( "Read Error" ); var sMessage = text( "The '%1' file could not be loaded." ).arg( sScriptPath ); var sButton = text( "&OK" ); // Inform the user MessageBox.information( sMessage, sTitle, sButton ); } // Clean up; do not leak memory oScript.deleteLater(); } // Return the result return bResult; }; /*********************************************************************** ***** DsInterface Prototype ***** ***********************************************************************/ // Create an interface object var s_oGui = new DsInterface(); /*********************************************************************/ function DsInterface() { this.oStyle = App.getStyle(); this.bUseStyle = App.version > 0x03000000; this.nMargin = this.bUseStyle ? this.oStyle.pixelMetric( "DZ_GeneralMargin" ) : 5; this.nSpacing = this.nMargin; this.nBtnHeight = this.bUseStyle ? this.oStyle.pixelMetric( "DZ_ButtonHeight" ) : 20; this.wDlg; this.wSaveFilterCmb; this.wTemplateCmbEdit; this.wDefaultLEdit; this.wSourceLEdit; this.wSourceRecurseCbx; this.wNativeExtGrp; this.wPoserExtGrp; this.wTargetLEdit; this.sNodeName, this.sBasePath, this.sExt; }; /***********************************************************************/ DsInterface.superclass = Object; /*********************************************************************/ /*********************************************************************/ // void : A method for building a save filter combobox DsInterface.prototype.buildSaveFilterCombobox = function( aExclude ) { // Get the asset IO manager var oAssetIOMgr = App.getAssetIOMgr(); // Declare variables we'll be using as we iterate var oAssetIOFilter, oSettings; // Define the list of filters; in display order var aFilters = [ "DzSceneAssetFilter", "DzSceneSubsetAssetFilter", "DzHierarchicalMaterialAssetFilter", "DzHierarchicalPoseAssetFilter", "DzWearablesAssetFilter", "DzCharacterAssetFilter", "DzPropertiesAssetFilter", "DzShapingAssetFilter", "DzPoseAssetFilter", "DzMaterialAssetFilter", "DzShaderAssetFilter", "DzCameraAssetFilter", "DzLightAssetFilter", "DzRenderSettingsAssetFilter", "DzSimulationSettingsAssetFilter", "DzDFormAssetFilter", "DzLayerAssetFilter", "DzPuppeteerAssetFilter", "---", "DzSceneSupportAssetFilter", "DzNodeSupportAssetFilter", "DzMorphSupportAssetFilter", "DzUVSupportAssetFilter", "DzShaderSupportAssetFilter", ]; // Declare working variables var sFilter; var nIdx; // Get the number of items in our list var nFilters = aFilters.length; // Iterate over our list for( var i = 0; i < nFilters; i += 1 ){ // Get the 'current' filter sFilter = aFilters[i]; // If the 'filter' is in the exclude list if( aExclude.indexOf( sFilter ) > -1 ) { // Next!! continue; } // If the 'filter' is a separator if( sFilter == "---" ) { // Insert a separator at the end this.wSaveFilterCmb.insertSeparator( this.wSaveFilterCmb.count ); // Next!! continue; } // Find the filter index nIdx = oAssetIOMgr.findFilter( sFilter ); // If the filter was not found if( nIdx < 0 ){ // Next!! continue; } // Get the filter oAssetIOFilter = oAssetIOMgr.getFilter( nIdx ); // Add the filter to the choices this.wSaveFilterCmb.addItem( oAssetIOFilter.getDescription().replace( "...", "" ), oAssetIOFilter.className() ); // Clean up; do not leak memory oAssetIOFilter.deleteLater(); } // Insert a separator between filters we have // explicitly handled and those we have not this.wSaveFilterCmb.insertSeparator( this.wSaveFilterCmb.count ); // Get the number of filters nFilters = oAssetIOMgr.getNumFilters(); // Iterate over all filters for( var i = 0; i < nFilters; i += 1 ){ // Get the 'current' filter oAssetIOFilter = oAssetIOMgr.getFilter( i ); // Get the filter classname sFilter = oAssetIOFilter.className(); // If the 'filter' has already been added // or it is in the exclude list if( aFilters.indexOf( sFilter ) > -1 || aExclude.indexOf( sFilter ) > -1 ){ // Clean up; do not leak memory oAssetIOFilter.deleteLater(); // Next!! continue; } // Add the filter to the choices this.wSaveFilterCmb.addItem( oAssetIOFilter.getDescription().replace( "...", "" ), oAssetIOFilter.className() ); // Clean up; do not leak memory oAssetIOFilter.deleteLater(); } }; /*********************************************************************/ // void : A method for building a save filter template combobox DsInterface.prototype.buildTemplateCombobox = function() { // Construct the path for the template file this.sBasePath = String( "%1/Save Filter Settings Templates/%2/%3" ) .arg( App.getAppDataPath() ) .arg( this.getAssetFilterName() ) .arg( this.sNodeName ); // Define the file extension for the files this.sExt = "json"; // Declare working variable var sPath; // Get the list of template files var aPaths = s_oFileSystem.getFileList( this.sBasePath, "*." + this.sExt, "String", true ); // If the list is empty if( aPaths.length < 1 ){ // Set the placeholder text this.wTemplateCmbEdit.placeholderText = text( "No templates found." ); // We are done... return; } // Clear the placeholder text this.wTemplateCmbEdit.placeholderText = text( "Select a template..." ); // Declare working variables var nStart, nEnd; // Iterate over the template paths for( var i = 0, nPaths = aPaths.length; i < nPaths; i += 1 ){ // Get the 'current' path sPath = aPaths[ i ]; // Set the start/end of the substring nStart = this.sBasePath.length + 1; nEnd = sPath.length - this.sExt.length - 1; // Get the relative basename sPath = sPath.substring( nStart, nEnd ); // Add the item this.wTemplateCmbEdit.addItem( sPath ); } }; /*********************************************************************/ // void : A method for handling when the save filter has changed DsInterface.prototype.handleSaveFilterChanged = function() { // Get the previous template var sPrevious = this.wTemplateCmbEdit.text; // Clear the template this.wTemplateCmbEdit.clear(); this.wTemplateCmbEdit.text = ""; // Rebuild the template options this.buildTemplateCombobox(); // Attempt to find the previous item in the list var nIdx = this.wTemplateCmbEdit.findItem( sPrevious ); // If the item is found if( nIdx > -1 ){ // Restore the previous value this.wTemplateCmbEdit.text = sPrevious; } // Enable/disable based on valid options this.updateAcceptButtonEnabled(); }; /*********************************************************************/ // void : A method for saving a template DsInterface.prototype.handleSaveTemplateClicked = function() { // Get the name of the asset filter var sAssetFilter = this.getAssetFilterName(); // Define the list of filters that had a bug // with displaying their option dialogs var aExclude = [ "DzMaterialAssetFilter", "DzShaderAssetFilter" ]; // If the version of the application is older than 4.11.0.229 // and the current filter is one that had a bug prior to that if( App.version64 < 0x0004000b000000e5 && aExclude.indexOf( sAssetFilter ) > -1 ){ // Define message strings var sTitle = text( "Resource Error" ); var sMessage = text( "Templates for the selected filter " + "cannot be created this way prior to version 4.11.0.229." ); var sButton = text( "&OK" ); // Inform the user MessageBox.information( sMessage, sTitle, sButton ); // We are done... return; } // If the template save script executes successfully if( executeAdjacentScript( "SaveFilter_Template_Save", [ sAssetFilter ] ) ){ // Cause the template selector to be rebuilt this.handleSaveFilterChanged(); } }; /*********************************************************************/ // void : A method for browsing to a directory and updating a line edit DsInterface.prototype.handleBrowseDirClicked = function() { // Get the text from the line edit var sPath = this.text; // Prompt the user for a the path var sPath = FileDialog.doDirectoryDialog( text( "Choose a Directory" ), "", sPath ); // If the user cancelled if( sPath.isEmpty() ){ //We are done... return; } // Update the line edit this.text = sPath; }; /*********************************************************************/ // void : A method for browsing to a file and updating a line edit DsInterface.prototype.handleBrowseFileClicked = function() { // Get the text from the line edit var sPath = this.text; // Prompt the user for a the path var sPath = FileDialog.doFileDialog( true, text( "Choose a File" ), sPath, "DSON User File (*.duf)" ); // If the user cancelled if( sPath.isEmpty() ){ //We are done... return; } // Update the line edit this.text = sPath; }; /*********************************************************************/ // void : A method for comparing the source and target directories DsInterface.prototype.checkSourceTargetMatch = function() { // If the source is the same as the target if( this.wSourceLEdit.text == this.wTargetLEdit.text ){ // Define common strings var sTitle = text( "Warning" ); var sMessage = text( "The source and target are the same. " + "This will cause source files to be overwritten." ); var sButton = text( "&OK" ); // Inform the user MessageBox.warning( sMessage, sTitle, sButton, "" ); } }; /*********************************************************************/ // String : A method for getting the current asset filter name DsInterface.prototype.getAssetFilterName = function() { // Return the classname of the selected asset filter return this.wSaveFilterCmb.itemData( this.wSaveFilterCmb.currentItem ); }; /*********************************************************************/ // String : A method for getting the current template path DsInterface.prototype.getTemplatePath = function() { // Get the chosen template path var sRelPath = this.wTemplateCmbEdit.text; // If a template file has not been selected if( sRelPath.isEmpty() ){ // Return an empty string return ""; } // Return the re-constructed path return String( "%1/%2.%3" ) .arg( this.sBasePath ) .arg( sRelPath ) .arg( this.sExt ); }; /*********************************************************************/ // String : A method for getting the current default path DsInterface.prototype.getDefaultPath = function() { // Return the path return this.wDefaultLEdit.text; }; /*********************************************************************/ // String : A method for getting the current source path DsInterface.prototype.getSourcePath = function() { // Return the path return this.wSourceLEdit.text; }; /*********************************************************************/ // Array : A method for getting the file extensions DsInterface.prototype.getFileExtensions = function() { // Initialize var aExtensions = []; // Declare working variable var wBtn; // Get the list of buttons in the native group var aButtons = this.wNativeExtGrp.buttons(); // Iterate over the buttons for( var i = 0, nButtons = aButtons.length; i < nButtons; i += 1 ){ // Get the 'current' button wBtn = aButtons[ i ]; // If the button is checked if( wBtn.checked ){ // Add the extension to the list aExtensions.push( wBtn.text ); } } // Get the list of buttons in the poser group aButtons = this.wPoserExtGrp.buttons(); // Iterate over the buttons for( var i = 0, nButtons = aButtons.length; i < nButtons; i += 1 ){ // Get the 'current' button wBtn = aButtons[ i ]; // If the button is checked if( wBtn.checked ){ // Add the extension to the list aExtensions.push( wBtn.text ); } } // Return the path return aExtensions; }; /*********************************************************************/ // String : A method for getting the current target path DsInterface.prototype.getTargetPath = function() { // Return the path return this.wTargetLEdit.text; }; /*********************************************************************/ // void : A method for validating options DsInterface.prototype.getOptionsValid = function() { // Return whether or not all values are valid return !this.getAssetFilterName().isEmpty() && !this.getTemplatePath().isEmpty() && !this.getSourcePath().isEmpty() && this.getFileExtensions().length > 0 && !this.getTargetPath().isEmpty(); }; /*********************************************************************/ // void : A method for updating the enabled state of the accept button DsInterface.prototype.updateAcceptButtonEnabled = function() { // Enable/disable based on valid options this.wDlg.setAcceptButtonEnabled( this.getOptionsValid() ); }; /*********************************************************************/ // Object : A method for getting input from the user DsInterface.prototype.doDialog = function( sTitle, sNodeName, sSrcPath ) { // Store the node name this.sNodeName = sNodeName; // Create the dialog this.wDlg = new DzBasicDialog(); // Get the wrapped widget for the dialog var oDlgWgt = this.wDlg.getWidget(); // Strip the space for a settings key var sKey = sTitle.replace( / /g, "" ) + "Dlg"; // Set an [unique] object name on the wrapped dialog widget; // this is used for recording position and size separately // from all other [uniquely named] DzBasicDialog instances oDlgWgt.objectName = sKey; // Set the title of the dialog this.wDlg.caption = text( sTitle ); // Create a widget var wMainWgt = new DzWidget( this.wDlg ); // Create a grid layout var lytMain = new DzGridLayout( wMainWgt ); lytMain.margin = this.nMargin; lytMain.spacing = this.nSpacing; // Initialize var nRow = 0; // Create a label var wLabel = new DzLabel( wMainWgt ); wLabel.text = text( "Filter :" ); wLabel.alignment = DzWidget.AlignRight | DzWidget.AlignVCenter; // Add the label to the layout lytMain.addWidget( wLabel, nRow, 0 ); // Create a combo box this.wSaveFilterCmb = new DzComboBox( wMainWgt ); // Set the height this.wSaveFilterCmb.setFixedHeight( this.nBtnHeight ); // Connect this.wSaveFilterCmb["currentIndexChanged(int)"].connect( s_oGui, s_oGui.handleSaveFilterChanged ); // Add the combo box to the layout lytMain.addWidget( this.wSaveFilterCmb, nRow, 1 ); nRow += 1; // Create a label wLabel = new DzLabel( wMainWgt ); wLabel.text = text( "Template :" ); wLabel.alignment = DzWidget.AlignRight | DzWidget.AlignVCenter; // Add the label to the layout lytMain.addWidget( wLabel, nRow, 0 ); // Create a widget var wTemplateWgt = new DzWidget( wMainWgt ); // Create a horizontal box layout var lytTemplate = new DzHBoxLayout( wTemplateWgt ); lytTemplate.margin = 0; lytTemplate.spacing = 0; // Create a combo edit this.wTemplateCmbEdit = new DzComboEdit( wTemplateWgt ); this.wTemplateCmbEdit.submenuDelimiter = "/"; this.wTemplateCmbEdit.menuSelectionIncludesPath = true; // Disable manual editing this.wTemplateCmbEdit.readOnly = true; // Connect this.wTemplateCmbEdit.textChanged.connect( s_oGui, s_oGui.updateAcceptButtonEnabled ); // Add the combo edit to the layout lytTemplate.addWidget( this.wTemplateCmbEdit ); // If the save script resides in the same folder as this one if( !getAdjacentScriptPath( "SaveFilter_Template_Save", false ).isEmpty() ){ // Create a button var wSaveTemplateBtn = new DzPushButton( wTemplateWgt ); wSaveTemplateBtn.text = "..."; wSaveTemplateBtn.setFixedWidth( this.nBtnHeight ); // Connect wSaveTemplateBtn.clicked.connect( s_oGui, s_oGui.handleSaveTemplateClicked ); // Add the button to the layout lytTemplate.addWidget( wSaveTemplateBtn ); } // Add the combo edit to the layout lytMain.addWidget( wTemplateWgt, nRow, 1 ); nRow += 1; // Create a label wLabel = new DzLabel( wMainWgt ); wLabel.text = text( "Default :" ); wLabel.alignment = DzWidget.AlignRight | DzWidget.AlignVCenter; // Add the label to the layout lytMain.addWidget( wLabel, nRow, 0 ); // Create a widget var wBrowseWgt = new DzWidget( wMainWgt ); // Create a horizontal box layout var lytBrowse = new DzHBoxLayout( wBrowseWgt ); lytBrowse.margin = 0; lytBrowse.spacing = 0; // Create a line edit this.wDefaultLEdit = new DzLineEdit( wBrowseWgt ); this.wDefaultLEdit.placeholderText = text( "Select a file to apply between files..." ); // Disable manual editing this.wDefaultLEdit.readOnly = true; // Add the line edit to the layout lytBrowse.addWidget( this.wDefaultLEdit ); // Create a button var wBrowseBtn = new DzPushButton( wBrowseWgt ); wBrowseBtn.text = "..."; wBrowseBtn.setFixedWidth( this.nBtnHeight ); // Connect wBrowseBtn.clicked.connect( this.wDefaultLEdit, s_oGui.handleBrowseFileClicked ); // Add the button to the layout lytBrowse.addWidget( wBrowseBtn ); // Add the browse wdget to the layout lytMain.addWidget( wBrowseWgt, nRow, 1 ); nRow += 1; // Create a label wLabel = new DzLabel( wMainWgt ); wLabel.text = text( "Source :" ); wLabel.alignment = DzWidget.AlignRight | DzWidget.AlignVCenter; // Add the label to the layout lytMain.addWidget( wLabel, nRow, 0 ); // Create a widget wBrowseWgt = new DzWidget( wMainWgt ); // Create a horizontal box layout lytBrowse = new DzHBoxLayout( wBrowseWgt ); lytBrowse.margin = 0; lytBrowse.spacing = 0; // Create a line edit this.wSourceLEdit = new DzLineEdit( wBrowseWgt ); this.wSourceLEdit.text = sSrcPath; this.wSourceLEdit.placeholderText = text( "Select a source directory..." ); // Disable manual editing this.wSourceLEdit.readOnly = true; // Connect this.wSourceLEdit.textChanged.connect( s_oGui, s_oGui.updateAcceptButtonEnabled ); // Add the line edit to the layout lytBrowse.addWidget( this.wSourceLEdit ); // Create a button wBrowseBtn = new DzPushButton( wBrowseWgt ); wBrowseBtn.text = "..."; wBrowseBtn.setFixedWidth( this.nBtnHeight ); // Connect wBrowseBtn.clicked.connect( this.wSourceLEdit, s_oGui.handleBrowseDirClicked ); // Add the button to the layout lytBrowse.addWidget( wBrowseBtn ); // Add the browse wdget to the layout lytMain.addWidget( wBrowseWgt, nRow, 1 ); nRow += 1; // Create a checkbox this.wSourceRecurseCbx = new DzCheckBox( wMainWgt ); this.wSourceRecurseCbx.text = text( "Recursive" ); lytMain.addWidget( this.wSourceRecurseCbx, nRow, 1 ); nRow += 1; // Create a label wLabel = new DzLabel( wMainWgt ); wLabel.text = text( "Type(s) :" ); wLabel.alignment = DzWidget.AlignRight | DzWidget.AlignVCenter; // Add the label to the layout lytMain.addWidget( wLabel, nRow, 0 ); // Create a button group box this.wNativeExtGrp = new DzHButtonGroup( wMainWgt ); this.wNativeExtGrp.insideMargin = this.nMargin; // Define a list of native formats var aNativeFormats = [ "*.duf", "*.dsf", "*.ds", "*.dsa", "*.dsb", "*.dse" ]; // Create a checkbox for each extension for( var i = 0, nFormats = aNativeFormats.length; i < nFormats; i += 1 ){ // Create a checkbox wButton = new DzCheckBox( this.wNativeExtGrp ); wButton.text = aNativeFormats[ i ]; wButton.checked = i == 0; // Connect wButton.clicked.connect( s_oGui, s_oGui.updateAcceptButtonEnabled ); } lytMain.addWidget( this.wNativeExtGrp, nRow, 1 ); nRow += 1; // Create a button group box this.wPoserExtGrp = new DzHButtonGroup( wMainWgt ); this.wPoserExtGrp.insideMargin = this.nMargin; this.wPoserExtGrp.columns = 2; // Define a list of poser formats var aPoserFormats = [ "*.pz2", "*.p2z", "*.fc2", "*.fcz", "*.hd2", "*.hdz", "*.lt2", "*.ltz", "*.cm2", "*.cmz", "*.mc6", "*.mcz" ]; // Create a checkbox for each extension for( var i = 0, nFormats = aPoserFormats.length; i < nFormats; i += 1 ){ // Create a checkbox wButton = new DzCheckBox( this.wPoserExtGrp ); wButton.text = aPoserFormats[ i ]; // Connect wButton.clicked.connect( s_oGui, s_oGui.updateAcceptButtonEnabled ); } lytMain.addWidget( this.wPoserExtGrp, nRow, 1 ); nRow += 1; // Create a label wLabel = new DzLabel( wMainWgt ); wLabel.text = text( "Target :" ); wLabel.alignment = DzWidget.AlignRight | DzWidget.AlignVCenter; // Add the label to the layout lytMain.addWidget( wLabel, nRow, 0 ); // Create a widget wBrowseWgt = new DzWidget( wMainWgt ); // Create a horizontal box layout lytBrowse = new DzHBoxLayout( wBrowseWgt ); lytBrowse.margin = 0; lytBrowse.spacing = 0; // Create a line edit this.wTargetLEdit = new DzLineEdit( wBrowseWgt ); this.wTargetLEdit.placeholderText = text( "Select a destination directory..." ); // Disable manual editing this.wTargetLEdit.readOnly = true; // Connect this.wTargetLEdit.textChanged.connect( s_oGui, s_oGui.updateAcceptButtonEnabled ); // Add the line edit to the layout lytBrowse.addWidget( this.wTargetLEdit ); // Create a button wBrowseBtn = new DzPushButton( wBrowseWgt ); wBrowseBtn.text = "..."; wBrowseBtn.setFixedWidth( this.nBtnHeight ); // Connect wBrowseBtn.clicked.connect( this.wTargetLEdit, s_oGui.handleBrowseDirClicked ); // Add the button to the layout lytBrowse.addWidget( wBrowseBtn ); // Add the browse wdget to the layout lytMain.addWidget( wBrowseWgt, nRow, 1 ); // Connect this.wSourceLEdit.textChanged.connect( s_oGui, s_oGui.checkSourceTargetMatch ); this.wTargetLEdit.textChanged.connect( s_oGui, s_oGui.checkSourceTargetMatch ); nRow += 1; // Add the main widget to the dialog this.wDlg.addWidget( wMainWgt ); // Get the wrapped widget for the dialog var oDlgWgt = this.wDlg.getWidget(); // Get the minimum size of the dialog var sizeHint = oDlgWgt.minimumSizeHint; // Set the fixed height of the dialog this.wDlg.setFixedHeight( sizeHint.height ); // Set the minimum width of the dialog this.wDlg.minWidth = 400; // Define the list of filters to exclude var aExclude = [ "DzSceneAssetFilter", "DzPuppeteerAssetFilter" ]; // Populate the combobox with save filters this.buildSaveFilterCombobox( aExclude ); // Populate the combobox with template this.buildTemplateCombobox(); // Enable/disable based on valid options this.updateAcceptButtonEnabled(); // If the user accepts the dialog if( this.wDlg.exec() ){ // Return the user's input return { "classname": this.getAssetFilterName(), "template": this.getTemplatePath(), "default": this.getDefaultPath(), "source": this.getSourcePath(), "recurse": this.wSourceRecurseCbx.checked, "types": this.getFileExtensions(), "target": this.getTargetPath() }; // If the user rejects the dialog } else { // return an empty object return {}; } }; /*********************************************************************** ***** DsFileSystem Prototype ***** ***********************************************************************/ // Create an interface object var s_oFileSystem = new DsFileSystem(); /*********************************************************************/ function DsFileSystem() { }; /***********************************************************************/ DsFileSystem.superclass = Object; /*********************************************************************/ // Array<String|DzDir> : Method for collecting an array of directory objects DsFileSystem.prototype.getDirectories = function( oDir, regxFilter, nFilter, nSort, sType, bRecurse ) { // Provide feedback debug( String("DsFileSystem::getDirectories( %1, \"%2\", %3, %4, \"%5\", %6 )") .arg( oDir.path() ) .arg( regxFilter ) .arg( nFilter ) .arg( nSort ) .arg( sType ) .arg( bRecurse ) ); // Declare working variable var sAbsPath; // Get the directory names var aDirs = oDir.entryList( regxFilter, nFilter, nSort ); // Iterate over the directory names for( var i = 0, nDirs = aDirs.length; i < nDirs; i += 1 ){ // Get the absolute path of the 'current' directory sAbsPath = String( "%1/%2" ).arg( oDir.absPath() ).arg( aDirs[ i ] ); // Based on the type requested switch( sType ){ default: case "String": // Update the name with the absolute path of the directory aDirs[ i ] = sAbsPath; // If we are recursing if( bRecurse ){ // Recursively collect the directory paths aDirs = aDirs.concat( this.getSubDirectories( new DzDir( sAbsPath ), regxFilter, nFilter, nSort, sType ) ); } break; case "DzDir": // Update the name with a directory object aDirs[ i ] = new DzDir( sAbsPath ); // If we are recursing if( bRecurse ){ // Recursively collect the directories aDirs = aDirs.concat( this.getSubDirectories( aDirs[ i ], regxFilter, nFilter, nSort, sType ) ); } break; } } // Return the result return aDirs; }; /*********************************************************************/ // Array<String|DzDir> : Method for recursively collecting an array of directory objects DsFileSystem.prototype.getSubDirectories = function( oDir, regxFilter, nFilter, nSort, sType ) { // Provide feedback debug( String( "DsFileSystem::getSubDirectories( %1, \"%2\", %3, %4, \"%5\" )" ) .arg( oDir.path() ) .arg( regxFilter ) .arg( nFilter ) .arg( nSort ) .arg( sType ) ); // Initialize var aSubDirs = []; // Get the immediate child directories var aDirs = this.getDirectories( oDir, regxFilter, nFilter, nSort, sType, true ); // Iterate over the directories for( var i = 0, nDirs = aDirs.length; i < nDirs; i += 1 ){ // Based on the type requested switch( sType ){ default: case "String": // Recursively collect the directory paths aSubDirs = aDirs.concat( this.getSubDirectories( new DzDir( aDirs[ i ] ), regxFilter, nFilter, nSort, sType ) ); break; case "DzDir": // Recursively collect the directories aSubDirs = aDirs.concat( this.getSubDirectories( aDirs[ i ], regxFilter, nFilter, nSort, sType, true ) ); break; } } // Return the result return aSubDirs; }; /*********************************************************************/ // Array<String|DzFileInfo|DzFile> : Method for collecting an array of files DsFileSystem.prototype.getFiles = function( oDir, regxFilter, nFilter, nSort, sType ) { // Provide feedback debug( String( "DsFileSystem::getFiles( %1, \"%2\", %3, %4, \"%5\" )" ) .arg( oDir.path() ) .arg( regxFilter ) .arg( nFilter ) .arg( nSort ) .arg( sType ) ); // Declare working variable var sAbsFilePath; // Get the file names var aFiles = oDir.entryList( regxFilter, nFilter, nSort ); // Iterate over the file names for( var i = 0, nFiles = aFiles.length; i < nFiles; i += 1 ){ // Get the absolute path of the 'current' file sAbsFilePath = oDir.absFilePath( aFiles[ i ] ); // Based on the type requested switch( sType ){ default: case "String": // Update the name with the absolute path of a file aFiles[ i ] = sAbsFilePath; break; case "DzFileInfo": // Update the name with a file info object aFiles[ i ] = new DzFileInfo( sAbsFilePath ); break; case "DzFile": // Update the name with a file object aFiles[ i ] = new DzFile( sAbsFilePath ); break; } } // Return the result return aFiles; }; /*********************************************************************/ // Array<String|DzDir> : Method for retrieving a list of directories DsFileSystem.prototype.getDirectoryList = function( sPath, sFilter, sType, bRecurse, bRelative ) { // Declare the output var aDirs = []; // Create a directory object var oBaseDir = new DzDir( sPath ); // If the directory doesn't exist if( !oBaseDir.exists() ){ // Clean up; do not leak memory oBaseDir.deleteLater(); // We are done... return aDirs; } // Get the directories var aDirs = this.getDirectories( oBaseDir, sFilter, DzDir.Dirs | DzDir.NoDotAndDotDot, DzDir.Name, sType, bRecurse ); // Clean up; do not leak memory oBaseDir.deleteLater(); // If we do not want relative paths if( !bRelative ){ // Return the result return aDirs; } // Declare working variables var sAbsPath, sRelPath; var oDir; // Iterate over the directories for( var i = 0, nDirs = aDirs.length; i < nDirs; i += 1 ){ // Based on the type requested switch( sType ){ default: case "String": // Get the 'current' path sAbsPath = aDirs[ i ]; // Get the relative portion of the path sRelPath = sAbsPath.substring( sPath.length ); // Update the path aDirs[ i ] = sRelPath; break; case "DzDir": // Get the 'current' directory oDir = aDirs[ i ]; // Get the path sAbsPath = oDir.path(); // Get the relative portion of the path sRelPath = sAbsPath.substring( sPath.length ); // Update the path oDir.setPath( sRelPath ); // Update the directory aDirs[ i ] = oDir; break; } } // Return the result return aDirs; }; /*********************************************************************/ // Array<String|DzFileInfo|DzFile> : Method for retrieving a list of files DsFileSystem.prototype.getFileList = function( sPath, sFilter, sType, bRecurse ) { // Initialize var aFiles = []; // Create a directory object var oBaseDir = new DzDir( sPath ); // If the directory doesn't exist if( !oBaseDir.exists() ){ // Clean up; do not leak memory oBaseDir.deleteLater(); // We are done... return aFiles; } // Get the files from the specified directory aFiles = this.getFiles( oBaseDir, sFilter, DzDir.Files, DzDir.Name, sType ); // Clean up; do not leak memory oBaseDir.deleteLater(); // If we are recursing if( bRecurse ){ // Declare working variable var oDir; // Get the directories var aDirs = this.getDirectoryList( sPath, "*", "DzDir", bRecurse ); // Iterate over the directories for( var i = 0, nDirs = aDirs.length; i < nDirs; i += 1 ){ // Get the 'current' directory oDir = aDirs[ i ]; // Append the files from the 'current' directory to the output aFiles = aFiles.concat( this.getFiles( oDir, sFilter, DzDir.Files, DzDir.Name, sType ) ); // Clean up; do not leak memory oDir.deleteLater(); } } // Return the result return aFiles; }; /*********************************************************************/ // Get the path of the script we will call; notify if it does not exist var sApplyScriptPath = getAdjacentScriptPath( "SaveFilter_Template_Apply", true ); // If the script is not found if( sApplyScriptPath.isEmpty() ){ // We are done... return; } // Declare working variables var sTitle, sMessage; // Define common strings var sButton = text( "&OK" ); // Create a script object var oScript = new DzScript(); // If the script does not load if( !oScript.loadFromFile( sApplyScriptPath ) ){ // Define message strings sTitle = text( "Read Error" ); sMessage = text( "The '%1' file could not be loaded." ).arg( sApplyScriptPath ); // Inform the user MessageBox.information( sMessage, sTitle, sButton ); // Clean up; do not leak memory oScript.deleteLater(); // We are done.. return; } // Get the root of the primary selection var oRootNode = getRootNode( Scene.getPrimarySelection() ); // If we do not have a selection if( !oRootNode ){ // Define message strings sTitle = text( "Selection Error" ); sMessage = text( "A node in the scene must be selected to continue." ); // Inform the user MessageBox.information( sMessage, sTitle, sButton ); // Clean up; do not leak memory oScript.deleteLater(); // We are done... return; } // Initialize var sPresetPath = ""; // Get the pane manager var oPaneMgr = MainWindow.getPaneMgr(); // If the pane manager was found if( oPaneMgr ){ // Find the Content Library pane var oPane = oPaneMgr.findPane( "DzContentLibraryPane" ); // If the pane was found if( oPane ){ // Get the selected container var oContainer = oPane.getSelectedContainer(); // If a native folder is selected if( inheritsType( oContainer, ["DzFolderAssetContainer"] ) /*&& oContainer.isNative*/ ){ // Update the preset file path sPresetPath = oPane.getSelectedContainerPath(); } } } // Prompt the user for input var oUserInput = s_oGui.doDialog( "Save Filter Template Batch", oRootNode.name, sPresetPath ); // Get the classname of the filter to use var sClassName = getObjectValue( oUserInput, "classname", "string" ); // If the user cancelled if( sClassName.isEmpty() ){ // We are done... return; } // Get the path of the template file to use var sTemplateFile = getObjectValue( oUserInput, "template", "string" ); // If the user cancelled if( sTemplateFile.isEmpty() ){ // We are done... return; } // Get the default path var sDefaultPath = getObjectValue( oUserInput, "default", "string" ); // Get the source path var sSourcePath = getObjectValue( oUserInput, "source", "string" ); // If the user cancelled if( sSourcePath.isEmpty() ){ // We are done... return; } // Get the source path var bSourceRecurse = getObjectValue( oUserInput, "recurse", "boolean" ); // Get the source extensions var aExtensions = getObjectValue( oUserInput, "types", "array" ); // If the user cancelled if( aExtensions.length < 1 ){ // We are done... return; } // Get the preset path sPresetPath = getObjectValue( oUserInput, "target", "string" ); // If the user cancelled if( sPresetPath.isEmpty() ){ // We are done... return; } // Get the list of native files var aAssets = s_oFileSystem.getFileList( sSourcePath, aExtensions.join( " " ), "String", bSourceRecurse ); // Get the number of assets var nAssets = aAssets.length; // Start the progress startProgress( text( "Batch Saving..." ), nAssets, true, true ); // Create a file info object var oAssetFileInfo = new DzFileInfo( "" ); //Declare working variable var sAsset, sAssetFilename, sPresetFile; // Get the content manager var oContentMgr = App.getContentMgr(); // Iterate over the asset paths for( var i = 0; i < nAssets; i += 1 ){ // Get the 'current' asset path sAsset = aAssets[i]; // Update the file info object oAssetFileInfo.setFile( sAsset ); // Load the file oContentMgr.openFile( sAsset ); // Get the asset file name sAssetFilename = oAssetFileInfo.fileName(); // Construct the preset file path sPresetFile = String( "%1/%2" ) .arg( sPresetPath ) .arg( sAssetFilename ); // Post a status update App.statusLine( text( "Processing %1" ).arg( sAssetFilename ) ); // Execute the script with our arguments oScript.execute( [ sClassName, sTemplateFile, sPresetFile ] ); // Step the progress stepProgress(); // If a default file was specified if( !sDefaultPath.isEmpty() ){ // Load the file oContentMgr.openFile( sDefaultPath ); } // Process events so that we can check user interaction processEvents(); // If the user cancelled if( progressIsCancelled() ){ // Post a status update App.statusLine( text( "User cancelled." ) ); // We are done... break; } } // Finish the progress finishProgress(); // Clean up; do not leak memory oScript.deleteLater(); oAssetFileInfo.deleteLater(); // Finalize the function and invoke })();