summaryrefslogtreecommitdiff
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--library/config.cpp231
-rw-r--r--library/config.h6
2 files changed, 168 insertions, 69 deletions
diff --git a/library/config.cpp b/library/config.cpp
index 61ff089..bdfcb3f 100644
--- a/library/config.cpp
+++ b/library/config.cpp
@@ -1,673 +1,770 @@
1/********************************************************************** 1/**********************************************************************
2** Copyright (C) 2000,2004 Trolltech AS. All rights reserved. 2** Copyright (C) 2000,2004 Trolltech AS. All rights reserved.
3** 3**
4** This file is part of Qtopia Environment. 4** This file is part of Qtopia Environment.
5** 5**
6** This file may be distributed and/or modified under the terms of the 6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free Software 7** GNU General Public License version 2 as published by the Free Software
8** Foundation and appearing in the file LICENSE.GPL included in the 8** Foundation and appearing in the file LICENSE.GPL included in the
9** packaging of this file. 9** packaging of this file.
10** 10**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13** 13**
14** See http://www.trolltech.com/gpl/ for GPL licensing information. 14** See http://www.trolltech.com/gpl/ for GPL licensing information.
15** 15**
16** Contact info@trolltech.com if any conditions of this licensing are 16** Contact info@trolltech.com if any conditions of this licensing are
17** not clear to you. 17** not clear to you.
18** 18**
19**********************************************************************/ 19**********************************************************************/
20 20
21#include <qdir.h> 21#include <qdir.h>
22#include <qmessagebox.h> 22#include <qmessagebox.h>
23#if QT_VERSION <= 230 && defined(QT_NO_CODECS) 23#if QT_VERSION <= 230 && defined(QT_NO_CODECS)
24#include <qtextcodec.h> 24#include <qtextcodec.h>
25#endif 25#endif
26#include <qtextstream.h> 26#include <qtextstream.h>
27 27
28#include <sys/stat.h> 28#include <sys/stat.h>
29#include <sys/types.h> 29#include <sys/types.h>
30#include <fcntl.h> 30#include <fcntl.h>
31#include <stdlib.h> 31#include <stdlib.h>
32#include <unistd.h> 32#include <unistd.h>
33 33
34#define QTOPIA_INTERNAL_LANGLIST 34#define QTOPIA_INTERNAL_LANGLIST
35#include "config.h" 35#include "config.h"
36#include "global.h" 36#include "global.h"
37#include "qpeapplication.h"
37 38
38 39
40/*
41 * Internal Class
42 */
43class ConfigPrivate {
44public:
45 ConfigPrivate() : multilang(FALSE) {}
46 ConfigPrivate(const ConfigPrivate& o) :
47 trfile(o.trfile),
48 trcontext(o.trcontext),
49 multilang(o.multilang)
50 {}
51 ConfigPrivate& operator=(const ConfigPrivate& o)
52 {
53 trfile = o.trfile;
54 trcontext = o.trcontext;
55 multilang = o.multilang;
56 return *this;
57 }
58
59 QString trfile;
60 QCString trcontext;
61 bool multilang;
62};
63
64/////////////////////////////////////////////////////////////////
65/////////////////////////////////////////////////////////////////
66
39/*! 67/*!
40 \internal 68 \internal
41*/ 69*/
42QString Config::configFilename(const QString& name, Domain d) 70QString Config::configFilename(const QString& name, Domain d)
43{ 71{
44 switch (d) { 72 switch (d) {
45 case File: 73 case File:
46 return name; 74 return name;
47 case User: { 75 case User: {
48 QDir dir = (QString(getenv("HOME")) + "/Settings"); 76 QDir dir = (QString(getenv("HOME")) + "/Settings");
49 if ( !dir.exists() ) 77 if ( !dir.exists() )
50 mkdir(dir.path().local8Bit(),0700); 78 mkdir(dir.path().local8Bit(),0700);
51 return dir.path() + "/" + name + ".conf"; 79 return dir.path() + "/" + name + ".conf";
52 } 80 }
53 } 81 }
54 return name; 82 return name;
55} 83}
56 84
85/* This cannot be made public because of binary compat issues */
86void Config::read( QTextStream &s )
87{
88#if QT_VERSION <= 230 && defined(QT_NO_CODECS)
89 // The below should work, but doesn't in Qt 2.3.0
90 s.setCodec( QTextCodec::codecForMib( 106 ) );
91#else
92 s.setEncoding( QTextStream::UnicodeUTF8 );
93#endif
94
95 QStringList list = QStringList::split('\n', s.read() );
96
97 for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
98 if ( !parse( *it ) ) {
99 git = groups.end();
100 return;
101 }
102 }
103}
104
57/*! 105/*!
58 \class Config config.h 106 \class Config config.h
59 \brief The Config class provides for saving application cofniguration state. 107 \brief The Config class provides for saving application cofniguration state.
60 108
61 You should keep a Config in existence only while you do not want others 109 You should keep a Config in existence only while you do not want others
62 to be able to change the state. There is no locking currently, but there 110 to be able to change the state. There is no locking currently, but there
63 may be in the future. 111 may be in the future.
64*/ 112*/
65 113
66/*! 114/*!
67 \enum Config::ConfigGroup 115 \enum Config::ConfigGroup
68 \internal 116 \internal
69*/ 117*/
70 118
71/*! 119/*!
72 \enum Config::Domain 120 \enum Config::Domain
73 121
74 \value File 122 \value File
75 \value User 123 \value User
76 124
77 See Config for details. 125 See Config for details.
78*/ 126*/
79 127
80/*! 128/*!
81 Constructs a config that will load or create a configuration with the 129 Constructs a config that will load or create a configuration with the
82 given \a name in the given \a domain. 130 given \a name in the given \a domain.
83 131
84 You must call setGroup() before doing much else with the Config. 132 You must call setGroup() before doing much else with the Config.
85 133
86 In the default Domain, \e User, 134 In the default Domain, \e User,
87 the configuration is user-specific. \a name should not contain "/" in 135 the configuration is user-specific. \a name should not contain "/" in
88 this case, and in general should be the name of the C++ class that is 136 this case, and in general should be the name of the C++ class that is
89 primarily responsible for maintaining the configuration. 137 primarily responsible for maintaining the configuration.
90 138
91 In the File Domain, \a name is an absolute filename. 139 In the File Domain, \a name is an absolute filename.
92*/ 140*/
93Config::Config( const QString &name, Domain domain ) 141Config::Config( const QString &name, Domain domain )
94 : filename( configFilename(name,domain) ) 142 : filename( configFilename(name,domain) )
95{ 143{
96 git = groups.end(); 144 git = groups.end();
145 d = 0;
97 read(); 146 read();
98 QStringList l = Global::languageList();
99 lang = l[0];
100 glang = l[1];
101} 147}
102 148
103 149
104// Sharp ROM compatibility 150// Sharp ROM compatibility
105Config::Config ( const QString &name, bool what ) 151Config::Config ( const QString &name, bool what )
106 : filename( configFilename(name,what ? User : File) ) 152 : filename( configFilename(name,what ? User : File) )
107{ 153{
108 git = groups.end(); 154 git = groups.end();
155 d = 0;
109 read(); 156 read();
110 QStringList l = Global::languageList();
111 lang = l[0];
112 glang = l[1];
113} 157}
114 158
115/*! 159/*!
116 Writes any changes to disk and destroys the in-memory object. 160 Writes any changes to disk and destroys the in-memory object.
117*/ 161*/
118Config::~Config() 162Config::~Config()
119{ 163{
120 if ( changed ) 164 if ( changed )
121 write(); 165 write();
166
167 delete d;
122} 168}
123 169
124/*! 170/*!
125 Returns whether the current group has an entry called \a key. 171 Returns whether the current group has an entry called \a key.
126*/ 172*/
127bool Config::hasKey( const QString &key ) const 173bool Config::hasKey( const QString &key ) const
128{ 174{
129 if ( groups.end() == git ) 175 if ( groups.end() == git )
130 return FALSE; 176 return FALSE;
131 ConfigGroup::ConstIterator it = ( *git ).find( key ); 177 ConfigGroup::ConstIterator it = ( *git ).find( key );
178 if ( it == ( *git ).end() ) {
179 if ( d && !d->trcontext.isNull() ) {
180 it = ( *git ).find( key + "[]" );
181 } else if ( d && d->multilang ) {
182 it = ( *git ).find( key + "["+lang+"]" );
183 if ( it == ( *git ).end() && !glang.isEmpty() )
184 it = ( *git ).find( key + "["+glang+"]" );
185 }
186 }
132 return it != ( *git ).end(); 187 return it != ( *git ).end();
133} 188}
134 189
135/*! 190/*!
136 Sets the current group for subsequent reading and writing of 191 Sets the current group for subsequent reading and writing of
137 entries to \a gname. Grouping allows the application to partition the namespace. 192 entries to \a gname. Grouping allows the application to partition the namespace.
138 193
139 This function must be called prior to any reading or writing 194 This function must be called prior to any reading or writing
140 of entries. 195 of entries.
141 196
142 The \a gname must not be empty. 197 The \a gname must not be empty.
143*/ 198*/
144void Config::setGroup( const QString &gname ) 199void Config::setGroup( const QString &gname )
145{ 200{
146 QMap< QString, ConfigGroup>::Iterator it = groups.find( gname ); 201 QMap< QString, ConfigGroup>::Iterator it = groups.find( gname );
147 if ( it == groups.end() ) { 202 if ( it == groups.end() ) {
148 git = groups.insert( gname, ConfigGroup() ); 203 git = groups.insert( gname, ConfigGroup() );
149 changed = TRUE; 204 changed = TRUE;
150 return; 205 return;
151 } 206 }
152 git = it; 207 git = it;
153} 208}
154 209
155/*! 210/*!
156 Writes a (\a key, \a value) entry to the current group. 211 Writes a (\a key, \a value) entry to the current group.
157 212
158 \sa readEntry() 213 \sa readEntry()
159*/ 214*/
160void Config::writeEntry( const QString &key, const char* value ) 215void Config::writeEntry( const QString &key, const char* value )
161{ 216{
162 writeEntry(key,QString(value)); 217 writeEntry(key,QString(value));
163} 218}
164 219
165/*! 220/*!
166 Writes a (\a key, \a value) entry to the current group. 221 Writes a (\a key, \a value) entry to the current group.
167 222
168 \sa readEntry() 223 \sa readEntry()
169*/ 224*/
170void Config::writeEntry( const QString &key, const QString &value ) 225void Config::writeEntry( const QString &key, const QString &value )
171{ 226{
172 if ( git == groups.end() ) { 227 if ( git == groups.end() ) {
173 qWarning( "no group set" ); 228 qWarning( "no group set" );
174 return; 229 return;
175 } 230 }
176 if ( (*git)[key] != value ) { 231 if ( (*git)[key] != value ) {
177 ( *git ).insert( key, value ); 232 ( *git ).insert( key, value );
178 changed = TRUE; 233 changed = TRUE;
179 } 234 }
180} 235}
181 236
182/* 237/*
183 Note that the degree of protection offered by the encryption here is 238 Note that the degree of protection offered by the encryption here is
184 only sufficient to avoid the most casual observation of the configuration 239 only sufficient to avoid the most casual observation of the configuration
185 files. People with access to the files can write down the contents and 240 files. People with access to the files can write down the contents and
186 decrypt it using this source code. 241 decrypt it using this source code.
187 242
188 Conceivably, and at some burden to the user, this encryption could 243 Conceivably, and at some burden to the user, this encryption could
189 be improved. 244 be improved.
190*/ 245*/
191static QString encipher(const QString& plain) 246static QString encipher(const QString& plain)
192{ 247{
193 // mainly, we make it long 248 // mainly, we make it long
194 QString cipher; 249 QString cipher;
195 int mix=28730492; 250 int mix=28730492;
196 for (int i=0; i<(int)plain.length(); i++) { 251 for (int i=0; i<(int)plain.length(); i++) {
197 int u = plain[i].unicode(); 252 int u = plain[i].unicode();
198 int c = u ^ mix; 253 int c = u ^ mix;
199 QString x = QString::number(c,36); 254 QString x = QString::number(c,36);
200 cipher.append(QChar('a'+x.length())); 255 cipher.append(QChar('a'+x.length()));
201 cipher.append(x); 256 cipher.append(x);
202 mix *= u; 257 mix *= u;
203 } 258 }
204 return cipher; 259 return cipher;
205} 260}
206 261
207static QString decipher(const QString& cipher) 262static QString decipher(const QString& cipher)
208{ 263{
209 QString plain; 264 QString plain;
210 int mix=28730492; 265 int mix=28730492;
211 for (int i=0; i<(int)cipher.length();) { 266 for (int i=0; i<(int)cipher.length();) {
212 int l = cipher[i].unicode()-'a'; 267 int l = cipher[i].unicode()-'a';
213 QString x = cipher.mid(i+1,l); i+=l+1; 268 QString x = cipher.mid(i+1,l); i+=l+1;
214 int u = x.toInt(0,36) ^ mix; 269 int u = x.toInt(0,36) ^ mix;
215 plain.append(QChar(u)); 270 plain.append(QChar(u));
216 mix *= u; 271 mix *= u;
217 } 272 }
218 return plain; 273 return plain;
219} 274}
220 275
221/*! 276/*!
222 Writes an encrypted (\a key, \a value) entry to the current group. 277 Writes an encrypted (\a key, \a value) entry to the current group.
223 278
224 Note that the degree of protection offered by the encryption is 279 Note that the degree of protection offered by the encryption is
225 only sufficient to avoid the most casual observation of the configuration 280 only sufficient to avoid the most casual observation of the configuration
226 files. 281 files.
227 282
228 \sa readEntry() 283 \sa readEntry()
229*/ 284*/
230void Config::writeEntryCrypt( const QString &key, const QString &value ) 285void Config::writeEntryCrypt( const QString &key, const QString &value )
231{ 286{
232 if ( git == groups.end() ) { 287 if ( git == groups.end() ) {
233 qWarning( "no group set" ); 288 qWarning( "no group set" );
234 return; 289 return;
235 } 290 }
236 QString evalue = encipher(value); 291 QString evalue = encipher(value);
237 if ( (*git)[key] != evalue ) { 292 if ( (*git)[key] != evalue ) {
238 ( *git ).insert( key, evalue ); 293 ( *git ).insert( key, evalue );
239 changed = TRUE; 294 changed = TRUE;
240 } 295 }
241} 296}
242 297
243/*! 298/*!
244 Writes a (\a key, \a num) entry to the current group. 299 Writes a (\a key, \a num) entry to the current group.
245 300
246 \sa readNumEntry() 301 \sa readNumEntry()
247*/ 302*/
248void Config::writeEntry( const QString &key, int num ) 303void Config::writeEntry( const QString &key, int num )
249{ 304{
250 QString s; 305 QString s;
251 s.setNum( num ); 306 s.setNum( num );
252 writeEntry( key, s ); 307 writeEntry( key, s );
253} 308}
254 309
255#ifdef Q_HAS_BOOL_TYPE 310#ifdef Q_HAS_BOOL_TYPE
256/*! 311/*!
257 Writes a (\a key, \a b) entry to the current group. This is equivalent 312 Writes a (\a key, \a b) entry to the current group. This is equivalent
258 to writing a 0 or 1 as an integer entry. 313 to writing a 0 or 1 as an integer entry.
259 314
260 \sa readBoolEntry() 315 \sa readBoolEntry()
261*/ 316*/
262void Config::writeEntry( const QString &key, bool b ) 317void Config::writeEntry( const QString &key, bool b )
263{ 318{
264 QString s; 319 QString s;
265 s.setNum( ( int )b ); 320 s.setNum( ( int )b );
266 writeEntry( key, s ); 321 writeEntry( key, s );
267} 322}
268#endif 323#endif
269 324
270/*! 325/*!
271 Writes a (\a key, \a lst) entry to the current group. The list 326 Writes a (\a key, \a lst) entry to the current group. The list
272 is separated by \a sep, so the strings must not contain that character. 327 is separated by \a sep, so the strings must not contain that character.
273 328
274 \sa readListEntry() 329 \sa readListEntry()
275*/ 330*/
276void Config::writeEntry( const QString &key, const QStringList &lst, const QChar &sep ) 331void Config::writeEntry( const QString &key, const QStringList &lst, const QChar &sep )
277{ 332{
278 QString s; 333 QString s;
279 QStringList::ConstIterator it = lst.begin(); 334 QStringList::ConstIterator it = lst.begin();
280 for ( ; it != lst.end(); ++it ) 335 for ( ; it != lst.end(); ++it )
281 s += *it + sep; 336 s += *it + sep;
282 writeEntry( key, s ); 337 writeEntry( key, s );
283} 338}
284 339
285/*! 340/*!
286 Removes the \a key entry from the current group. Does nothing if 341 Removes the \a key entry from the current group. Does nothing if
287 there is no such entry. 342 there is no such entry.
288*/ 343*/
289 344
290void Config::removeEntry( const QString &key ) 345void Config::removeEntry( const QString &key )
291{ 346{
292 if ( git == groups.end() ) { 347 if ( git == groups.end() ) {
293 qWarning( "no group set" ); 348 qWarning( "no group set" );
294 return; 349 return;
295 } 350 }
296 ( *git ).remove( key ); 351 ( *git ).remove( key );
297 changed = TRUE; 352 changed = TRUE;
298} 353}
299 354
300/*! 355/*!
301 \fn bool Config::operator == ( const Config & other ) const 356 \fn bool Config::operator == ( const Config & other ) const
302 357
303 Tests for equality with \a other. Config objects are equal if they refer to the same filename. 358 Tests for equality with \a other. Config objects are equal if they refer to the same filename.
304*/ 359*/
305 360
306/*! 361/*!
307 \fn bool Config::operator != ( const Config & other ) const 362 \fn bool Config::operator != ( const Config & other ) const
308 363
309 Tests for inequality with \a other. Config objects are equal if they refer to the same filename. 364 Tests for inequality with \a other. Config objects are equal if they refer to the same filename.
310*/ 365*/
311 366
367
312/*! 368/*!
313 \fn QString Config::readEntry( const QString &key, const QString &deflt ) const 369 \fn QString Config::readEntry( const QString &key, const QString &deflt ) const
314 370
315 Reads a string entry stored with \a key, defaulting to \a deflt if there is no entry. 371 Reads a string entry stored with \a key, defaulting to \a deflt if there is no entry.
316*/ 372*/
317 373
374/*
375 * ### !LocalTranslator::translate was kept out!
376 *
377 */
378
318/*! 379/*!
319 \internal 380 \internal
320 For compatibility, non-const version. 381 For compatibility, non-const version.
321*/ 382*/
322QString Config::readEntry( const QString &key, const QString &deflt ) 383QString Config::readEntry( const QString &key, const QString &deflt )
323{ 384{
324 QString res = readEntryDirect( key+"["+lang+"]" ); 385 QString r;
325 if ( !res.isNull() ) 386 if ( d && !d->trcontext.isNull() ) {
326 return res; 387 // Still try untranslated first, becuase:
327 if ( !glang.isEmpty() ) { 388 // 1. It's the common case
328 res = readEntryDirect( key+"["+glang+"]" ); 389 // 2. That way the value can be WRITTEN (becoming untranslated)
329 if ( !res.isNull() ) 390 r = readEntryDirect( key );
330 return res; 391 if ( !r.isNull() )
392 return r;
393 r = readEntryDirect( key + "[]" );
394 if ( !r.isNull() )
395 return qApp->translate(d->trfile,d->trcontext,r);
396 } else if ( d && d->multilang ) {
397 // For compatibilitity
398 r = readEntryDirect( key + "["+lang+"]" );
399 if ( !r.isNull() )
400 return r;
401 if ( !glang.isEmpty() ) {
402 r = readEntryDirect( key + "["+glang+"]" );
403 if ( !r.isNull() )
404 return r;
405 }
331 } 406 }
332 return readEntryDirect( key, deflt ); 407 r = readEntryDirect( key, deflt );
408 return r;
333} 409}
334 410
335/*! 411/*!
336 \fn QString Config::readEntryCrypt( const QString &key, const QString &deflt ) const 412 \fn QString Config::readEntryCrypt( const QString &key, const QString &deflt ) const
337 413
338 Reads an encrypted string entry stored with \a key, defaulting to \a deflt if there is no entry. 414 Reads an encrypted string entry stored with \a key, defaulting to \a deflt if there is no entry.
339*/ 415*/
340 416
341/*! 417/*!
342 \internal 418 \internal
343 For compatibility, non-const version. 419 For compatibility, non-const version.
344*/ 420*/
345QString Config::readEntryCrypt( const QString &key, const QString &deflt ) 421QString Config::readEntryCrypt( const QString &key, const QString &deflt )
346{ 422{
347 QString res = readEntryDirect( key+"["+lang+"]" ); 423 QString res = readEntry( key );
348 if ( res.isNull() && glang.isEmpty() )
349 res = readEntryDirect( key+"["+glang+"]" );
350 if ( res.isNull() )
351 res = readEntryDirect( key, QString::null );
352 if ( res.isNull() ) 424 if ( res.isNull() )
353 return deflt; 425 return deflt;
354 return decipher(res); 426 return decipher(res);
355} 427}
356 428
357/*! 429/*!
358 \fn QString Config::readEntryDirect( const QString &key, const QString &deflt ) const 430 \fn QString Config::readEntryDirect( const QString &key, const QString &deflt ) const
359 \internal 431 \internal
360*/ 432*/
361 433
362/*! 434/*!
363 \internal 435 \internal
364 For compatibility, non-const version. 436 For compatibility, non-const version.
365*/ 437*/
366QString Config::readEntryDirect( const QString &key, const QString &deflt ) 438QString Config::readEntryDirect( const QString &key, const QString &deflt )
367{ 439{
368 if ( git == groups.end() ) { 440 if ( git == groups.end() ) {
369 //qWarning( "no group set" ); 441 //qWarning( "no group set" );
370 return deflt; 442 return deflt;
371 } 443 }
372 ConfigGroup::ConstIterator it = ( *git ).find( key ); 444 ConfigGroup::ConstIterator it = ( *git ).find( key );
373 if ( it != ( *git ).end() ) 445 if ( it != ( *git ).end() )
374 return *it; 446 return *it;
375 else 447 else
376 return deflt; 448 return deflt;
377} 449}
378 450
379/*! 451/*!
380 \fn int Config::readNumEntry( const QString &key, int deflt ) const 452 \fn int Config::readNumEntry( const QString &key, int deflt ) const
381 Reads a numeric entry stored with \a key, defaulting to \a deflt if there is no entry. 453 Reads a numeric entry stored with \a key, defaulting to \a deflt if there is no entry.
382*/ 454*/
383 455
384/*! 456/*!
385 \internal 457 \internal
386 For compatibility, non-const version. 458 For compatibility, non-const version.
387*/ 459*/
388int Config::readNumEntry( const QString &key, int deflt ) 460int Config::readNumEntry( const QString &key, int deflt )
389{ 461{
390 QString s = readEntry( key ); 462 QString s = readEntry( key );
391 if ( s.isEmpty() ) 463 if ( s.isEmpty() )
392 return deflt; 464 return deflt;
393 else 465 else
394 return s.toInt(); 466 return s.toInt();
395} 467}
396 468
397/*! 469/*!
398 \fn bool Config::readBoolEntry( const QString &key, bool deflt ) const 470 \fn bool Config::readBoolEntry( const QString &key, bool deflt ) const
399 Reads a bool entry stored with \a key, defaulting to \a deflt if there is no entry. 471 Reads a bool entry stored with \a key, defaulting to \a deflt if there is no entry.
400*/ 472*/
401 473
402/*! 474/*!
403 \internal 475 \internal
404 For compatibility, non-const version. 476 For compatibility, non-const version.
405*/ 477*/
406bool Config::readBoolEntry( const QString &key, bool deflt ) 478bool Config::readBoolEntry( const QString &key, bool deflt )
407{ 479{
408 QString s = readEntry( key ); 480 QString s = readEntry( key );
409 if ( s.isEmpty() ) 481 if ( s.isEmpty() )
410 return deflt; 482 return deflt;
411 else 483 else
412 return (bool)s.toInt(); 484 return (bool)s.toInt();
413} 485}
414 486
415/*! 487/*!
416 \fn QStringList Config::readListEntry( const QString &key, const QChar &sep ) const 488 \fn QStringList Config::readListEntry( const QString &key, const QChar &sep ) const
417 Reads a string list entry stored with \a key, and with \a sep as the separator. 489 Reads a string list entry stored with \a key, and with \a sep as the separator.
418*/ 490*/
419 491
420/*! 492/*!
421 \internal 493 \internal
422 For compatibility, non-const version. 494 For compatibility, non-const version.
423*/ 495*/
424QStringList Config::readListEntry( const QString &key, const QChar &sep ) 496QStringList Config::readListEntry( const QString &key, const QChar &sep )
425{ 497{
426 QString s = readEntry( key ); 498 QString s = readEntry( key );
427 if ( s.isEmpty() ) 499 if ( s.isEmpty() )
428 return QStringList(); 500 return QStringList();
429 else 501 else
430 return QStringList::split( sep, s ); 502 return QStringList::split( sep, s );
431} 503}
432 504
433/*! 505/*!
434 Removes all entries from the current group. 506 Removes all entries from the current group.
435*/ 507*/
436void Config::clearGroup() 508void Config::clearGroup()
437{ 509{
438 if ( git == groups.end() ) { 510 if ( git == groups.end() ) {
439 qWarning( "no group set" ); 511 qWarning( "no group set" );
440 return; 512 return;
441 } 513 }
442 if ( !(*git).isEmpty() ) { 514 if ( !(*git).isEmpty() ) {
443 ( *git ).clear(); 515 ( *git ).clear();
444 changed = TRUE; 516 changed = TRUE;
445 } 517 }
446} 518}
447 519
448/*! 520/*!
449 \internal 521 \internal
450*/ 522*/
451void Config::write( const QString &fn ) 523void Config::write( const QString &fn )
452{ 524{
453 QString strNewFile; 525 QString strNewFile;
454 if ( !fn.isEmpty() ) 526 if ( !fn.isEmpty() )
455 filename = fn; 527 filename = fn;
456 strNewFile = filename + ".new"; 528 strNewFile = filename + ".new";
457 529
458 QFile f( strNewFile ); 530 QFile f( strNewFile );
459 if ( !f.open( IO_WriteOnly|IO_Raw ) ) { 531 if ( !f.open( IO_WriteOnly|IO_Raw ) ) {
460 qWarning( "could not open for writing `%s'", strNewFile.latin1() ); 532 qWarning( "could not open for writing `%s'", strNewFile.latin1() );
461 git = groups.end(); 533 git = groups.end();
462 return; 534 return;
463 } 535 }
464 536
465 QString str; 537 QString str;
466 QCString cstr; 538 QCString cstr;
467 QMap< QString, ConfigGroup >::Iterator g_it = groups.begin(); 539 QMap< QString, ConfigGroup >::Iterator g_it = groups.begin();
468 540
469 for ( ; g_it != groups.end(); ++g_it ) { 541 for ( ; g_it != groups.end(); ++g_it ) {
470 str += "[" + g_it.key() + "]\n"; 542 str += "[" + g_it.key() + "]\n";
471 ConfigGroup::Iterator e_it = ( *g_it ).begin(); 543 ConfigGroup::Iterator e_it = ( *g_it ).begin();
472 for ( ; e_it != ( *g_it ).end(); ++e_it ) 544 for ( ; e_it != ( *g_it ).end(); ++e_it )
473 str += e_it.key() + " = " + *e_it + "\n"; 545 str += e_it.key() + " = " + *e_it + "\n";
474 } 546 }
475 cstr = str.utf8(); 547 cstr = str.utf8();
476 548
477 int total_length; 549 int total_length;
478 total_length = f.writeBlock( cstr.data(), cstr.length() ); 550 total_length = f.writeBlock( cstr.data(), cstr.length() );
479 if ( total_length != int(cstr.length()) ) { 551 if ( total_length != int(cstr.length()) ) {
480 QMessageBox::critical( 0, QObject::tr("Out of Space"), 552 QMessageBox::critical( 0, QObject::tr("Out of Space"),
481 QObject::tr("There was a problem creating\nConfiguration Information \nfor this program.\n\nPlease free up some space and\ntry again.") ); 553 QObject::tr("There was a problem creating\nConfiguration Information \nfor this program.\n\nPlease free up some space and\ntry again.") );
482 f.close(); 554 f.close();
483 QFile::remove( strNewFile ); 555 QFile::remove( strNewFile );
484 return; 556 return;
485 } 557 }
486 558
487 f.close(); 559 f.close();
488 // now rename the file... 560 // now rename the file...
489 if ( rename( strNewFile, filename ) < 0 ) { 561 if ( rename( strNewFile, filename ) < 0 ) {
490 qWarning( "problem renaming the file %s to %s", strNewFile.latin1(), 562 qWarning( "problem renaming the file %s to %s", strNewFile.latin1(),
491 filename.latin1() ); 563 filename.latin1() );
492 QFile::remove( strNewFile ); 564 QFile::remove( strNewFile );
565 return;
493 } 566 }
567
568 changed = FALSE;
494} 569}
495 570
496/*! 571/*!
497 Returns whether the Config is in a valid state. 572 Returns whether the Config is in a valid state.
498*/ 573*/
499bool Config::isValid() const 574bool Config::isValid() const
500{ 575{
501 return groups.end() != git; 576 return groups.end() != git;
502} 577}
503 578
504/*! 579/*!
505 \internal 580 \internal
506*/ 581*/
507void Config::read() 582void Config::read()
508{ 583{
509 changed = FALSE; 584 changed = FALSE;
510 585
511 if ( !QFileInfo( filename ).exists() ) { 586 QString readFilename(filename);
512 git = groups.end(); 587
513 return; 588 if ( !QFile::exists(filename) ) {
589 bool failed = TRUE;
590 QFileInfo fi(filename);
591 QString settingsDir = QDir::homeDirPath() + "/Settings";
592 if (fi.dirPath(TRUE) == settingsDir) {
593 // User setting - see if there is a default in $OPIEDIR/etc/default/
594 QString dftlFile = QPEApplication::qpeDir() + "etc/default/" + fi.fileName();
595 if (QFile::exists(dftlFile)) {
596 readFilename = dftlFile;
597 failed = FALSE;
598 }
599 }
600 if (failed) {
601 git = groups.end();
602 return;
603 }
514 } 604 }
515 605
516 QFile f( filename ); 606
607 QFile f( readFilename );
517 if ( !f.open( IO_ReadOnly ) ) { 608 if ( !f.open( IO_ReadOnly ) ) {
518 git = groups.end(); 609 git = groups.end();
519 return; 610 return;
520 } 611 }
521 612
522 613 if (f.getch()!='[') {
523 // hack to avoid problems if big files are passed to test
524 // if they are valid configs ( like passing a mp3 ... )
525 // I just hope that there are no conf files > 100000 byte
526 // not the best solution, find something else later
527 if ( f.getch()!='[' ||f.size() > 100000 ) {
528 git = groups.end(); 614 git = groups.end();
529 return; 615 return;
530 } 616 }
531 f.ungetch('['); 617 f.ungetch('[');
532 618
533
534 QTextStream s( &f ); 619 QTextStream s( &f );
535#if QT_VERSION <= 230 && defined(QT_NO_CODECS) 620 read( s );
536 // The below should work, but doesn't in Qt 2.3.0
537 s.setCodec( QTextCodec::codecForMib( 106 ) );
538#else
539 s.setEncoding( QTextStream::UnicodeUTF8 );
540#endif
541
542 QStringList list = QStringList::split('\n', s.read() );
543 f.close(); 621 f.close();
544
545 for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
546 if ( !parse( *it ) ) {
547 git = groups.end();
548 return;
549 }
550 }
551} 622}
552 623
553/*! 624/*!
554 \internal 625 \internal
555*/ 626*/
556bool Config::parse( const QString &l ) 627bool Config::parse( const QString &l )
557{ 628{
558 QString line = l.stripWhiteSpace(); 629 QString line = l.stripWhiteSpace();
559
560 if ( line [0] == QChar ( '#' ))
561 return true; // ignore comments
562
563 if ( line[ 0 ] == QChar( '[' ) ) { 630 if ( line[ 0 ] == QChar( '[' ) ) {
564 QString gname = line; 631 QString gname = line;
565 gname = gname.remove( 0, 1 ); 632 gname = gname.remove( 0, 1 );
566 if ( gname[ (int)gname.length() - 1 ] == QChar( ']' ) ) 633 if ( gname[ (int)gname.length() - 1 ] == QChar( ']' ) )
567 gname = gname.remove( gname.length() - 1, 1 ); 634 gname = gname.remove( gname.length() - 1, 1 );
568 git = groups.insert( gname, ConfigGroup() ); 635 git = groups.insert( gname, ConfigGroup() );
569 } else if ( !line.isEmpty() ) { 636 } else if ( !line.isEmpty() ) {
570 if ( git == groups.end() ) 637 if ( git == groups.end() )
571 return FALSE; 638 return FALSE;
572 int eq = line.find( '=' ); 639 int eq = line.find( '=' );
573 if ( eq == -1 ) 640 if ( eq == -1 )
574 return FALSE; 641 return FALSE;
575 QString key = line.left(eq).stripWhiteSpace(); 642 QString key = line.left(eq).stripWhiteSpace();
576 QString value = line.mid(eq+1).stripWhiteSpace(); 643 QString value = line.mid(eq+1).stripWhiteSpace();
577 ( *git ).insert( key, value ); 644
645 if ( git.key() == "Translation" ) {
646 if ( key == "File" ) {
647 if ( !d )
648 d = new ConfigPrivate;
649 d->trfile = value;
650 } else if ( key == "Context" ) {
651 if ( !d )
652 d = new ConfigPrivate;
653 d->trcontext = value.latin1();
654 } else if ( key.startsWith("Comment") ) {
655 return TRUE; // ignore comment for ts file
656 } else {
657 return FALSE; // Unrecognized
658 }
659 }
660
661 int kl = key.length();
662 if ( kl > 1 && key[kl-1] == ']' && key[kl-2] != '[' ) {
663 // Old-style translation (inefficient)
664 if ( !d )
665 d = new ConfigPrivate;
666 if ( !d->multilang ) {
667 QStringList l = Global::languageList();
668 lang = l[0];
669 glang = l[1];
670 d->multilang = TRUE;
671 }
672 }
673
674 ( *git ).insert( key, value );
578 } 675 }
579 return TRUE; 676 return TRUE;
580} 677}
581 678
582 679
583 680
584bool Config::hasGroup( const QString& name )const { 681bool Config::hasGroup( const QString& name )const {
585 return ( groups. find ( name ) != groups. end ( )); 682 return ( groups. find ( name ) != groups. end ( ));
586}; 683};
587 684
588QStringList Config::groupList()const { 685QStringList Config::groupList()const {
589 QStringList sl; 686 QStringList sl;
590 for ( ConfigGroupMap::ConstIterator it = groups. begin ( ); it != groups. end ( ); ++it ) 687 for ( ConfigGroupMap::ConstIterator it = groups. begin ( ); it != groups. end ( ); ++it )
591 sl << it.key(); 688 sl << it.key();
592 689
593 return sl; 690 return sl;
594}; 691};
595 692
596///////////// 693/////////////
597// Qtopia 2.1 Functions 694// Qtopia 2.1 Functions
598// 695//
599//////////// 696////////////
600 697
601QStringList Config::allGroups()const { 698QStringList Config::allGroups()const {
602 return groupList(); 699 return groupList();
603} 700}
604 701
605/*! 702/*!
606 Returns the time stamp for the config identified by \a name. The 703 Returns the time stamp for the config identified by \a name. The
607 time stamp represents the time the config was last committed to storage. 704 time stamp represents the time the config was last committed to storage.
608 Returns 0 if there is no time stamp available for the config. 705 Returns 0 if there is no time stamp available for the config.
609 706
610 A \a domain can optionally be specified and defaults to User. 707 A \a domain can optionally be specified and defaults to User.
611 See \l{Config()} for details. 708 See \l{Config()} for details.
612 709
613 First availability: Qtopia 2.0 710 First availability: Qtopia 2.0
614*/ 711*/
615long Config::timeStamp(const QString& name, Domain domain) 712long Config::timeStamp(const QString& name, Domain domain)
616{ 713{
617#ifdef Q_WS_WIN 714#ifdef Q_WS_WIN
618 // Too slow (many conversions too and from time_t and QDataTime) 715 // Too slow (many conversions too and from time_t and QDataTime)
619 QDateTime epoch; 716 QDateTime epoch;
620 epoch.setTime_t(0); 717 epoch.setTime_t(0);
621 return epoch.secsTo(QFileInfo(Config::configFilename(name,domain)).lastModified()); 718 return epoch.secsTo(QFileInfo(Config::configFilename(name,domain)).lastModified());
622#else 719#else
623 QString fn = Config::configFilename(name,domain); 720 QString fn = Config::configFilename(name,domain);
624 struct stat b; 721 struct stat b;
625 if (lstat( QFile::encodeName(fn).data(), &b ) == 0) 722 if (lstat( QFile::encodeName(fn).data(), &b ) == 0)
626 return b.st_mtime; 723 return b.st_mtime;
627 else 724 else
628 return 0; 725 return 0;
629#endif 726#endif
630} 727}
631 728
632 729
633/*! 730/*!
634 Removes the current group (and all its entries). 731 Removes the current group (and all its entries).
635 732
636 The current group becomes unset. 733 The current group becomes unset.
637 734
638 First availability: Qtopia 2.0 735 First availability: Qtopia 2.0
639*/ 736*/
640void Config::removeGroup() 737void Config::removeGroup()
641{ 738{
642 if ( git == groups.end() ) { 739 if ( git == groups.end() ) {
643 qWarning( "no group set" ); 740 qWarning( "no group set" );
644 return; 741 return;
645 } 742 }
646 743
647 groups.remove(git.key()); 744 groups.remove(git.key());
648 git = groups.end(); 745 git = groups.end();
649 changed = TRUE; 746 changed = TRUE;
650} 747}
651 748
652/*! 749/*!
653 Removes the current group (and all its entries). 750 Removes the current group (and all its entries).
654 751
655 The current group becomes unset. 752 The current group becomes unset.
656 753
657 First availability: Qtopia 2.0 754 First availability: Qtopia 2.0
658*/ 755*/
659void Config::removeGroup(const QString& g) 756void Config::removeGroup(const QString& g)
660{ 757{
661 groups.remove(g); 758 groups.remove(g);
662 git = groups.end(); 759 git = groups.end();
663} 760}
664 761
665 762
666 763
667/*! 764/*!
668 Writes a (\a key, \a lst) entry to the current group. 765 Writes a (\a key, \a lst) entry to the current group.
669 766
670 The list is 767 The list is
671 separated by the two characters "^e", and "^" withing the strings 768 separated by the two characters "^e", and "^" withing the strings
672 is replaced by "^^", such that the strings may contain any character, 769 is replaced by "^^", such that the strings may contain any character,
673 including "^". 770 including "^".
diff --git a/library/config.h b/library/config.h
index 29ba0d6..f8d3bf7 100644
--- a/library/config.h
+++ b/library/config.h
@@ -1,108 +1,110 @@
1/********************************************************************** 1/**********************************************************************
2** Copyright (C) 2000, 2004 Trolltech AS. All rights reserved. 2** Copyright (C) 2000, 2004 Trolltech AS. All rights reserved.
3** 3**
4** This file is part of Qtopia Environment. 4** This file is part of Qtopia Environment.
5** 5**
6** This file may be distributed and/or modified under the terms of the 6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free Software 7** GNU General Public License version 2 as published by the Free Software
8** Foundation and appearing in the file LICENSE.GPL included in the 8** Foundation and appearing in the file LICENSE.GPL included in the
9** packaging of this file. 9** packaging of this file.
10** 10**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13** 13**
14** See http://www.trolltech.com/gpl/ for GPL licensing information. 14** See http://www.trolltech.com/gpl/ for GPL licensing information.
15** 15**
16** Contact info@trolltech.com if any conditions of this licensing are 16** Contact info@trolltech.com if any conditions of this licensing are
17** not clear to you. 17** not clear to you.
18** 18**
19**********************************************************************/ 19**********************************************************************/
20 20
21#ifndef CONFIG_H 21#ifndef CONFIG_H
22#define CONFIG_H 22#define CONFIG_H
23 23
24// ##### could use QSettings with Qt 3.0 24// ##### could use QSettings with Qt 3.0
25 25
26#include <qpe/qpeglobal.h> 26#include <qpe/qpeglobal.h>
27 27
28#include <qmap.h> 28#include <qmap.h>
29#include <qstringlist.h> 29#include <qstringlist.h>
30 30
31typedef QMap< QString, QString > ConfigGroup; 31typedef QMap< QString, QString > ConfigGroup;
32typedef QMap< QString, ConfigGroup> ConfigGroupMap; 32typedef QMap< QString, ConfigGroup> ConfigGroupMap;
33 33
34class QTextStream;
34class ConfigPrivate; 35class ConfigPrivate;
35class Config 36class Config
36{ 37{
37public: 38public:
38 39
39 enum Domain { File, User }; 40 enum Domain { File, User };
40 Config( const QString &name, Domain domain=User ); 41 Config( const QString &name, Domain domain=User );
41 ~Config(); 42 ~Config();
42 43
43 QTOPIA_MERGED_METHOD(static long timeStamp( const QString &name, Domain domain=User ), "2.1"); 44 QTOPIA_MERGED_METHOD(static long timeStamp( const QString &name, Domain domain=User ), "2.1");
44 45
45 bool operator == ( const Config & other ) const { return (filename == other.filename); } 46 bool operator == ( const Config & other ) const { return (filename == other.filename); }
46 bool operator != ( const Config & other ) const { return (filename != other.filename); } 47 bool operator != ( const Config & other ) const { return (filename != other.filename); }
47 48
48 bool isValid() const; 49 bool isValid() const;
49 bool hasKey( const QString &key ) const; 50 bool hasKey( const QString &key ) const;
50 51
51 // inline for better SharpROM BC 52 // inline for better SharpROM BC
52 NOT_IN_QPE(bool hasGroup ( const QString &gname ) const); 53 NOT_IN_QPE(bool hasGroup ( const QString &gname ) const);
53 NOT_IN_QPE(QStringList groupList ( ) const); 54 NOT_IN_QPE(QStringList groupList ( ) const);
54 55
55 void setGroup( const QString &gname ); 56 void setGroup( const QString &gname );
56 void writeEntry( const QString &key, const char* value ); 57 void writeEntry( const QString &key, const char* value );
57 void writeEntry( const QString &key, const QString &value ); 58 void writeEntry( const QString &key, const QString &value );
58 void writeEntryCrypt( const QString &key, const QString &value ); 59 void writeEntryCrypt( const QString &key, const QString &value );
59 void writeEntry( const QString &key, int num ); 60 void writeEntry( const QString &key, int num );
60#ifdef Q_HAS_BOOL_TYPE 61#ifdef Q_HAS_BOOL_TYPE
61 void writeEntry( const QString &key, bool b ); 62 void writeEntry( const QString &key, bool b );
62#endif 63#endif
63 void writeEntry( const QString &key, const QStringList &lst, const QChar &sep ); 64 void writeEntry( const QString &key, const QStringList &lst, const QChar &sep );
64 QTOPIA_MERGED_METHOD(void writeEntry( const QString &key, const QStringList &lst ), "2.1.0"); 65 QTOPIA_MERGED_METHOD(void writeEntry( const QString &key, const QStringList &lst ), "2.1.0");
65 66
66 void removeEntry( const QString &key ); 67 void removeEntry( const QString &key );
67 68
68 QString readEntry( const QString &key, const QString &deflt = QString::null ) const; 69 QString readEntry( const QString &key, const QString &deflt = QString::null ) const;
69 QString readEntryCrypt( const QString &key, const QString &deflt = QString::null ) const; 70 QString readEntryCrypt( const QString &key, const QString &deflt = QString::null ) const;
70 QString readEntryDirect( const QString &key, const QString &deflt = QString::null ) const; 71 QString readEntryDirect( const QString &key, const QString &deflt = QString::null ) const;
71 int readNumEntry( const QString &key, int deflt = -1 ) const; 72 int readNumEntry( const QString &key, int deflt = -1 ) const;
72 bool readBoolEntry( const QString &key, bool deflt = FALSE ) const; 73 bool readBoolEntry( const QString &key, bool deflt = FALSE ) const;
73 QStringList readListEntry( const QString &key, const QChar &sep ) const; 74 QStringList readListEntry( const QString &key, const QChar &sep ) const;
74 QTOPIA_MERGED_METHOD(QStringList readListEntry( const QString &key ) const, "2.1.0"); 75 QTOPIA_MERGED_METHOD(QStringList readListEntry( const QString &key ) const, "2.1.0");
75 76
76 // For compatibility, non-const versions. 77 // For compatibility, non-const versions.
77 QString readEntry( const QString &key, const QString &deflt ); 78 QString readEntry( const QString &key, const QString &deflt );
78 QString readEntryCrypt( const QString &key, const QString &deflt ); 79 QString readEntryCrypt( const QString &key, const QString &deflt );
79 QString readEntryDirect( const QString &key, const QString &deflt ); 80 QString readEntryDirect( const QString &key, const QString &deflt );
80 int readNumEntry( const QString &key, int deflt ); 81 int readNumEntry( const QString &key, int deflt );
81 bool readBoolEntry( const QString &key, bool deflt ); 82 bool readBoolEntry( const QString &key, bool deflt );
82 QStringList readListEntry( const QString &key, const QChar &sep ); 83 QStringList readListEntry( const QString &key, const QChar &sep );
83 84
84 void clearGroup(); 85 void clearGroup();
85 QTOPIA_MERGED_METHOD(void removeGroup(), "2.1.0"); 86 QTOPIA_MERGED_METHOD(void removeGroup(), "2.1.0");
86 QTOPIA_MERGED_METHOD(void removeGroup(const QString&), "2.1.0"); 87 QTOPIA_MERGED_METHOD(void removeGroup(const QString&), "2.1.0");
87 QTOPIA_MERGED_METHOD(QStringList allGroups() const, "2.1.0"); 88 QTOPIA_MERGED_METHOD(QStringList allGroups() const, "2.1.0");
88 89
89 void write( const QString &fn = QString::null ); 90 void write( const QString &fn = QString::null );
90 91
91protected: 92protected:
92 void read(); 93 void read();
93 bool parse( const QString &line ); 94 bool parse( const QString &line );
94 95
95 QMap< QString, ConfigGroup > groups; 96 ConfigGroupMap groups;
96 QMap< QString, ConfigGroup >::Iterator git; 97 ConfigGroupMap::Iterator git;
97 QString filename; 98 QString filename;
98 QString lang; 99 QString lang;
99 QString glang; 100 QString glang;
100 bool changed; 101 bool changed;
101 ConfigPrivate *d; 102 ConfigPrivate *d;
102 static QString configFilename(const QString& name, Domain); 103 static QString configFilename(const QString& name, Domain);
103 104
104private: // Sharp ROM compatibility 105private: // Sharp ROM compatibility
105 Config( const QString &name, bool what ); 106 Config( const QString &name, bool what );
107 void read( QTextStream &s);
106}; 108};
107 109
108#endif 110#endif