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