|
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 ***************************************************************************/ |
|
21 |
|
22 // version 2 |
|
23 |
|
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 |
|
28 |
|
29 // TODO: Fix up error reporting |
|
30 |
|
31 #include <qdom.h> |
|
32 #include <qfile.h> |
|
33 #include <qtextstream.h> |
|
34 |
|
35 #include "as_pref.h" |
|
36 |
|
37 ////////////////////////////////////////////////////////////////////////////// |
|
38 // Construction // |
|
39 ////////////////////////////////////////////////////////////////////////////// |
|
40 |
|
41 ////////////////////////////////////////////////////////////////////////////// |
|
42 // Preferences() |
|
43 // ------------- |
|
44 // Constructor. Takes the preferences file name as an argument. |
|
45 |
|
46 Preferences::Preferences(const QString& filename, |
|
47 const QString& format, |
|
48 const QString& version) |
|
49 : dirty_(false), |
|
50 currentgroup_(), |
|
51 file_(filename), |
|
52 format_(format), |
|
53 version_(version), |
|
54 filestate_(false), |
|
55 formatstate_(false), |
|
56 groups_() |
|
57 { |
|
58 readData(); |
|
59 dirty_ = false; |
|
60 currentgroup_ = "Default"; |
|
61 } |
|
62 |
|
63 ////////////////////////////////////////////////////////////////////////////// |
|
64 // ~Preferences() |
|
65 // --------------- |
|
66 // Destructor |
|
67 |
|
68 Preferences::~Preferences() |
|
69 { |
|
70 if (dirty_) writeData(); |
|
71 } |
|
72 |
|
73 ////////////////////////////////////////////////////////////////////////////// |
|
74 // Settings |
|
75 ////////////////////////////////////////////////////////////////////////////// |
|
76 |
|
77 ////////////////////////////////////////////////////////////////////////////// |
|
78 // getBoolean() |
|
79 // ------------ |
|
80 // Get a boolean value |
|
81 |
|
82 bool Preferences::getBool(const QString& key, bool def) |
|
83 { |
|
84 buffer_ = getString(key, def ? "true" : "false"); |
|
85 if (buffer_.isEmpty()) return def; |
|
86 if (buffer_.contains("true")) |
|
87 return true; |
|
88 else |
|
89 return false; |
|
90 } |
|
91 |
|
92 ////////////////////////////////////////////////////////////////////////////// |
|
93 // setBoolean() |
|
94 // ------------ |
|
95 // Set a boolean value |
|
96 |
|
97 void Preferences::setBool(const QString& key, bool value) |
|
98 { |
|
99 groups_[currentgroup_][key] = value ? "true" : "false"; |
|
100 dirty_ = true; |
|
101 } |
|
102 |
|
103 ////////////////////////////////////////////////////////////////////////////// |
|
104 // getNumber() |
|
105 // ----------- |
|
106 // Get a number value |
|
107 |
|
108 // TODO: this might be a place for templates |
|
109 |
|
110 long Preferences::getNumber(const QString& key, long def) |
|
111 { |
|
112 buffer_ = getString(key, QString::number(def)); |
|
113 if (buffer_.isEmpty()) return def; |
|
114 |
|
115 bool ok; |
|
116 long num = buffer_.toLong(&ok); |
|
117 if (ok) return num; |
|
118 else return def; |
|
119 } |
|
120 |
|
121 ////////////////////////////////////////////////////////////////////////////// |
|
122 // setNumber() |
|
123 // ----------- |
|
124 // Set a number value |
|
125 |
|
126 void Preferences::setNumber(const QString& key, long value) |
|
127 { |
|
128 buffer_.setNum(value); |
|
129 |
|
130 groups_[currentgroup_][key] = buffer_; |
|
131 dirty_ = true; |
|
132 } |
|
133 |
|
134 ////////////////////////////////////////////////////////////////////////////// |
|
135 // getDouble() |
|
136 // ----------- |
|
137 // Get a double value |
|
138 |
|
139 double Preferences::getDouble(const QString& key, double def) |
|
140 { |
|
141 buffer_ = getString(key, QString::number(def)); |
|
142 if (buffer_.isEmpty()) return def; |
|
143 |
|
144 bool ok; |
|
145 double num = buffer_.toDouble(&ok); |
|
146 if (ok) return num; |
|
147 else return def; |
|
148 } |
|
149 |
|
150 ////////////////////////////////////////////////////////////////////////////// |
|
151 // setDouble() |
|
152 // ----------- |
|
153 // Set a double value |
|
154 |
|
155 void Preferences::setDouble(const QString& key, double value) |
|
156 { |
|
157 buffer_.setNum(value); |
|
158 |
|
159 groups_[currentgroup_][key] = buffer_; |
|
160 dirty_ = true; |
|
161 } |
|
162 |
|
163 |
|
164 ////////////////////////////////////////////////////////////////////////////// |
|
165 // getString() |
|
166 // ----------- |
|
167 // Get a string value |
|
168 |
|
169 QString Preferences::getString(const QString& key, const QString& def) |
|
170 { |
|
171 buffer_ = ""; |
|
172 if (groups_.contains(currentgroup_)) { |
|
173 if (groups_[currentgroup_].contains(key)) { |
|
174 buffer_ = groups_[currentgroup_][key]; |
|
175 } |
|
176 } |
|
177 if (buffer_.isEmpty()) return def; |
|
178 return buffer_; |
|
179 } |
|
180 |
|
181 ////////////////////////////////////////////////////////////////////////////// |
|
182 // setString() |
|
183 // ----------- |
|
184 // Set a string value |
|
185 |
|
186 void Preferences::setString(const QString& key, const QString& value) |
|
187 { |
|
188 groups_[currentgroup_][key] = value; |
|
189 dirty_ = true; |
|
190 } |
|
191 |
|
192 ////////////////////////////////////////////////////////////////////////////// |
|
193 // removeValue() |
|
194 // ------------- |
|
195 // Remove a value from the preferences |
|
196 |
|
197 void Preferences::removeKey(const QString& key) |
|
198 { |
|
199 groups_[currentgroup_].remove(key); |
|
200 } |
|
201 |
|
202 ////////////////////////////////////////////////////////////////////////////// |
|
203 // removeGroup() |
|
204 // ------------- |
|
205 // Remove a group from the preferences, and all its options |
|
206 |
|
207 void Preferences::removeGroup() |
|
208 { |
|
209 groups_.remove(currentgroup_); |
|
210 } |
|
211 |
|
212 ////////////////////////////////////////////////////////////////////////////// |
|
213 // flush() |
|
214 // ------- |
|
215 // Flush the preferences to file |
|
216 |
|
217 void Preferences::flush() |
|
218 { |
|
219 if (dirty_) { |
|
220 writeData(); |
|
221 dirty_ = false; |
|
222 } |
|
223 } |
|
224 |
|
225 ////////////////////////////////////////////////////////////////////////////// |
|
226 // Serialization // |
|
227 ////////////////////////////////////////////////////////////////////////////// |
|
228 |
|
229 ////////////////////////////////////////////////////////////////////////////// |
|
230 // readData() |
|
231 // ---------- |
|
232 // Read data from the file |
|
233 |
|
234 void Preferences::readData() |
|
235 { |
|
236 // open file |
|
237 QFile* datafile = new QFile(file_); |
|
238 if (!datafile->open(IO_ReadOnly)) { |
|
239 // error opening file |
|
240 qWarning("Error: cannot open preferences file " + file_); |
|
241 datafile->close(); |
|
242 delete (datafile); |
|
243 filestate_ = false; |
|
244 return; |
|
245 } |
|
246 filestate_ = true; |
|
247 |
|
248 // open dom document |
|
249 QDomDocument doc("preferences"); |
|
250 if (!doc.setContent(datafile)) { |
|
251 qWarning("Error: " + file_ + " is not a proper preferences file"); |
|
252 datafile->close(); |
|
253 delete (datafile); |
|
254 formatstate_ = false; |
|
255 return; |
|
256 } |
|
257 datafile->close(); |
|
258 delete (datafile); |
|
259 |
|
260 // check the doc type and stuff |
|
261 if (doc.doctype().name() != "preferences") { |
|
262 // wrong file type |
|
263 qWarning("Error: " +file_ + " is not a valid preferences file"); |
|
264 formatstate_ = false; |
|
265 return; |
|
266 } |
|
267 QDomElement root = doc.documentElement(); |
|
268 if (root.attribute("application") != format_) { |
|
269 // right file type, wrong application |
|
270 qWarning("Error: " + file_ + " is not a preferences file for " + format_); |
|
271 formatstate_ = false; |
|
272 return; |
|
273 } |
|
274 // We don't care about application version... |
|
275 |
|
276 // get list of groups |
|
277 QDomNodeList nodes = root.elementsByTagName("group"); |
|
278 |
|
279 // iterate through the groups |
|
280 QDomNodeList options; |
|
281 for (unsigned n=0; n<nodes.count(); ++n) { |
|
282 if (nodes.item(n).isElement()) { |
|
283 processGroup(nodes.item(n).toElement()); |
|
284 } |
|
285 } |
|
286 formatstate_ = true; |
|
287 } |
|
288 |
|
289 void Preferences::processGroup(QDomElement group) |
|
290 { |
|
291 QDomElement elem; |
|
292 QDomNodeList options; |
|
293 currentgroup_ = group.attribute("name", "Default"); |
|
294 options = group.elementsByTagName("option"); |
|
295 for (unsigned n=0; n<options.count(); ++n) { |
|
296 if (options.item(n).isElement()) { |
|
297 elem = options.item(n).toElement(); |
|
298 setString(elem.attribute("key"), elem.attribute("value")); |
|
299 } |
|
300 } |
|
301 } |
|
302 |
|
303 ////////////////////////////////////////////////////////////////////////////// |
|
304 // writeData() |
|
305 // ----------- |
|
306 // Write data out to the file |
|
307 |
|
308 void Preferences::writeData() |
|
309 { |
|
310 QDomDocument doc("preferences"); |
|
311 |
|
312 // create the root element |
|
313 QDomElement root = doc.createElement(doc.doctype().name()); |
|
314 root.setAttribute("version", version_); |
|
315 root.setAttribute("application", format_); |
|
316 |
|
317 // now do our options group by group |
|
318 QMap<QString, PrefMap>::Iterator git; |
|
319 PrefMap::Iterator pit; |
|
320 QDomElement group, option; |
|
321 for (git = groups_.begin(); git != groups_.end(); ++git) { |
|
322 // create a group element |
|
323 group = doc.createElement("group"); |
|
324 group.setAttribute("name", git.key()); |
|
325 // add in options |
|
326 for (pit = (*git).begin(); pit != (*git).end(); ++pit) { |
|
327 option = doc.createElement("option"); |
|
328 option.setAttribute("key", pit.key()); |
|
329 option.setAttribute("value", pit.data()); |
|
330 group.appendChild(option); |
|
331 } |
|
332 root.appendChild(group); |
|
333 } |
|
334 doc.appendChild(root); |
|
335 |
|
336 // open file |
|
337 QFile* datafile = new QFile(file_); |
|
338 if (!datafile->open(IO_WriteOnly)) { |
|
339 // error opening file |
|
340 qWarning("Error: Cannot open preferences file " + file_); |
|
341 datafile->close(); |
|
342 delete (datafile); |
|
343 filestate_ = false; |
|
344 return; |
|
345 } |
|
346 filestate_ = true; |
|
347 |
|
348 // write it out |
|
349 QTextStream textstream(datafile); |
|
350 doc.save(textstream, 0); |
|
351 datafile->close(); |
|
352 delete (datafile); |
|
353 formatstate_ = true; |
|
354 } |