-rw-r--r-- | qmake/tools/qsettings.cpp | 1955 |
1 files changed, 1955 insertions, 0 deletions
diff --git a/qmake/tools/qsettings.cpp b/qmake/tools/qsettings.cpp new file mode 100644 index 0000000..5de105c --- a/dev/null +++ b/qmake/tools/qsettings.cpp | |||
@@ -0,0 +1,1955 @@ | |||
1 | /**************************************************************************** | ||
2 | ** $Id$ | ||
3 | ** | ||
4 | ** Implementation of QSettings class | ||
5 | ** | ||
6 | ** Created: 2000.06.26 | ||
7 | ** | ||
8 | ** Copyright (C) 2000-2002 Trolltech AS. All rights reserved. | ||
9 | ** | ||
10 | ** This file is part of the tools module of the Qt GUI Toolkit. | ||
11 | ** | ||
12 | ** This file may be distributed under the terms of the Q Public License | ||
13 | ** as defined by Trolltech AS of Norway and appearing in the file | ||
14 | ** LICENSE.QPL included in the packaging of this file. | ||
15 | ** | ||
16 | ** This file may be distributed and/or modified under the terms of the | ||
17 | ** GNU General Public License version 2 as published by the Free Software | ||
18 | ** Foundation and appearing in the file LICENSE.GPL included in the | ||
19 | ** packaging of this file. | ||
20 | ** | ||
21 | ** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition | ||
22 | ** licenses may use this file in accordance with the Qt Commercial License | ||
23 | ** Agreement provided with the Software. | ||
24 | ** | ||
25 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE | ||
26 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
27 | ** | ||
28 | ** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for | ||
29 | ** information about Qt Commercial License Agreements. | ||
30 | ** See http://www.trolltech.com/qpl/ for QPL licensing information. | ||
31 | ** See http://www.trolltech.com/gpl/ for GPL licensing information. | ||
32 | ** | ||
33 | ** Contact info@trolltech.com if any conditions of this licensing are | ||
34 | ** not clear to you. | ||
35 | ** | ||
36 | **********************************************************************/ | ||
37 | |||
38 | #include "qplatformdefs.h" | ||
39 | |||
40 | // POSIX Large File Support redefines open -> open64 | ||
41 | static inline int qt_open( const char *pathname, int flags, mode_t mode ) | ||
42 | { return ::open( pathname, flags, mode ); } | ||
43 | #if defined(open) | ||
44 | # undef open | ||
45 | #endif | ||
46 | |||
47 | // POSIX Large File Support redefines truncate -> truncate64 | ||
48 | #if defined(truncate) | ||
49 | # undef truncate | ||
50 | #endif | ||
51 | |||
52 | #include "qsettings.h" | ||
53 | |||
54 | #ifndef QT_NO_SETTINGS | ||
55 | |||
56 | #include "qdir.h" | ||
57 | #include "qfile.h" | ||
58 | #include "qfileinfo.h" | ||
59 | #include "qmap.h" | ||
60 | #include "qtextstream.h" | ||
61 | #include "qregexp.h" | ||
62 | #include <private/qsettings_p.h> | ||
63 | #include <errno.h> | ||
64 | |||
65 | /*! | ||
66 | \class QSettings | ||
67 | \brief The QSettings class provides persistent platform-independent application settings. | ||
68 | |||
69 | \ingroup io | ||
70 | \ingroup misc | ||
71 | \mainclass | ||
72 | |||
73 | On Unix systems, QSettings uses text files to store settings. On Windows | ||
74 | systems, QSettings uses the system registry. On Mac OS X, QSettings will | ||
75 | behave as on Unix, and store to text files. | ||
76 | |||
77 | Each setting comprises an identifying key and the data associated with | ||
78 | the key. A key is a unicode string which consists of \e two or more | ||
79 | subkeys. A subkey is a slash, '/', followed by one or more unicode | ||
80 | characters (excluding slashes, newlines, carriage returns and equals, | ||
81 | '=', signs). The associated data, called the entry or value, may be a | ||
82 | boolean, an integer, a double, a string or a list of strings. Entry | ||
83 | strings may contain any unicode characters. | ||
84 | |||
85 | If you want to save and restore the entire desktop's settings, i.e. | ||
86 | which applications are running, use QSettings to save the settings | ||
87 | for each individual application and QSessionManager to save the | ||
88 | desktop's session. | ||
89 | |||
90 | Example settings: | ||
91 | \code | ||
92 | /MyCompany/MyApplication/background color | ||
93 | /MyCompany/MyApplication/foreground color | ||
94 | /MyCompany/MyApplication/geometry/x | ||
95 | /MyCompany/MyApplication/geometry/y | ||
96 | /MyCompany/MyApplication/geometry/width | ||
97 | /MyCompany/MyApplication/geometry/height | ||
98 | /MyCompany/MyApplication/recent files/1 | ||
99 | /MyCompany/MyApplication/recent files/2 | ||
100 | /MyCompany/MyApplication/recent files/3 | ||
101 | \endcode | ||
102 | Each line above is a complete key, made up of subkeys. | ||
103 | |||
104 | A typical usage pattern for application startup: | ||
105 | \code | ||
106 | QSettings settings; | ||
107 | settings.insertSearchPath( QSettings::Windows, "/MyCompany" ); | ||
108 | // No search path needed for Unix; see notes further on. | ||
109 | // Use default values if the keys don't exist | ||
110 | QString bgColor = settings.readEntry( "/MyApplication/background color", "white" ); | ||
111 | int width = settings.readNumEntry( "/MyApplication/geometry/width", 640 ); | ||
112 | // ... | ||
113 | \endcode | ||
114 | |||
115 | A typical usage pattern for application exit or 'save preferences': | ||
116 | \code | ||
117 | QSettings settings; | ||
118 | settings.insertSearchPath( QSettings::Windows, "/MyCompany" ); | ||
119 | // No search path needed for Unix; see notes further on. | ||
120 | settings.writeEntry( "/MyApplication/background color", bgColor ); | ||
121 | settings.writeEntry( "/MyApplication/geometry/width", width ); | ||
122 | // ... | ||
123 | \endcode | ||
124 | |||
125 | You can get a list of entry-holding keys by calling entryList(), and | ||
126 | a list of key-holding keys using subkeyList(). | ||
127 | |||
128 | \code | ||
129 | QStringList keys = entryList( "/MyApplication" ); | ||
130 | // keys contains 'background color' and 'foreground color'. | ||
131 | |||
132 | QStringList keys = entryList( "/MyApplication/recent files" ); | ||
133 | // keys contains '1', '2' and '3'. | ||
134 | |||
135 | QStringList subkeys = subkeyList( "/MyApplication" ); | ||
136 | // subkeys contains 'geometry' and 'recent files' | ||
137 | |||
138 | QStringList subkeys = subkeyList( "/MyApplication/recent files" ); | ||
139 | // subkeys is empty. | ||
140 | \endcode | ||
141 | |||
142 | If you wish to use a different search path call insertSearchPath() | ||
143 | as often as necessary to add your preferred paths. Call | ||
144 | removeSearchPath() to remove any unwanted paths. | ||
145 | |||
146 | Since settings for Windows are stored in the registry there are size | ||
147 | limits as follows: | ||
148 | \list | ||
149 | \i A subkey may not exceed 255 characters. | ||
150 | \i An entry's value may not exceed 16,300 characters. | ||
151 | \i All the values of a key (for example, all the 'recent files' | ||
152 | subkeys values), may not exceed 65,535 characters. | ||
153 | \endlist | ||
154 | |||
155 | These limitations are not enforced on Unix. | ||
156 | |||
157 | \section1 Notes for Unix Applications | ||
158 | |||
159 | There is no universally accepted place for storing application | ||
160 | settings under Unix. In the examples the settings file will be | ||
161 | searched for in the following directories: | ||
162 | \list 1 | ||
163 | \i INSTALL/etc/settings | ||
164 | \i /opt/MyCompany/share/etc | ||
165 | \i /opt/MyCompany/share/MyApplication/etc | ||
166 | \i $HOME/.qt | ||
167 | \endlist | ||
168 | When reading settings the files are searched in the order shown | ||
169 | above, with later settings overriding earlier settings. Files for | ||
170 | which the user doesn't have read permission are ignored. When saving | ||
171 | settings QSettings works in the order shown above, writing | ||
172 | to the first settings file for which the user has write permission. | ||
173 | (\c INSTALL is the directory where Qt was installed. This can be | ||
174 | modified by using the configure script's -prefix argument ) | ||
175 | |||
176 | If you want to put the settings in a particular place in the | ||
177 | filesystem you could do this: | ||
178 | \code | ||
179 | settings.insertSearchPath( QSettings::Unix, "/opt/MyCompany/share" ); | ||
180 | \endcode | ||
181 | |||
182 | But in practice you may prefer not to use a search path for Unix. | ||
183 | For example the following code: | ||
184 | \code | ||
185 | settings.writeEntry( "/MyApplication/geometry/width", width ); | ||
186 | \endcode | ||
187 | will end up writing the "geometry/width" setting to the file | ||
188 | \c{$HOME/.qt/myapplicationrc} (assuming that the application is | ||
189 | being run by an ordinary user, i.e. not by root). | ||
190 | |||
191 | For cross-platform applications you should ensure that the Windows | ||
192 | size limitations are not exceeded. | ||
193 | */ | ||
194 | |||
195 | /*! | ||
196 | \enum QSettings::System | ||
197 | |||
198 | \value Mac Macintosh execution environments | ||
199 | \value Unix Mac OS X, Unix, Linux and Unix-like execution environments | ||
200 | \value Windows Windows execution environments | ||
201 | */ | ||
202 | |||
203 | /*! | ||
204 | \enum QSettings::Format | ||
205 | |||
206 | \value Native Store the settings in a platform dependent location | ||
207 | \value Ini Store the settings in a text file | ||
208 | */ | ||
209 | |||
210 | /*! | ||
211 | \enum QSettings::Scope | ||
212 | |||
213 | \value Global Save settings as global as possible | ||
214 | \value User Save settings in user space | ||
215 | */ | ||
216 | |||
217 | #if defined(Q_OS_UNIX) | ||
218 | typedef int HANDLE; | ||
219 | #define Q_LOCKREAD F_RDLCK | ||
220 | #define Q_LOCKWRITE F_WRLCK | ||
221 | /* | ||
222 | Locks the file specified by name. The lockfile is created as a | ||
223 | hidden file in the same directory as the target file, with .lock | ||
224 | appended to the name. For example, "/etc/settings/onerc" uses a | ||
225 | lockfile named "/etc/settings/.onerc.lock". The type argument | ||
226 | controls the type of the lock, it can be either F_RDLCK for a read | ||
227 | lock, or F_WRLCK for a write lock. | ||
228 | |||
229 | A file descriptor for the lock file is returned, and should be | ||
230 | closed with closelock() when the lock is no longer needed. | ||
231 | */ | ||
232 | static HANDLE openlock( const QString &name, int type ) | ||
233 | { | ||
234 | QFileInfo info( name ); | ||
235 | // lockfile should be hidden, and never removed | ||
236 | QString lockfile = info.dirPath() + "/." + info.fileName() + ".lock"; | ||
237 | |||
238 | // open the lockfile | ||
239 | HANDLE fd = qt_open( QFile::encodeName( lockfile ), | ||
240 | O_RDWR | O_CREAT, S_IRUSR | S_IWUSR ); | ||
241 | |||
242 | if ( fd < 0 ) { | ||
243 | // failed to open the lock file, most likely because of permissions | ||
244 | return fd; | ||
245 | } | ||
246 | |||
247 | struct flock fl; | ||
248 | fl.l_type = type; | ||
249 | fl.l_whence = SEEK_SET; | ||
250 | fl.l_start = 0; | ||
251 | fl.l_len = 0; | ||
252 | if ( fcntl( fd, F_SETLKW, &fl ) == -1 ) { | ||
253 | // the lock failed, so we should fail silently, so that people | ||
254 | // using filesystems that do not support locking don't see | ||
255 | // numerous warnings about a failed lock | ||
256 | close( fd ); | ||
257 | fd = -1; | ||
258 | } | ||
259 | |||
260 | return fd; | ||
261 | } | ||
262 | |||
263 | /* | ||
264 | Closes the lock file specified by fd. fd is the file descriptor | ||
265 | returned by the openlock() function. | ||
266 | */ | ||
267 | static void closelock( HANDLE fd ) | ||
268 | { | ||
269 | if ( fd < 0 ) { | ||
270 | // the lock file is not open | ||
271 | return; | ||
272 | } | ||
273 | |||
274 | struct flock fl; | ||
275 | fl.l_type = F_UNLCK; | ||
276 | fl.l_whence = SEEK_SET; | ||
277 | fl.l_start = 0; | ||
278 | fl.l_len = 0; | ||
279 | // ignore the return value, so that the unlock fails silently | ||
280 | (void) fcntl( fd, F_SETLKW, &fl ); | ||
281 | |||
282 | close( fd ); | ||
283 | } | ||
284 | #elif defined(Q_WS_WIN) | ||
285 | #define Q_LOCKREAD 1 | ||
286 | #define Q_LOCKWRITE 2 | ||
287 | |||
288 | static HANDLE openlock( const QString &name, int /*type*/ ) | ||
289 | { | ||
290 | if ( !QFile::exists( name ) ) | ||
291 | return 0; | ||
292 | |||
293 | return 0; | ||
294 | |||
295 | HANDLE fd = 0; | ||
296 | |||
297 | QT_WA( { | ||
298 | fd = CreateFileW( (TCHAR*)name.ucs2(), GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); | ||
299 | } , { | ||
300 | fd = CreateFileA( name.local8Bit(), GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); | ||
301 | } ); | ||
302 | |||
303 | if ( !LockFile( fd, 0, 0, -1, -1 ) ) { | ||
304 | #ifdef QT_CHECK_STATE | ||
305 | qWarning( "QSettings: openlock failed!" ); | ||
306 | #endif | ||
307 | } | ||
308 | return fd; | ||
309 | } | ||
310 | |||
311 | void closelock( HANDLE fd ) | ||
312 | { | ||
313 | if ( !fd ) | ||
314 | return; | ||
315 | |||
316 | if ( !UnlockFile( fd, 0, 0, -1, -1 ) ) { | ||
317 | #ifdef QT_CHECK_STATE | ||
318 | qWarning( "QSettings: closelock failed!"); | ||
319 | #endif | ||
320 | } | ||
321 | CloseHandle( fd ); | ||
322 | } | ||
323 | #endif | ||
324 | |||
325 | |||
326 | QSettingsGroup::QSettingsGroup() | ||
327 | : modified(FALSE) | ||
328 | { | ||
329 | } | ||
330 | |||
331 | |||
332 | |||
333 | |||
334 | void QSettingsHeading::read(const QString &filename) | ||
335 | { | ||
336 | if (! QFileInfo(filename).exists()) | ||
337 | return; | ||
338 | |||
339 | HANDLE lockfd = openlock( filename, Q_LOCKREAD ); | ||
340 | |||
341 | QFile file(filename); | ||
342 | if (! file.open(IO_ReadOnly)) { | ||
343 | #if defined(QT_CHECK_STATE) | ||
344 | qWarning("QSettings: failed to open file '%s'", filename.latin1()); | ||
345 | #endif | ||
346 | return; | ||
347 | } | ||
348 | |||
349 | git = end(); | ||
350 | |||
351 | QTextStream stream(&file); | ||
352 | stream.setEncoding(QTextStream::UnicodeUTF8); | ||
353 | while (! stream.atEnd()) | ||
354 | parseLine(stream); | ||
355 | |||
356 | git = end(); | ||
357 | |||
358 | file.close(); | ||
359 | |||
360 | closelock( lockfd ); | ||
361 | } | ||
362 | |||
363 | |||
364 | void QSettingsHeading::parseLine(QTextStream &stream) | ||
365 | { | ||
366 | QString line = stream.readLine(); | ||
367 | if (line.isEmpty()) | ||
368 | // empty line... we'll allow it | ||
369 | return; | ||
370 | |||
371 | if (line[0] == QChar('#')) | ||
372 | // commented line | ||
373 | return; | ||
374 | |||
375 | if (line[0] == QChar('[')) { | ||
376 | QString gname = line; | ||
377 | |||
378 | gname = gname.remove(0, 1); | ||
379 | if (gname[(int)gname.length() - 1] == QChar(']')) | ||
380 | gname = gname.remove(gname.length() - 1, 1); | ||
381 | |||
382 | git = find(gname); | ||
383 | if (git == end()) | ||
384 | git = replace(gname, QSettingsGroup()); | ||
385 | } else { | ||
386 | if (git == end()) { | ||
387 | #if defined(QT_CHECK_STATE) | ||
388 | qWarning("QSettings: line '%s' out of group", line.latin1()); | ||
389 | #endif | ||
390 | return; | ||
391 | } | ||
392 | |||
393 | int i = line.find('='); | ||
394 | if (i == -1) { | ||
395 | #if defined(QT_CHECK_STATE) | ||
396 | qWarning("QSettings: malformed line '%s' in group '%s'", | ||
397 | line.latin1(), git.key().latin1()); | ||
398 | #endif | ||
399 | return; | ||
400 | } else { | ||
401 | QString key, value; | ||
402 | key = line.left(i); | ||
403 | value = ""; | ||
404 | bool esc=TRUE; | ||
405 | i++; | ||
406 | while (esc) { | ||
407 | esc = FALSE; | ||
408 | for ( ; i < (int)line.length(); i++ ) { | ||
409 | if ( esc ) { | ||
410 | if ( line[i] == 'n' ) | ||
411 | value.append('\n'); // escaped newline | ||
412 | else if ( line[i] == '0' ) | ||
413 | value = QString::null; // escaped empty string | ||
414 | else | ||
415 | value.append(line[i]); | ||
416 | esc = FALSE; | ||
417 | } else if ( line[i] == '\\' ) | ||
418 | esc = TRUE; | ||
419 | else | ||
420 | value.append(line[i]); | ||
421 | } | ||
422 | if ( esc ) { | ||
423 | // Backwards-compatiblity... | ||
424 | // still escaped at EOL - manually escaped "newline" | ||
425 | if (stream.atEnd()) { | ||
426 | #if defined(QT_CHECK_STATE) | ||
427 | qWarning("QSettings: reached end of file, expected continued line"); | ||
428 | #endif | ||
429 | break; | ||
430 | } | ||
431 | value.append('\n'); | ||
432 | line = stream.readLine(); | ||
433 | i = 0; | ||
434 | } | ||
435 | } | ||
436 | |||
437 | (*git).insert(key, value); | ||
438 | } | ||
439 | } | ||
440 | } | ||
441 | |||
442 | #ifdef Q_WS_WIN // for homedirpath reading from registry | ||
443 | #include "qt_windows.h" | ||
444 | #include "qlibrary.h" | ||
445 | |||
446 | #ifndef CSIDL_APPDATA | ||
447 | #define CSIDL_APPDATA 0x001a // <user name>\Application Data | ||
448 | #endif | ||
449 | #ifndef CSIDL_COMMON_APPDATA | ||
450 | #define CSIDL_COMMON_APPDATA 0x0023 // All Users\Application Data | ||
451 | #endif | ||
452 | |||
453 | #endif | ||
454 | |||
455 | QSettingsPrivate::QSettingsPrivate( QSettings::Format format ) | ||
456 | : groupDirty( TRUE ), modified(FALSE), globalScope(TRUE) | ||
457 | { | ||
458 | #if defined(Q_WS_WIN) || defined(Q_OS_MAC) | ||
459 | if ( format != QSettings::Ini ) | ||
460 | return; | ||
461 | #endif | ||
462 | |||
463 | QString appSettings(QDir::homeDirPath() + "/.qt/"); | ||
464 | QString defPath; | ||
465 | #ifdef Q_WS_WIN | ||
466 | #ifdef Q_OS_TEMP | ||
467 | TCHAR path[MAX_PATH]; | ||
468 | SHGetSpecialFolderPath( 0, path, CSIDL_APPDATA, FALSE ); | ||
469 | appSettings = QString::fromUcs2( path ); | ||
470 | SHGetSpecialFolderPath( 0, path, CSIDL_COMMON_APPDATA, FALSE ); | ||
471 | defPath = QString::fromUcs2( path ); | ||
472 | #else | ||
473 | QLibrary library( "shell32" ); | ||
474 | library.setAutoUnload( FALSE ); | ||
475 | QT_WA( { | ||
476 | typedef BOOL (WINAPI*GetSpecialFolderPath)(HWND, LPTSTR, int, BOOL); | ||
477 | GetSpecialFolderPath SHGetSpecialFolderPath = (GetSpecialFolderPath)library.resolve( "SHGetSpecialFolderPathW" ); | ||
478 | if ( SHGetSpecialFolderPath ) { | ||
479 | TCHAR path[MAX_PATH]; | ||
480 | SHGetSpecialFolderPath( 0, path, CSIDL_APPDATA, FALSE ); | ||
481 | appSettings = QString::fromUcs2( (ushort*)path ); | ||
482 | SHGetSpecialFolderPath( 0, path, CSIDL_COMMON_APPDATA, FALSE ); | ||
483 | defPath = QString::fromUcs2( (ushort*)path ); | ||
484 | } | ||
485 | } , { | ||
486 | typedef BOOL (WINAPI*GetSpecialFolderPath)(HWND, char*, int, BOOL); | ||
487 | GetSpecialFolderPath SHGetSpecialFolderPath = (GetSpecialFolderPath)library.resolve( "SHGetSpecialFolderPathA" ); | ||
488 | if ( SHGetSpecialFolderPath ) { | ||
489 | char path[MAX_PATH]; | ||
490 | SHGetSpecialFolderPath( 0, path, CSIDL_APPDATA, FALSE ); | ||
491 | appSettings = QString::fromLocal8Bit( path ); | ||
492 | SHGetSpecialFolderPath( 0, path, CSIDL_COMMON_APPDATA, FALSE ); | ||
493 | defPath = QString::fromLocal8Bit( path ); | ||
494 | } | ||
495 | } ); | ||
496 | #endif // Q_OS_TEMP | ||
497 | #else | ||
498 | // for now | ||
499 | #define QSETTINGS_DEFAULT_PATH_SUFFIX "/etc/settings" | ||
500 | |||
501 | defPath = qInstallPath(); | ||
502 | defPath += QSETTINGS_DEFAULT_PATH_SUFFIX; | ||
503 | #endif | ||
504 | QDir dir(appSettings); | ||
505 | if (! dir.exists()) { | ||
506 | if (! dir.mkdir(dir.path())) | ||
507 | #if defined(QT_CHECK_STATE) | ||
508 | qWarning("QSettings: error creating %s", dir.path().latin1()); | ||
509 | #endif | ||
510 | } | ||
511 | |||
512 | if ( !!defPath ) | ||
513 | searchPaths.append(defPath); | ||
514 | searchPaths.append(dir.path()); | ||
515 | } | ||
516 | |||
517 | QSettingsPrivate::~QSettingsPrivate() | ||
518 | { | ||
519 | } | ||
520 | |||
521 | QSettingsGroup QSettingsPrivate::readGroup() | ||
522 | { | ||
523 | QSettingsHeading hd; | ||
524 | QSettingsGroup grp; | ||
525 | |||
526 | QMap<QString,QSettingsHeading>::Iterator headingsit = headings.find(heading); | ||
527 | if (headingsit != headings.end()) | ||
528 | hd = *headingsit; | ||
529 | |||
530 | QSettingsHeading::Iterator grpit = hd.find(group); | ||
531 | if (grpit == hd.end()) { | ||
532 | QStringList::Iterator it = searchPaths.begin(); | ||
533 | while (it != searchPaths.end()) { | ||
534 | QString filebase = heading.lower().replace(QRegExp("\\s+"), "_"); | ||
535 | QString fn((*it++) + "/" + filebase + "rc"); | ||
536 | if (! hd.contains(fn + "cached")) { | ||
537 | hd.read(fn); | ||
538 | hd.insert(fn + "cached", QSettingsGroup()); | ||
539 | } | ||
540 | } | ||
541 | |||
542 | headings.replace(heading, hd); | ||
543 | |||
544 | grpit = hd.find(group); | ||
545 | if (grpit != hd.end()) | ||
546 | grp = *grpit; | ||
547 | } else if (hd.count() != 0) | ||
548 | grp = *grpit; | ||
549 | |||
550 | return grp; | ||
551 | } | ||
552 | |||
553 | |||
554 | void QSettingsPrivate::removeGroup(const QString &key) | ||
555 | { | ||
556 | QSettingsHeading hd; | ||
557 | QSettingsGroup grp; | ||
558 | bool found = FALSE; | ||
559 | |||
560 | QMap<QString,QSettingsHeading>::Iterator headingsit = headings.find(heading); | ||
561 | if (headingsit != headings.end()) | ||
562 | hd = *headingsit; | ||
563 | |||
564 | QSettingsHeading::Iterator grpit = hd.find(group); | ||
565 | if (grpit == hd.end()) { | ||
566 | QStringList::Iterator it = searchPaths.begin(); | ||
567 | while (it != searchPaths.end()) { | ||
568 | QString filebase = heading.lower().replace(QRegExp("\\s+"), "_"); | ||
569 | QString fn((*it++) + "/" + filebase + "rc"); | ||
570 | if (! hd.contains(fn + "cached")) { | ||
571 | hd.read(fn); | ||
572 | hd.insert(fn + "cached", QSettingsGroup()); | ||
573 | } | ||
574 | } | ||
575 | |||
576 | headings.replace(heading, hd); | ||
577 | |||
578 | grpit = hd.find(group); | ||
579 | if (grpit != hd.end()) { | ||
580 | found = TRUE; | ||
581 | grp = *grpit; | ||
582 | } | ||
583 | } else if (hd.count() != 0) { | ||
584 | found = TRUE; | ||
585 | grp = *grpit; | ||
586 | } | ||
587 | |||
588 | if (found) { | ||
589 | grp.remove(key); | ||
590 | |||
591 | if (grp.count() > 0) | ||
592 | hd.replace(group, grp); | ||
593 | else | ||
594 | hd.remove(group); | ||
595 | |||
596 | if (hd.count() > 0) | ||
597 | headings.replace(heading, hd); | ||
598 | else | ||
599 | headings.remove(heading); | ||
600 | |||
601 | modified = TRUE; | ||
602 | } | ||
603 | } | ||
604 | |||
605 | |||
606 | void QSettingsPrivate::writeGroup(const QString &key, const QString &value) | ||
607 | { | ||
608 | QSettingsHeading hd; | ||
609 | QSettingsGroup grp; | ||
610 | |||
611 | QMap<QString,QSettingsHeading>::Iterator headingsit = headings.find(heading); | ||
612 | if (headingsit != headings.end()) | ||
613 | hd = *headingsit; | ||
614 | |||
615 | QSettingsHeading::Iterator grpit = hd.find(group); | ||
616 | if (grpit == hd.end()) { | ||
617 | QStringList::Iterator it = searchPaths.begin(); | ||
618 | while (it != searchPaths.end()) { | ||
619 | QString filebase = heading.lower().replace(QRegExp("\\s+"), "_"); | ||
620 | QString fn((*it++) + "/" + filebase + "rc"); | ||
621 | if (! hd.contains(fn + "cached")) { | ||
622 | hd.read(fn); | ||
623 | hd.insert(fn + "cached", QSettingsGroup()); | ||
624 | } | ||
625 | } | ||
626 | |||
627 | headings.replace(heading, hd); | ||
628 | |||
629 | grpit = hd.find(group); | ||
630 | if (grpit != hd.end()) | ||
631 | grp = *grpit; | ||
632 | } else if (hd.count() != 0) | ||
633 | grp = *grpit; | ||
634 | |||
635 | grp.modified = TRUE; | ||
636 | grp.replace(key, value); | ||
637 | hd.replace(group, grp); | ||
638 | headings.replace(heading, hd); | ||
639 | |||
640 | modified = TRUE; | ||
641 | } | ||
642 | |||
643 | |||
644 | QDateTime QSettingsPrivate::modificationTime() | ||
645 | { | ||
646 | QSettingsHeading hd = headings[heading]; | ||
647 | QSettingsGroup grp = hd[group]; | ||
648 | |||
649 | QDateTime datetime; | ||
650 | |||
651 | QStringList::Iterator it = searchPaths.begin(); | ||
652 | while (it != searchPaths.end()) { | ||
653 | QFileInfo fi((*it++) + "/" + heading + "rc"); | ||
654 | if (fi.exists() && fi.lastModified() > datetime) | ||
655 | datetime = fi.lastModified(); | ||
656 | } | ||
657 | |||
658 | return datetime; | ||
659 | } | ||
660 | |||
661 | static bool verifyKey( const QString &key ) | ||
662 | { | ||
663 | if ( key.isEmpty() || key[0] != '/' || key.contains( QRegExp("[=\\\\r\\\\n" ) ) ) | ||
664 | return FALSE; | ||
665 | return TRUE; | ||
666 | } | ||
667 | |||
668 | static inline QString groupKey( const QString &group, const QString &key ) | ||
669 | { | ||
670 | if ( group.endsWith( "/" ) || key.startsWith( "/" ) ) | ||
671 | return group + key; | ||
672 | return group + "/" + key; | ||
673 | } | ||
674 | |||
675 | /*! | ||
676 | Inserts \a path into the settings search path. The semantics of \a | ||
677 | path depends on the system \a s. | ||
678 | |||
679 | When \a s is \e Windows and the execution environment is \e not | ||
680 | Windows the function does nothing. Similarly when \a s is \e Unix and | ||
681 | the execution environment is \e not Unix the function does nothing. | ||
682 | |||
683 | When \a s is \e Windows, and the execution environment is Windows, the | ||
684 | search path list will be used as the first subfolder of the "Software" | ||
685 | folder in the registry. | ||
686 | |||
687 | When reading settings the folders are searched forwards from the | ||
688 | first folder (listed below) to the last, returning the first | ||
689 | settings found, and ignoring any folders for which the user doesn't | ||
690 | have read permission. | ||
691 | \list 1 | ||
692 | \i HKEY_CURRENT_USER/Software/MyCompany/MyApplication | ||
693 | \i HKEY_LOCAL_MACHINE/Software/MyCompany/MyApplication | ||
694 | \i HKEY_CURRENT_USER/Software/MyApplication | ||
695 | \i HKEY_LOCAL_MACHINE/Software/MyApplication | ||
696 | \endlist | ||
697 | |||
698 | \code | ||
699 | QSettings settings; | ||
700 | settings.insertSearchPath( QSettings::Windows, "/MyCompany" ); | ||
701 | settings.writeEntry( "/MyApplication/Tip of the day", TRUE ); | ||
702 | \endcode | ||
703 | The code above will write the subkey "Tip of the day" into the \e | ||
704 | first of the registry folders listed below that is found and for | ||
705 | which the user has write permission. | ||
706 | \list 1 | ||
707 | \i HKEY_LOCAL_MACHINE/Software/MyCompany/MyApplication | ||
708 | \i HKEY_CURRENT_USER/Software/MyCompany/MyApplication | ||
709 | \i HKEY_LOCAL_MACHINE/Software/MyApplication | ||
710 | \i HKEY_CURRENT_USER/Software/MyApplication | ||
711 | \endlist | ||
712 | If a setting is found in the HKEY_CURRENT_USER space, this setting | ||
713 | is overwritten independently of write permissions in the | ||
714 | HKEY_LOCAL_MACHINE space. | ||
715 | |||
716 | When \a s is \e Unix, and the execution environment is Unix, the | ||
717 | search path list will be used when trying to determine a suitable | ||
718 | filename for reading and writing settings files. By default, there are | ||
719 | two entries in the search path: | ||
720 | |||
721 | \list 1 | ||
722 | \i INSTALL/etc - where \c INSTALL is the directory where Qt was installed. | ||
723 | \i $HOME/.qt/ - where \c $HOME is the user's home directory. | ||
724 | \endlist | ||
725 | |||
726 | All insertions into the search path will go before $HOME/.qt/. | ||
727 | For example: | ||
728 | \code | ||
729 | QSettings settings; | ||
730 | settings.insertSearchPath( QSettings::Unix, "/opt/MyCompany/share/etc" ); | ||
731 | settings.insertSearchPath( QSettings::Unix, "/opt/MyCompany/share/MyApplication/etc" ); | ||
732 | // ... | ||
733 | \endcode | ||
734 | Will result in a search path of: | ||
735 | \list 1 | ||
736 | \i INSTALL/etc | ||
737 | \i /opt/MyCompany/share/etc | ||
738 | \i /opt/MyCompany/share/MyApplication/etc | ||
739 | \i $HOME/.qt | ||
740 | \endlist | ||
741 | When reading settings the files are searched in the order shown | ||
742 | above, with later settings overriding earlier settings. Files for | ||
743 | which the user doesn't have read permission are ignored. When saving | ||
744 | settings QSettings works in the order shown above, writing | ||
745 | to the first settings file for which the user has write permission. | ||
746 | |||
747 | Settings under Unix are stored in files whose names are based on the | ||
748 | first subkey of the key (not including the search path). The algorithm | ||
749 | for creating names is essentially: lowercase the first subkey, replace | ||
750 | spaces with underscores and add 'rc', e.g. | ||
751 | <tt>/MyCompany/MyApplication/background color</tt> will be stored in | ||
752 | <tt>myapplicationrc</tt> (assuming that <tt>/MyCompany</tt> is part of | ||
753 | the search path). | ||
754 | |||
755 | \sa removeSearchPath() | ||
756 | |||
757 | */ | ||
758 | void QSettings::insertSearchPath( System s, const QString &path) | ||
759 | { | ||
760 | #if defined(Q_WS_WIN) || defined(Q_OS_MAC) | ||
761 | if ( d->sysd ) { | ||
762 | d->sysInsertSearchPath( s, path ); | ||
763 | return; | ||
764 | } | ||
765 | #endif | ||
766 | |||
767 | if ( !verifyKey( path ) ) { | ||
768 | #if defined(QT_CHECK_STATE) | ||
769 | qWarning( "QSettings::insertSearchPath: Invalid key: '%s'", path.isNull() ? "(null)" : path.latin1() ); | ||
770 | #endif | ||
771 | return; | ||
772 | } | ||
773 | |||
774 | #if defined(Q_WS_WIN) || defined(Q_OS_MAC) | ||
775 | if ( d->sysd && s != Unix ) { | ||
776 | #else | ||
777 | if ( s != Unix ) { | ||
778 | #endif | ||
779 | #ifdef Q_OS_MAC | ||
780 | if(s != Mac) //mac is respected on the mac as well | ||
781 | #endif | ||
782 | return; | ||
783 | } | ||
784 | |||
785 | QStringList::Iterator it = d->searchPaths.find(d->searchPaths.last()); | ||
786 | if (it != d->searchPaths.end()) { | ||
787 | d->searchPaths.insert(it, path); | ||
788 | } | ||
789 | } | ||
790 | |||
791 | |||
792 | /*! | ||
793 | Removes all occurrences of \a path (using exact matching) from the | ||
794 | settings search path for system \a s. Note that the default search | ||
795 | paths cannot be removed. | ||
796 | |||
797 | \sa insertSearchPath() | ||
798 | */ | ||
799 | void QSettings::removeSearchPath( System s, const QString &path) | ||
800 | { | ||
801 | if ( !verifyKey( path ) ) { | ||
802 | #if defined(QT_CHECK_STATE) | ||
803 | qWarning( "QSettings::insertSearchPath: Invalid key: '%s'", path.isNull() ? "(null)" : path.latin1() ); | ||
804 | #endif | ||
805 | return; | ||
806 | } | ||
807 | |||
808 | #ifdef Q_WS_WIN | ||
809 | if ( d->sysd ) { | ||
810 | d->sysRemoveSearchPath( s, path ); | ||
811 | return; | ||
812 | } | ||
813 | #endif | ||
814 | #if defined(Q_WS_WIN) || defined(Q_OS_MAC) | ||
815 | if ( d->sysd && s != Unix ) { | ||
816 | #else | ||
817 | if ( s != Unix ) { | ||
818 | #endif | ||
819 | #ifdef Q_OS_MAC | ||
820 | if(s != Mac) //mac is respected on the mac as well | ||
821 | #endif | ||
822 | return; | ||
823 | } | ||
824 | |||
825 | if (path == d->searchPaths.first() || path == d->searchPaths.last()) | ||
826 | return; | ||
827 | |||
828 | d->searchPaths.remove(path); | ||
829 | } | ||
830 | |||
831 | |||
832 | /*! | ||
833 | Creates a settings object. | ||
834 | */ | ||
835 | QSettings::QSettings() | ||
836 | { | ||
837 | d = new QSettingsPrivate( Native ); | ||
838 | Q_CHECK_PTR(d); | ||
839 | |||
840 | #if defined(Q_WS_WIN) || defined(Q_OS_MAC) | ||
841 | d->sysd = 0; | ||
842 | d->sysInit(); | ||
843 | #endif | ||
844 | } | ||
845 | |||
846 | /*! | ||
847 | Creates a settings object. If \a format is 'Ini' the settings will | ||
848 | be stored in a text file, using the Unix strategy (see above). If \a format | ||
849 | is 'Native', the settings will be stored in a platform specific way | ||
850 | (ie. the Windows registry). | ||
851 | */ | ||
852 | QSettings::QSettings( Format format ) | ||
853 | { | ||
854 | d = new QSettingsPrivate( format ); | ||
855 | Q_CHECK_PTR(d); | ||
856 | |||
857 | #if defined(Q_WS_WIN) || defined(Q_OS_MAC) | ||
858 | d->sysd = 0; | ||
859 | if ( format == Native ) | ||
860 | d->sysInit(); | ||
861 | #else | ||
862 | Q_UNUSED(format); | ||
863 | #endif | ||
864 | } | ||
865 | |||
866 | /*! | ||
867 | Destroys the settings object. All modifications made to the settings | ||
868 | will automatically be saved. | ||
869 | |||
870 | */ | ||
871 | QSettings::~QSettings() | ||
872 | { | ||
873 | sync(); | ||
874 | |||
875 | #if defined(Q_WS_WIN) || defined(Q_OS_MAC) | ||
876 | if ( d->sysd ) | ||
877 | d->sysClear(); | ||
878 | #endif | ||
879 | |||
880 | delete d; | ||
881 | } | ||
882 | |||
883 | |||
884 | /*! \internal | ||
885 | Writes all modifications to the settings to disk. If any errors are | ||
886 | encountered, this function returns FALSE, otherwise it will return TRUE. | ||
887 | */ | ||
888 | bool QSettings::sync() | ||
889 | { | ||
890 | #if defined(Q_WS_WIN) || defined(Q_OS_MAC) | ||
891 | if ( d->sysd ) | ||
892 | return d->sysSync(); | ||
893 | #endif | ||
894 | if (! d->modified) | ||
895 | // fake success | ||
896 | return TRUE; | ||
897 | |||
898 | bool success = TRUE; | ||
899 | QMap<QString,QSettingsHeading>::Iterator it = d->headings.begin(); | ||
900 | |||
901 | while (it != d->headings.end()) { | ||
902 | // determine filename | ||
903 | QSettingsHeading hd(*it); | ||
904 | QSettingsHeading::Iterator hdit = hd.begin(); | ||
905 | QFile file; | ||
906 | |||
907 | QStringList::Iterator pit = d->searchPaths.begin(); | ||
908 | while (pit != d->searchPaths.end()) { | ||
909 | QString filebase = it.key().lower().replace(QRegExp("\\s+"), "_"); | ||
910 | QFileInfo di(*pit); | ||
911 | QFileInfo fi((*pit++) + "/" + filebase + "rc"); | ||
912 | |||
913 | if ((fi.exists() && fi.isFile() && fi.isWritable()) || | ||
914 | (! fi.exists() && di.isDir() && di.isWritable())) { | ||
915 | file.setName(fi.filePath()); | ||
916 | break; | ||
917 | } | ||
918 | } | ||
919 | |||
920 | it++; | ||
921 | |||
922 | if (file.name().isNull() || file.name().isEmpty()) { | ||
923 | |||
924 | #ifdef QT_CHECK_STATE | ||
925 | qWarning("QSettings::sync: filename is null/empty"); | ||
926 | #endif // QT_CHECK_STATE | ||
927 | |||
928 | success = FALSE; | ||
929 | continue; | ||
930 | } | ||
931 | |||
932 | HANDLE lockfd = openlock( file.name(), Q_LOCKWRITE ); | ||
933 | |||
934 | if (! file.open(IO_WriteOnly)) { | ||
935 | |||
936 | #ifdef QT_CHECK_STATE | ||
937 | qWarning("QSettings::sync: failed to open '%s' for writing", | ||
938 | file.name().latin1()); | ||
939 | #endif // QT_CHECK_STATE | ||
940 | |||
941 | success = FALSE; | ||
942 | continue; | ||
943 | } | ||
944 | |||
945 | // spew to file | ||
946 | QTextStream stream(&file); | ||
947 | stream.setEncoding(QTextStream::UnicodeUTF8); | ||
948 | |||
949 | while (hdit != hd.end()) { | ||
950 | if ((*hdit).count() > 0) { | ||
951 | stream << "[" << hdit.key() << "]" << endl; | ||
952 | |||
953 | QSettingsGroup grp(*hdit); | ||
954 | QSettingsGroup::Iterator grpit = grp.begin(); | ||
955 | |||
956 | while (grpit != grp.end()) { | ||
957 | QString v = grpit.data(); | ||
958 | if ( v.isNull() ) { | ||
959 | v = "\\0"; // escape null string | ||
960 | } else { | ||
961 | v.replace("\\", "\\\\"); // escape backslash | ||
962 | v.replace("\n", "\\n"); // escape newlines | ||
963 | } | ||
964 | |||
965 | stream << grpit.key() << "=" << v << endl; | ||
966 | grpit++; | ||
967 | } | ||
968 | |||
969 | stream << endl; | ||
970 | } | ||
971 | |||
972 | hdit++; | ||
973 | } | ||
974 | |||
975 | if (file.status() != IO_Ok) { | ||
976 | |||
977 | #ifdef QT_CHECK_STATE | ||
978 | qWarning("QSettings::sync: error at end of write"); | ||
979 | #endif // QT_CHECK_STATE | ||
980 | |||
981 | success = FALSE; | ||
982 | } | ||
983 | |||
984 | file.close(); | ||
985 | |||
986 | closelock( lockfd ); | ||
987 | } | ||
988 | |||
989 | d->modified = FALSE; | ||
990 | |||
991 | return success; | ||
992 | } | ||
993 | |||
994 | |||
995 | /*! | ||
996 | \fn bool QSettings::readBoolEntry(const QString &key, bool def, bool *ok ) const | ||
997 | |||
998 | Reads the entry specified by \a key, and returns a bool, or the | ||
999 | default value, \a def, if the entry couldn't be read. | ||
1000 | If \a ok is non-null, *ok is set to TRUE if the key was read, FALSE | ||
1001 | otherwise. | ||
1002 | |||
1003 | \sa readEntry(), readNumEntry(), readDoubleEntry(), writeEntry(), removeEntry() | ||
1004 | */ | ||
1005 | |||
1006 | /*! | ||
1007 | \internal | ||
1008 | */ | ||
1009 | bool QSettings::readBoolEntry(const QString &key, bool def, bool *ok ) | ||
1010 | { | ||
1011 | if ( !verifyKey( key ) ) { | ||
1012 | #if defined(QT_CHECK_STATE) | ||
1013 | qWarning( "QSettings::readBoolEntry: Invalid key: '%s'", key.isNull() ? "(null)" : key.latin1() ); | ||
1014 | #endif | ||
1015 | if ( ok ) | ||
1016 | *ok = FALSE; | ||
1017 | |||
1018 | return def; | ||
1019 | } | ||
1020 | |||
1021 | QString theKey = groupKey( group(), key ); | ||
1022 | #if defined(Q_WS_WIN) || defined(Q_OS_MAC) | ||
1023 | if ( d->sysd ) | ||
1024 | return d->sysReadBoolEntry( theKey, def, ok ); | ||
1025 | #endif | ||
1026 | |||
1027 | QString value = readEntry( theKey, ( def ? "true" : "false" ), ok ); | ||
1028 | |||
1029 | if (value.lower() == "true") | ||
1030 | return TRUE; | ||
1031 | else if (value.lower() == "false") | ||
1032 | return FALSE; | ||
1033 | else if (value == "1") | ||
1034 | return TRUE; | ||
1035 | else if (value == "0") | ||
1036 | return FALSE; | ||
1037 | |||
1038 | if (! value.isEmpty()) | ||
1039 | qWarning("QSettings::readBoolEntry: '%s' is not 'true' or 'false'", | ||
1040 | value.latin1()); | ||
1041 | if ( ok ) | ||
1042 | *ok = FALSE; | ||
1043 | return def; | ||
1044 | } | ||
1045 | |||
1046 | |||
1047 | /*! | ||
1048 | \fn double QSettings::readDoubleEntry(const QString &key, double def, bool *ok ) const | ||
1049 | |||
1050 | Reads the entry specified by \a key, and returns a double, or the | ||
1051 | default value, \a def, if the entry couldn't be read. | ||
1052 | If \a ok is non-null, *ok is set to TRUE if the key was read, FALSE | ||
1053 | otherwise. | ||
1054 | |||
1055 | \sa readEntry(), readNumEntry(), readBoolEntry(), writeEntry(), removeEntry() | ||
1056 | */ | ||
1057 | |||
1058 | /*! | ||
1059 | \internal | ||
1060 | */ | ||
1061 | double QSettings::readDoubleEntry(const QString &key, double def, bool *ok ) | ||
1062 | { | ||
1063 | if ( !verifyKey( key ) ) { | ||
1064 | #if defined(QT_CHECK_STATE) | ||
1065 | qWarning( "QSettings::readDoubleEntry: Invalid key: '%s'", key.isNull() ? "(null)" : key.latin1() ); | ||
1066 | #endif | ||
1067 | if ( ok ) | ||
1068 | *ok = FALSE; | ||
1069 | |||
1070 | return def; | ||
1071 | } | ||
1072 | |||
1073 | QString theKey = groupKey( group(), key ); | ||
1074 | #if defined(Q_WS_WIN) || defined(Q_OS_MAC) | ||
1075 | if ( d->sysd ) | ||
1076 | return d->sysReadDoubleEntry( theKey, def, ok ); | ||
1077 | #endif | ||
1078 | |||
1079 | QString value = readEntry( theKey, QString::number(def), ok ); | ||
1080 | bool conv_ok; | ||
1081 | double retval = value.toDouble( &conv_ok ); | ||
1082 | if ( conv_ok ) | ||
1083 | return retval; | ||
1084 | if ( ! value.isEmpty() ) | ||
1085 | qWarning( "QSettings::readDoubleEntry: '%s' is not a number", | ||
1086 | value.latin1() ); | ||
1087 | if ( ok ) | ||
1088 | *ok = FALSE; | ||
1089 | return def; | ||
1090 | } | ||
1091 | |||
1092 | |||
1093 | /*! | ||
1094 | \fn int QSettings::readNumEntry(const QString &key, int def, bool *ok ) const | ||
1095 | |||
1096 | Reads the entry specified by \a key, and returns an integer, or the | ||
1097 | default value, \a def, if the entry couldn't be read. | ||
1098 | If \a ok is non-null, *ok is set to TRUE if the key was read, FALSE | ||
1099 | otherwise. | ||
1100 | |||
1101 | \sa readEntry(), readDoubleEntry(), readBoolEntry(), writeEntry(), removeEntry() | ||
1102 | */ | ||
1103 | |||
1104 | /*! | ||
1105 | \internal | ||
1106 | */ | ||
1107 | int QSettings::readNumEntry(const QString &key, int def, bool *ok ) | ||
1108 | { | ||
1109 | if ( !verifyKey( key ) ) { | ||
1110 | #if defined(QT_CHECK_STATE) | ||
1111 | qWarning( "QSettings::readNumEntry: Invalid key: '%s'", key.isNull() ? "(null)" : key.latin1() ); | ||
1112 | #endif | ||
1113 | if ( ok ) | ||
1114 | *ok = FALSE; | ||
1115 | return def; | ||
1116 | } | ||
1117 | |||
1118 | QString theKey = groupKey( group(), key ); | ||
1119 | |||
1120 | #if defined(Q_WS_WIN) || defined(Q_OS_MAC) | ||
1121 | if ( d->sysd ) | ||
1122 | return d->sysReadNumEntry( theKey, def, ok ); | ||
1123 | #endif | ||
1124 | |||
1125 | QString value = readEntry( theKey, QString::number( def ), ok ); | ||
1126 | bool conv_ok; | ||
1127 | int retval = value.toInt( &conv_ok ); | ||
1128 | if ( conv_ok ) | ||
1129 | return retval; | ||
1130 | if ( ! value.isEmpty() ) | ||
1131 | qWarning( "QSettings::readNumEntry: '%s' is not a number", | ||
1132 | value.latin1() ); | ||
1133 | if ( ok ) | ||
1134 | *ok = FALSE; | ||
1135 | return def; | ||
1136 | } | ||
1137 | |||
1138 | |||
1139 | /*! | ||
1140 | \fn QString QSettings::readEntry(const QString &key, const QString &def, bool *ok ) const | ||
1141 | |||
1142 | Reads the entry specified by \a key, and returns a QString, or the | ||
1143 | default value, \a def, if the entry couldn't be read. | ||
1144 | If \a ok is non-null, *ok is set to TRUE if the key was read, FALSE | ||
1145 | otherwise. | ||
1146 | |||
1147 | \sa readListEntry(), readNumEntry(), readDoubleEntry(), readBoolEntry(), writeEntry(), removeEntry() | ||
1148 | */ | ||
1149 | |||
1150 | /*! | ||
1151 | \internal | ||
1152 | */ | ||
1153 | QString QSettings::readEntry(const QString &key, const QString &def, bool *ok ) | ||
1154 | { | ||
1155 | if ( !verifyKey( key ) ) { | ||
1156 | #if defined(QT_CHECK_STATE) | ||
1157 | qWarning( "QSettings::readEntry: Invalid key: '%s'", key.isNull() ? "(null)" : key.latin1() ); | ||
1158 | #endif | ||
1159 | if ( ok ) | ||
1160 | *ok = FALSE; | ||
1161 | |||
1162 | return def; | ||
1163 | } | ||
1164 | |||
1165 | QString theKey = groupKey( group(), key ); | ||
1166 | |||
1167 | #if defined(Q_WS_WIN) || defined(Q_OS_MAC) | ||
1168 | if ( d->sysd ) | ||
1169 | return d->sysReadEntry( theKey, def, ok ); | ||
1170 | #endif | ||
1171 | |||
1172 | if ( ok ) // no, everything is not ok | ||
1173 | *ok = FALSE; | ||
1174 | |||
1175 | QString realkey; | ||
1176 | |||
1177 | if (theKey[0] == '/') { | ||
1178 | // parse our key | ||
1179 | QStringList list(QStringList::split('/', theKey)); | ||
1180 | |||
1181 | if (list.count() < 2) { | ||
1182 | #ifdef QT_CHECK_STATE | ||
1183 | qWarning("QSettings::readEntry: invalid key '%s'", theKey.latin1()); | ||
1184 | #endif // QT_CHECK_STATE | ||
1185 | if ( ok ) | ||
1186 | *ok = FALSE; | ||
1187 | return def; | ||
1188 | } | ||
1189 | |||
1190 | if (list.count() == 2) { | ||
1191 | d->heading = list[0]; | ||
1192 | d->group = "General"; | ||
1193 | realkey = list[1]; | ||
1194 | } else { | ||
1195 | d->heading = list[0]; | ||
1196 | d->group = list[1]; | ||
1197 | |||
1198 | // remove the group from the list | ||
1199 | list.remove(list.at(1)); | ||
1200 | // remove the heading from the list | ||
1201 | list.remove(list.at(0)); | ||
1202 | |||
1203 | realkey = list.join("/"); | ||
1204 | } | ||
1205 | } else | ||
1206 | realkey = theKey; | ||
1207 | |||
1208 | QSettingsGroup grp = d->readGroup(); | ||
1209 | QString retval = grp[realkey]; | ||
1210 | if ( retval.isNull() ) | ||
1211 | retval = def; | ||
1212 | else if ( ok ) // everything is ok | ||
1213 | *ok = TRUE; | ||
1214 | return retval; | ||
1215 | } | ||
1216 | |||
1217 | |||
1218 | #if !defined(Q_NO_BOOL_TYPE) | ||
1219 | /*! | ||
1220 | Writes the boolean entry \a value into key \a key. The \a key is | ||
1221 | created if it doesn't exist. Any previous value is overwritten by \a | ||
1222 | value. | ||
1223 | |||
1224 | If an error occurs the settings are left unchanged and FALSE is | ||
1225 | returned; otherwise TRUE is returned. | ||
1226 | |||
1227 | \sa readListEntry(), readNumEntry(), readDoubleEntry(), readBoolEntry(), removeEntry() | ||
1228 | */ | ||
1229 | bool QSettings::writeEntry(const QString &key, bool value) | ||
1230 | { | ||
1231 | if ( !verifyKey( key ) ) { | ||
1232 | #if defined(QT_CHECK_STATE) | ||
1233 | qWarning( "QSettings::writeEntry: Invalid key: '%s'", key.isNull() ? "(null)" : key.latin1() ); | ||
1234 | #endif | ||
1235 | return FALSE; | ||
1236 | } | ||
1237 | |||
1238 | QString theKey = groupKey( group(), key ); | ||
1239 | |||
1240 | #if defined(Q_WS_WIN) || defined(Q_OS_MAC) | ||
1241 | if ( d->sysd ) | ||
1242 | return d->sysWriteEntry( theKey, value ); | ||
1243 | #endif | ||
1244 | QString s(value ? "true" : "false"); | ||
1245 | return writeEntry(theKey, s); | ||
1246 | } | ||
1247 | #endif | ||
1248 | |||
1249 | |||
1250 | /*! | ||
1251 | \overload | ||
1252 | Writes the double entry \a value into key \a key. The \a key is | ||
1253 | created if it doesn't exist. Any previous value is overwritten by \a | ||
1254 | value. | ||
1255 | |||
1256 | If an error occurs the settings are left unchanged and FALSE is | ||
1257 | returned; otherwise TRUE is returned. | ||
1258 | |||
1259 | \sa readListEntry(), readNumEntry(), readDoubleEntry(), readBoolEntry(), removeEntry() | ||
1260 | */ | ||
1261 | bool QSettings::writeEntry(const QString &key, double value) | ||
1262 | { | ||
1263 | if ( !verifyKey( key ) ) { | ||
1264 | #if defined(QT_CHECK_STATE) | ||
1265 | qWarning( "QSettings::writeEntry: Invalid key: '%s'", key.isNull() ? "(null)" : key.latin1() ); | ||
1266 | #endif | ||
1267 | return FALSE; | ||
1268 | } | ||
1269 | |||
1270 | QString theKey = groupKey( group(), key ); | ||
1271 | |||
1272 | #if defined(Q_WS_WIN) || defined(Q_OS_MAC) | ||
1273 | if ( d->sysd ) | ||
1274 | return d->sysWriteEntry( theKey, value ); | ||
1275 | #endif | ||
1276 | QString s(QString::number(value)); | ||
1277 | return writeEntry(theKey, s); | ||
1278 | } | ||
1279 | |||
1280 | |||
1281 | /*! | ||
1282 | \overload | ||
1283 | Writes the integer entry \a value into key \a key. The \a key is | ||
1284 | created if it doesn't exist. Any previous value is overwritten by \a | ||
1285 | value. | ||
1286 | |||
1287 | If an error occurs the settings are left unchanged and FALSE is | ||
1288 | returned; otherwise TRUE is returned. | ||
1289 | |||
1290 | \sa readListEntry(), readNumEntry(), readDoubleEntry(), readBoolEntry(), removeEntry() | ||
1291 | */ | ||
1292 | bool QSettings::writeEntry(const QString &key, int value) | ||
1293 | { | ||
1294 | if ( !verifyKey( key ) ) { | ||
1295 | #if defined(QT_CHECK_STATE) | ||
1296 | qWarning( "QSettings::writeEntry: Invalid key: '%s'", key.isNull() ? "(null)" : key.latin1() ); | ||
1297 | #endif | ||
1298 | return FALSE; | ||
1299 | } | ||
1300 | |||
1301 | QString theKey = groupKey( group(), key ); | ||
1302 | |||
1303 | #if defined(Q_WS_WIN) || defined(Q_OS_MAC) | ||
1304 | if ( d->sysd ) | ||
1305 | return d->sysWriteEntry( theKey, value ); | ||
1306 | #endif | ||
1307 | QString s(QString::number(value)); | ||
1308 | return writeEntry(theKey, s); | ||
1309 | } | ||
1310 | |||
1311 | |||
1312 | /*! | ||
1313 | \internal | ||
1314 | |||
1315 | Writes the entry specified by \a key with the string-literal \a value, | ||
1316 | replacing any previous setting. If \a value is zero-length or null, the | ||
1317 | entry is replaced by an empty setting. | ||
1318 | |||
1319 | \e NOTE: This function is provided because some compilers use the | ||
1320 | writeEntry (const QString &, bool) overload for this code: | ||
1321 | writeEntry ("/foo/bar", "baz") | ||
1322 | |||
1323 | If an error occurs, this functions returns FALSE and the object is left | ||
1324 | unchanged. | ||
1325 | |||
1326 | \sa readEntry(), removeEntry() | ||
1327 | */ | ||
1328 | bool QSettings::writeEntry(const QString &key, const char *value) | ||
1329 | { | ||
1330 | if ( !verifyKey( key ) ) { | ||
1331 | #if defined(QT_CHECK_STATE) | ||
1332 | qWarning( "QSettings::writeEntry: Invalid key: '%s'", key.isNull() ? "(null)" : key.latin1() ); | ||
1333 | #endif | ||
1334 | return FALSE; | ||
1335 | } | ||
1336 | |||
1337 | QString theKey = groupKey( group(), key ); | ||
1338 | |||
1339 | return writeEntry(theKey, QString(value)); | ||
1340 | } | ||
1341 | |||
1342 | |||
1343 | /*! | ||
1344 | \overload | ||
1345 | Writes the string entry \a value into key \a key. The \a key is | ||
1346 | created if it doesn't exist. Any previous value is overwritten by \a | ||
1347 | value. If \a value is an empty string or a null string the key's | ||
1348 | value will be an empty string. | ||
1349 | |||
1350 | If an error occurs the settings are left unchanged and FALSE is | ||
1351 | returned; otherwise TRUE is returned. | ||
1352 | |||
1353 | \sa readListEntry(), readNumEntry(), readDoubleEntry(), readBoolEntry(), removeEntry() | ||
1354 | */ | ||
1355 | bool QSettings::writeEntry(const QString &key, const QString &value) | ||
1356 | { | ||
1357 | if ( !verifyKey( key ) ) { | ||
1358 | #if defined(QT_CHECK_STATE) | ||
1359 | qWarning( "QSettings::writeEntry: Invalid key: '%s'", key.isNull() ? "(null)" : key.latin1() ); | ||
1360 | #endif | ||
1361 | return FALSE; | ||
1362 | } | ||
1363 | |||
1364 | QString theKey = groupKey( group(), key ); | ||
1365 | |||
1366 | #if defined(Q_WS_WIN) || defined(Q_OS_MAC) | ||
1367 | if ( d->sysd ) | ||
1368 | return d->sysWriteEntry( theKey, value ); | ||
1369 | #endif | ||
1370 | // NOTE: we *do* allow value to be a null/empty string | ||
1371 | |||
1372 | QString realkey; | ||
1373 | |||
1374 | if (theKey[0] == '/') { | ||
1375 | // parse our key | ||
1376 | QStringList list(QStringList::split('/', theKey)); | ||
1377 | |||
1378 | if (list.count() < 2) { | ||
1379 | #ifdef QT_CHECK_STATE | ||
1380 | qWarning("QSettings::writeEntry: invalid key '%s'", theKey.latin1()); | ||
1381 | #endif // QT_CHECK_STATE | ||
1382 | |||
1383 | return FALSE; | ||
1384 | } | ||
1385 | |||
1386 | if (list.count() == 2) { | ||
1387 | d->heading = list[0]; | ||
1388 | d->group = "General"; | ||
1389 | realkey = list[1]; | ||
1390 | } else { | ||
1391 | d->heading = list[0]; | ||
1392 | d->group = list[1]; | ||
1393 | |||
1394 | // remove the group from the list | ||
1395 | list.remove(list.at(1)); | ||
1396 | // remove the heading from the list | ||
1397 | list.remove(list.at(0)); | ||
1398 | |||
1399 | realkey = list.join("/"); | ||
1400 | } | ||
1401 | } else | ||
1402 | realkey = theKey; | ||
1403 | |||
1404 | d->writeGroup(realkey, value); | ||
1405 | return TRUE; | ||
1406 | } | ||
1407 | |||
1408 | |||
1409 | /*! | ||
1410 | Removes the entry specified by \a key. | ||
1411 | |||
1412 | Returns TRUE if the entry existed and was removed; otherwise returns FALSE. | ||
1413 | |||
1414 | \sa readEntry(), writeEntry() | ||
1415 | */ | ||
1416 | bool QSettings::removeEntry(const QString &key) | ||
1417 | { | ||
1418 | if ( !verifyKey( key ) ) { | ||
1419 | #if defined(QT_CHECK_STATE) | ||
1420 | qWarning( "QSettings::removeEntry: Invalid key: '%s'", key.isNull() ? "(null)" : key.latin1() ); | ||
1421 | #endif | ||
1422 | return FALSE; | ||
1423 | } | ||
1424 | |||
1425 | QString theKey = groupKey( group(), key ); | ||
1426 | |||
1427 | #if defined(Q_WS_WIN) || defined(Q_OS_MAC) | ||
1428 | if ( d->sysd ) | ||
1429 | return d->sysRemoveEntry( theKey ); | ||
1430 | #endif | ||
1431 | |||
1432 | QString realkey; | ||
1433 | |||
1434 | if (theKey[0] == '/') { | ||
1435 | // parse our key | ||
1436 | QStringList list(QStringList::split('/', theKey)); | ||
1437 | |||
1438 | if (list.count() < 2) { | ||
1439 | #ifdef QT_CHECK_STATE | ||
1440 | qWarning("QSettings::removeEntry: invalid key '%s'", theKey.latin1()); | ||
1441 | #endif // QT_CHECK_STATE | ||
1442 | |||
1443 | return FALSE; | ||
1444 | } | ||
1445 | |||
1446 | if (list.count() == 2) { | ||
1447 | d->heading = list[0]; | ||
1448 | d->group = "General"; | ||
1449 | realkey = list[1]; | ||
1450 | } else { | ||
1451 | d->heading = list[0]; | ||
1452 | d->group = list[1]; | ||
1453 | |||
1454 | // remove the group from the list | ||
1455 | list.remove(list.at(1)); | ||
1456 | // remove the heading from the list | ||
1457 | list.remove(list.at(0)); | ||
1458 | |||
1459 | realkey = list.join("/"); | ||
1460 | } | ||
1461 | } else | ||
1462 | realkey = theKey; | ||
1463 | |||
1464 | d->removeGroup(realkey); | ||
1465 | return TRUE; | ||
1466 | } | ||
1467 | |||
1468 | |||
1469 | /*! | ||
1470 | Returns a list of the keys which contain entries under \a key. Does \e | ||
1471 | not return any keys that contain keys. | ||
1472 | |||
1473 | Example settings: | ||
1474 | \code | ||
1475 | /MyCompany/MyApplication/background color | ||
1476 | /MyCompany/MyApplication/foreground color | ||
1477 | /MyCompany/MyApplication/geometry/x | ||
1478 | /MyCompany/MyApplication/geometry/y | ||
1479 | /MyCompany/MyApplication/geometry/width | ||
1480 | /MyCompany/MyApplication/geometry/height | ||
1481 | \endcode | ||
1482 | \code | ||
1483 | QStringList keys = entryList( "/MyCompany/MyApplication" ); | ||
1484 | \endcode | ||
1485 | \c keys contains 'background color' and 'foreground color'. It does | ||
1486 | not contain 'geometry' because this key contains keys not entries. | ||
1487 | |||
1488 | To access the geometry values could either use subkeyList() to read | ||
1489 | the keys and then read each entry, or simply read each entry | ||
1490 | directly by specifying its full key, e.g. | ||
1491 | "/MyCompany/MyApplication/geometry/y". | ||
1492 | |||
1493 | \sa subkeyList() | ||
1494 | */ | ||
1495 | QStringList QSettings::entryList(const QString &key) const | ||
1496 | { | ||
1497 | if ( !verifyKey( key ) ) { | ||
1498 | #if defined(QT_CHECK_STATE) | ||
1499 | qWarning( "QSettings::entryList: Invalid key: %s", key.isNull() ? "(null)" : key.latin1() ); | ||
1500 | #endif | ||
1501 | return QStringList(); | ||
1502 | } | ||
1503 | |||
1504 | QString theKey = groupKey( group(), key ); | ||
1505 | |||
1506 | #if defined(Q_WS_WIN) || defined(Q_OS_MAC) | ||
1507 | if ( d->sysd ) | ||
1508 | return d->sysEntryList( theKey ); | ||
1509 | #endif | ||
1510 | |||
1511 | QString realkey; | ||
1512 | if (theKey[0] == '/') { | ||
1513 | // parse our key | ||
1514 | QStringList list(QStringList::split('/', theKey)); | ||
1515 | |||
1516 | if (list.count() < 1) { | ||
1517 | #ifdef QT_CHECK_STATE | ||
1518 | qWarning("QSettings::listEntries: invalid key '%s'", theKey.latin1()); | ||
1519 | #endif // QT_CHECK_STATE | ||
1520 | |||
1521 | return QStringList(); | ||
1522 | } | ||
1523 | |||
1524 | if (list.count() == 1) { | ||
1525 | d->heading = list[0]; | ||
1526 | d->group = "General"; | ||
1527 | } else { | ||
1528 | d->heading = list[0]; | ||
1529 | d->group = list[1]; | ||
1530 | |||
1531 | // remove the group from the list | ||
1532 | list.remove(list.at(1)); | ||
1533 | // remove the heading from the list | ||
1534 | list.remove(list.at(0)); | ||
1535 | |||
1536 | realkey = list.join("/"); | ||
1537 | } | ||
1538 | } else | ||
1539 | realkey = theKey; | ||
1540 | |||
1541 | QSettingsGroup grp = d->readGroup(); | ||
1542 | QSettingsGroup::Iterator it = grp.begin(); | ||
1543 | QStringList ret; | ||
1544 | QString itkey; | ||
1545 | while (it != grp.end()) { | ||
1546 | itkey = it.key(); | ||
1547 | it++; | ||
1548 | |||
1549 | if ( realkey.length() > 0 ) { | ||
1550 | if ( itkey.left( realkey.length() ) != realkey ) | ||
1551 | continue; | ||
1552 | else | ||
1553 | itkey.remove( 0, realkey.length() + 1 ); | ||
1554 | } | ||
1555 | |||
1556 | if ( itkey.find( '/' ) != -1 ) | ||
1557 | continue; | ||
1558 | |||
1559 | ret << itkey; | ||
1560 | } | ||
1561 | |||
1562 | return ret; | ||
1563 | } | ||
1564 | |||
1565 | |||
1566 | /*! | ||
1567 | Returns a list of the keys which contain keys under \a key. Does \e | ||
1568 | not return any keys that contain entries. | ||
1569 | |||
1570 | Example settings: | ||
1571 | \code | ||
1572 | /MyCompany/MyApplication/background color | ||
1573 | /MyCompany/MyApplication/foreground color | ||
1574 | /MyCompany/MyApplication/geometry/x | ||
1575 | /MyCompany/MyApplication/geometry/y | ||
1576 | /MyCompany/MyApplication/geometry/width | ||
1577 | /MyCompany/MyApplication/geometry/height | ||
1578 | /MyCompany/MyApplication/recent files/1 | ||
1579 | /MyCompany/MyApplication/recent files/2 | ||
1580 | /MyCompany/MyApplication/recent files/3 | ||
1581 | \endcode | ||
1582 | \code | ||
1583 | QStringList keys = subkeyList( "/MyCompany/MyApplication" ); | ||
1584 | \endcode | ||
1585 | \c keys contains 'geometry' and 'recent files'. It does not contain | ||
1586 | 'background color' or 'foreground color' because they are keys which | ||
1587 | contain entries not keys. To get a list of keys that have values | ||
1588 | rather than subkeys use entryList(). | ||
1589 | |||
1590 | \sa entryList() | ||
1591 | */ | ||
1592 | QStringList QSettings::subkeyList(const QString &key) const | ||
1593 | { | ||
1594 | if ( !verifyKey( key ) ) { | ||
1595 | #if defined(QT_CHECK_STATE) | ||
1596 | qWarning( "QSettings::subkeyList: Invalid key: %s", key.isNull() ? "(null)" : key.latin1() ); | ||
1597 | #endif | ||
1598 | return QStringList(); | ||
1599 | } | ||
1600 | |||
1601 | QString theKey = groupKey( group(), key ); | ||
1602 | |||
1603 | #if defined(Q_WS_WIN) || defined(Q_OS_MAC) | ||
1604 | if ( d->sysd ) | ||
1605 | return d->sysSubkeyList( theKey ); | ||
1606 | #endif | ||
1607 | |||
1608 | QString realkey; | ||
1609 | if (theKey[0] == '/') { | ||
1610 | // parse our key | ||
1611 | QStringList list(QStringList::split('/', theKey)); | ||
1612 | |||
1613 | if (list.count() < 1) { | ||
1614 | #ifdef QT_CHECK_STATE | ||
1615 | qWarning("QSettings::subkeyList: invalid key '%s'", theKey.latin1()); | ||
1616 | #endif // QT_CHECK_STATE | ||
1617 | |||
1618 | return QStringList(); | ||
1619 | } | ||
1620 | |||
1621 | if (list.count() == 1) { | ||
1622 | d->heading = list[0]; | ||
1623 | d->group = "General"; | ||
1624 | } else { | ||
1625 | d->heading = list[0]; | ||
1626 | d->group = list[1]; | ||
1627 | |||
1628 | // remove the group from the list | ||
1629 | list.remove(list.at(1)); | ||
1630 | // remove the heading from the list | ||
1631 | list.remove(list.at(0)); | ||
1632 | |||
1633 | realkey = list.join("/"); | ||
1634 | } | ||
1635 | } else | ||
1636 | realkey = theKey; | ||
1637 | |||
1638 | QSettingsGroup grp = d->readGroup(); | ||
1639 | QSettingsGroup::Iterator it = grp.begin(); | ||
1640 | QStringList ret; | ||
1641 | QString itkey; | ||
1642 | while (it != grp.end()) { | ||
1643 | itkey = it.key(); | ||
1644 | it++; | ||
1645 | |||
1646 | if ( realkey.length() > 0 ) { | ||
1647 | if ( itkey.left( realkey.length() ) != realkey ) | ||
1648 | continue; | ||
1649 | else | ||
1650 | itkey.remove( 0, realkey.length() + 1 ); | ||
1651 | } | ||
1652 | |||
1653 | int slash = itkey.find( '/' ); | ||
1654 | if ( slash == -1 ) | ||
1655 | continue; | ||
1656 | itkey.truncate( slash ); | ||
1657 | |||
1658 | if ( ! ret.contains( itkey ) ) | ||
1659 | ret << itkey; | ||
1660 | } | ||
1661 | |||
1662 | return ret; | ||
1663 | } | ||
1664 | |||
1665 | |||
1666 | /*! | ||
1667 | \internal | ||
1668 | |||
1669 | This function returns the time of last modification for \a key. | ||
1670 | */ | ||
1671 | QDateTime QSettings::lastModficationTime(const QString &key) | ||
1672 | { | ||
1673 | if ( !verifyKey( key ) ) { | ||
1674 | #if defined(QT_CHECK_STATE) | ||
1675 | qWarning( "QSettings::lastModficationTime: Invalid key: '%s'", key.isNull() ? "(null)" : key.latin1() ); | ||
1676 | #endif | ||
1677 | return QDateTime(); | ||
1678 | } | ||
1679 | |||
1680 | QString theKey = groupKey( group(), key ); | ||
1681 | |||
1682 | #if defined(Q_WS_WIN) || defined(Q_OS_MAC) | ||
1683 | if ( d->sysd ) | ||
1684 | return QDateTime(); | ||
1685 | #endif | ||
1686 | |||
1687 | if (theKey[0] == '/') { | ||
1688 | // parse our key | ||
1689 | QStringList list(QStringList::split('/', theKey)); | ||
1690 | |||
1691 | if (list.count() < 2) { | ||
1692 | #ifdef QT_CHECK_STATE | ||
1693 | qWarning("QSettings::lastModficationTime: invalid key '%s'", theKey.latin1()); | ||
1694 | #endif // QT_CHECK_STATE | ||
1695 | |||
1696 | return QDateTime(); | ||
1697 | } | ||
1698 | |||
1699 | if (list.count() == 2) { | ||
1700 | d->heading = list[0]; | ||
1701 | d->group = "General"; | ||
1702 | } else { | ||
1703 | d->heading = list[0]; | ||
1704 | d->group = list[1]; | ||
1705 | } | ||
1706 | } | ||
1707 | |||
1708 | return d->modificationTime(); | ||
1709 | } | ||
1710 | |||
1711 | |||
1712 | /*! | ||
1713 | \overload | ||
1714 | |||
1715 | Writes the string list entry \a value into key \a key. The \a key | ||
1716 | is created if it doesn't exist. Any previous value is overwritten | ||
1717 | by \a value. The list is stored as a sequence of strings separated | ||
1718 | by \a separator, so none of the strings in the list should contain | ||
1719 | the separator. If the list is empty or null the key's value will | ||
1720 | be an empty string. | ||
1721 | |||
1722 | If an error occurs the settings are left unchanged and FALSE is | ||
1723 | returned; otherwise returns TRUE. | ||
1724 | |||
1725 | \sa readListEntry(), readNumEntry(), readDoubleEntry(), readBoolEntry(), removeEntry() | ||
1726 | */ | ||
1727 | bool QSettings::writeEntry(const QString &key, const QStringList &value, | ||
1728 | const QChar &separator) | ||
1729 | { | ||
1730 | QString s(value.join(separator)); | ||
1731 | return writeEntry(key, s); | ||
1732 | } | ||
1733 | |||
1734 | /*! | ||
1735 | \overload | ||
1736 | |||
1737 | Writes the string list entry \a value into key \a key. The \a key | ||
1738 | is created if it doesn't exist. Any previous value is overwritten | ||
1739 | by \a value. | ||
1740 | |||
1741 | If an error occurs the settings are left unchanged and FALSE is | ||
1742 | returned; otherwise returns TRUE. | ||
1743 | |||
1744 | \sa readListEntry(), readNumEntry(), readDoubleEntry(), readBoolEntry(), removeEntry() | ||
1745 | */ | ||
1746 | bool QSettings::writeEntry(const QString &key, const QStringList &value) | ||
1747 | { | ||
1748 | QString s; | ||
1749 | for (QStringList::ConstIterator it=value.begin(); it!=value.end(); ++it) { | ||
1750 | QString el = *it; | ||
1751 | if ( el.isNull() ) { | ||
1752 | el = "^0"; | ||
1753 | } else { | ||
1754 | el.replace("^", "^^"); | ||
1755 | } | ||
1756 | s+=el; | ||
1757 | s+="^e"; // end of element | ||
1758 | } | ||
1759 | return writeEntry(key, s); | ||
1760 | } | ||
1761 | |||
1762 | |||
1763 | /*! | ||
1764 | \overload QStringList QSettings::readListEntry(const QString &key, const QChar &separator, bool *ok ) const | ||
1765 | |||
1766 | Reads the entry specified by \a key as a string. The \a separator | ||
1767 | is used to create a QStringList by calling QStringList::split(\a | ||
1768 | separator, entry). If \a ok is not 0: \a *ok is set to TRUE if the | ||
1769 | key was read, otherwise \a *ok is set to FALSE. | ||
1770 | |||
1771 | Note that if you want to iterate over the list, you should iterate | ||
1772 | over a copy, e.g. | ||
1773 | \code | ||
1774 | QStringList list = mySettings.readListEntry( "size", " " ); | ||
1775 | QStringList::Iterator it = list.begin(); | ||
1776 | while( it != list.end() ) { | ||
1777 | myProcessing( *it ); | ||
1778 | ++it; | ||
1779 | } | ||
1780 | \endcode | ||
1781 | |||
1782 | \sa readEntry(), readDoubleEntry(), readBoolEntry(), writeEntry(), removeEntry(), QStringList::split() | ||
1783 | */ | ||
1784 | |||
1785 | /*! | ||
1786 | \internal | ||
1787 | */ | ||
1788 | QStringList QSettings::readListEntry(const QString &key, const QChar &separator, bool *ok ) | ||
1789 | { | ||
1790 | QString value = readEntry( key, QString::null, ok ); | ||
1791 | if ( ok && !*ok ) | ||
1792 | return QStringList(); | ||
1793 | |||
1794 | return QStringList::split(separator, value); | ||
1795 | } | ||
1796 | |||
1797 | /*! | ||
1798 | \fn QStringList QSettings::readListEntry(const QString &key, bool *ok ) const | ||
1799 | Reads the entry specified by \a key as a string. If \a ok is not | ||
1800 | 0, \a *ok is set to TRUE if the key was read, otherwise \a *ok is | ||
1801 | set to FALSE. | ||
1802 | |||
1803 | Note that if you want to iterate over the list, you should iterate | ||
1804 | over a copy, e.g. | ||
1805 | \code | ||
1806 | QStringList list = mySettings.readListEntry( "recentfiles" ); | ||
1807 | QStringList::Iterator it = list.begin(); | ||
1808 | while( it != list.end() ) { | ||
1809 | myProcessing( *it ); | ||
1810 | ++it; | ||
1811 | } | ||
1812 | \endcode | ||
1813 | |||
1814 | \sa readEntry(), readDoubleEntry(), readBoolEntry(), writeEntry(), removeEntry(), QStringList::split() | ||
1815 | */ | ||
1816 | |||
1817 | /*! | ||
1818 | \internal | ||
1819 | */ | ||
1820 | QStringList QSettings::readListEntry(const QString &key, bool *ok ) | ||
1821 | { | ||
1822 | QString value = readEntry( key, QString::null, ok ); | ||
1823 | if ( ok && !*ok ) | ||
1824 | return QStringList(); | ||
1825 | QStringList l; | ||
1826 | QString s; | ||
1827 | bool esc=FALSE; | ||
1828 | for (int i=0; i<(int)value.length(); i++) { | ||
1829 | if ( esc ) { | ||
1830 | if ( value[i] == 'e' ) { // end-of-string | ||
1831 | l.append(s); | ||
1832 | s=""; | ||
1833 | } else if ( value[i] == '0' ) { // null string | ||
1834 | s=QString::null; | ||
1835 | } else { | ||
1836 | s.append(value[i]); | ||
1837 | } | ||
1838 | esc=FALSE; | ||
1839 | } else if ( value[i] == '^' ) { | ||
1840 | esc = TRUE; | ||
1841 | } else { | ||
1842 | s.append(value[i]); | ||
1843 | if ( i == (int)value.length()-1 ) | ||
1844 | l.append(s); | ||
1845 | } | ||
1846 | } | ||
1847 | return l; | ||
1848 | } | ||
1849 | |||
1850 | /*! | ||
1851 | Insert platform-dependent paths from platform-independent information. | ||
1852 | |||
1853 | The \a domain should be an Internet domain name | ||
1854 | controlled by the producer of the software, eg. Trolltech products | ||
1855 | use "trolltech.com". | ||
1856 | |||
1857 | The \a product should be the official name of the product. | ||
1858 | |||
1859 | The \a scope should be | ||
1860 | QSettings::User for user-specific settings, or | ||
1861 | QSettings::Global for system-wide settings (generally | ||
1862 | these will be read-only to many users). | ||
1863 | */ | ||
1864 | |||
1865 | void QSettings::setPath( const QString &domain, const QString &product, Scope scope ) | ||
1866 | { | ||
1867 | // On Windows, any trailing ".com(\..*)" is stripped from the domain. The | ||
1868 | // Global scope corresponds to HKEY_LOCAL_MACHINE, and User corresponds to | ||
1869 | // HKEY_CURRENT_USER. Note that on some installations, not all users can | ||
1870 | // write to the Global scope. On UNIX, any trailing ".com(\..*)" is stripped | ||
1871 | // from the domain. The Global scope corresponds to "/opt" (this would be | ||
1872 | // configurable at library build time - eg. to "/usr/local" or "/usr"), | ||
1873 | // while the User scope corresponds to $HOME/.*rc. | ||
1874 | // Note that on most installations, not all users can write to the System | ||
1875 | // scope. | ||
1876 | // | ||
1877 | // On MacOS X, if there is no "." in domain, append ".com", then reverse the | ||
1878 | // order of the elements (Mac OS uses "com.apple.finder" as domain+product). | ||
1879 | // The Global scope corresponds to /Library/Preferences/*.plist, while the | ||
1880 | // User scope corresponds to ~/Library/Preferences/*.plist. | ||
1881 | // Note that on most installations, not all users can write to the System | ||
1882 | // scope. | ||
1883 | QString actualSearchPath; | ||
1884 | int lastDot = domain.findRev( '.' ); | ||
1885 | |||
1886 | #if defined(Q_WS_WIN) | ||
1887 | actualSearchPath = "/" + domain.mid( 0, lastDot ) + "/" + product; | ||
1888 | insertSearchPath( Windows, actualSearchPath ); | ||
1889 | #elif defined(Q_WS_MAC) | ||
1890 | QString topLevelDomain = domain.right( domain.length() - lastDot - 1 ) + "."; | ||
1891 | if ( topLevelDomain.isEmpty() ) | ||
1892 | topLevelDomain = "com."; | ||
1893 | actualSearchPath = "/" + topLevelDomain + domain.left( lastDot ) + product; | ||
1894 | insertSearchPath( Mac, actualSearchPath ); | ||
1895 | #else | ||
1896 | actualSearchPath = "/" + domain.mid( 0, lastDot ) + "/" + product; | ||
1897 | insertSearchPath( Unix, actualSearchPath ); | ||
1898 | #endif | ||
1899 | |||
1900 | d->globalScope = scope == Global; | ||
1901 | } | ||
1902 | |||
1903 | /*! | ||
1904 | Appends \a group to the current key prefix. | ||
1905 | */ | ||
1906 | void QSettings::beginGroup( const QString &group ) | ||
1907 | { | ||
1908 | d->groupStack.push( group ); | ||
1909 | d->groupDirty = TRUE; | ||
1910 | } | ||
1911 | |||
1912 | /*! | ||
1913 | Undo previous calls to beginGroup(). Note that a single beginGroup("a/b/c") is undone | ||
1914 | by a single call to endGroup(). | ||
1915 | */ | ||
1916 | void QSettings::endGroup() | ||
1917 | { | ||
1918 | d->groupStack.pop(); | ||
1919 | d->groupDirty = TRUE; | ||
1920 | } | ||
1921 | |||
1922 | /*! | ||
1923 | Set the current key prefix to the empty string. | ||
1924 | */ | ||
1925 | void QSettings::resetGroup() | ||
1926 | { | ||
1927 | d->groupStack.clear(); | ||
1928 | d->groupDirty = FALSE; | ||
1929 | d->groupPrefix = QString::null; | ||
1930 | } | ||
1931 | |||
1932 | /*! | ||
1933 | Returns the current key prefix, or a null string if there is no key prefix set. | ||
1934 | |||
1935 | \sa beginGroup(); | ||
1936 | */ | ||
1937 | QString QSettings::group() const | ||
1938 | { | ||
1939 | if ( d->groupDirty ) { | ||
1940 | d->groupDirty = FALSE; | ||
1941 | d->groupPrefix = QString::null; | ||
1942 | |||
1943 | QValueStack<QString>::Iterator it = d->groupStack.begin(); | ||
1944 | while ( it != d->groupStack.end() ) { | ||
1945 | QString group = *it; | ||
1946 | ++it; | ||
1947 | if ( group[0] != '/' ) | ||
1948 | group = "/" + group; | ||
1949 | d->groupPrefix += group; | ||
1950 | } | ||
1951 | } | ||
1952 | return d->groupPrefix; | ||
1953 | } | ||
1954 | |||
1955 | #endif | ||