source: vendor/trolltech/current/src/tools/qsettings.cpp

Last change on this file was 2, checked in by dmik, 20 years ago

Imported xplatform parts of the official release 3.3.1 from Trolltech

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