summaryrefslogtreecommitdiff
path: root/qmake/tools/qsettings.cpp
Unidiff
Diffstat (limited to 'qmake/tools/qsettings.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--qmake/tools/qsettings.cpp1955
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
41static 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)
218typedef 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 */
232static 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*/
267static 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
288static 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
311void 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
326QSettingsGroup::QSettingsGroup()
327 : modified(FALSE)
328{
329}
330
331
332
333
334void 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
364void 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
455QSettingsPrivate::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
517QSettingsPrivate::~QSettingsPrivate()
518{
519}
520
521QSettingsGroup 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
554void 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
606void 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
644QDateTime 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
661static 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
668static 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*/
758void 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*/
799void 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*/
835QSettings::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*/
852QSettings::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*/
871QSettings::~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*/
888bool 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*/
1009bool 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*/
1061double 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*/
1107int 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*/
1153QString 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*/
1229bool 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*/
1261bool 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*/
1292bool 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*/
1328bool 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*/
1355bool 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*/
1416bool 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*/
1495QStringList 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*/
1592QStringList 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*/
1671QDateTime 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*/
1727bool 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*/
1746bool 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*/
1788QStringList 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*/
1820QStringList 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
1865void 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*/
1906void 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*/
1916void 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*/
1925void 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*/
1937QString 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