summaryrefslogtreecommitdiff
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--library/config.cpp195
1 files changed, 195 insertions, 0 deletions
diff --git a/library/config.cpp b/library/config.cpp
index bdfcb3f..f68c336 100644
--- a/library/config.cpp
+++ b/library/config.cpp
@@ -1,258 +1,431 @@
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 <sys/time.h>
30#include <fcntl.h> 31#include <fcntl.h>
31#include <stdlib.h> 32#include <stdlib.h>
33#include <time.h>
32#include <unistd.h> 34#include <unistd.h>
33 35
34#define QTOPIA_INTERNAL_LANGLIST 36#define QTOPIA_INTERNAL_LANGLIST
35#include "config.h" 37#include "config.h"
36#include "global.h" 38#include "global.h"
37#include "qpeapplication.h" 39#include "qpeapplication.h"
38 40
39 41
40/* 42/*
41 * Internal Class 43 * Internal Class
42 */ 44 */
43class ConfigPrivate { 45class ConfigPrivate {
44public: 46public:
45 ConfigPrivate() : multilang(FALSE) {} 47 ConfigPrivate() : multilang(FALSE) {}
46 ConfigPrivate(const ConfigPrivate& o) : 48 ConfigPrivate(const ConfigPrivate& o) :
47 trfile(o.trfile), 49 trfile(o.trfile),
48 trcontext(o.trcontext), 50 trcontext(o.trcontext),
49 multilang(o.multilang) 51 multilang(o.multilang)
50 {} 52 {}
51 ConfigPrivate& operator=(const ConfigPrivate& o) 53 ConfigPrivate& operator=(const ConfigPrivate& o)
52 { 54 {
53 trfile = o.trfile; 55 trfile = o.trfile;
54 trcontext = o.trcontext; 56 trcontext = o.trcontext;
55 multilang = o.multilang; 57 multilang = o.multilang;
56 return *this; 58 return *this;
57 } 59 }
58 60
59 QString trfile; 61 QString trfile;
60 QCString trcontext; 62 QCString trcontext;
61 bool multilang; 63 bool multilang;
62}; 64};
63 65
64///////////////////////////////////////////////////////////////// 66/////////////////////////////////////////////////////////////////
65///////////////////////////////////////////////////////////////// 67/////////////////////////////////////////////////////////////////
66 68
69#ifndef Q_OS_WIN32
70
71//#define DEBUG_CONFIG_CACHE
72
73const int CONFIG_CACHE_SIZE = 8192;
74const int CONFIG_CACHE_TIMEOUT = 1000;
75
76class ConfigData
77{
78public:
79 ConfigData(const ConfigData& o) :
80 cfg(o.cfg),
81 priv(o.priv ? new ConfigPrivate(*o.priv) : 0),
82 mtime(o.mtime),
83 size(o.size),
84 used(o.used)
85 { }
86
87 ConfigData& operator=(const ConfigData& o)
88 {
89 cfg = o.cfg;
90 delete priv;
91 priv = o.priv ? new ConfigPrivate(*o.priv) : 0;
92 mtime = o.mtime;
93 size = o.size;
94 used = o.used;
95 return *this;
96 }
97
98 ConfigData() : priv(0) {}
99 ~ConfigData() { delete priv; }
100
101 ConfigGroupMap cfg;
102 ConfigPrivate *priv; // Owned by this object
103 time_t mtime;
104 unsigned int size;
105 struct timeval used;
106};
107
108class ConfigCache : public QObject
109{
110public:
111 ConfigCache();
112
113 void insert(const QString &filename, const ConfigGroupMap &cfg, const ConfigPrivate* priv);
114 bool find(const QString &filename, ConfigGroupMap &cfg, ConfigPrivate*& priv);
115 void remove(const QString &filename);
116
117protected:
118 void timerEvent(QTimerEvent *);
119
120private:
121 void removeLru();
122
123 QMap<QString, ConfigData> configData;
124 unsigned int totalsize;
125 int tid;
126};
127
128ConfigCache::ConfigCache() : QObject(), totalsize(0), tid(0)
129{
130}
131
132void ConfigCache::insert(const QString &filename, const ConfigGroupMap &cfg, const ConfigPrivate* priv)
133{
134 // use stat() rather than QFileInfo for speed.
135 struct stat sbuf;
136 stat(filename.local8Bit().data(), &sbuf);
137
138 if (sbuf.st_size < CONFIG_CACHE_SIZE/2) {
139 ConfigData data;
140 data.cfg = cfg;
141 data.priv = priv ? new ConfigPrivate(*priv) : 0;
142 data.mtime = sbuf.st_mtime;
143 data.size = sbuf.st_size;
144 gettimeofday(&data.used, 0);
145
146 remove(filename);
147 configData.insert(filename, data);
148
149 totalsize += data.size;
150#ifdef DEBUG_CONFIG_CACHE
151 qDebug("++++++ insert %s", filename.latin1());
152#endif
153 }
154
155 if (totalsize > (uint)CONFIG_CACHE_SIZE) {
156 // We'll delay deleting anything until later.
157 // This lets us grow quite large during some operations,
158 // but we'll be reduced to a decent size later.
159 // This works well with the main use case - app startup.
160 if (!tid)
161 tid = startTimer(CONFIG_CACHE_TIMEOUT);
162 }
163}
164
165bool ConfigCache::find(const QString &filename, ConfigGroupMap &cfg, ConfigPrivate*& priv)
166{
167 QMap<QString, ConfigData>::Iterator it = configData.find(filename);
168 if (it != configData.end()) {
169 ConfigData data = *it;
170 // use stat() rather than QFileInfo for speed.
171 struct stat sbuf;
172 stat(filename.local8Bit().data(), &sbuf);
173
174 if (data.mtime == sbuf.st_mtime && (int)data.size == sbuf.st_size) {
175 cfg = data.cfg;
176 delete priv;
177 priv = data.priv ? new ConfigPrivate(*data.priv) : 0;
178 gettimeofday(&data.used, 0);
179#ifdef DEBUG_CONFIG_CACHE
180 qDebug("******* Cache hit: %s", filename.latin1());
181#endif
182 return TRUE;
183 }
184 }
185
186#ifdef DEBUG_CONFIG_CACHE
187 qDebug("------- Cache miss: %s", filename.latin1());
188#endif
189
190 return FALSE;
191}
192
193void ConfigCache::remove(const QString &filename)
194{
195 QMap<QString, ConfigData>::Iterator it = configData.find(filename);
196 if (it != configData.end()) {
197 totalsize -= (*it).size;
198 configData.remove(it);
199 }
200}
201
202void ConfigCache::timerEvent(QTimerEvent *)
203{
204#ifdef DEBUG_CONFIG_CACHE
205 qDebug( "cache size: %d", totalsize);
206#endif
207 while (totalsize > (uint)CONFIG_CACHE_SIZE)
208 removeLru();
209 killTimer(tid);
210 tid = 0;
211}
212
213void ConfigCache::removeLru()
214{
215 QMap<QString, ConfigData>::Iterator it = configData.begin();
216 QMap<QString, ConfigData>::Iterator lru = it;
217 ++it;
218 for (; it != configData.end(); ++it) {
219 if ((*it).used.tv_sec < (*lru).used.tv_sec ||
220 ((*it).used.tv_sec == (*lru).used.tv_sec &&
221 (*it).used.tv_usec < (*lru).used.tv_usec))
222 lru = it;
223 }
224
225#ifdef DEBUG_CONFIG_CACHE
226 qDebug("Cache full, removing: %s", lru.key().latin1());
227#endif
228 totalsize -= (*lru).size;
229 configData.remove(lru);
230}
231
232static ConfigCache *qpe_configCache = 0;
233
234#endif /* Q_OS_WIN32 */
235
236
237// ==========================================================================
238
239
67/*! 240/*!
68 \internal 241 \internal
69*/ 242*/
70QString Config::configFilename(const QString& name, Domain d) 243QString Config::configFilename(const QString& name, Domain d)
71{ 244{
72 switch (d) { 245 switch (d) {
73 case File: 246 case File:
74 return name; 247 return name;
75 case User: { 248 case User: {
76 QDir dir = (QString(getenv("HOME")) + "/Settings"); 249 QDir dir = (QString(getenv("HOME")) + "/Settings");
77 if ( !dir.exists() ) 250 if ( !dir.exists() )
78 mkdir(dir.path().local8Bit(),0700); 251 mkdir(dir.path().local8Bit(),0700);
79 return dir.path() + "/" + name + ".conf"; 252 return dir.path() + "/" + name + ".conf";
80 } 253 }
81 } 254 }
82 return name; 255 return name;
83} 256}
84 257
85/* This cannot be made public because of binary compat issues */ 258/* This cannot be made public because of binary compat issues */
86void Config::read( QTextStream &s ) 259void Config::read( QTextStream &s )
87{ 260{
88#if QT_VERSION <= 230 && defined(QT_NO_CODECS) 261#if QT_VERSION <= 230 && defined(QT_NO_CODECS)
89 // The below should work, but doesn't in Qt 2.3.0 262 // The below should work, but doesn't in Qt 2.3.0
90 s.setCodec( QTextCodec::codecForMib( 106 ) ); 263 s.setCodec( QTextCodec::codecForMib( 106 ) );
91#else 264#else
92 s.setEncoding( QTextStream::UnicodeUTF8 ); 265 s.setEncoding( QTextStream::UnicodeUTF8 );
93#endif 266#endif
94 267
95 QStringList list = QStringList::split('\n', s.read() ); 268 QStringList list = QStringList::split('\n', s.read() );
96 269
97 for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) { 270 for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
98 if ( !parse( *it ) ) { 271 if ( !parse( *it ) ) {
99 git = groups.end(); 272 git = groups.end();
100 return; 273 return;
101 } 274 }
102 } 275 }
103} 276}
104 277
105/*! 278/*!
106 \class Config config.h 279 \class Config config.h
107 \brief The Config class provides for saving application cofniguration state. 280 \brief The Config class provides for saving application cofniguration state.
108 281
109 You should keep a Config in existence only while you do not want others 282 You should keep a Config in existence only while you do not want others
110 to be able to change the state. There is no locking currently, but there 283 to be able to change the state. There is no locking currently, but there
111 may be in the future. 284 may be in the future.
112*/ 285*/
113 286
114/*! 287/*!
115 \enum Config::ConfigGroup 288 \enum Config::ConfigGroup
116 \internal 289 \internal
117*/ 290*/
118 291
119/*! 292/*!
120 \enum Config::Domain 293 \enum Config::Domain
121 294
122 \value File 295 \value File
123 \value User 296 \value User
124 297
125 See Config for details. 298 See Config for details.
126*/ 299*/
127 300
128/*! 301/*!
129 Constructs a config that will load or create a configuration with the 302 Constructs a config that will load or create a configuration with the
130 given \a name in the given \a domain. 303 given \a name in the given \a domain.
131 304
132 You must call setGroup() before doing much else with the Config. 305 You must call setGroup() before doing much else with the Config.
133 306
134 In the default Domain, \e User, 307 In the default Domain, \e User,
135 the configuration is user-specific. \a name should not contain "/" in 308 the configuration is user-specific. \a name should not contain "/" in
136 this case, and in general should be the name of the C++ class that is 309 this case, and in general should be the name of the C++ class that is
137 primarily responsible for maintaining the configuration. 310 primarily responsible for maintaining the configuration.
138 311
139 In the File Domain, \a name is an absolute filename. 312 In the File Domain, \a name is an absolute filename.
140*/ 313*/
141Config::Config( const QString &name, Domain domain ) 314Config::Config( const QString &name, Domain domain )
142 : filename( configFilename(name,domain) ) 315 : filename( configFilename(name,domain) )
143{ 316{
144 git = groups.end(); 317 git = groups.end();
145 d = 0; 318 d = 0;
146 read(); 319 read();
147} 320}
148 321
149 322
150// Sharp ROM compatibility 323// Sharp ROM compatibility
151Config::Config ( const QString &name, bool what ) 324Config::Config ( const QString &name, bool what )
152 : filename( configFilename(name,what ? User : File) ) 325 : filename( configFilename(name,what ? User : File) )
153{ 326{
154 git = groups.end(); 327 git = groups.end();
155 d = 0; 328 d = 0;
156 read(); 329 read();
157} 330}
158 331
159/*! 332/*!
160 Writes any changes to disk and destroys the in-memory object. 333 Writes any changes to disk and destroys the in-memory object.
161*/ 334*/
162Config::~Config() 335Config::~Config()
163{ 336{
164 if ( changed ) 337 if ( changed )
165 write(); 338 write();
166 339
167 delete d; 340 delete d;
168} 341}
169 342
170/*! 343/*!
171 Returns whether the current group has an entry called \a key. 344 Returns whether the current group has an entry called \a key.
172*/ 345*/
173bool Config::hasKey( const QString &key ) const 346bool Config::hasKey( const QString &key ) const
174{ 347{
175 if ( groups.end() == git ) 348 if ( groups.end() == git )
176 return FALSE; 349 return FALSE;
177 ConfigGroup::ConstIterator it = ( *git ).find( key ); 350 ConfigGroup::ConstIterator it = ( *git ).find( key );
178 if ( it == ( *git ).end() ) { 351 if ( it == ( *git ).end() ) {
179 if ( d && !d->trcontext.isNull() ) { 352 if ( d && !d->trcontext.isNull() ) {
180 it = ( *git ).find( key + "[]" ); 353 it = ( *git ).find( key + "[]" );
181 } else if ( d && d->multilang ) { 354 } else if ( d && d->multilang ) {
182 it = ( *git ).find( key + "["+lang+"]" ); 355 it = ( *git ).find( key + "["+lang+"]" );
183 if ( it == ( *git ).end() && !glang.isEmpty() ) 356 if ( it == ( *git ).end() && !glang.isEmpty() )
184 it = ( *git ).find( key + "["+glang+"]" ); 357 it = ( *git ).find( key + "["+glang+"]" );
185 } 358 }
186 } 359 }
187 return it != ( *git ).end(); 360 return it != ( *git ).end();
188} 361}
189 362
190/*! 363/*!
191 Sets the current group for subsequent reading and writing of 364 Sets the current group for subsequent reading and writing of
192 entries to \a gname. Grouping allows the application to partition the namespace. 365 entries to \a gname. Grouping allows the application to partition the namespace.
193 366
194 This function must be called prior to any reading or writing 367 This function must be called prior to any reading or writing
195 of entries. 368 of entries.
196 369
197 The \a gname must not be empty. 370 The \a gname must not be empty.
198*/ 371*/
199void Config::setGroup( const QString &gname ) 372void Config::setGroup( const QString &gname )
200{ 373{
201 QMap< QString, ConfigGroup>::Iterator it = groups.find( gname ); 374 QMap< QString, ConfigGroup>::Iterator it = groups.find( gname );
202 if ( it == groups.end() ) { 375 if ( it == groups.end() ) {
203 git = groups.insert( gname, ConfigGroup() ); 376 git = groups.insert( gname, ConfigGroup() );
204 changed = TRUE; 377 changed = TRUE;
205 return; 378 return;
206 } 379 }
207 git = it; 380 git = it;
208} 381}
209 382
210/*! 383/*!
211 Writes a (\a key, \a value) entry to the current group. 384 Writes a (\a key, \a value) entry to the current group.
212 385
213 \sa readEntry() 386 \sa readEntry()
214*/ 387*/
215void Config::writeEntry( const QString &key, const char* value ) 388void Config::writeEntry( const QString &key, const char* value )
216{ 389{
217 writeEntry(key,QString(value)); 390 writeEntry(key,QString(value));
218} 391}
219 392
220/*! 393/*!
221 Writes a (\a key, \a value) entry to the current group. 394 Writes a (\a key, \a value) entry to the current group.
222 395
223 \sa readEntry() 396 \sa readEntry()
224*/ 397*/
225void Config::writeEntry( const QString &key, const QString &value ) 398void Config::writeEntry( const QString &key, const QString &value )
226{ 399{
227 if ( git == groups.end() ) { 400 if ( git == groups.end() ) {
228 qWarning( "no group set" ); 401 qWarning( "no group set" );
229 return; 402 return;
230 } 403 }
231 if ( (*git)[key] != value ) { 404 if ( (*git)[key] != value ) {
232 ( *git ).insert( key, value ); 405 ( *git ).insert( key, value );
233 changed = TRUE; 406 changed = TRUE;
234 } 407 }
235} 408}
236 409
237/* 410/*
238 Note that the degree of protection offered by the encryption here is 411 Note that the degree of protection offered by the encryption here is
239 only sufficient to avoid the most casual observation of the configuration 412 only sufficient to avoid the most casual observation of the configuration
240 files. People with access to the files can write down the contents and 413 files. People with access to the files can write down the contents and
241 decrypt it using this source code. 414 decrypt it using this source code.
242 415
243 Conceivably, and at some burden to the user, this encryption could 416 Conceivably, and at some burden to the user, this encryption could
244 be improved. 417 be improved.
245*/ 418*/
246static QString encipher(const QString& plain) 419static QString encipher(const QString& plain)
247{ 420{
248 // mainly, we make it long 421 // mainly, we make it long
249 QString cipher; 422 QString cipher;
250 int mix=28730492; 423 int mix=28730492;
251 for (int i=0; i<(int)plain.length(); i++) { 424 for (int i=0; i<(int)plain.length(); i++) {
252 int u = plain[i].unicode(); 425 int u = plain[i].unicode();
253 int c = u ^ mix; 426 int c = u ^ mix;
254 QString x = QString::number(c,36); 427 QString x = QString::number(c,36);
255 cipher.append(QChar('a'+x.length())); 428 cipher.append(QChar('a'+x.length()));
256 cipher.append(x); 429 cipher.append(x);
257 mix *= u; 430 mix *= u;
258 } 431 }
@@ -376,438 +549,460 @@ void Config::removeEntry( const QString &key )
376 * 549 *
377 */ 550 */
378 551
379/*! 552/*!
380 \internal 553 \internal
381 For compatibility, non-const version. 554 For compatibility, non-const version.
382*/ 555*/
383QString Config::readEntry( const QString &key, const QString &deflt ) 556QString Config::readEntry( const QString &key, const QString &deflt )
384{ 557{
385 QString r; 558 QString r;
386 if ( d && !d->trcontext.isNull() ) { 559 if ( d && !d->trcontext.isNull() ) {
387 // Still try untranslated first, becuase: 560 // Still try untranslated first, becuase:
388 // 1. It's the common case 561 // 1. It's the common case
389 // 2. That way the value can be WRITTEN (becoming untranslated) 562 // 2. That way the value can be WRITTEN (becoming untranslated)
390 r = readEntryDirect( key ); 563 r = readEntryDirect( key );
391 if ( !r.isNull() ) 564 if ( !r.isNull() )
392 return r; 565 return r;
393 r = readEntryDirect( key + "[]" ); 566 r = readEntryDirect( key + "[]" );
394 if ( !r.isNull() ) 567 if ( !r.isNull() )
395 return qApp->translate(d->trfile,d->trcontext,r); 568 return qApp->translate(d->trfile,d->trcontext,r);
396 } else if ( d && d->multilang ) { 569 } else if ( d && d->multilang ) {
397 // For compatibilitity 570 // For compatibilitity
398 r = readEntryDirect( key + "["+lang+"]" ); 571 r = readEntryDirect( key + "["+lang+"]" );
399 if ( !r.isNull() ) 572 if ( !r.isNull() )
400 return r; 573 return r;
401 if ( !glang.isEmpty() ) { 574 if ( !glang.isEmpty() ) {
402 r = readEntryDirect( key + "["+glang+"]" ); 575 r = readEntryDirect( key + "["+glang+"]" );
403 if ( !r.isNull() ) 576 if ( !r.isNull() )
404 return r; 577 return r;
405 } 578 }
406 } 579 }
407 r = readEntryDirect( key, deflt ); 580 r = readEntryDirect( key, deflt );
408 return r; 581 return r;
409} 582}
410 583
411/*! 584/*!
412 \fn QString Config::readEntryCrypt( const QString &key, const QString &deflt ) const 585 \fn QString Config::readEntryCrypt( const QString &key, const QString &deflt ) const
413 586
414 Reads an encrypted string entry stored with \a key, defaulting to \a deflt if there is no entry. 587 Reads an encrypted string entry stored with \a key, defaulting to \a deflt if there is no entry.
415*/ 588*/
416 589
417/*! 590/*!
418 \internal 591 \internal
419 For compatibility, non-const version. 592 For compatibility, non-const version.
420*/ 593*/
421QString Config::readEntryCrypt( const QString &key, const QString &deflt ) 594QString Config::readEntryCrypt( const QString &key, const QString &deflt )
422{ 595{
423 QString res = readEntry( key ); 596 QString res = readEntry( key );
424 if ( res.isNull() ) 597 if ( res.isNull() )
425 return deflt; 598 return deflt;
426 return decipher(res); 599 return decipher(res);
427} 600}
428 601
429/*! 602/*!
430 \fn QString Config::readEntryDirect( const QString &key, const QString &deflt ) const 603 \fn QString Config::readEntryDirect( const QString &key, const QString &deflt ) const
431 \internal 604 \internal
432*/ 605*/
433 606
434/*! 607/*!
435 \internal 608 \internal
436 For compatibility, non-const version. 609 For compatibility, non-const version.
437*/ 610*/
438QString Config::readEntryDirect( const QString &key, const QString &deflt ) 611QString Config::readEntryDirect( const QString &key, const QString &deflt )
439{ 612{
440 if ( git == groups.end() ) { 613 if ( git == groups.end() ) {
441 //qWarning( "no group set" ); 614 //qWarning( "no group set" );
442 return deflt; 615 return deflt;
443 } 616 }
444 ConfigGroup::ConstIterator it = ( *git ).find( key ); 617 ConfigGroup::ConstIterator it = ( *git ).find( key );
445 if ( it != ( *git ).end() ) 618 if ( it != ( *git ).end() )
446 return *it; 619 return *it;
447 else 620 else
448 return deflt; 621 return deflt;
449} 622}
450 623
451/*! 624/*!
452 \fn int Config::readNumEntry( const QString &key, int deflt ) const 625 \fn int Config::readNumEntry( const QString &key, int deflt ) const
453 Reads a numeric entry stored with \a key, defaulting to \a deflt if there is no entry. 626 Reads a numeric entry stored with \a key, defaulting to \a deflt if there is no entry.
454*/ 627*/
455 628
456/*! 629/*!
457 \internal 630 \internal
458 For compatibility, non-const version. 631 For compatibility, non-const version.
459*/ 632*/
460int Config::readNumEntry( const QString &key, int deflt ) 633int Config::readNumEntry( const QString &key, int deflt )
461{ 634{
462 QString s = readEntry( key ); 635 QString s = readEntry( key );
463 if ( s.isEmpty() ) 636 if ( s.isEmpty() )
464 return deflt; 637 return deflt;
465 else 638 else
466 return s.toInt(); 639 return s.toInt();
467} 640}
468 641
469/*! 642/*!
470 \fn bool Config::readBoolEntry( const QString &key, bool deflt ) const 643 \fn bool Config::readBoolEntry( const QString &key, bool deflt ) const
471 Reads a bool entry stored with \a key, defaulting to \a deflt if there is no entry. 644 Reads a bool entry stored with \a key, defaulting to \a deflt if there is no entry.
472*/ 645*/
473 646
474/*! 647/*!
475 \internal 648 \internal
476 For compatibility, non-const version. 649 For compatibility, non-const version.
477*/ 650*/
478bool Config::readBoolEntry( const QString &key, bool deflt ) 651bool Config::readBoolEntry( const QString &key, bool deflt )
479{ 652{
480 QString s = readEntry( key ); 653 QString s = readEntry( key );
481 if ( s.isEmpty() ) 654 if ( s.isEmpty() )
482 return deflt; 655 return deflt;
483 else 656 else
484 return (bool)s.toInt(); 657 return (bool)s.toInt();
485} 658}
486 659
487/*! 660/*!
488 \fn QStringList Config::readListEntry( const QString &key, const QChar &sep ) const 661 \fn QStringList Config::readListEntry( const QString &key, const QChar &sep ) const
489 Reads a string list entry stored with \a key, and with \a sep as the separator. 662 Reads a string list entry stored with \a key, and with \a sep as the separator.
490*/ 663*/
491 664
492/*! 665/*!
493 \internal 666 \internal
494 For compatibility, non-const version. 667 For compatibility, non-const version.
495*/ 668*/
496QStringList Config::readListEntry( const QString &key, const QChar &sep ) 669QStringList Config::readListEntry( const QString &key, const QChar &sep )
497{ 670{
498 QString s = readEntry( key ); 671 QString s = readEntry( key );
499 if ( s.isEmpty() ) 672 if ( s.isEmpty() )
500 return QStringList(); 673 return QStringList();
501 else 674 else
502 return QStringList::split( sep, s ); 675 return QStringList::split( sep, s );
503} 676}
504 677
505/*! 678/*!
506 Removes all entries from the current group. 679 Removes all entries from the current group.
507*/ 680*/
508void Config::clearGroup() 681void Config::clearGroup()
509{ 682{
510 if ( git == groups.end() ) { 683 if ( git == groups.end() ) {
511 qWarning( "no group set" ); 684 qWarning( "no group set" );
512 return; 685 return;
513 } 686 }
514 if ( !(*git).isEmpty() ) { 687 if ( !(*git).isEmpty() ) {
515 ( *git ).clear(); 688 ( *git ).clear();
516 changed = TRUE; 689 changed = TRUE;
517 } 690 }
518} 691}
519 692
520/*! 693/*!
521 \internal 694 \internal
522*/ 695*/
523void Config::write( const QString &fn ) 696void Config::write( const QString &fn )
524{ 697{
525 QString strNewFile; 698 QString strNewFile;
526 if ( !fn.isEmpty() ) 699 if ( !fn.isEmpty() )
527 filename = fn; 700 filename = fn;
528 strNewFile = filename + ".new"; 701 strNewFile = filename + ".new";
529 702
530 QFile f( strNewFile ); 703 QFile f( strNewFile );
531 if ( !f.open( IO_WriteOnly|IO_Raw ) ) { 704 if ( !f.open( IO_WriteOnly|IO_Raw ) ) {
532 qWarning( "could not open for writing `%s'", strNewFile.latin1() ); 705 qWarning( "could not open for writing `%s'", strNewFile.latin1() );
533 git = groups.end(); 706 git = groups.end();
534 return; 707 return;
535 } 708 }
536 709
537 QString str; 710 QString str;
538 QCString cstr; 711 QCString cstr;
539 QMap< QString, ConfigGroup >::Iterator g_it = groups.begin(); 712 QMap< QString, ConfigGroup >::Iterator g_it = groups.begin();
540 713
541 for ( ; g_it != groups.end(); ++g_it ) { 714 for ( ; g_it != groups.end(); ++g_it ) {
542 str += "[" + g_it.key() + "]\n"; 715 str += "[" + g_it.key() + "]\n";
543 ConfigGroup::Iterator e_it = ( *g_it ).begin(); 716 ConfigGroup::Iterator e_it = ( *g_it ).begin();
544 for ( ; e_it != ( *g_it ).end(); ++e_it ) 717 for ( ; e_it != ( *g_it ).end(); ++e_it )
545 str += e_it.key() + " = " + *e_it + "\n"; 718 str += e_it.key() + " = " + *e_it + "\n";
546 } 719 }
547 cstr = str.utf8(); 720 cstr = str.utf8();
548 721
549 int total_length; 722 int total_length;
550 total_length = f.writeBlock( cstr.data(), cstr.length() ); 723 total_length = f.writeBlock( cstr.data(), cstr.length() );
551 if ( total_length != int(cstr.length()) ) { 724 if ( total_length != int(cstr.length()) ) {
552 QMessageBox::critical( 0, QObject::tr("Out of Space"), 725 QMessageBox::critical( 0, QObject::tr("Out of Space"),
553 QObject::tr("There was a problem creating\nConfiguration Information \nfor this program.\n\nPlease free up some space and\ntry again.") ); 726 QObject::tr("There was a problem creating\nConfiguration Information \nfor this program.\n\nPlease free up some space and\ntry again.") );
554 f.close(); 727 f.close();
555 QFile::remove( strNewFile ); 728 QFile::remove( strNewFile );
556 return; 729 return;
557 } 730 }
558 731
559 f.close(); 732 f.close();
560 // now rename the file... 733 // now rename the file...
561 if ( rename( strNewFile, filename ) < 0 ) { 734 if ( rename( strNewFile, filename ) < 0 ) {
562 qWarning( "problem renaming the file %s to %s", strNewFile.latin1(), 735 qWarning( "problem renaming the file %s to %s", strNewFile.latin1(),
563 filename.latin1() ); 736 filename.latin1() );
564 QFile::remove( strNewFile ); 737 QFile::remove( strNewFile );
565 return; 738 return;
566 } 739 }
567 740
741#ifndef Q_OS_WIN32
742 if (qpe_configCache)
743 qpe_configCache->insert(filename, groups, d);
744#endif
568 changed = FALSE; 745 changed = FALSE;
569} 746}
570 747
571/*! 748/*!
572 Returns whether the Config is in a valid state. 749 Returns whether the Config is in a valid state.
573*/ 750*/
574bool Config::isValid() const 751bool Config::isValid() const
575{ 752{
576 return groups.end() != git; 753 return groups.end() != git;
577} 754}
578 755
579/*! 756/*!
580 \internal 757 \internal
581*/ 758*/
582void Config::read() 759void Config::read()
583{ 760{
584 changed = FALSE; 761 changed = FALSE;
585 762
586 QString readFilename(filename); 763 QString readFilename(filename);
587 764
588 if ( !QFile::exists(filename) ) { 765 if ( !QFile::exists(filename) ) {
589 bool failed = TRUE; 766 bool failed = TRUE;
590 QFileInfo fi(filename); 767 QFileInfo fi(filename);
591 QString settingsDir = QDir::homeDirPath() + "/Settings"; 768 QString settingsDir = QDir::homeDirPath() + "/Settings";
592 if (fi.dirPath(TRUE) == settingsDir) { 769 if (fi.dirPath(TRUE) == settingsDir) {
593 // User setting - see if there is a default in $OPIEDIR/etc/default/ 770 // User setting - see if there is a default in $OPIEDIR/etc/default/
594 QString dftlFile = QPEApplication::qpeDir() + "etc/default/" + fi.fileName(); 771 QString dftlFile = QPEApplication::qpeDir() + "etc/default/" + fi.fileName();
595 if (QFile::exists(dftlFile)) { 772 if (QFile::exists(dftlFile)) {
596 readFilename = dftlFile; 773 readFilename = dftlFile;
597 failed = FALSE; 774 failed = FALSE;
598 } 775 }
599 } 776 }
600 if (failed) { 777 if (failed) {
601 git = groups.end(); 778 git = groups.end();
602 return; 779 return;
603 } 780 }
604 } 781 }
605 782
783#ifndef Q_OS_WIN32
784 if (!qpe_configCache)
785 qpe_configCache = new ConfigCache;
786
787 if (qpe_configCache->find(readFilename, groups, d)) {
788 if ( d && d->multilang ) {
789 QStringList l = Global::languageList();
790 lang = l[0];
791 glang = l[1];
792 }
793 git = groups.begin();
794 return;
795 }
796#endif
606 797
607 QFile f( readFilename ); 798 QFile f( readFilename );
608 if ( !f.open( IO_ReadOnly ) ) { 799 if ( !f.open( IO_ReadOnly ) ) {
609 git = groups.end(); 800 git = groups.end();
610 return; 801 return;
611 } 802 }
612 803
613 if (f.getch()!='[') { 804 if (f.getch()!='[') {
614 git = groups.end(); 805 git = groups.end();
615 return; 806 return;
616 } 807 }
617 f.ungetch('['); 808 f.ungetch('[');
618 809
619 QTextStream s( &f ); 810 QTextStream s( &f );
620 read( s ); 811 read( s );
621 f.close(); 812 f.close();
813
814#ifndef Q_OS_WIN32
815 qpe_configCache->insert(readFilename, groups, d);
816#endif
622} 817}
623 818
624/*! 819/*!
625 \internal 820 \internal
626*/ 821*/
627bool Config::parse( const QString &l ) 822bool Config::parse( const QString &l )
628{ 823{
629 QString line = l.stripWhiteSpace(); 824 QString line = l.stripWhiteSpace();
630 if ( line[ 0 ] == QChar( '[' ) ) { 825 if ( line[ 0 ] == QChar( '[' ) ) {
631 QString gname = line; 826 QString gname = line;
632 gname = gname.remove( 0, 1 ); 827 gname = gname.remove( 0, 1 );
633 if ( gname[ (int)gname.length() - 1 ] == QChar( ']' ) ) 828 if ( gname[ (int)gname.length() - 1 ] == QChar( ']' ) )
634 gname = gname.remove( gname.length() - 1, 1 ); 829 gname = gname.remove( gname.length() - 1, 1 );
635 git = groups.insert( gname, ConfigGroup() ); 830 git = groups.insert( gname, ConfigGroup() );
636 } else if ( !line.isEmpty() ) { 831 } else if ( !line.isEmpty() ) {
637 if ( git == groups.end() ) 832 if ( git == groups.end() )
638 return FALSE; 833 return FALSE;
639 int eq = line.find( '=' ); 834 int eq = line.find( '=' );
640 if ( eq == -1 ) 835 if ( eq == -1 )
641 return FALSE; 836 return FALSE;
642 QString key = line.left(eq).stripWhiteSpace(); 837 QString key = line.left(eq).stripWhiteSpace();
643 QString value = line.mid(eq+1).stripWhiteSpace(); 838 QString value = line.mid(eq+1).stripWhiteSpace();
644 839
645 if ( git.key() == "Translation" ) { 840 if ( git.key() == "Translation" ) {
646 if ( key == "File" ) { 841 if ( key == "File" ) {
647 if ( !d ) 842 if ( !d )
648 d = new ConfigPrivate; 843 d = new ConfigPrivate;
649 d->trfile = value; 844 d->trfile = value;
650 } else if ( key == "Context" ) { 845 } else if ( key == "Context" ) {
651 if ( !d ) 846 if ( !d )
652 d = new ConfigPrivate; 847 d = new ConfigPrivate;
653 d->trcontext = value.latin1(); 848 d->trcontext = value.latin1();
654 } else if ( key.startsWith("Comment") ) { 849 } else if ( key.startsWith("Comment") ) {
655 return TRUE; // ignore comment for ts file 850 return TRUE; // ignore comment for ts file
656 } else { 851 } else {
657 return FALSE; // Unrecognized 852 return FALSE; // Unrecognized
658 } 853 }
659 } 854 }
660 855
661 int kl = key.length(); 856 int kl = key.length();
662 if ( kl > 1 && key[kl-1] == ']' && key[kl-2] != '[' ) { 857 if ( kl > 1 && key[kl-1] == ']' && key[kl-2] != '[' ) {
663 // Old-style translation (inefficient) 858 // Old-style translation (inefficient)
664 if ( !d ) 859 if ( !d )
665 d = new ConfigPrivate; 860 d = new ConfigPrivate;
666 if ( !d->multilang ) { 861 if ( !d->multilang ) {
667 QStringList l = Global::languageList(); 862 QStringList l = Global::languageList();
668 lang = l[0]; 863 lang = l[0];
669 glang = l[1]; 864 glang = l[1];
670 d->multilang = TRUE; 865 d->multilang = TRUE;
671 } 866 }
672 } 867 }
673 868
674 ( *git ).insert( key, value ); 869 ( *git ).insert( key, value );
675 } 870 }
676 return TRUE; 871 return TRUE;
677} 872}
678 873
679 874
680 875
681bool Config::hasGroup( const QString& name )const { 876bool Config::hasGroup( const QString& name )const {
682 return ( groups. find ( name ) != groups. end ( )); 877 return ( groups. find ( name ) != groups. end ( ));
683}; 878};
684 879
685QStringList Config::groupList()const { 880QStringList Config::groupList()const {
686 QStringList sl; 881 QStringList sl;
687 for ( ConfigGroupMap::ConstIterator it = groups. begin ( ); it != groups. end ( ); ++it ) 882 for ( ConfigGroupMap::ConstIterator it = groups. begin ( ); it != groups. end ( ); ++it )
688 sl << it.key(); 883 sl << it.key();
689 884
690 return sl; 885 return sl;
691}; 886};
692 887
693///////////// 888/////////////
694// Qtopia 2.1 Functions 889// Qtopia 2.1 Functions
695// 890//
696//////////// 891////////////
697 892
698QStringList Config::allGroups()const { 893QStringList Config::allGroups()const {
699 return groupList(); 894 return groupList();
700} 895}
701 896
702/*! 897/*!
703 Returns the time stamp for the config identified by \a name. The 898 Returns the time stamp for the config identified by \a name. The
704 time stamp represents the time the config was last committed to storage. 899 time stamp represents the time the config was last committed to storage.
705 Returns 0 if there is no time stamp available for the config. 900 Returns 0 if there is no time stamp available for the config.
706 901
707 A \a domain can optionally be specified and defaults to User. 902 A \a domain can optionally be specified and defaults to User.
708 See \l{Config()} for details. 903 See \l{Config()} for details.
709 904
710 First availability: Qtopia 2.0 905 First availability: Qtopia 2.0
711*/ 906*/
712long Config::timeStamp(const QString& name, Domain domain) 907long Config::timeStamp(const QString& name, Domain domain)
713{ 908{
714#ifdef Q_WS_WIN 909#ifdef Q_WS_WIN
715 // Too slow (many conversions too and from time_t and QDataTime) 910 // Too slow (many conversions too and from time_t and QDataTime)
716 QDateTime epoch; 911 QDateTime epoch;
717 epoch.setTime_t(0); 912 epoch.setTime_t(0);
718 return epoch.secsTo(QFileInfo(Config::configFilename(name,domain)).lastModified()); 913 return epoch.secsTo(QFileInfo(Config::configFilename(name,domain)).lastModified());
719#else 914#else
720 QString fn = Config::configFilename(name,domain); 915 QString fn = Config::configFilename(name,domain);
721 struct stat b; 916 struct stat b;
722 if (lstat( QFile::encodeName(fn).data(), &b ) == 0) 917 if (lstat( QFile::encodeName(fn).data(), &b ) == 0)
723 return b.st_mtime; 918 return b.st_mtime;
724 else 919 else
725 return 0; 920 return 0;
726#endif 921#endif
727} 922}
728 923
729 924
730/*! 925/*!
731 Removes the current group (and all its entries). 926 Removes the current group (and all its entries).
732 927
733 The current group becomes unset. 928 The current group becomes unset.
734 929
735 First availability: Qtopia 2.0 930 First availability: Qtopia 2.0
736*/ 931*/
737void Config::removeGroup() 932void Config::removeGroup()
738{ 933{
739 if ( git == groups.end() ) { 934 if ( git == groups.end() ) {
740 qWarning( "no group set" ); 935 qWarning( "no group set" );
741 return; 936 return;
742 } 937 }
743 938
744 groups.remove(git.key()); 939 groups.remove(git.key());
745 git = groups.end(); 940 git = groups.end();
746 changed = TRUE; 941 changed = TRUE;
747} 942}
748 943
749/*! 944/*!
750 Removes the current group (and all its entries). 945 Removes the current group (and all its entries).
751 946
752 The current group becomes unset. 947 The current group becomes unset.
753 948
754 First availability: Qtopia 2.0 949 First availability: Qtopia 2.0
755*/ 950*/
756void Config::removeGroup(const QString& g) 951void Config::removeGroup(const QString& g)
757{ 952{
758 groups.remove(g); 953 groups.remove(g);
759 git = groups.end(); 954 git = groups.end();
760} 955}
761 956
762 957
763 958
764/*! 959/*!
765 Writes a (\a key, \a lst) entry to the current group. 960 Writes a (\a key, \a lst) entry to the current group.
766 961
767 The list is 962 The list is
768 separated by the two characters "^e", and "^" withing the strings 963 separated by the two characters "^e", and "^" withing the strings
769 is replaced by "^^", such that the strings may contain any character, 964 is replaced by "^^", such that the strings may contain any character,
770 including "^". 965 including "^".
771 966
772 Null strings are also allowed, and are recorded as "^0" in the string. 967 Null strings are also allowed, and are recorded as "^0" in the string.
773 968
774 First availability: Qtopia 2.0 969 First availability: Qtopia 2.0
775 970
776 \sa readListEntry() 971 \sa readListEntry()
777*/ 972*/
778void Config::writeEntry( const QString &key, const QStringList &lst ) 973void Config::writeEntry( const QString &key, const QStringList &lst )
779{ 974{
780 QString s; 975 QString s;
781 for (QStringList::ConstIterator it=lst.begin(); it!=lst.end(); ++it) { 976 for (QStringList::ConstIterator it=lst.begin(); it!=lst.end(); ++it) {
782 QString el = *it; 977 QString el = *it;
783 if ( el.isNull() ) { 978 if ( el.isNull() ) {
784 el = "^0"; 979 el = "^0";
785 } else { 980 } else {
786 el.replace(QRegExp("\\^"), "^^"); 981 el.replace(QRegExp("\\^"), "^^");
787 } 982 }
788 s+=el; 983 s+=el;
789 s+="^e"; // end of element 984 s+="^e"; // end of element
790 } 985 }
791 writeEntry(key, s); 986 writeEntry(key, s);
792} 987}
793 988
794/*! 989/*!
795 Returns the string list entry stored using \a key and with 990 Returns the string list entry stored using \a key and with
796 the escaped seperator convention described in writeListEntry(). 991 the escaped seperator convention described in writeListEntry().
797 992
798 First availability: Qtopia 2.0 993 First availability: Qtopia 2.0
799*/ 994*/
800QStringList Config::readListEntry( const QString &key ) const 995QStringList Config::readListEntry( const QString &key ) const
801{ 996{
802 QString value = readEntry( key, QString::null ); 997 QString value = readEntry( key, QString::null );
803 QStringList l; 998 QStringList l;
804 QString s; 999 QString s;
805 bool esc=FALSE; 1000 bool esc=FALSE;
806 for (int i=0; i<(int)value.length(); i++) { 1001 for (int i=0; i<(int)value.length(); i++) {
807 if ( esc ) { 1002 if ( esc ) {
808 if ( value[i] == 'e' ) { // end-of-string 1003 if ( value[i] == 'e' ) { // end-of-string
809 l.append(s); 1004 l.append(s);
810 s=""; 1005 s="";
811 } else if ( value[i] == '0' ) { // null string 1006 } else if ( value[i] == '0' ) { // null string
812 s=QString::null; 1007 s=QString::null;
813 } else { 1008 } else {