-rw-r--r-- | library/config.cpp | 264 |
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 | */ |
45 | class ConfigPrivate { | 45 | class ConfigPrivate { |
46 | public: | 46 | public: |
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 | |||
73 | const int CONFIG_CACHE_SIZE = 8192; | ||
74 | const int CONFIG_CACHE_TIMEOUT = 1000; | ||
75 | |||
76 | class ConfigData | 72 | class ConfigData |
77 | { | 73 | { |
78 | public: | 74 | public: |
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 | ||
108 | class ConfigCache : public QObject | ||
109 | { | ||
110 | public: | ||
111 | ConfigCache(); | ||
112 | 91 | ||
113 | void insert(const QString &filename, const ConfigGroupMap &cfg, const ConfigPrivate* priv); | 92 | class ConfigCache : public QObject { |
114 | bool find(const QString &filename, ConfigGroupMap &cfg, ConfigPrivate*& priv); | 93 | public: |
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 ); | ||
117 | protected: | 100 | protected: |
118 | void timerEvent(QTimerEvent *); | 101 | void timerEvent( QTimerEvent* ); |
119 | 102 | ||
120 | private: | 103 | private: |
104 | ConfigCache(); | ||
105 | void remove( const QString& fileName ); | ||
121 | void removeLru(); | 106 | void removeLru(); |
122 | 107 | ||
123 | QMap<QString, ConfigData> configData; | 108 | private: |
124 | unsigned int totalsize; | 109 | QMap<QString, ConfigData> m_cached; |
125 | int tid; | 110 | unsigned int m_totalSize; |
111 | int m_tid; | ||
112 | private: | ||
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 | ||
128 | ConfigCache::ConfigCache() : QObject(), totalsize(0), tid(0) | 118 | ConfigCache* ConfigCache::m_inst = 0; |
129 | { | 119 | /* |
130 | } | 120 | * get destroyed when qApp gets destroyed |
131 | 121 | */ | |
132 | void ConfigCache::insert(const QString &filename, const ConfigGroupMap &cfg, const ConfigPrivate* priv) | 122 | ConfigCache::ConfigCache() : QObject( qApp ), m_totalSize( 0 ), m_tid( 0 ) {} |
133 | { | 123 | ConfigCache* 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 | ||
165 | bool ConfigCache::find(const QString &filename, ConfigGroupMap &cfg, ConfigPrivate*& priv) | 130 | void 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 | ||
193 | void 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 | ||
202 | void ConfigCache::timerEvent(QTimerEvent *) | 140 | void 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 | |||
213 | void 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 | |
155 | void 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 | ||
232 | static ConfigCache *qpe_configCache = 0; | 163 | void 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 | |||
191 | bool 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 | */ |
243 | QString Config::configFilename(const QString& name, Domain d) | 223 | QString 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 */ |
259 | void Config::read( QTextStream &s ) | 239 | void 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 | */ |
314 | Config::Config( const QString &name, Domain domain ) | 294 | Config::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 |
324 | Config::Config ( const QString &name, bool what ) | 304 | Config::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 | */ |
335 | Config::~Config() | 315 | Config::~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 | */ |
346 | bool Config::hasKey( const QString &key ) const | 326 | bool 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 | */ |
372 | void Config::setGroup( const QString &gname ) | 352 | void 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 | */ |
388 | void Config::writeEntry( const QString &key, const char* value ) | 368 | void 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 | */ |
398 | void Config::writeEntry( const QString &key, const QString &value ) | 378 | void 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 | */ |
419 | static QString encipher(const QString& plain) | 399 | static 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 | ||
435 | static QString decipher(const QString& cipher) | 415 | static 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 | ||
518 | void Config::removeEntry( const QString &key ) | 498 | void 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 | */ |
556 | QString Config::readEntry( const QString &key, const QString &deflt ) | 536 | QString 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 | */ |
594 | QString Config::readEntryCrypt( const QString &key, const QString &deflt ) | 574 | QString 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 | */ |
611 | QString Config::readEntryDirect( const QString &key, const QString &deflt ) | 591 | QString 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 | */ |
633 | int Config::readNumEntry( const QString &key, int deflt ) | 613 | int 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 | */ |
651 | bool Config::readBoolEntry( const QString &key, bool deflt ) | 631 | bool 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 | */ |
669 | QStringList Config::readListEntry( const QString &key, const QChar &sep ) | 649 | QStringList 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 | */ |
681 | void Config::clearGroup() | 661 | void 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 | */ |
696 | void Config::write( const QString &fn ) | 676 | void 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 | */ |
751 | bool Config::isValid() const | 733 | bool 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 | */ |
759 | void Config::read() | 741 | void 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 | */ |
822 | bool Config::parse( const QString &l ) | 802 | bool 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 | ||
876 | bool Config::hasGroup( const QString& name )const { | 856 | bool Config::hasGroup( const QString& name )const { |
877 | return ( groups. find ( name ) != groups. end ( )); | 857 | return ( groups. find ( name ) != groups. end ( )); |
878 | }; | 858 | }; |
879 | 859 | ||
880 | QStringList Config::groupList()const { | 860 | QStringList 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 | ||
893 | QStringList Config::allGroups()const { | 873 | QStringList 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 | */ |
907 | long Config::timeStamp(const QString& name, Domain domain) | 887 | long 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 | */ |
932 | void Config::removeGroup() | 912 | void 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 | */ |
951 | void Config::removeGroup(const QString& g) | 931 | void 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 | */ |
973 | void Config::writeEntry( const QString &key, const QStringList &lst ) | 953 | void 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 | */ |
995 | QStringList Config::readListEntry( const QString &key ) const | 975 | QStringList 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; |