Save and load user‘s ComboBox values

Hi!

I’m looking for a solution which makes it possible for the user to save the current selections of the ComboBoxes in a named file and load them again if the user needs exactly these settings again.

All I found was this: http://macscripter.net/viewtopic.php?id=24606

But as I’m new to scripting at all I’m not sure if
“this is what I have to search for
“this is what I need
“it’s possible at all

I’m using Xcode 5.1.1 on OS X 10.9

Thanks for your help!

That posting was for AppleScript Studio, which is no longer supported. The easiest way to do what you want is to use bindings, and bind the value of each combo box to the Shared User Defaults Controller.

Thanks a lot! I bought your e-book and can now understand much more. Great work!

But I think in this case the User Defaults is not the solutions for me because I want the different combinations of many ComboBoxes’ values to save in different files and load them at a later point.

I managed to write the values of the ComboBox to a .plist. I didn’t use bindings as you suggested because I think they would collide with the Referencing Outlets I use for the same ComboBox in another part of the script. But nevertheless it works out for me so far.
Now I want to load them from the .plist back into the ComboBox respectively set the value of the ComboBox. I expected a line like

set ComboBox1's stringValue() to loadedChoiceComboBox1

could do that. But it seems much more difficult. This is the save/load part of my code (I deleted the many other ComboBoxes):


    on saveSettings_(sender)
        
        tell application "System Events"
            -- create an empty property list dictionary item
            set the parent_dictionary to make new property list item with properties {kind:record}
            -- create new property list file using the empty dictionary list item as contents
            set the plistfile_path to "~/Desktop/example.plist"
            set this_plistfile to ¬
            make new property list file with properties {contents:parent_dictionary, name:plistfile_path}
            -- add new property list items of each of the supported types
            make new property list item at end of property list items of contents of this_plistfile ¬
            with properties {kind:boolean, name:"ChoiceComboBox1", value: ComboBox1's stringValue() as text}
        end tell
        
    end saveSettings_
    
    on loadSettings_(sender)
    
        set the plistfile_path to "~/Desktop/example.plist"
        tell application "System Events"
            tell property list file plistfile_path
                tell contents
                    set loadedChoiceComboBox1 to value of property list item "ChoiceComboBox1" as text
                    set ComboBox1's stringValue() to loadedChoiceComboBox1
                end tell
            end tell
        end tell
    
    end loadSettings_

Also I’m not sure if a boolean kind is the write way to store the data.

Any suggestions, solutions, comments?

Thanks!

You don’t need to use System Events: use ASObjC. Just build your list of records, convert it to an NSArray, then save that using -writeToFile:atomically:, and read it in again using -arrayWithContentsOfFile:.

Sorry I don’t get it but maybe I’m getting nearer. I managed to build the ComboBox’s values via bindings to an Array Controller which has a binding to a list as you describe it in your book.
What doesn’t work is writing the .plist with writeToFile (it still works with System Events).

The problem:

Unrecognized function writeToFile_atomically_
Unrecognized function arrayWithArray_

why do these functions not work?



property theValues: {"apple", "banana", "orange"}

on saveSettings_(sender)
    
   theValues's writeToFile:"/desktop/xxx.plist" atomically:true
    
end saveSettings_

You need to make an NSArray first:

property theValues: {"apple", "banana", "orange"}

on saveSettings_(sender)
set anNSArray to current application's NSArray's arrayWithArray:theValues
anNSArray's writeToFile:"/desktop/xxx.plist" atomically:true
end saveSettings_

Hi!

I finally managed saving a ComboBox’s value into a .plist file and updateing it by loading the value from the .plist again. Heres the code:

    on saveSettings_(sender)-- save settings to .plist file
        tell application "System Events"
            -- create an empty property list dictionary item
            set the parent_dictionary to make new property list item with properties {kind:record}
            -- create new property list file using the empty dictionary list item as contents
            set the plistfile_path to "~/Desktop/myes_settings.plist"
            set this_plistfile to ¬
            make new property list file with properties {contents:parent_dictionary, name:plistfile_path}
            -- add new property list items of each of the supported types
            make new property list item at end of property list items of contents of this_plistfile ¬
            with properties {kind:boolean, name:"ChoiceComboBox1", value: ComboBox1's stringValue() as text}
        end tell
    end saveSettings_
on loadSettings_(sender)--loading .plist
        set theOutputFolder to path to desktop folder as string
        set thePListPath to POSIX path of (theOutputFolder & "myes_settings.plist")
        tell application "System Events"
            tell property list file thePListPath
                tell contents
                    
                    ComboBox1's selectItemWithObjectValue_(value of property list item "ChoiceComboBox1")

                end tell
            end tell
        end tell
        
    end loadSettings_

To make it more comfortable I’d like to give the user the chance to have a modal dialog where he can define filename and directory. I started with chapter 17 in your book and used

tell current application's NSSavePanel to set thePanel to makeSaveAt_types_name_prompt_title_(path to home folder, {"plist"}, "Project_Font", "Save the file", "Save As")
        tell thePanel to set thePath to showModal()
        if thePath = missing value then
            log "Cancel pressed"
            else
            log thePath
        end if

to have a modal dialog.
What I don’t understand is how to combine the two things. Can’t I just pass the variable thePath to the ºtell application "System Events"¹?

Go back and read message #4. You don’t need to use System Events at all to read in the property list – it’s just slowing things down.

Again thanks for your respond! :slight_smile:
Okay, but this gives me only a .plist with the content of theValues. Am I doing something wrong?

    on saveSettings_(sender)
        
        set theOutputFolder to path to desktop folder as string
        set thePListPath to POSIX path of (theOutputFolder & "Settings2.plist")
        set anNSArray to current application's NSArray's arrayWithArray:theValues
        anNSArray's writeToFile: thePListPath atomically:true
        
    end saveSettings_

this leads to a .plist like:

fixed no-break space no-break space 1 em 1/2 em 1/3 em 1/4 em 1/6 em 1/8 em 1/24 em

I want the users choice of the 9 possibilities above of more than 40 ComboBoxes in a .plist like:

ChoiceComboBox1 1/2 em ChoiceComboBox2 1/8 em ChoiceComboBox3 1/24 em ChoiceComboBox4 1 em ChoiceComboBox5 1/24 em ChoiceComboBox6 1/8 em ...

Would your proposal make it also easier to have a modal save/load dialog?

You want to save a dictionary (ie, record) of the values, not an array/list. The saving method is the same. How you build the dictionary is up to you.

But if the choices are a fixed list, you should probably be using menus or matrixes rather than comboboxes.

Getting closer! I think ComboBoxes are the right choice for my intention.

The code for storing the choice of a ComboBox into a file combined with a modal save dialog:

set thePanel to current application's NSSavePanel's savePanel()
        tell thePanel
            its setMessage:"Save the data:"
            its setAllowedFileTypes:{"plist"}
            its setNameFieldStringValue:"Project_Fontname"
            its setShowsHiddenFiles:false
            its setTreatsFilePackagesAsDirectories:false
            set returnCode to its runModal() as integer
        end tell
        if returnCode = (current application's NSFileHandlingPanelOKButton) as integer then
            set thePosixPath to thePanel's |URL|()'s |path|()
            
            set ChoiceComboBox1 to objectValueOfSelectedItem of ComboBox1
            ChoiceComboBox1's writeToFile: thePosixPath atomically:true
            
            else
            -- cancel button
            log "Cancel pressed"
        end if

First thing is that I’m not sure how to put all values of the ComboBoxes in one file, the second thing is that it’s actually not a real .plist with and . Not sure if I can access them properly via e.g. “line 3” or something.

To me it would be easier if I could figure out why this doesn’t work:

on saveSettings_(sender)-- save settings to .plist file
        set thePanel to current application's NSSavePanel's savePanel()
        tell thePanel
            its setMessage:"Save the data:"
            its setAllowedFileTypes:{"plist"}
            its setNameFieldStringValue:"Project_Fontname"
            its setShowsHiddenFiles:false
            its setTreatsFilePackagesAsDirectories:false
            set returnCode to its runModal() as integer
        end tell
        if returnCode = (current application's NSFileHandlingPanelOKButton) as integer then
            
            tell application "System Events"
                -- create an empty property list dictionary item
                set the parent_dictionary to make new property list item with properties {kind:record}
                -- create new property list file using the empty dictionary list item as contents
                set the plistfile_path to thePanel's |URL|()'s |path|()
                set this_plistfile to ¬
                make new property list file with properties {contents:parent_dictionary, name:plistfile_path}
                -- add new property list items of each of the supported types
                make new property list item at end of property list items of contents of this_plistfile ¬
                with properties {kind:boolean, name:"ChoiceComboBox1", value: ComboBox1's stringValue() as text}
                make new property list item at end of property list items of contents of this_plistfile ¬
                with properties {kind:boolean, name:"ChoiceComboBox2", value: ComboBox2's stringValue() as text}
                make new property list item at end of property list items of contents of this_plistfile ¬
                with properties {kind:boolean, name:"ChoiceComboBox3", value: ComboBox3's stringValue() as text}
                make new property list item at end of property list items of contents of this_plistfile ¬
                with properties {kind:boolean, name:"ChoiceComboBox4", value: ComboBox4's stringValue() as text}
                make new property list item at end of property list items of contents of this_plistfile ¬
                with properties {kind:boolean, name:"ChoiceComboBox5", value: ComboBox5's stringValue() as text}
                make new property list item at end of property list items of contents of this_plistfile ¬
                with properties {kind:boolean, name:"ChoiceComboBox6", value: ComboBox6's stringValue() as text}
                make new property list item at end of property list items of contents of this_plistfile ¬
                with properties {kind:boolean, name:"ChoiceComboBox7", value: ComboBox7's stringValue() as text}
                make new property list item at end of property list items of contents of this_plistfile ¬
                with properties {kind:boolean, name:"ChoiceComboBox8", value: ComboBox8's stringValue() as text}
                make new property list item at end of property list items of contents of this_plistfile ¬
                with properties {kind:boolean, name:"ChoiceComboBox9", value: ComboBox9's stringValue() as text}
                make new property list item at end of property list items of contents of this_plistfile ¬
                with properties {kind:boolean, name:"ChoiceComboBox10", value: ComboBox10's stringValue() as text}
...
                
            end tell
            else
            -- cancel button
            log "Cancel pressed"
        end if
        
        
    end saveSettings_

Is it because of the limited scope of the variable?

No, it would be easier if you did as I suggested:

set theDict to current application's NSDictionary's dictionaryWithObjects:{ComboBox1's stringValue(), ComboBox2's stringValue(), ...} forKeys:{"ChoiceComboBox1", "ChoiceComboBox2", ...}
theDict's writeToURL:(thePanel's URL {}) atomically:true

Yes, you’re right! That would be much easier. Sorry, as you see Im not deep into it. :rolleyes:

Now I get this message, which confuses me:

2014-07-21 13:33:23.273 Myes 2.1[608:303] -[NSAppleEventDescriptor isFileURL]: unrecognized selector sent to instance 0x618000030de0
2014-07-21 13:33:23.277 Myes 2.1[608:303] *** -[AppDelegate saveSettings:]: -[NSAppleEventDescriptor isFileURL]: unrecognized selector sent to instance 0x618000030de0 (error -10000)

    on saveSettings_(sender)
        
        set thePanel to current application's NSSavePanel's savePanel()
        
        tell thePanel
            its setMessage:"Save the data:"
            its setAllowedFileTypes:{"plist"}
            its setNameFieldStringValue:"Project_Fontname"
            its setShowsHiddenFiles:false
            its setTreatsFilePackagesAsDirectories:false
            set returnCode to its runModal() as integer
        end tell
        
        if returnCode = (current application's NSFileHandlingPanelOKButton) as integer then
            set theDict to current application's NSDictionary's dictionaryWithObjects:{ComboBox1's stringValue(), ComboBox2's stringValue()} forKeys:{"ChoiceComboBox1", "ChoiceComboBox2"}
            theDict's writeToURL:(thePanel's URL {}) atomically:true
        end if
        
    end saveSettings_

There’s a terminology conflict – it should be: |URL|(), not URL {}.

It works perfectly! Thank u so much!

One last thing. Do I have to use “objectForKey_(“ChoiceComboBox1”)” to call it again? Or “ComboBox1’s selectItemWithObjectValue_(value of property list item “ChoiceComboBox1”)”

I suppose its no longer -arrayWithContentsOfFile: as you suggested it in post #4.

    on loadSettings_()
            -- set up open panel
        set thePanel to current application's NSOpenPanel's openPanel()
        tell thePanel
            its setMessage:"Choose an .plist:"
            its setExtensionHidden:false
            its setShowsHiddenFiles:false
            its setTreatsFilePackagesAsDirectories:false
            its setCanChooseFiles:true
            its setCanChooseDirectories:false
            its setAllowsMultipleSelection:false
            its setResolvesAliases:true
            set theResult to its runModal() -- show as a modal dialog
        end tell
        if theResult = current application's NSFileHandlingPanelOKButton then
            set theURLs to thePanel's |URLs|() as list
            return item 1 of theURLs
            
            ComboBox1's objectForKey_("ChoiceComboBox1")--????

            else -- user hit Cancel
            return missing value
        end if
    end loadSettings_

You’d read it like this:

set theNSDictionary to current application's NSDictionary's dictionaryWithContentsOfURL:(thePanel's |URLs|()'s objectAtIndex:0)