You want to easily persist a set of settings in your application.
The easiest way to accomplish this is to work with a file embedded database: Read the settings from the database when the application loads and save them just before it closes.
There are many settings you might implement in your application and want to persist--the position of all its windows, the color scheme the users might choose, the name of the default user profile; in short, everything you would like to implement.
Look at the settings database, contained in a SQLite 3 file, and a JavaScript static class which helps loading and persisting the setting values.
For the sake of simplicity, we'll use the database file from within the application directory. In the database we'll need a name and a value column. We'll also put a namespace column, just to be able to group easier similar settings. Just in case we'll add also a unique index to be sure we don't have duplicate records.
CREATE TABLE settings (IdSetting INTEGER PRIMARY KEY, name TEXT, namespace TEXT, value TEXT);
CREATE UNIQUE INDEX [UNIQ] ON [settings]([name] DESC,[namespace] DESC)
We'll have all the initial settings populated in the database, settings.db:
+--------------------------------------+
| 1 | title | NULL | Set. example |
| 2 | x | position | 79 |
| 3 | y | position | 305 |
| 4 | width | size | 220 |
| 5 | height | size | 320 |
+--------------------------------------+
In this example, "title" stores the title of the application, "x" and "y" in namespace "position" persist the application's position on the screen, and "width" and "height" in namespace "size" persist the dimensions of the application's window.
In the JavaScript class we'll implement two methods: load and save. The load method will read everything from the database and load it into the class itself. The save method will compare the setting values at load time with the setting values when the method was called and if something was modified, those entries will be updated in the database.
Settings.js
//a "static" class to handle our app settings
var Settings = {
//some static properties to hold db connection and the inital state
__db: null,
__result: null,
//this method will load the settings from the db
__load: function(dbconn) {
Settings.__db = dbconn;
//execute simple select * on the settings table
var stmt = new air.SQLStatement();
stmt.sqlConnection = dbconn;
stmt.text = "select IdSetting, name, value, namespace from settings";
stmt.execute();
var result = stmt.getResult().data;
//save the settings in the class property __result
Settings.__result = result;
//cycle trough the db result and make properties into the class itself
for( var i=0; i<result.length; i++ ){
//if the property has namespace create one for it
if (result[i].namespace!=null) {
//fetch setting property with namespace
if (!Settings[result[i].namespace]) {
Settings[result[i].namespace] = {};
}
Settings[result[i].namespace][result[i].name] = result[i].value;
} else {
//a plain setting property - create it directly in the class
Settings[result[i].name] = result[i].value;
}
}
//make sure we don't cause memory leaks
stmt = null;
result = null;
},
//this method will save all changed settings
__save: function() {
var stmt = new air.SQLStatement();
stmt.sqlConnection = Settings.__db;
//walk trough all settings INITALLY loaded from the database
for (var i = 0; i < Settings.__result.length; i++) {
//check if the current property has namespace
if (Settings.__result[i].namespace!=null) {
//check if the initial value is equal to the current value
if ( Settings[Settings.__result[i].namespace][Settings.__result[i].name] != Settings.__result[i].value ) {
//update the db. bound parameters are always better
stmt.text = "update settings set value= :value where name= :name and namespace= :namespace";
stmt.parameters[":name"] = Settings.__result[i].name;
stmt.parameters[":value"] = Settings[Settings.__result[i].namespace][Settings.__result[i].name];
stmt.parameters[":namespace"] = Settings.__result[i].namespace;
stmt.execute();
}
}
else {
//check if the initial value is equal to the current value
if (Settings[Settings.__result[i].name] != Settings.__result[i].value) {
//update the db, look for namespace equals NULL
stmt.text = "update settings set value= :value where name= :name and namespace IS NULL";
stmt.parameters[":name"] = Settings.__result[i].name;
stmt.parameters[":value"] = Settings[Settings.__result[i].name];
stmt.execute();
}
}
}
stmt = null;
}
};
The class method names are prefixed with "__" to keep cleaner the class namespace, because you might want to have setting names "load" or "save" (which would overwrite the methods if they didn't have those prefixes).
When you call the __load method and provide it with valid database connection, you can read and write settings like this:
Settings.namespace.propertyX
For properties which are designated to a namespace, and
Settings.propertyY
which don't have a namespace, you can read and write like this:
Settings.position.x = 100;
var myTitle = Settings.title;
And to demonstrate better how to use the class here is a simple application that persists its window position on the screen, the window dimensions and the window title.
<html>
<head>
<script type="text/javascript" src="AIRAliases.js"></script>
<script type="text/javascript" src="Settings.js"></script>
<script type="text/javascript">
var db = null;
var stmt = null;
//the settings database in the app directory
var dbFile = air.File.applicationDirectory.resolvePath("settings.db");
//on application load connect to the db
function onApplicationLoad() {
//add handler to save the settings
window.nativeWindow.addEventListener("closing", onWindowClose);
//open connection to settings.db database
db = new air.SQLConnection();
db.addEventListener( air.SQLEvent.OPEN, onDatabaseOpen );
db.open( dbFile, air.SQLMode.CREATE );
}
//read the settings from db
function onDatabaseOpen(e) {
Settings.__load(db);
//set x, y and window title
window.nativeWindow.x = Settings.position.x
window.nativeWindow.y = Settings.position.y;
window.nativeWindow.width = Settings.size.width;
window.nativeWindow.height = Settings.size.height;
window.nativeWindow.title = Settings.title;
//show the window
window.nativeWindow.visible = true;
}
//method to set window's title
function setTitle() {
//update window's title
window.nativeWindow.title = document.getElementById('titleFld').value;
//update the settings object
Settings.title = document.getElementById('titleFld').value;
}
//read the x and y before the window is closed and save them to db
function onWindowClose() {
Settings.position.x = window.nativeWindow.x;
Settings.position.y = window.nativeWindow.y;
Settings.size.width = window.nativeWindow.width;
Settings.size.height = window.nativeWindow.height;
//save the settings
Settings.__save();
}
</script>
<style>
body {padding: 10px; color: #ccc; background: #333;}
input {width:190px;}
</style>
</head>
<body onload="onApplicationLoad()">
Change the title of the application:<hr /><br />
Window title: <br />
<input type="text" id="titleFld" /><br />
<input type="button" value="Change window title" onClick="setTitle()" />
<br /><br />
Change window position on the screen, resize it and change the title and these settings will be saved for the next time you run the program
</body>
</html>
+