Below is an example demonstrating how one might go about parsing information from an .ini file, converting that information into a JSON object, providing a dialog that allows an end user to select options that modify the data, and then convert the data back into its original form - writing it back to the .ini file.
// DAZ Studio version 4.7.0.12 filetype DAZ Script // Define an anonymous function; // serves as our main loop, // limits the scope of variables (function(){ var s_sToolName = "Install Manager Configuration"; var s_sScriptPath = getScriptFileName(); var s_oScriptFile = new DzFileInfo( s_sScriptPath ); // Install Manager configuration file keywords var s_sAccount = "Account"; var s_sAccountTitle = "AccountTitle"; var s_sAllowDesktopShorcuts = "AllowDesktopShorcuts"; var s_sAllowStartMenuShorcuts = "AllowStartMenuShorcuts"; var s_sAppBitArch = "AppBitArch"; var s_sApplicationPaths = "ApplicationPaths"; var s_sAppName = "AppName"; var s_sAppPath = "AppPath"; var s_sAppVersion = "AppVersion"; var s_sAutoDelete = "AutoDelete"; var s_sAutoInstall = "AutoInstall"; var s_sCurInstallPath = "CurInstallPath"; var s_sCurrentTabIndex = "CurrentTabIndex"; var s_sDownloadDetailsToggled = "DownloadDetailsToggled"; var s_sDownloadDisplayHidden = "DownloadDisplayHidden"; var s_sDownloadPath = "DownloadPath"; var s_sDownloadSortIndex = "DownloadSortIndex"; var s_sGeneral = "General"; var s_sInstallDetailsToggled = "InstallDetailsToggled"; var s_sInstallDisplayHidden = "InstallDisplayHidden"; var s_sInstalledDetailsToggled = "InstalledDetailsToggled"; var s_sInstalledSortIndex = "InstalledSortIndex"; var s_sInstallPath = "InstallPath"; var s_sInstallPaths = "InstallPaths"; var s_sInstallPathTitle = "InstallPathTitle"; var s_sInstallSortIndex = "InstallSortIndex"; var s_sMarkInstalledContentAsNew = "MarkInstalledContentAsNew"; var s_sMaxConnections = "MaxConnections"; var s_sOverrideManifestDir = "OverrideManifestDir"; var s_sOverrideThumbnailDir = "OverrideThumbnailDir"; var s_sRememberPassword = "RememberPassword"; var s_sShowProductInfo = "ShowProductInfo"; var s_sShowTips = "ShowTips"; var s_sSize = "size"; var s_sSoftware32Path = "Software32Path"; var s_sSoftware64Path = "Software64Path"; var s_sTagID = "TagID"; var s_sTags = "Tags"; var s_sTagValue = "TagValue"; var s_sUpdatesToPrevious = "UpdatesToPrevious"; // Local keywords var s_sItems = "items"; // Keyword collections var s_aMultiPartSectionNames = [ s_sInstallPaths, s_sApplicationPaths, s_sTags ]; var s_aValidSectionNames = [ s_sGeneral ].concat( s_aMultiPartSectionNames ); var s_aGeneralKeyNames = [ s_sAccount, s_sAccountTitle, s_sAllowDesktopShorcuts, s_sAllowStartMenuShorcuts, s_sAutoDelete, s_sAutoInstall, s_sCurInstallPath, s_sCurrentTabIndex, s_sDownloadDetailsToggled, s_sDownloadDisplayHidden, s_sDownloadPath, s_sDownloadSortIndex, s_sInstallDetailsToggled, s_sInstallDisplayHidden, s_sInstalledDetailsToggled, s_sInstalledSortIndex, s_sInstallSortIndex, s_sMarkInstalledContentAsNew, s_sMaxConnections, s_sOverrideManifestDir, s_sOverrideThumbnailDir, s_sRememberPassword, s_sShowProductInfo, s_sShowTips, s_sSoftware32Path, s_sSoftware64Path, s_sUpdatesToPrevious ]; var s_aInstallPathsKeyNames = [ s_sInstallPathTitle, s_sInstallPath ]; var s_aApplicationPathsKeyNames = [ s_sAppName, s_sAppVersion, s_sAppBitArch, s_sAppPath ]; var s_aTagsKeyNames = [ s_sTagID, s_sTagValue ]; var s_aMultiPartKeyNames = [ s_sSize ].concat( s_aInstallPathsKeyNames, s_aApplicationPathsKeyNames, s_aTagsKeyNames ); var s_aValidKeyNames = s_aGeneralKeyNames.concat( s_aMultiPartKeyNames ); // Common strings var s_sNativeFormats = text( "DAZ Studio Formats" ); var s_sPoserFormats = text( "Poser Formats" ); var s_sOtherFormats = text( "Other Import Formats" ); // Helpers var s_oStringHelper = new DzStringHelper(); var s_oArrayHelper = new DzArrayHelper(); // Listview created in one function; referenced in another var s_wRemoteView = undefined; var s_wLocalView = undefined; /*********************************************************************/ // 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; }; /*********************************************************************/ // Array : Checks unique items, unchecks non-unique items function setUniqueItems( aKnownValues, wListView, nColumn, bIgnoreDepth, nDepth ) { // Initialize variables var aValues = aKnownValues; var nValues = aValues.length; // Declare working variables var wListViewItem; var sValue; // Get all of the items from the listview var aListItems = wListView.getItems( DzListView.All ); // Iterate over the items for( var i = 0; i < aListItems.length; i += 1 ){ // Get the 'current' item wListViewItem = aListItems[ i ]; // If we are ignoring items and the item is at the ignore depth if( bIgnoreDepth && wListViewItem.depth() == nDepth ){ // Uncheck it; if it's a controller it'll get checked // according to the checked state of it's children wListViewItem.on = false; // Next!! continue; } // Get the text from the item sValue = wListViewItem.text( nColumn ); // Append the text to our list, if it is not already there aValues = s_oArrayHelper.addToArray( aValues, sValue ); // If the text did not already exist in the list; the length of the array has grown if( aValues.length > nValues ){ // Check the item; i.e. it's unique wListViewItem.on = true; // Update our count nValues = aValues.length; // If the path already existed } else { // Uncheck the item; i.e. it is not unique wListViewItem.on = false; } } // Return the [modified] array return aValues; }; /*********************************************************************/ // void : Checks uniquely mapped directory items, unchecks non-unique items function setUniqueMappedDirs() { // If our listviews are not defined if( typeof( s_wRemoteView ) == undefined || typeof( s_wLocalView ) == undefined ){ // We are done... return; } // Define common values var nDataColumn = 1; var bSkipRoot = true; var nRootDepth = 0; // Check the items that are unique var aRemotePaths = setUniqueItems( [], s_wRemoteView, nDataColumn, bSkipRoot, nRootDepth ); var aUniquePaths = setUniqueItems( aRemotePaths, s_wLocalView, nDataColumn, bSkipRoot, nRootDepth ); }; /*********************************************************************/ // void : Adds the mapped directories known by Install Manager function addRemoteMappedPaths( wListView, aPathItems ) { // If we do not have paths if( aPathItems.length < 1 ){ // We are done return; } // Declare working variables var wPathItem; var sPath; var oPathItem; // Create the root item var wRootItem = new DzCheckListItem( wListView, DzCheckListItem.CheckBoxController ); // Set the text wRootItem.setText( 0, text( "All Current" ) ); // Expand the item; show it's children wRootItem.open = true; // Iterate over the mapped items, in reverse order, // because we want the same order as they currently // exist, and adding an item prepends to the list for( var i = aPathItems.length; i > 0; i -= 1 ){ // Get the 'current' item; we adjust the index // because we are iterating in reverse order oPathItem = aPathItems[ i - 1 ]; // Get the path from the item sPath = oPathItem[ s_sInstallPath ]; // Create an item for the path wPathItem = new DzCheckListItem( wRootItem, DzCheckListItem.CheckBox ); // Set the label wPathItem.setText( 0, oPathItem[ s_sInstallPathTitle ] ); // Set the path wPathItem.setText( 1, sPath ); } }; /*********************************************************************/ // void : Adds the mapped directories known by DAZ Studio as items, based on type function addLocalMappedPaths( wListView, sType ) { // Get the content manager var oContentMgr = App.getContentMgr(); // Initialize the number of directories var nDirs = -1; // Based on type, set the number of directories switch( sType ){ case s_sNativeFormats: nDirs = oContentMgr.getNumContentDirectories(); break; case s_sPoserFormats: nDirs = oContentMgr.getNumPoserDirectories(); break; case s_sOtherFormats: nDirs = oContentMgr.getNumImportDirectories(); break; default: return; } // If we have directories if( nDirs > 0 ){ // Create the root item for the type var wRootItem = new DzCheckListItem( wListView, DzCheckListItem.CheckBoxController ); // Set the text to the type wRootItem.setText( 0, sType ); // Expand the item; show it's children wRootItem.open = true; // Declare working variables var nDir; var sPath; var oFolder; var wPathItem; // Iterate over the directories, in reverse order, // because we want them displayed in the same order // as they currently exist, and adding an item // prepends to the list for( var i = nDirs; i > 0; i -= 1 ){ // Adjust the index because we are iterating in reverse order nDir = (i - 1); // Based on type, get the n'th folder switch( sType ){ case s_sNativeFormats: oFolder = oContentMgr.getContentDirectory( nDir ); break; case s_sPoserFormats: oFolder = oContentMgr.getPoserDirectory( nDir ); break; case s_sOtherFormats: oFolder = oContentMgr.getImportDirectory( nDir ); break; default: oFolder = undefined; break; } // If we do not have a folder if( !oFolder ){ // Next!! continue; } // Get the full path of the folder sPath = oFolder.fullPath; // Create an item for the path wPathItem = new DzCheckListItem( wRootItem, DzCheckListItem.CheckBox ); // Set the label wPathItem.setText( 0, oFolder.label ); // Set the path wPathItem.setText( 1, sPath ); } } }; /*********************************************************************/ // Array : Retrieve checked path items from a listview function getCheckedPathItems( wListView ) { // Define the array of items to be returned var aItems = []; // Declare working variables var wItem; var oItem; // Get the checked items var aCheckedItems = wListView.getItems( DzListView.Checked ); // Iterate over the checked items for( var i = 0; i < aCheckedItems.length; i += 1 ){ // Get the 'current' item wItem = aCheckedItems[ i ]; // If the item is at the root depth; i.e. it's a checkbox controller if( wItem.depth() == 0 ){ // Next!! continue; } // Define an object for the item oItem = {}; // Set the label oItem[ s_sInstallPathTitle ] = wItem.text( 0 ); // Set the path oItem[ s_sInstallPath ] = wItem.text( 1 ); // Add the item to the return array aItems = s_oArrayHelper.addToArray( aItems, oItem ); } // Return the path items return aItems; }; /*********************************************************************/ // Array : Prompt the user to choose directories to be mapped function getUserMappedDirs( sAccount, aAccountMappedItems ) { // Define common values var sObjectNamePrefix = s_oStringHelper.stripSpaces( s_sToolName ); var sLabel = text( "Label" ); var sPath = text( "Path" ); var sInstallManager = text( "Install Manager" ); var sContentPathShortcuts = text( "Content Path Shortcuts" ); var sRemoteTitle = String("%1 %2 :").arg( sInstallManager ).arg( sContentPathShortcuts ); var sLocalTitle = text( "%1 Mapped Directories :" ).arg( App.appName ); var sSelectUniques = text( "Select Uniques" ); // Create a basic dialog var wDlg = new DzBasicDialog(); // Set the title wDlg.caption = String("%1 (%2)").arg( s_sToolName ).arg( sAccount ); // Get the wrapped QWidget var oDlg = wDlg.getWidget(); // Set the object name; used to store/retrieve unique dialog geometry oDlg.objectName = sObjectNamePrefix; // Create a label var wLbl = new DzLabel( wDlg ); // Get the wrapped QWidget var oLbl = wLbl.getWidget(); // Set the object name; used for interactive lessons and inline help oLbl.objectName = String("%1DescriptionLbl").arg( sObjectNamePrefix ); // Set styling options on the label wLbl.wordWrap = true; // If the application version is 4.10.0.22 or newer if( App.version64 >= 0x0004000a00000016 ){ // Disable eliding wLbl.elideMode = DzWidget.ElideNone; } // Set the text wLbl.text = text( "Use the lists displayed below to select which paths to " + "map as %1 within %2.<br/><br/>The \"What's This?\" button, in the lower left " + "corner of this dialog, can be used to view more information about a " + "particular widget; simply press the button, then click on the widget." + "<hr>").arg( sContentPathShortcuts ).arg( sInstallManager ); // Add the label to the dialog wDlg.addWidget( wLbl ); // Create a group box var wRemoteGrpBx = new DzVGroupBox( wDlg ); // Get the wrapped QWidget var oRemoteGrpBx = wRemoteGrpBx.getWidget(); // Set the object name; used for interactive lessons and inline help oRemoteGrpBx.objectName = String("%1RemoteGrpBx").arg( sObjectNamePrefix ); // Set the title wRemoteGrpBx.title = sRemoteTitle; // Set styling options on the group wRemoteGrpBx.flat = true; wRemoteGrpBx.insideMargin = nMargin; // Set the what's this text wRemoteGrpBx.whatsThis = String("<b>%1 %2</b><br/><br/>%3") .arg( sInstallManager ) .arg( sContentPathShortcuts ) .arg( text( "Use this list to indicate which of the %1 currently defined in " + "%2, for the current account, you would like to keep defined.<br/><br/>By " + "default, and upon pressing the \"%3\" button, all of the items in this " + "list that have a unique path will be checked; all items that do not have " + "a unique path will be unchecked.") .arg( sContentPathShortcuts ) .arg( sInstallManager ) .arg( sSelectUniques ) ); // Add the group box to the dialog wDlg.addWidget( wRemoteGrpBx ); // Get the current style var oStyle = App.getStyle(); // Get pixel metrics from the style var nMargin = oStyle.pixelMetric( "DZ_GeneralMargin" ); var nStepSize = oStyle.pixelMetric( "DZ_TreeStepSize" ); // Create a listview; for remote mappings // we'll see why its defined as a global shortly s_wRemoteView = new DzListView( wRemoteGrpBx ); // Get the wrapped QWidget var oListView = s_wRemoteView.getWidget(); // Set the object name; used for interactive lessons and inline help oListView.objectName = String("%1RemoteLView").arg( sObjectNamePrefix ); // Add the label column s_wRemoteView.addColumn( sLabel ); // Add the path column s_wRemoteView.addColumn( sPath ); // Set selection to highlight all columns s_wRemoteView.allColumnsShowFocus = true; // Disable sorting; set the sorting column to none s_wRemoteView.setSorting( -1 ); // Set styling options on the listview s_wRemoteView.itemMargin = nMargin; s_wRemoteView.treeStepSize = nStepSize; // Set the what's this text s_wRemoteView.whatsThis = wRemoteGrpBx.whatsThis; // Add items for the known mappings; addRemoteMappedPaths( s_wRemoteView, aAccountMappedItems ); // Create a label var wLocalGrpBx = new DzVGroupBox( wDlg ); // Get the wrapped QWidget var oLocalGrpBx = wLocalGrpBx.getWidget(); // Set the object name; used for interactive lessons and inline help oLocalGrpBx.objectName = String("%1LocalGrpBx").arg( sObjectNamePrefix ); // Set the title wLocalGrpBx.title = sLocalTitle; // Set styling options on the group wLocalGrpBx.flat = true; wLocalGrpBx.insideMargin = nMargin; // Set the what's this text wLocalGrpBx.whatsThis = String("<b>%1</b><br/><br/>%2") .arg( sLocalTitle.replace( " :", "" ) ) .arg( text( "Use this list to indicate which of the %1 you would like to " + "make available as shortcuts within %2, for the current account.<br/><br/>" + "Avoid selecting more than one entry with the same path in this list and " + "the \"%3\" list. Use the \"%4\" button to help select the paths that are " + "unique in both lists.") .arg( sLocalTitle.replace( " :", "" ) ) .arg( sInstallManager ) .arg( sRemoteTitle.replace( " :", "" ) ) .arg( sSelectUniques ) ); // Add the label to the dialog wDlg.addWidget( wLocalGrpBx ); // Create a listview; for locally known mappings // we'll see why its defined as a global shortly s_wLocalView = new DzListView( wLocalGrpBx ); // Get the wrapped QWidget oListView = s_wLocalView.getWidget(); // Set the object name; used for interactive lessons and inline help oListView.objectName = String("%1LocalLView").arg( sObjectNamePrefix ); // Add the label column s_wLocalView.addColumn( sLabel ); // Add the path column s_wLocalView.addColumn( sPath ); // Set selection to highlight all columns s_wLocalView.allColumnsShowFocus = true; // Disable sorting; set the sorting column to none s_wLocalView.setSorting( -1 ); // Set styling options on the listview s_wLocalView.itemMargin = nMargin; s_wLocalView.treeStepSize = nStepSize; // Set the what's this text s_wLocalView.whatsThis = wLocalGrpBx.whatsThis; // Add items for the mapped directories; // we do this in reverse of the order we want them // to be displayed in, because adding an item // prepends it to the list and we are not sorting addLocalMappedPaths( s_wLocalView, s_sOtherFormats ); addLocalMappedPaths( s_wLocalView, s_sPoserFormats ); addLocalMappedPaths( s_wLocalView, s_sNativeFormats ); // Set the [unique] paths checked by default setUniqueMappedDirs(); // Create a button var wUniquesBtn = new DzPushButton( wDlg ); // Get the wrapped QWidget var oUniquesBtn = wUniquesBtn.getWidget(); // Set the object name; used for interactive lessons and inline help oUniquesBtn.objectName = String("%1UniquesBtn").arg( sObjectNamePrefix ); // Set the text wUniquesBtn.text = sSelectUniques; // Set the tooltip text wUniquesBtn.toolTip = text( "Click to restore the selection of unique paths in both lists" ); // Set the what's this text wUniquesBtn.whatsThis = String("<b>%1</b><br/><br/>%2.<br/><br/>%3") .arg( wUniquesBtn.text ).arg( wUniquesBtn.toolTip ) .arg( text( "The path of each item in the \"%1\" and \"%2\" lists are checked " + "for uniqueness. If the path of an item is unique, that item becomes " + "checked. If the path of an item is not unique, that item becomes " + "unchecked. Root items are \"tri-state\"; they become checked or " + "unchecked according to the checked state of their respective children.") .arg( sRemoteTitle.replace( " :", "" ) ) .arg( sLocalTitle.replace( " :", "" ) ) ); // Add the button to the dialog button box wDlg.addButton( wUniquesBtn ); // Connect the button pressed signal to the function that checks unique paths; // the function depends on the listview being defined, and so this is why we // defined the listview in the global scope connect( wUniquesBtn, "pressed()", setUniqueMappedDirs ); // If the user cancelled if( !wDlg.exec() ){ // Return an empty array return []; } // Get the checked remote items var aItems = getCheckedPathItems( s_wRemoteView ); // Get the checked local items, too aItems = aItems.concat( getCheckedPathItems( s_wLocalView ) ); // Return the checked items return aItems; }; /*********************************************************************/ // String : Prompt the user to choose an account function getUserAccount( aAccounts ) { // Get the current author var oAuthor = App.getCurrentAuthor(); // Get the name of the author var sAuthor = oAuthor.name // Create a basic dialog var wDlg = new DzBasicDialog(); // Set the title wDlg.caption = s_sToolName; // Get the wrapped QWidget var oDlg = wDlg.getWidget(); // Set the object name; used to store/retrieve unique dialog geometry oDlg.objectName = s_oStringHelper.stripSpaces( s_sToolName ) + "Account"; // Create a button group var wAccountGrp = new DzVButtonGroup( wDlg ); // Get the wrapped QWidget oAccountGrp = wAccountGrp.getWidget(); // Set the object name; used for interactive lessons and inline help oAccountGrp.objectName = oDlg.objectName + "BGrp"; // Set the title of the group wAccountGrp.title = text( "Choose an Account :" ); // Declare working variables var wRadioBtn; var oRadioBtn; var sLabel; var sWhatsThis = String("<b>%1</b><br/><br/>%2."); // Iterate over the accounts for( var i = 0; i < aAccounts.length; i += 1 ){ // Create a radio button wRadioBtn = new DzRadioButton( wAccountGrp ); // Get the wrapped QWidget oRadioBtn = wRadioBtn.getWidget(); // Set the object name; used for interactive lessons and inline help oRadioBtn.objectName = oDlg.objectName + "RBtn"; // Get the URI decoded name of the account sLabel = decodeURIComponent( aAccounts[i] ); // Strip the file extension from the label sLabel = sLabel.substring( 0, sLabel.lastIndexOf(".") ); // Set the button text wRadioBtn.text = sLabel; // Set the tooltip text wRadioBtn.toolTip = text( "Select to modify the \"%1\" account" ).arg( sLabel ); // Set the what's this text wRadioBtn.whatsThis = sWhatsThis.arg( sLabel ).arg( wRadioBtn.toolTip ); // Add the button to the group wAccountGrp.addButton( wRadioBtn, i ); // If the label is the current author if( sLabel == sAuthor ){ // Set that button as the default wRadioBtn.checked = true; } } // If no default was set if( wAccountGrp.selected < 0 && wRadioBtn ){ // Set the last button as the defalt wRadioBtn.checked = true; } // Add the group to the dialog wDlg.addWidget( wAccountGrp ); // If the user doesn't cancel if( wDlg.exec() ){ // Return the user's choice return aAccounts[ wAccountGrp.selected ]; } // Return no choice made return ""; }; /*********************************************************************/ // Object : Reads an Install Manager configuration *.ini and converts it to a JSON object function parseInstallManagerConfig( sConfigPath ) { // Initialize the return object var oData = {}; // Create a file object for the config var oConfigFile = new DzFile( sConfigPath ); // Open the file for reading oConfigFile.open( DzFile.ReadOnly ); // Read the lines from the file var aLines = oConfigFile.readLines(); // Close the file oConfigFile.close(); // Declare working variables var sLine = ""; var aParts = [], aItems = []; var sSection = "", sKey = "", sValue = ""; var nKey = 0, nValue = 0; var vValue = undefined; var oSection, oItem; var bInRange; // Iterate over the lines for( var i = 0; i < aLines.length; i += 1 ){ // Get the 'current' line, trimmed of leading/trailing whitespace sLine = aLines[i].trim(); // If the line is empty if( sLine.isEmpty() ){ // Next!! continue; } // Split the line between key and value aParts = sLine.split( "=" ); // Set the key to the first part sKey = aParts.shift(); // Set the value to the rest sValue = aParts.join( "=" ); // If the key starts and ends with square brackets if( sKey.startsWith( "[" ) && sKey.endsWith( "]" ) ){ // If we have a section and a name if( oSection && !sSection.isEmpty() ){ // Update the section oData[ sSection ] = oSection; } // Get the name of the section sSection = sKey.substring( 1, sKey.length - 1 ); // If the section name is not valid if( s_aValidSectionNames.indexOf( sSection ) < 0 ){ // Reset the section name sSection = ""; // Record/report the problem print( "Invalid Section :", sKey ); } // Create a section object oSection = {}; // Next line!! continue; } // If we do not have a value if( sValue.isEmpty() ){ // Next!! continue; } // If the key is multi-part; index\key if( sKey.indexOf( "\\" ) > -1 ){ // Split the key aParts = sKey.split( "\\" ); // Set the index from the first part; adjust for zero-based nKey = Number( aParts.shift() ) - 1; // Set the key to the rest sKey = aParts.join( "\\" ); // If the key is not multi-part } else { // Set the index to be outside the valid multi-part range nKey = -1; } // If the key name is not valid if( s_aValidKeyNames.indexOf( sKey ) == -1 ) { // Record/report the problem print( "Invalid Key :", sKey ); // Next line!! continue; } // If the value is the string representation of true if( sValue == "true" ){ // Set the value to record to the boolean vValue = true; // If the value is the string representation of false } else if( sValue == "false" ){ // Set the value to record to the boolean vValue = false; // If the value is the string representation of a number } else if( Number( sValue ) == sValue ){ // Convert the string to a number nValue = Number( sValue ); // If the number is fractional if( nValue % 1 > 0 ){ // Set the value to record to the floating point conversion vValue = parseFloat( sValue ); // If the number is whole } else { // Set the value to record to the integer conversion vValue = parseInt( sValue ); } // If the value is a string } else { // Set the value to record to the string vValue = sValue; } // If the name of the key is 'size' if( sKey == s_sSize ){ // Pre-size an array for the items aItems = new Array( vValue ); } // If the key index is within range; it's a multi-part key bInRange = (nKey > -1 && nKey < aItems.length); if( bInRange ){ // Get the 'current' item oItem = aItems[ nKey ]; // If the object is null; it will be the first time, // due to pre-sizing the array if( oItem == null ){ // Create a new object oItem = {}; } } // If we have an item and the index is in range; multi-part key if( oItem && bInRange ){ // Set the item's key to the value oItem[ sKey ] = vValue; // Update the item in the array aItems[ nKey ] = oItem; // Update the section with the items oSection[ s_sItems ] = aItems; // If the key is anything other than 'size' } else if( sKey != s_sSize ){ // Set the value of the key, in the 'current' section oSection[ sKey ] = vValue; } } // If the section is named if( !sSection.isEmpty() ){ // Update the section on the data object oData[ sSection ] = oSection; } // Return the data object return oData; }; /*********************************************************************/ // void : Converts Install Manager configuration data (JSON) and writes to an *.ini file function writeInstallManagerConfig( sConfigPath, oConfigData ) { // Create a file object for the config var oConfigFile = new DzFile( sConfigPath ); // Open the file for writing oConfigFile.open( DzFile.WriteOnly ); // Declare working variables var aKeyNames, aItemNames, aItems; var sSection, sKey, sValue; var oSection, oItem; // Get the section names from the object var aSectionNames = Object.keys( oConfigData ); // Iterate over the section names for( var i = 0; i < aSectionNames.length; i += 1 ){ // If this is not the first iteration if( i > 0 ){ // Write an empty separation line oConfigFile.writeLine( "" ); } // Get the 'current' section name sSection = aSectionNames[ i ]; // Write the section line oConfigFile.writeLine( String("[%1]").arg( sSection ) ); // Get the 'current' section object oSection = oConfigData[ sSection ]; // If we do not have an object if( !oSection ){ // Next!! continue; } // Get the key names from it aKeyNames = Object.keys( oSection ); // Iterate over the key names for( var j = 0; j < aKeyNames.length; j += 1 ){ // Get the 'current' key name sKey = aKeyNames[ j ]; // If the key is not named "items" if( sKey != s_sItems ){ // Write the key and its value oConfigFile.writeLine( String("%1=%2") .arg( sKey ).arg( oSection[ sKey ] ) ); // Next!! continue; } // Get the items array aItems = oSection[ sKey ]; // Write the 'size' key and value for this section oConfigFile.writeLine( String("%1=%2") .arg( s_sSize ).arg( aItems.length ) ); // Iterate over the items for( var k = 0; k < aItems.length; k += 1 ){ // Get the 'current' item oItem = aItems[ k ]; // Get the names of the keys aItemNames = Object.keys( oItem ); // Iterate over the key names for( var m = 0; m < aItemNames.length; m += 1 ){ // Get the 'current' key sKey = aItemNames[ m ]; // Write the multi-part key and value for this item oConfigFile.writeLine( String("%1\\%2=%3") .arg( k + 1 ).arg( sKey ).arg( oItem[ sKey ] ) ); } } } } // Close the file oConfigFile.close(); }; /*********************************************************************/ // void : Do... whatever it is we do function begin() { // Get the appdata directory var oConfigDir = new DzDir( App.getAppDataPath() ); // Up a directory; out of the application's directory oConfigDir.cdUp(); // Change to the Install Manager directory oConfigDir.cd( "InstallManager" ); // Change to the user accounts directory oConfigDir.cd( "UserAccounts" ); // Declare working variable for the config path var sConfigPath = String("%1/Account.ini").arg( oConfigDir.path() ); // Get all of the ini files in the directory var aConfigFiles = oConfigDir.entryList( "*.ini", DzDir.Files ); // If there is only one if( aConfigFiles.length == 1 ){ // Use it sConfigPath = String("%1/%2").arg( oConfigDir.path() ).arg( aConfigFiles[0] ); // If there are multiple } else if( aConfigFiles.length > 1 ) { // Prompt the user to pick one sConfigPath = String("%1/%2").arg( oConfigDir.path() ).arg( getUserAccount( aConfigFiles ) ); } // Create a file info object var oConfigFile = new DzFileInfo( sConfigPath ); // If the file doesn't exist if( !oConfigFile.exists() ){ // Inform the user MessageBox.information( text( "An account configuration file could not be found. Create an account " + "using Install Manager and then try again."), s_sToolName, text( "&OK" ) ); // We cannot continue return; } // Convert the config file at the path to a JSON object var oConfigData = parseInstallManagerConfig( sConfigPath ); // If the JSON object has install paths defined if( oConfigData.hasOwnProperty( s_sInstallPaths ) ){ // Prompt the user to choose which ones they want mapped var aInstallPaths = getUserMappedDirs( decodeURIComponent( oConfigFile.baseName() ), oConfigData[ s_sInstallPaths ][ s_sItems ] ); // If the user did not cancel (or choose none) if( aInstallPaths.length > 0 ){ // Update the JSON object with the user's choices oConfigData[ s_sInstallPaths ][ s_sItems ] = aInstallPaths; // Write the config data to file writeInstallManagerConfig( sConfigPath, oConfigData ); } } }; /*********************************************************************/ // Start doing stuff begin(); // Finalize the function and invoke })();