User Tools

Site Tools


Save Filter Template Apply

Summary

Below is an example demonstrating how to read recorded settings for a save filter from a JSON template file and use them to control saving from that save filter.

See Also:

API Areas of Interest

Example

SaveFilter_Template_Apply.dsa
// Define an anonymous function;
// serves as our main loop,
// limits the scope of variables
(function(){
 
	// Get the arguments passed in
	var s_aArgs = getArguments();
 
	// 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.wTargetLEdit;
		this.wNameLEdit;
 
		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 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 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;
	};
 
	/*********************************************************************/
	// 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 target path
	DsInterface.prototype.getTargetPath = function()
	{
		// Get the target path
		var sPath = this.wTargetLEdit.text;
		// Get the target name
		var sName = this.wNameLEdit.text;
 
		// Return the path
		return !sPath.isEmpty() && !sName.isEmpty() ?
				String("%1/%2.duf").arg( sPath ).arg( sName ) : "";
	};
 
	/*********************************************************************/
	// 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.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, sTgtPath )
	{
		// 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( "Target :" );
		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( wMainWgt );
		lytBrowse.margin = 0;
		lytBrowse.spacing = 0;
 
		// Create a line edit
		this.wTargetLEdit = new DzLineEdit( wMainWgt );
		this.wTargetLEdit.placeholderText = text( "Select a destination file..." );
		this.wTargetLEdit.text = sTgtPath;
		// 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 );
 
		nRow += 1;
 
		// Create a label
		wLabel = new DzLabel( wMainWgt );
		wLabel.text = text( "Name :" );
		wLabel.alignment = DzWidget.AlignRight | DzWidget.AlignVCenter;
		// Add the label to the layout
		lytMain.addWidget( wLabel, nRow, 0 );
 
		// Create a widget
		var wNameWgt = new DzWidget( wMainWgt );
 
		// Create a horizontal box layout
		var lytName = new DzHBoxLayout( wNameWgt );
		lytName.margin = 0;
		lytName.spacing = 0;
 
		// Create a line edit
		this.wNameLEdit = new DzLineEdit( wMainWgt );
		this.wNameLEdit.placeholderText = text( "Enter a name for the file to save..." );
		// Connect
		this.wNameLEdit.textChanged.connect( s_oGui, s_oGui.updateAcceptButtonEnabled );
		// Add the line edit to the layout
		lytName.addWidget( this.wNameLEdit );
 
		// Create a label
		wLabel = new DzLabel( wMainWgt );
		wLabel.text = ".duf";
		// Add the label to the layout
		lytName.addWidget( wLabel );
 
		// Add the line edit to the layout
		lytMain.addWidget( wNameWgt, nRow, 1 );
 
		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 = 350;
 
		// Define the list of filters to exclude
		var aExclude = [ "DzSceneAssetFilter", "DzPuppeteerAssetFilter" ];
		// Populate the combobox with save filters
		this.buildSaveFilterCombobox( aExclude );
 
		// Populate the combobox with templates
		this.buildTemplateCombobox( aExclude );
 
		// 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(),
				"target": this.getTargetPath()
			};
		// If the user rejects the dialog
		} else {
			// return an empty object
			return {};
		}
	};
 
	/*********************************************************************/
	// void : A function for setting the required options
	function setRequiredOptions( oSettings, bShowOptions )
	{
		// Set the initial state of the compress file checkbox
		oSettings.setBoolValue( "CompressOutput", false );
 
		// Do not to show the options
		oSettings.setBoolValue( "RunSilent", !bShowOptions );
	};
 
	/***********************************************************************
	***** 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;
	};
 
	/*********************************************************************/
	// Define common message variables
	var sTitle = text( "Critical Error" );
	var sMessage = text( "An asset filter with the class name " +
			"\"%1\" could not be found.").arg( sClassName )
	var sButton = text( "&OK" );
 
	// 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 );
 
		// We are done...
		return;
	}
 
	// Initialize
	var sClassName = "";
	var sTemplateFile = "";
 	var sPresetPath = "";
 	var sPresetFile = "";
 
	// If three args were passed in, and they are all strings
	if( s_aArgs.length == 3 &&
	typeof( s_aArgs[0] ) == "string" &&
	typeof( s_aArgs[1] ) == "string" &&
	typeof( s_aArgs[2] ) == "string" ){
		// Update the classname of the filter to use
		sClassName = s_aArgs[0];
		// Update the template file path
		sTemplateFile = s_aArgs[1];
		// Update the save file path
		sPresetFile = s_aArgs[2];
	// If we are executed "standalone"
	} else {
		// 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 Apply",
					oRootNode.name,
					sPresetPath
				);
 
		// Get the classname of the filter to use
		sClassName = getObjectValue( oUserInput, "classname", "string" );
 
		// Get the path of the template file to use
		sTemplateFile = getObjectValue( oUserInput, "template", "string" );
 
		// Get the path of the file to save to
		sPresetFile = getObjectValue( oUserInput, "target", "string" );
	}
 
	// If the user cancelled
	if( sClassName.isEmpty() || sTemplateFile.isEmpty() || sPresetFile.isEmpty() ){
		// We are done...
		return;
	}
 
	// Get the asset IO manager
	var oAssetIOMgr = App.getAssetIOMgr();
	// Find the index of the asset filter with our classname
	var nAssetIOFilter = oAssetIOMgr.findFilter( sClassName );
	// If we did not find our asset filter
	if( nAssetIOFilter < 0 ){
		// Inform the user
		MessageBox.critical( sMessage, sTitle, sButton );
 
		// We are done...
		return;
	}
 
	// Get the asset filter at the prescribed index
	var oAssetIOFilter = oAssetIOMgr.getFilter( nAssetIOFilter );
	// If we do not have a valid asset filter
	if( !oAssetIOFilter ){
		// Inform the user
		MessageBox.critical( sMessage, sTitle, sButton );
 
		// We are done...
		return;
	}
 
	// Create a settings object
	var oSettings = new DzFileIOSettings();
 
	// Create a new file object
	var oTemplateFile = new DzFile( sTemplateFile );
 
	// Open the file for reading
	oTemplateFile.open( DzFile.ReadOnly );
 
	// Read the settings data from the file
	var sTemplateData = oTemplateFile.read();
 
	// Close the file
	oTemplateFile.close();
 
	// Clean up; do not leak memory
	oTemplateFile.deleteLater();
 
	// Populate the settings object from the data
	oSettings.fromString( sTemplateData );
 
	// Debug
	debug( "Read:", oSettings.toJsonString() );
 
	// Define the key used to refer to a node in node based filters
	var sKey = "NodeNames";
	// If the key is present
	if( oSettings.hasKey( sKey ) ){
		// Get the settings
		var oNamesSettings = oSettings.getSettingsValue( sKey );
		// Define the key of the settings to replace
		var sSelectionKey = "@selection";
		// If we have the settings and it has the setting to replace as a key
		if( oNamesSettings && oNamesSettings.hasKey( sSelectionKey ) ){
			// Get the setting to replace
			var oSelectionSettings = oNamesSettings.getSettingsValue( sSelectionKey );
			// If we have the settings
			if( oSelectionSettings ){
				// Copy the settings to a new settings with the root node name
				var oNodeSettings = oNamesSettings.setSettingsValue( oRootNode.name, oSelectionSettings );
				// Remove the setting to replace
				oNamesSettings.removeValue( sSelectionKey );
			}
		}
	}
 
	// Set required options; override read data if needed
	setRequiredOptions( oSettings, false );
 
	// Define whether or not to save metadata
	var bSaveMetadata = true;
 
	// Use the asset manager to save a file, with the filter and settings
	var oError = oAssetIOMgr.doSaveWithOptions( oAssetIOFilter,
			oSettings, !bSaveMetadata, sPresetFile, sPresetPath, "" );
 
	// Create a file info object for the load/save path
	var oLoadSaveFileInfo = new DzFileInfo( oAssetIOFilter.getDoSavePath() );
 
	// Update the filter load/save path
	oAssetIOFilter.setLoadSavePath( oLoadSaveFileInfo.path() );
 
	// If there was no error
	if( oError.valueOf() == 0x00000000 ){
		// Debug
		debug( "Saved:", sPresetFile );
	// If there was an error
	} else {
		// Debug
		debug( "Error:", getErrorMessage( oError ) );
	}
 
	// Clean up; do not leak memory
	oLoadSaveFileInfo.deleteLater();
	oAssetIOFilter.deleteLater();
 
// Finalize the function and invoke
})();