revUp - Updates and news for the Revolution community
Issue 99 | oct 28th 2010 Contact the Editor | How to Contribute

Collecting User Preferences: Part 1
How to painlessly get and set your user preferences in a LiveCode application

by Klaus Major

Hello and welcome to part 1 (of 2) of my newsletter article.

As many of you will be aware, modern operating systems lock running executables so you need to take some care to save your users preferences correctly and avoid the experience of having everything your user entered disappear when the standalone is closed.

LiveCode offers to save your (sub-)stacks as separate files when saving as a standalone, but this will not work for most of you! Modern operation systems are in fact multi-user systems and are very picky when it comes to writing files. If the current user of your software is not logged-in as an administrator then this method will also fail, since only the administrator has write permission in the application folder.

To show you that we can store all this info in a text file in a place where we definitely do have write permission, I wrote this article.

In this part we will learn how to store user preferences (contents of text fields, hilite states of buttons and thumbpositions of scrollbars) in a text file and of course how we can put these settings back into our application.

Please download the little example stack here, you will find everything discussed below in the stack scripts of the main- and the substack.

It is just a simple stack with a substack where you/the user can enter a name, select a folder, check some checkboxes and scroll a scrollbar.


To check it out, you should open that stack, go to the prefs, do some settings, close the prefs stack and then quit LiveCode without saving. When you open the stack the next time all your input is there as you left it!

What do we need for this purpose?
1. A place where we do have write permissions on the users hard disk.

I wrote this little function that will return a folder where we definitively have write permission. See my comments for further info about these folder on the different platforms!

Hint:
There are some caveats on Windows Vista, please check this URL for further information.

## This function will return the path to the current users
# preferences folder
## /Users/User name/Library/Preferences on the Mac and
## C:/Documents and Settings/User Name/Application Data
## and the path to the current users HOME folder on Linux
function mkprefsfolder
   
   ## Check the platform to decide where to store the file(s)
   switch the platform
      case "MacOS"
         
         ## The folder "Preferences" in the current users
         # "Library" folder:
         put specialFolderPath("preferences") into spfp
         break
      case "Win32"
         
         ## Everything >= Win2000
         if the systemversion contains "NT" then
            put specialFolderPath(26) into spfp
         else
            
            ## Win95, 96, 97, 98, 98ME and 99 :-)
            ## Should be something like C:/System
            ## But I am not sure...
            put specialfolderpath("system") into spfp
         end if
         break
      default
         
         ## Linux
         ## The current users HOME folder
         put $HOME into spfp
         break
   end switch
   
   ## It is good style to create subfolder with the name of
   # your APP or Company there!
   ## I use a folder named "RevNewsLetter10_2010", so you can
   # find and delete it later!
   if there is not a folder (spfp & "/RevNewsLetter10_2010") then
      create folder (spfp & "/RevNewsLetter10_2010" )
   end if
   
   ## Return the path including trailing SLASH, ready for use!
   return (spfp & "/RevNewsLetter10_2010/")
end mkprefsfolder 

2. We need a function to get the content of already saved prefs-files.

This function will return EMPTY if there is no file yet!
Hint: You can give your file any name and externsion you like!

## This function will rertun the content of our previously
# saved prefs file or EMPTY,
## if the file has not yet been saved!
function mk_getprefs
   put mkprefsfolder() into tPath
   if there is a file (tPath & "my_first_prefs.txt") then
      return url("file:" & tPath & "my_first_prefs.txt")
   else
      ## not yet saved
      return empty
   end if
end mk_getprefs 

3. And we need another function that will store the complete prefs that we will pass to this function as (the only) parameter.

This could also be a handler, but this way we can check if the function returns empty on success or not and inform the user that there were some problems when writing the prefs to file.

## This finction will write the complete prefs to the above
# mentioned file:
## This could also be a HANDLER but making it a finction we can
# check if the writing
## of the text file did not encounter any error!
function mk_setprefs tPrefs
   put mkprefsfolder() into tPath
   
   ## We write the prefs "en bloc" to the file
   put tPrefs into url("file:" & tPath & "my_first_prefs.txt")
   
   ## This will be empty if everything is OK, but will contain
   # a hint on what might have gone wrong
   return the result
end mk_setprefs 

These functions are stored in the script of the mainstack.

4. We need create a format for storing our prefs in text format.

There are surely a lot more ways to make this possible but I choose this format:
  • One prefs per line and the infos divided by a TAB, so we can "set the itemdel to TAB" and access all necessary information
  • Type of object (field, button or scrollbar) TAB Name of object TAB Value (fields content, hilite of button or thumbposition of scrollbar)

Since we only have one card in this example, we do not need to store the card number and stack name where the object is located!

5. Now we need handlers that collect the users input and pass it to the function mentioned above that will store the preferences to a file, take the stored info and "restore" the users input when the user opens that prefs stack the next time.

They are located in the stack script of the substack "Preferences_sub".
When the user closes the stack, we collect his/her input and write this info to the users harddisk:

## We store all the prefs when the stack closes again:
on closestack
   
   ## Collect everything we need to store
   ## (The order does not matter, since we also store the NAMES
   # of the controls!):
   ## The two fields with the users name
   put "field" & TAB & "name" & TAB & fld "name" & CR into tPrefs
   put "field" & TAB & "first_name" & TAB & fld "first_name" & \
          CR after tPrefs
   
   ## The three checkboxes (Pets)
   put "button" & TAB & "Cats" & TAB & the hilite of btn "Cats" \
          & CR after tPrefs
   put "button" & TAB & "Dogs" & TAB & the hilite of btn "Dogs" \
          & CR after tPrefs
   put "button" & TAB & "Mice" & TAB & the hilite of btn "Mice" \
          & CR after tPrefs
   
   ## Scrollbar (Number of pets)
   put "scrollbar" & TAB & "numofpets" & TAB & the thumbpos of \
          sb "numofpets" & CR after tPrefs
   
   ## Finally the folder for images that the user has selected:
   put "field" & TAB & "imagefolder" & TAB & fld "imagefolder" \
          after tPrefs
   
   ## Now we call the function that will store this to a text
   # file
   put mk_setprefs(tPrefs) into tResult
   
   ## Better doublecheck!
   if tResult <> empty then
      answer "There was an error when saving the preferences!" \
             & CR & tResult
   end if
end closestack 

Checking if the file was written successfully at the end of this script is of course optional, but keep in mind that the developers (WE!) are always blamed if something goes wrong, so get used to taking care of everything that might go wrong! ;-)

And here "on preopenstack" we get the saved prefs, if there are any, and restore the last user input:

## We put all stored values (back) into the appropriate
# fields/buttons...
on preopenstack
   
   ## Get the content of the prefs file
   put mk_getprefs() into tPrefs
   
   ## Nothing saved so far?
   ## Then wen can leave this handler right now!
   if tPrefs = empty then
      exit preopenstack
   end if
   lock screen
   
   ## Now we parse the prefs file and set the hilite of
   # buttons, contents of fields
   ## and thumbpositions of scrollbars as we stored it!
   
   ## The format of the prefs file is:
   ## Type of control (button, field or scrollbar) TAB Name of
   # control TAB Value/content
   set itemdel to TAB
   repeat for each line i in tPrefs
      put item 1 of i into tType
      put item 2 of i into tName
      put item 3 of i into tValue
      
      ## Here we need to "switch" since we cannot use the same
      # syntax for e.g. buttons as for fields!
      switch tType
         case "button"
            set the hilite of btn tName to tValue
            break
         case "field"
            put tValue into fld tName
            break
         case "scrollbar"
            set the thumbpos of sb tName to tValue
            break
            ##case XXX... This way we can expand this later if
            # necessary
            ##
            ## break
      end switch
   end repeat
   ## DONE!
   
   unlock screen
end preopenstack 

Well, that's it basically. I hope that "What you mean standalones cannot save themselves?" is not threatening you anymore! :-)
In the next article I will show you how to expand these scripts to also support binary data, collect and restore controls from more than one card and more.

HAVE FUN!

About the Author

Klaus Major is a experienced scripter with expertise dating back many years. His company, major-k, offers custom software development and LiveCode mentoring. Klaus also enjoys playing
electric bass guitar in jazz and rockbands.

Main Menu

What's New

Get your RunRevLive.11 Ticket Today