author | zecke <zecke> | 2004-12-26 13:32:10 (UTC) |
---|---|---|
committer | zecke <zecke> | 2004-12-26 13:32:10 (UTC) |
commit | d8f38f36ad533f93d46c8ff883c6b42f15c96c28 (patch) (unidiff) | |
tree | 27f14def0ffc5d2b94cbd8aad7afbb66d532151d /library | |
parent | 4f5d6b7aff824a8a0f692cbab98b5cfe933de933 (diff) | |
download | opie-d8f38f36ad533f93d46c8ff883c6b42f15c96c28.zip opie-d8f38f36ad533f93d46c8ff883c6b42f15c96c28.tar.gz opie-d8f38f36ad533f93d46c8ff883c6b42f15c96c28.tar.bz2 |
Config is now cached
-rw-r--r-- | library/config.cpp | 195 |
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,839 +1,1034 @@ | |||
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 | */ |
43 | class ConfigPrivate { | 45 | class ConfigPrivate { |
44 | public: | 46 | public: |
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 | |||
73 | const int CONFIG_CACHE_SIZE = 8192; | ||
74 | const int CONFIG_CACHE_TIMEOUT = 1000; | ||
75 | |||
76 | class ConfigData | ||
77 | { | ||
78 | public: | ||
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 | |||
108 | class ConfigCache : public QObject | ||
109 | { | ||
110 | public: | ||
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 | |||
117 | protected: | ||
118 | void timerEvent(QTimerEvent *); | ||
119 | |||
120 | private: | ||
121 | void removeLru(); | ||
122 | |||
123 | QMap<QString, ConfigData> configData; | ||
124 | unsigned int totalsize; | ||
125 | int tid; | ||
126 | }; | ||
127 | |||
128 | ConfigCache::ConfigCache() : QObject(), totalsize(0), tid(0) | ||
129 | { | ||
130 | } | ||
131 | |||
132 | void 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 | |||
165 | bool 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 | |||
193 | void 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 | |||
202 | void 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 | |||
213 | void 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 | |||
232 | static ConfigCache *qpe_configCache = 0; | ||
233 | |||
234 | #endif /* Q_OS_WIN32 */ | ||
235 | |||
236 | |||
237 | // ========================================================================== | ||
238 | |||
239 | |||
67 | /*! | 240 | /*! |
68 | \internal | 241 | \internal |
69 | */ | 242 | */ |
70 | QString Config::configFilename(const QString& name, Domain d) | 243 | QString 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 */ |
86 | void Config::read( QTextStream &s ) | 259 | void 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 | */ |
141 | Config::Config( const QString &name, Domain domain ) | 314 | Config::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 |
151 | Config::Config ( const QString &name, bool what ) | 324 | Config::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 | */ |
162 | Config::~Config() | 335 | Config::~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 | */ |
173 | bool Config::hasKey( const QString &key ) const | 346 | bool 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 | */ |
199 | void Config::setGroup( const QString &gname ) | 372 | void 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 | */ |
215 | void Config::writeEntry( const QString &key, const char* value ) | 388 | void 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 | */ |
225 | void Config::writeEntry( const QString &key, const QString &value ) | 398 | void 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 | */ |
246 | static QString encipher(const QString& plain) | 419 | static 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 | } |
259 | return cipher; | 432 | return cipher; |
260 | } | 433 | } |
261 | 434 | ||
262 | static QString decipher(const QString& cipher) | 435 | static QString decipher(const QString& cipher) |
263 | { | 436 | { |
264 | QString plain; | 437 | QString plain; |
265 | int mix=28730492; | 438 | int mix=28730492; |
266 | for (int i=0; i<(int)cipher.length();) { | 439 | for (int i=0; i<(int)cipher.length();) { |
267 | int l = cipher[i].unicode()-'a'; | 440 | int l = cipher[i].unicode()-'a'; |
268 | QString x = cipher.mid(i+1,l); i+=l+1; | 441 | QString x = cipher.mid(i+1,l); i+=l+1; |
269 | int u = x.toInt(0,36) ^ mix; | 442 | int u = x.toInt(0,36) ^ mix; |
270 | plain.append(QChar(u)); | 443 | plain.append(QChar(u)); |
271 | mix *= u; | 444 | mix *= u; |
272 | } | 445 | } |
273 | return plain; | 446 | return plain; |
274 | } | 447 | } |
275 | 448 | ||
276 | /*! | 449 | /*! |
277 | Writes an encrypted (\a key, \a value) entry to the current group. | 450 | Writes an encrypted (\a key, \a value) entry to the current group. |
278 | 451 | ||
279 | Note that the degree of protection offered by the encryption is | 452 | Note that the degree of protection offered by the encryption is |
280 | only sufficient to avoid the most casual observation of the configuration | 453 | only sufficient to avoid the most casual observation of the configuration |
281 | files. | 454 | files. |
282 | 455 | ||
283 | \sa readEntry() | 456 | \sa readEntry() |
284 | */ | 457 | */ |
285 | void Config::writeEntryCrypt( const QString &key, const QString &value ) | 458 | void Config::writeEntryCrypt( const QString &key, const QString &value ) |
286 | { | 459 | { |
287 | if ( git == groups.end() ) { | 460 | if ( git == groups.end() ) { |
288 | qWarning( "no group set" ); | 461 | qWarning( "no group set" ); |
289 | return; | 462 | return; |
290 | } | 463 | } |
291 | QString evalue = encipher(value); | 464 | QString evalue = encipher(value); |
292 | if ( (*git)[key] != evalue ) { | 465 | if ( (*git)[key] != evalue ) { |
293 | ( *git ).insert( key, evalue ); | 466 | ( *git ).insert( key, evalue ); |
294 | changed = TRUE; | 467 | changed = TRUE; |
295 | } | 468 | } |
296 | } | 469 | } |
297 | 470 | ||
298 | /*! | 471 | /*! |
299 | Writes a (\a key, \a num) entry to the current group. | 472 | Writes a (\a key, \a num) entry to the current group. |
300 | 473 | ||
301 | \sa readNumEntry() | 474 | \sa readNumEntry() |
302 | */ | 475 | */ |
303 | void Config::writeEntry( const QString &key, int num ) | 476 | void Config::writeEntry( const QString &key, int num ) |
304 | { | 477 | { |
305 | QString s; | 478 | QString s; |
306 | s.setNum( num ); | 479 | s.setNum( num ); |
307 | writeEntry( key, s ); | 480 | writeEntry( key, s ); |
308 | } | 481 | } |
309 | 482 | ||
310 | #ifdef Q_HAS_BOOL_TYPE | 483 | #ifdef Q_HAS_BOOL_TYPE |
311 | /*! | 484 | /*! |
312 | Writes a (\a key, \a b) entry to the current group. This is equivalent | 485 | Writes a (\a key, \a b) entry to the current group. This is equivalent |
313 | to writing a 0 or 1 as an integer entry. | 486 | to writing a 0 or 1 as an integer entry. |
314 | 487 | ||
315 | \sa readBoolEntry() | 488 | \sa readBoolEntry() |
316 | */ | 489 | */ |
317 | void Config::writeEntry( const QString &key, bool b ) | 490 | void Config::writeEntry( const QString &key, bool b ) |
318 | { | 491 | { |
319 | QString s; | 492 | QString s; |
320 | s.setNum( ( int )b ); | 493 | s.setNum( ( int )b ); |
321 | writeEntry( key, s ); | 494 | writeEntry( key, s ); |
322 | } | 495 | } |
323 | #endif | 496 | #endif |
324 | 497 | ||
325 | /*! | 498 | /*! |
326 | Writes a (\a key, \a lst) entry to the current group. The list | 499 | Writes a (\a key, \a lst) entry to the current group. The list |
327 | is separated by \a sep, so the strings must not contain that character. | 500 | is separated by \a sep, so the strings must not contain that character. |
328 | 501 | ||
329 | \sa readListEntry() | 502 | \sa readListEntry() |
330 | */ | 503 | */ |
331 | void Config::writeEntry( const QString &key, const QStringList &lst, const QChar &sep ) | 504 | void Config::writeEntry( const QString &key, const QStringList &lst, const QChar &sep ) |
332 | { | 505 | { |
333 | QString s; | 506 | QString s; |
334 | QStringList::ConstIterator it = lst.begin(); | 507 | QStringList::ConstIterator it = lst.begin(); |
335 | for ( ; it != lst.end(); ++it ) | 508 | for ( ; it != lst.end(); ++it ) |
336 | s += *it + sep; | 509 | s += *it + sep; |
337 | writeEntry( key, s ); | 510 | writeEntry( key, s ); |
338 | } | 511 | } |
339 | 512 | ||
340 | /*! | 513 | /*! |
341 | Removes the \a key entry from the current group. Does nothing if | 514 | Removes the \a key entry from the current group. Does nothing if |
342 | there is no such entry. | 515 | there is no such entry. |
343 | */ | 516 | */ |
344 | 517 | ||
345 | void Config::removeEntry( const QString &key ) | 518 | void Config::removeEntry( const QString &key ) |
346 | { | 519 | { |
347 | if ( git == groups.end() ) { | 520 | if ( git == groups.end() ) { |
348 | qWarning( "no group set" ); | 521 | qWarning( "no group set" ); |
349 | return; | 522 | return; |
350 | } | 523 | } |
351 | ( *git ).remove( key ); | 524 | ( *git ).remove( key ); |
352 | changed = TRUE; | 525 | changed = TRUE; |
353 | } | 526 | } |
354 | 527 | ||
355 | /*! | 528 | /*! |
356 | \fn bool Config::operator == ( const Config & other ) const | 529 | \fn bool Config::operator == ( const Config & other ) const |
357 | 530 | ||
358 | Tests for equality with \a other. Config objects are equal if they refer to the same filename. | 531 | Tests for equality with \a other. Config objects are equal if they refer to the same filename. |
359 | */ | 532 | */ |
360 | 533 | ||
361 | /*! | 534 | /*! |
362 | \fn bool Config::operator != ( const Config & other ) const | 535 | \fn bool Config::operator != ( const Config & other ) const |
363 | 536 | ||
364 | Tests for inequality with \a other. Config objects are equal if they refer to the same filename. | 537 | Tests for inequality with \a other. Config objects are equal if they refer to the same filename. |
365 | */ | 538 | */ |
366 | 539 | ||
367 | 540 | ||
368 | /*! | 541 | /*! |
369 | \fn QString Config::readEntry( const QString &key, const QString &deflt ) const | 542 | \fn QString Config::readEntry( const QString &key, const QString &deflt ) const |
370 | 543 | ||
371 | Reads a string entry stored with \a key, defaulting to \a deflt if there is no entry. | 544 | Reads a string entry stored with \a key, defaulting to \a deflt if there is no entry. |
372 | */ | 545 | */ |
373 | 546 | ||
374 | /* | 547 | /* |
375 | * ### !LocalTranslator::translate was kept out! | 548 | * ### !LocalTranslator::translate was kept out! |
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 | */ |
383 | QString Config::readEntry( const QString &key, const QString &deflt ) | 556 | QString 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 | */ |
421 | QString Config::readEntryCrypt( const QString &key, const QString &deflt ) | 594 | QString 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 | */ |
438 | QString Config::readEntryDirect( const QString &key, const QString &deflt ) | 611 | QString 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 | */ |
460 | int Config::readNumEntry( const QString &key, int deflt ) | 633 | int 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 | */ |
478 | bool Config::readBoolEntry( const QString &key, bool deflt ) | 651 | bool 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 | */ |
496 | QStringList Config::readListEntry( const QString &key, const QChar &sep ) | 669 | QStringList 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 | */ |
508 | void Config::clearGroup() | 681 | void 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 | */ |
523 | void Config::write( const QString &fn ) | 696 | void 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 | */ |
574 | bool Config::isValid() const | 751 | bool 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 | */ |
582 | void Config::read() | 759 | void 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 | */ |
627 | bool Config::parse( const QString &l ) | 822 | bool 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 | ||
681 | bool Config::hasGroup( const QString& name )const { | 876 | bool Config::hasGroup( const QString& name )const { |
682 | return ( groups. find ( name ) != groups. end ( )); | 877 | return ( groups. find ( name ) != groups. end ( )); |
683 | }; | 878 | }; |
684 | 879 | ||
685 | QStringList Config::groupList()const { | 880 | QStringList 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 | ||
698 | QStringList Config::allGroups()const { | 893 | QStringList 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 | */ |
712 | long Config::timeStamp(const QString& name, Domain domain) | 907 | long 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 | */ |
737 | void Config::removeGroup() | 932 | void 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 | */ |
756 | void Config::removeGroup(const QString& g) | 951 | void 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 | */ |
778 | void Config::writeEntry( const QString &key, const QStringList &lst ) | 973 | void 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 | */ |
800 | QStringList Config::readListEntry( const QString &key ) const | 995 | QStringList 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 { |
814 | s.append(value[i]); | 1009 | s.append(value[i]); |
815 | } | 1010 | } |
816 | esc = FALSE; | 1011 | esc = FALSE; |
817 | } else if ( value[i] == '^' ) { | 1012 | } else if ( value[i] == '^' ) { |
818 | esc = TRUE; | 1013 | esc = TRUE; |
819 | } else { | 1014 | } else { |
820 | s.append(value[i]); | 1015 | s.append(value[i]); |
821 | if ( i == (int)value.length()-1 ) | 1016 | if ( i == (int)value.length()-1 ) |
822 | l.append(s); | 1017 | l.append(s); |
823 | } | 1018 | } |
824 | } | 1019 | } |
825 | return l; | 1020 | return l; |
826 | } | 1021 | } |
827 | 1022 | ||
828 | QString Config::readEntry( const QString &key, const QString &deflt ) const | 1023 | QString Config::readEntry( const QString &key, const QString &deflt ) const |
829 | { return ((Config*)this)->readEntry(key,deflt); } | 1024 | { return ((Config*)this)->readEntry(key,deflt); } |
830 | QString Config::readEntryCrypt( const QString &key, const QString &deflt ) const | 1025 | QString Config::readEntryCrypt( const QString &key, const QString &deflt ) const |
831 | { return ((Config*)this)->readEntryCrypt(key,deflt); } | 1026 | { return ((Config*)this)->readEntryCrypt(key,deflt); } |
832 | QString Config::readEntryDirect( const QString &key, const QString &deflt ) const | 1027 | QString Config::readEntryDirect( const QString &key, const QString &deflt ) const |
833 | { return ((Config*)this)->readEntryDirect(key,deflt); } | 1028 | { return ((Config*)this)->readEntryDirect(key,deflt); } |
834 | int Config::readNumEntry( const QString &key, int deflt ) const | 1029 | int Config::readNumEntry( const QString &key, int deflt ) const |
835 | { return ((Config*)this)->readNumEntry(key,deflt); } | 1030 | { return ((Config*)this)->readNumEntry(key,deflt); } |
836 | bool Config::readBoolEntry( const QString &key, bool deflt ) const | 1031 | bool Config::readBoolEntry( const QString &key, bool deflt ) const |
837 | { return ((Config*)this)->readBoolEntry(key,deflt); } | 1032 | { return ((Config*)this)->readBoolEntry(key,deflt); } |
838 | QStringList Config::readListEntry( const QString &key, const QChar &sep ) const | 1033 | QStringList Config::readListEntry( const QString &key, const QChar &sep ) const |
839 | { return ((Config*)this)->readListEntry(key,sep); } | 1034 | { return ((Config*)this)->readListEntry(key,sep); } |