Fri, 05 Dec 2008 23:15:28 +0100
Correct version number and date in documentation.
1 /***************************************************************************
2 preferences.cc
3 -------------------
4 A class to access persistant preferences for an application. Utilizes XML/DOM.
5 Basic format is:
6 <!DOCTYPE preferences>
7 <preferences version="0.1" application="MyApp" >
8 <group name="Default" >
9 <option key="alpha" value="true" />
10 <option key="beta" value="99" />
11 <option key="gamma" value="test" />
12 </group>
13 </preferences>
14 -------------------
15 begin Tue Sep 12 2000
16 author David Johnson, david@usermode.org
17 -------------------
18 Copyright 2000, David Johnson
19 Please see the header file for copyright and license information
20 ***************************************************************************/
22 // version 2
24 // TODO: fix up to account for worst case scenarios:
25 // keys without values in file, and
26 // checking for a key that doesn't exist puts it into the map
27 // then it gets written out if dirty, possibly corrupting the file
29 // TODO: Fix up error reporting
31 #define QT3_SUPPORT
33 #include <Qt/qdom.h>
34 #include <qfile.h>
35 #include <qtextstream.h>
37 #include "as_pref.h"
39 //////////////////////////////////////////////////////////////////////////////
40 // Construction //
41 //////////////////////////////////////////////////////////////////////////////
43 //////////////////////////////////////////////////////////////////////////////
44 // Preferences()
45 // -------------
46 // Constructor. Takes the preferences file name as an argument.
48 Preferences::Preferences(const QString& filename,
49 const QString& format,
50 const QString& version)
51 : dirty_(false),
52 currentgroup_(),
53 file_(filename),
54 format_(format),
55 version_(version),
56 filestate_(false),
57 formatstate_(false),
58 groups_()
59 {
60 readData();
61 dirty_ = false;
62 currentgroup_ = "Default";
63 }
65 //////////////////////////////////////////////////////////////////////////////
66 // ~Preferences()
67 // ---------------
68 // Destructor
70 Preferences::~Preferences()
71 {
72 if (dirty_) writeData();
73 }
75 //////////////////////////////////////////////////////////////////////////////
76 // Settings
77 //////////////////////////////////////////////////////////////////////////////
79 //////////////////////////////////////////////////////////////////////////////
80 // getBoolean()
81 // ------------
82 // Get a boolean value
84 bool Preferences::getBool(const QString& key, bool def)
85 {
86 buffer_ = getString(key, def ? "true" : "false");
87 if (buffer_.isEmpty()) return def;
88 if (buffer_.contains("true"))
89 return true;
90 else
91 return false;
92 }
94 //////////////////////////////////////////////////////////////////////////////
95 // setBoolean()
96 // ------------
97 // Set a boolean value
99 void Preferences::setBool(const QString& key, bool value)
100 {
101 groups_[currentgroup_][key] = value ? "true" : "false";
102 dirty_ = true;
103 }
105 //////////////////////////////////////////////////////////////////////////////
106 // getNumber()
107 // -----------
108 // Get a number value
110 // TODO: this might be a place for templates
112 long Preferences::getNumber(const QString& key, long def)
113 {
114 buffer_ = getString(key, QString::number(def));
115 if (buffer_.isEmpty()) return def;
117 bool ok;
118 long num = buffer_.toLong(&ok);
119 if (ok) return num;
120 else return def;
121 }
123 //////////////////////////////////////////////////////////////////////////////
124 // setNumber()
125 // -----------
126 // Set a number value
128 void Preferences::setNumber(const QString& key, long value)
129 {
130 buffer_.setNum(value);
132 groups_[currentgroup_][key] = buffer_;
133 dirty_ = true;
134 }
136 //////////////////////////////////////////////////////////////////////////////
137 // getDouble()
138 // -----------
139 // Get a double value
141 double Preferences::getDouble(const QString& key, double def)
142 {
143 buffer_ = getString(key, QString::number(def));
144 if (buffer_.isEmpty()) return def;
146 bool ok;
147 double num = buffer_.toDouble(&ok);
148 if (ok) return num;
149 else return def;
150 }
152 //////////////////////////////////////////////////////////////////////////////
153 // setDouble()
154 // -----------
155 // Set a double value
157 void Preferences::setDouble(const QString& key, double value)
158 {
159 buffer_.setNum(value);
161 groups_[currentgroup_][key] = buffer_;
162 dirty_ = true;
163 }
166 //////////////////////////////////////////////////////////////////////////////
167 // getString()
168 // -----------
169 // Get a string value
171 QString Preferences::getString(const QString& key, const QString& def)
172 {
173 buffer_ = "";
174 if (groups_.contains(currentgroup_)) {
175 if (groups_[currentgroup_].contains(key)) {
176 buffer_ = groups_[currentgroup_][key];
177 }
178 }
179 if (buffer_.isEmpty()) return def;
180 return buffer_;
181 }
183 //////////////////////////////////////////////////////////////////////////////
184 // setString()
185 // -----------
186 // Set a string value
188 void Preferences::setString(const QString& key, const QString& value)
189 {
190 groups_[currentgroup_][key] = value;
191 dirty_ = true;
192 }
194 //////////////////////////////////////////////////////////////////////////////
195 // removeValue()
196 // -------------
197 // Remove a value from the preferences
199 void Preferences::removeKey(const QString& key)
200 {
201 groups_[currentgroup_].remove(key);
202 }
204 //////////////////////////////////////////////////////////////////////////////
205 // removeGroup()
206 // -------------
207 // Remove a group from the preferences, and all its options
209 void Preferences::removeGroup()
210 {
211 groups_.remove(currentgroup_);
212 }
214 //////////////////////////////////////////////////////////////////////////////
215 // flush()
216 // -------
217 // Flush the preferences to file
219 void Preferences::flush()
220 {
221 if (dirty_) {
222 writeData();
223 dirty_ = false;
224 }
225 }
227 //////////////////////////////////////////////////////////////////////////////
228 // Serialization //
229 //////////////////////////////////////////////////////////////////////////////
231 //////////////////////////////////////////////////////////////////////////////
232 // readData()
233 // ----------
234 // Read data from the file
236 void Preferences::readData()
237 {
238 // open file
239 QFile* datafile = new QFile(file_);
240 if (!datafile->open(QIODevice::ReadOnly)) {
241 // error opening file
242 qWarning("Error: cannot open preferences file " + file_);
243 datafile->close();
244 delete (datafile);
245 filestate_ = false;
246 return;
247 }
248 filestate_ = true;
250 // open dom document
251 QDomDocument doc("preferences");
252 if (!doc.setContent(datafile)) {
253 qWarning("Error: " + file_ + " is not a proper preferences file");
254 datafile->close();
255 delete (datafile);
256 formatstate_ = false;
257 return;
258 }
259 datafile->close();
260 delete (datafile);
262 // check the doc type and stuff
263 if (doc.doctype().name() != "preferences") {
264 // wrong file type
265 qWarning("Error: " +file_ + " is not a valid preferences file");
266 formatstate_ = false;
267 return;
268 }
269 QDomElement root = doc.documentElement();
270 if (root.attribute("application") != format_) {
271 // right file type, wrong application
272 qWarning("Error: " + file_ + " is not a preferences file for " + format_);
273 formatstate_ = false;
274 return;
275 }
276 // We don't care about application version...
278 // get list of groups
279 QDomNodeList nodes = root.elementsByTagName("group");
281 // iterate through the groups
282 QDomNodeList options;
283 for (unsigned n=0; n<nodes.count(); ++n) {
284 if (nodes.item(n).isElement()) {
285 processGroup(nodes.item(n).toElement());
286 }
287 }
288 formatstate_ = true;
289 }
291 void Preferences::processGroup(QDomElement group)
292 {
293 QDomElement elem;
294 QDomNodeList options;
295 currentgroup_ = group.attribute("name", "Default");
296 options = group.elementsByTagName("option");
297 for (unsigned n=0; n<options.count(); ++n) {
298 if (options.item(n).isElement()) {
299 elem = options.item(n).toElement();
300 setString(elem.attribute("key"), elem.attribute("value"));
301 }
302 }
303 }
305 //////////////////////////////////////////////////////////////////////////////
306 // writeData()
307 // -----------
308 // Write data out to the file
310 void Preferences::writeData()
311 {
312 QDomDocument doc("preferences");
314 // create the root element
315 QDomElement root = doc.createElement(doc.doctype().name());
316 root.setAttribute("version", version_);
317 root.setAttribute("application", format_);
319 // now do our options group by group
320 QMap<QString, PrefMap>::Iterator git;
321 PrefMap::Iterator pit;
322 QDomElement group, option;
323 for (git = groups_.begin(); git != groups_.end(); ++git) {
324 // create a group element
325 group = doc.createElement("group");
326 group.setAttribute("name", git.key());
327 // add in options
328 for (pit = (*git).begin(); pit != (*git).end(); ++pit) {
329 option = doc.createElement("option");
330 option.setAttribute("key", pit.key());
331 option.setAttribute("value", pit.data());
332 group.appendChild(option);
333 }
334 root.appendChild(group);
335 }
336 doc.appendChild(root);
338 // open file
339 QFile* datafile = new QFile(file_);
340 if (!datafile->open(QIODevice::WriteOnly)) {
341 // error opening file
342 qWarning("Error: Cannot open preferences file " + file_);
343 datafile->close();
344 delete (datafile);
345 filestate_ = false;
346 return;
347 }
348 filestate_ = true;
350 // write it out
351 QTextStream textstream(datafile);
352 doc.save(textstream, 0);
353 datafile->close();
354 delete (datafile);
355 formatstate_ = true;
356 }