summaryrefslogtreecommitdiff
path: root/qmake/tools/qsettings.cpp
Side-by-side diff
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 @@
+/****************************************************************************
+** $Id$
+**
+** Implementation of QSettings class
+**
+** Created: 2000.06.26
+**
+** Copyright (C) 2000-2002 Trolltech AS. All rights reserved.
+**
+** This file is part of the tools module of the Qt GUI Toolkit.
+**
+** This file may be distributed under the terms of the Q Public License
+** as defined by Trolltech AS of Norway and appearing in the file
+** LICENSE.QPL included in the packaging of this file.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
+** licenses may use this file in accordance with the Qt Commercial License
+** Agreement provided with the Software.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
+** information about Qt Commercial License Agreements.
+** See http://www.trolltech.com/qpl/ for QPL licensing information.
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+#include "qplatformdefs.h"
+
+// POSIX Large File Support redefines open -> open64
+static inline int qt_open( const char *pathname, int flags, mode_t mode )
+{ return ::open( pathname, flags, mode ); }
+#if defined(open)
+# undef open
+#endif
+
+// POSIX Large File Support redefines truncate -> truncate64
+#if defined(truncate)
+# undef truncate
+#endif
+
+#include "qsettings.h"
+
+#ifndef QT_NO_SETTINGS
+
+#include "qdir.h"
+#include "qfile.h"
+#include "qfileinfo.h"
+#include "qmap.h"
+#include "qtextstream.h"
+#include "qregexp.h"
+#include <private/qsettings_p.h>
+#include <errno.h>
+
+/*!
+ \class QSettings
+ \brief The QSettings class provides persistent platform-independent application settings.
+
+ \ingroup io
+ \ingroup misc
+ \mainclass
+
+ On Unix systems, QSettings uses text files to store settings. On Windows
+ systems, QSettings uses the system registry. On Mac OS X, QSettings will
+ behave as on Unix, and store to text files.
+
+ Each setting comprises an identifying key and the data associated with
+ the key. A key is a unicode string which consists of \e two or more
+ subkeys. A subkey is a slash, '/', followed by one or more unicode
+ characters (excluding slashes, newlines, carriage returns and equals,
+ '=', signs). The associated data, called the entry or value, may be a
+ boolean, an integer, a double, a string or a list of strings. Entry
+ strings may contain any unicode characters.
+
+ If you want to save and restore the entire desktop's settings, i.e.
+ which applications are running, use QSettings to save the settings
+ for each individual application and QSessionManager to save the
+ desktop's session.
+
+ Example settings:
+ \code
+ /MyCompany/MyApplication/background color
+ /MyCompany/MyApplication/foreground color
+ /MyCompany/MyApplication/geometry/x
+ /MyCompany/MyApplication/geometry/y
+ /MyCompany/MyApplication/geometry/width
+ /MyCompany/MyApplication/geometry/height
+ /MyCompany/MyApplication/recent files/1
+ /MyCompany/MyApplication/recent files/2
+ /MyCompany/MyApplication/recent files/3
+ \endcode
+ Each line above is a complete key, made up of subkeys.
+
+ A typical usage pattern for application startup:
+ \code
+ QSettings settings;
+ settings.insertSearchPath( QSettings::Windows, "/MyCompany" );
+ // No search path needed for Unix; see notes further on.
+ // Use default values if the keys don't exist
+ QString bgColor = settings.readEntry( "/MyApplication/background color", "white" );
+ int width = settings.readNumEntry( "/MyApplication/geometry/width", 640 );
+ // ...
+ \endcode
+
+ A typical usage pattern for application exit or 'save preferences':
+ \code
+ QSettings settings;
+ settings.insertSearchPath( QSettings::Windows, "/MyCompany" );
+ // No search path needed for Unix; see notes further on.
+ settings.writeEntry( "/MyApplication/background color", bgColor );
+ settings.writeEntry( "/MyApplication/geometry/width", width );
+ // ...
+ \endcode
+
+ You can get a list of entry-holding keys by calling entryList(), and
+ a list of key-holding keys using subkeyList().
+
+ \code
+ QStringList keys = entryList( "/MyApplication" );
+ // keys contains 'background color' and 'foreground color'.
+
+ QStringList keys = entryList( "/MyApplication/recent files" );
+ // keys contains '1', '2' and '3'.
+
+ QStringList subkeys = subkeyList( "/MyApplication" );
+ // subkeys contains 'geometry' and 'recent files'
+
+ QStringList subkeys = subkeyList( "/MyApplication/recent files" );
+ // subkeys is empty.
+ \endcode
+
+ If you wish to use a different search path call insertSearchPath()
+ as often as necessary to add your preferred paths. Call
+ removeSearchPath() to remove any unwanted paths.
+
+ Since settings for Windows are stored in the registry there are size
+ limits as follows:
+ \list
+ \i A subkey may not exceed 255 characters.
+ \i An entry's value may not exceed 16,300 characters.
+ \i All the values of a key (for example, all the 'recent files'
+ subkeys values), may not exceed 65,535 characters.
+ \endlist
+
+ These limitations are not enforced on Unix.
+
+ \section1 Notes for Unix Applications
+
+ There is no universally accepted place for storing application
+ settings under Unix. In the examples the settings file will be
+ searched for in the following directories:
+ \list 1
+ \i INSTALL/etc/settings
+ \i /opt/MyCompany/share/etc
+ \i /opt/MyCompany/share/MyApplication/etc
+ \i $HOME/.qt
+ \endlist
+ When reading settings the files are searched in the order shown
+ above, with later settings overriding earlier settings. Files for
+ which the user doesn't have read permission are ignored. When saving
+ settings QSettings works in the order shown above, writing
+ to the first settings file for which the user has write permission.
+ (\c INSTALL is the directory where Qt was installed. This can be
+ modified by using the configure script's -prefix argument )
+
+ If you want to put the settings in a particular place in the
+ filesystem you could do this:
+ \code
+ settings.insertSearchPath( QSettings::Unix, "/opt/MyCompany/share" );
+ \endcode
+
+ But in practice you may prefer not to use a search path for Unix.
+ For example the following code:
+ \code
+ settings.writeEntry( "/MyApplication/geometry/width", width );
+ \endcode
+ will end up writing the "geometry/width" setting to the file
+ \c{$HOME/.qt/myapplicationrc} (assuming that the application is
+ being run by an ordinary user, i.e. not by root).
+
+ For cross-platform applications you should ensure that the Windows
+ size limitations are not exceeded.
+*/
+
+/*!
+ \enum QSettings::System
+
+ \value Mac Macintosh execution environments
+ \value Unix Mac OS X, Unix, Linux and Unix-like execution environments
+ \value Windows Windows execution environments
+*/
+
+/*!
+ \enum QSettings::Format
+
+ \value Native Store the settings in a platform dependent location
+ \value Ini Store the settings in a text file
+*/
+
+/*!
+ \enum QSettings::Scope
+
+ \value Global Save settings as global as possible
+ \value User Save settings in user space
+*/
+
+#if defined(Q_OS_UNIX)
+typedef int HANDLE;
+#define Q_LOCKREAD F_RDLCK
+#define Q_LOCKWRITE F_WRLCK
+/*
+ Locks the file specified by name. The lockfile is created as a
+ hidden file in the same directory as the target file, with .lock
+ appended to the name. For example, "/etc/settings/onerc" uses a
+ lockfile named "/etc/settings/.onerc.lock". The type argument
+ controls the type of the lock, it can be either F_RDLCK for a read
+ lock, or F_WRLCK for a write lock.
+
+ A file descriptor for the lock file is returned, and should be
+ closed with closelock() when the lock is no longer needed.
+ */
+static HANDLE openlock( const QString &name, int type )
+{
+ QFileInfo info( name );
+ // lockfile should be hidden, and never removed
+ QString lockfile = info.dirPath() + "/." + info.fileName() + ".lock";
+
+ // open the lockfile
+ HANDLE fd = qt_open( QFile::encodeName( lockfile ),
+ O_RDWR | O_CREAT, S_IRUSR | S_IWUSR );
+
+ if ( fd < 0 ) {
+ // failed to open the lock file, most likely because of permissions
+ return fd;
+ }
+
+ struct flock fl;
+ fl.l_type = type;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = 0;
+ fl.l_len = 0;
+ if ( fcntl( fd, F_SETLKW, &fl ) == -1 ) {
+ // the lock failed, so we should fail silently, so that people
+ // using filesystems that do not support locking don't see
+ // numerous warnings about a failed lock
+ close( fd );
+ fd = -1;
+ }
+
+ return fd;
+}
+
+/*
+ Closes the lock file specified by fd. fd is the file descriptor
+ returned by the openlock() function.
+*/
+static void closelock( HANDLE fd )
+{
+ if ( fd < 0 ) {
+ // the lock file is not open
+ return;
+ }
+
+ struct flock fl;
+ fl.l_type = F_UNLCK;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = 0;
+ fl.l_len = 0;
+ // ignore the return value, so that the unlock fails silently
+ (void) fcntl( fd, F_SETLKW, &fl );
+
+ close( fd );
+}
+#elif defined(Q_WS_WIN)
+#define Q_LOCKREAD 1
+#define Q_LOCKWRITE 2
+
+static HANDLE openlock( const QString &name, int /*type*/ )
+{
+ if ( !QFile::exists( name ) )
+ return 0;
+
+ return 0;
+
+ HANDLE fd = 0;
+
+ QT_WA( {
+ fd = CreateFileW( (TCHAR*)name.ucs2(), GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
+ } , {
+ fd = CreateFileA( name.local8Bit(), GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
+ } );
+
+ if ( !LockFile( fd, 0, 0, -1, -1 ) ) {
+#ifdef QT_CHECK_STATE
+ qWarning( "QSettings: openlock failed!" );
+#endif
+ }
+ return fd;
+}
+
+void closelock( HANDLE fd )
+{
+ if ( !fd )
+ return;
+
+ if ( !UnlockFile( fd, 0, 0, -1, -1 ) ) {
+#ifdef QT_CHECK_STATE
+ qWarning( "QSettings: closelock failed!");
+#endif
+ }
+ CloseHandle( fd );
+}
+#endif
+
+
+QSettingsGroup::QSettingsGroup()
+ : modified(FALSE)
+{
+}
+
+
+
+
+void QSettingsHeading::read(const QString &filename)
+{
+ if (! QFileInfo(filename).exists())
+ return;
+
+ HANDLE lockfd = openlock( filename, Q_LOCKREAD );
+
+ QFile file(filename);
+ if (! file.open(IO_ReadOnly)) {
+#if defined(QT_CHECK_STATE)
+ qWarning("QSettings: failed to open file '%s'", filename.latin1());
+#endif
+ return;
+ }
+
+ git = end();
+
+ QTextStream stream(&file);
+ stream.setEncoding(QTextStream::UnicodeUTF8);
+ while (! stream.atEnd())
+ parseLine(stream);
+
+ git = end();
+
+ file.close();
+
+ closelock( lockfd );
+}
+
+
+void QSettingsHeading::parseLine(QTextStream &stream)
+{
+ QString line = stream.readLine();
+ if (line.isEmpty())
+ // empty line... we'll allow it
+ return;
+
+ if (line[0] == QChar('#'))
+ // commented line
+ return;
+
+ if (line[0] == QChar('[')) {
+ QString gname = line;
+
+ gname = gname.remove(0, 1);
+ if (gname[(int)gname.length() - 1] == QChar(']'))
+ gname = gname.remove(gname.length() - 1, 1);
+
+ git = find(gname);
+ if (git == end())
+ git = replace(gname, QSettingsGroup());
+ } else {
+ if (git == end()) {
+#if defined(QT_CHECK_STATE)
+ qWarning("QSettings: line '%s' out of group", line.latin1());
+#endif
+ return;
+ }
+
+ int i = line.find('=');
+ if (i == -1) {
+#if defined(QT_CHECK_STATE)
+ qWarning("QSettings: malformed line '%s' in group '%s'",
+ line.latin1(), git.key().latin1());
+#endif
+ return;
+ } else {
+ QString key, value;
+ key = line.left(i);
+ value = "";
+ bool esc=TRUE;
+ i++;
+ while (esc) {
+ esc = FALSE;
+ for ( ; i < (int)line.length(); i++ ) {
+ if ( esc ) {
+ if ( line[i] == 'n' )
+ value.append('\n'); // escaped newline
+ else if ( line[i] == '0' )
+ value = QString::null; // escaped empty string
+ else
+ value.append(line[i]);
+ esc = FALSE;
+ } else if ( line[i] == '\\' )
+ esc = TRUE;
+ else
+ value.append(line[i]);
+ }
+ if ( esc ) {
+ // Backwards-compatiblity...
+ // still escaped at EOL - manually escaped "newline"
+ if (stream.atEnd()) {
+#if defined(QT_CHECK_STATE)
+ qWarning("QSettings: reached end of file, expected continued line");
+#endif
+ break;
+ }
+ value.append('\n');
+ line = stream.readLine();
+ i = 0;
+ }
+ }
+
+ (*git).insert(key, value);
+ }
+ }
+}
+
+#ifdef Q_WS_WIN // for homedirpath reading from registry
+#include "qt_windows.h"
+#include "qlibrary.h"
+
+#ifndef CSIDL_APPDATA
+#define CSIDL_APPDATA 0x001a // <user name>\Application Data
+#endif
+#ifndef CSIDL_COMMON_APPDATA
+#define CSIDL_COMMON_APPDATA 0x0023 // All Users\Application Data
+#endif
+
+#endif
+
+QSettingsPrivate::QSettingsPrivate( QSettings::Format format )
+ : groupDirty( TRUE ), modified(FALSE), globalScope(TRUE)
+{
+#if defined(Q_WS_WIN) || defined(Q_OS_MAC)
+ if ( format != QSettings::Ini )
+ return;
+#endif
+
+ QString appSettings(QDir::homeDirPath() + "/.qt/");
+ QString defPath;
+#ifdef Q_WS_WIN
+#ifdef Q_OS_TEMP
+ TCHAR path[MAX_PATH];
+ SHGetSpecialFolderPath( 0, path, CSIDL_APPDATA, FALSE );
+ appSettings = QString::fromUcs2( path );
+ SHGetSpecialFolderPath( 0, path, CSIDL_COMMON_APPDATA, FALSE );
+ defPath = QString::fromUcs2( path );
+#else
+ QLibrary library( "shell32" );
+ library.setAutoUnload( FALSE );
+ QT_WA( {
+ typedef BOOL (WINAPI*GetSpecialFolderPath)(HWND, LPTSTR, int, BOOL);
+ GetSpecialFolderPath SHGetSpecialFolderPath = (GetSpecialFolderPath)library.resolve( "SHGetSpecialFolderPathW" );
+ if ( SHGetSpecialFolderPath ) {
+ TCHAR path[MAX_PATH];
+ SHGetSpecialFolderPath( 0, path, CSIDL_APPDATA, FALSE );
+ appSettings = QString::fromUcs2( (ushort*)path );
+ SHGetSpecialFolderPath( 0, path, CSIDL_COMMON_APPDATA, FALSE );
+ defPath = QString::fromUcs2( (ushort*)path );
+ }
+ } , {
+ typedef BOOL (WINAPI*GetSpecialFolderPath)(HWND, char*, int, BOOL);
+ GetSpecialFolderPath SHGetSpecialFolderPath = (GetSpecialFolderPath)library.resolve( "SHGetSpecialFolderPathA" );
+ if ( SHGetSpecialFolderPath ) {
+ char path[MAX_PATH];
+ SHGetSpecialFolderPath( 0, path, CSIDL_APPDATA, FALSE );
+ appSettings = QString::fromLocal8Bit( path );
+ SHGetSpecialFolderPath( 0, path, CSIDL_COMMON_APPDATA, FALSE );
+ defPath = QString::fromLocal8Bit( path );
+ }
+ } );
+#endif // Q_OS_TEMP
+#else
+// for now
+#define QSETTINGS_DEFAULT_PATH_SUFFIX "/etc/settings"
+
+ defPath = qInstallPath();
+ defPath += QSETTINGS_DEFAULT_PATH_SUFFIX;
+#endif
+ QDir dir(appSettings);
+ if (! dir.exists()) {
+ if (! dir.mkdir(dir.path()))
+#if defined(QT_CHECK_STATE)
+ qWarning("QSettings: error creating %s", dir.path().latin1());
+#endif
+ }
+
+ if ( !!defPath )
+ searchPaths.append(defPath);
+ searchPaths.append(dir.path());
+}
+
+QSettingsPrivate::~QSettingsPrivate()
+{
+}
+
+QSettingsGroup QSettingsPrivate::readGroup()
+{
+ QSettingsHeading hd;
+ QSettingsGroup grp;
+
+ QMap<QString,QSettingsHeading>::Iterator headingsit = headings.find(heading);
+ if (headingsit != headings.end())
+ hd = *headingsit;
+
+ QSettingsHeading::Iterator grpit = hd.find(group);
+ if (grpit == hd.end()) {
+ QStringList::Iterator it = searchPaths.begin();
+ while (it != searchPaths.end()) {
+ QString filebase = heading.lower().replace(QRegExp("\\s+"), "_");
+ QString fn((*it++) + "/" + filebase + "rc");
+ if (! hd.contains(fn + "cached")) {
+ hd.read(fn);
+ hd.insert(fn + "cached", QSettingsGroup());
+ }
+ }
+
+ headings.replace(heading, hd);
+
+ grpit = hd.find(group);
+ if (grpit != hd.end())
+ grp = *grpit;
+ } else if (hd.count() != 0)
+ grp = *grpit;
+
+ return grp;
+}
+
+
+void QSettingsPrivate::removeGroup(const QString &key)
+{
+ QSettingsHeading hd;
+ QSettingsGroup grp;
+ bool found = FALSE;
+
+ QMap<QString,QSettingsHeading>::Iterator headingsit = headings.find(heading);
+ if (headingsit != headings.end())
+ hd = *headingsit;
+
+ QSettingsHeading::Iterator grpit = hd.find(group);
+ if (grpit == hd.end()) {
+ QStringList::Iterator it = searchPaths.begin();
+ while (it != searchPaths.end()) {
+ QString filebase = heading.lower().replace(QRegExp("\\s+"), "_");
+ QString fn((*it++) + "/" + filebase + "rc");
+ if (! hd.contains(fn + "cached")) {
+ hd.read(fn);
+ hd.insert(fn + "cached", QSettingsGroup());
+ }
+ }
+
+ headings.replace(heading, hd);
+
+ grpit = hd.find(group);
+ if (grpit != hd.end()) {
+ found = TRUE;
+ grp = *grpit;
+ }
+ } else if (hd.count() != 0) {
+ found = TRUE;
+ grp = *grpit;
+ }
+
+ if (found) {
+ grp.remove(key);
+
+ if (grp.count() > 0)
+ hd.replace(group, grp);
+ else
+ hd.remove(group);
+
+ if (hd.count() > 0)
+ headings.replace(heading, hd);
+ else
+ headings.remove(heading);
+
+ modified = TRUE;
+ }
+}
+
+
+void QSettingsPrivate::writeGroup(const QString &key, const QString &value)
+{
+ QSettingsHeading hd;
+ QSettingsGroup grp;
+
+ QMap<QString,QSettingsHeading>::Iterator headingsit = headings.find(heading);
+ if (headingsit != headings.end())
+ hd = *headingsit;
+
+ QSettingsHeading::Iterator grpit = hd.find(group);
+ if (grpit == hd.end()) {
+ QStringList::Iterator it = searchPaths.begin();
+ while (it != searchPaths.end()) {
+ QString filebase = heading.lower().replace(QRegExp("\\s+"), "_");
+ QString fn((*it++) + "/" + filebase + "rc");
+ if (! hd.contains(fn + "cached")) {
+ hd.read(fn);
+ hd.insert(fn + "cached", QSettingsGroup());
+ }
+ }
+
+ headings.replace(heading, hd);
+
+ grpit = hd.find(group);
+ if (grpit != hd.end())
+ grp = *grpit;
+ } else if (hd.count() != 0)
+ grp = *grpit;
+
+ grp.modified = TRUE;
+ grp.replace(key, value);
+ hd.replace(group, grp);
+ headings.replace(heading, hd);
+
+ modified = TRUE;
+}
+
+
+QDateTime QSettingsPrivate::modificationTime()
+{
+ QSettingsHeading hd = headings[heading];
+ QSettingsGroup grp = hd[group];
+
+ QDateTime datetime;
+
+ QStringList::Iterator it = searchPaths.begin();
+ while (it != searchPaths.end()) {
+ QFileInfo fi((*it++) + "/" + heading + "rc");
+ if (fi.exists() && fi.lastModified() > datetime)
+ datetime = fi.lastModified();
+ }
+
+ return datetime;
+}
+
+static bool verifyKey( const QString &key )
+{
+ if ( key.isEmpty() || key[0] != '/' || key.contains( QRegExp("[=\\\\r\\\\n" ) ) )
+ return FALSE;
+ return TRUE;
+}
+
+static inline QString groupKey( const QString &group, const QString &key )
+{
+ if ( group.endsWith( "/" ) || key.startsWith( "/" ) )
+ return group + key;
+ return group + "/" + key;
+}
+
+/*!
+ Inserts \a path into the settings search path. The semantics of \a
+ path depends on the system \a s.
+
+ When \a s is \e Windows and the execution environment is \e not
+ Windows the function does nothing. Similarly when \a s is \e Unix and
+ the execution environment is \e not Unix the function does nothing.
+
+ When \a s is \e Windows, and the execution environment is Windows, the
+ search path list will be used as the first subfolder of the "Software"
+ folder in the registry.
+
+ When reading settings the folders are searched forwards from the
+ first folder (listed below) to the last, returning the first
+ settings found, and ignoring any folders for which the user doesn't
+ have read permission.
+ \list 1
+ \i HKEY_CURRENT_USER/Software/MyCompany/MyApplication
+ \i HKEY_LOCAL_MACHINE/Software/MyCompany/MyApplication
+ \i HKEY_CURRENT_USER/Software/MyApplication
+ \i HKEY_LOCAL_MACHINE/Software/MyApplication
+ \endlist
+
+ \code
+ QSettings settings;
+ settings.insertSearchPath( QSettings::Windows, "/MyCompany" );
+ settings.writeEntry( "/MyApplication/Tip of the day", TRUE );
+ \endcode
+ The code above will write the subkey "Tip of the day" into the \e
+ first of the registry folders listed below that is found and for
+ which the user has write permission.
+ \list 1
+ \i HKEY_LOCAL_MACHINE/Software/MyCompany/MyApplication
+ \i HKEY_CURRENT_USER/Software/MyCompany/MyApplication
+ \i HKEY_LOCAL_MACHINE/Software/MyApplication
+ \i HKEY_CURRENT_USER/Software/MyApplication
+ \endlist
+ If a setting is found in the HKEY_CURRENT_USER space, this setting
+ is overwritten independently of write permissions in the
+ HKEY_LOCAL_MACHINE space.
+
+ When \a s is \e Unix, and the execution environment is Unix, the
+ search path list will be used when trying to determine a suitable
+ filename for reading and writing settings files. By default, there are
+ two entries in the search path:
+
+ \list 1
+ \i INSTALL/etc - where \c INSTALL is the directory where Qt was installed.
+ \i $HOME/.qt/ - where \c $HOME is the user's home directory.
+ \endlist
+
+ All insertions into the search path will go before $HOME/.qt/.
+ For example:
+ \code
+ QSettings settings;
+ settings.insertSearchPath( QSettings::Unix, "/opt/MyCompany/share/etc" );
+ settings.insertSearchPath( QSettings::Unix, "/opt/MyCompany/share/MyApplication/etc" );
+ // ...
+ \endcode
+ Will result in a search path of:
+ \list 1
+ \i INSTALL/etc
+ \i /opt/MyCompany/share/etc
+ \i /opt/MyCompany/share/MyApplication/etc
+ \i $HOME/.qt
+ \endlist
+ When reading settings the files are searched in the order shown
+ above, with later settings overriding earlier settings. Files for
+ which the user doesn't have read permission are ignored. When saving
+ settings QSettings works in the order shown above, writing
+ to the first settings file for which the user has write permission.
+
+ Settings under Unix are stored in files whose names are based on the
+ first subkey of the key (not including the search path). The algorithm
+ for creating names is essentially: lowercase the first subkey, replace
+ spaces with underscores and add 'rc', e.g.
+ <tt>/MyCompany/MyApplication/background color</tt> will be stored in
+ <tt>myapplicationrc</tt> (assuming that <tt>/MyCompany</tt> is part of
+ the search path).
+
+ \sa removeSearchPath()
+
+*/
+void QSettings::insertSearchPath( System s, const QString &path)
+{
+#if defined(Q_WS_WIN) || defined(Q_OS_MAC)
+ if ( d->sysd ) {
+ d->sysInsertSearchPath( s, path );
+ return;
+ }
+#endif
+
+ if ( !verifyKey( path ) ) {
+#if defined(QT_CHECK_STATE)
+ qWarning( "QSettings::insertSearchPath: Invalid key: '%s'", path.isNull() ? "(null)" : path.latin1() );
+#endif
+ return;
+ }
+
+#if defined(Q_WS_WIN) || defined(Q_OS_MAC)
+ if ( d->sysd && s != Unix ) {
+#else
+ if ( s != Unix ) {
+#endif
+#ifdef Q_OS_MAC
+ if(s != Mac) //mac is respected on the mac as well
+#endif
+ return;
+ }
+
+ QStringList::Iterator it = d->searchPaths.find(d->searchPaths.last());
+ if (it != d->searchPaths.end()) {
+ d->searchPaths.insert(it, path);
+ }
+}
+
+
+/*!
+ Removes all occurrences of \a path (using exact matching) from the
+ settings search path for system \a s. Note that the default search
+ paths cannot be removed.
+
+ \sa insertSearchPath()
+*/
+void QSettings::removeSearchPath( System s, const QString &path)
+{
+ if ( !verifyKey( path ) ) {
+#if defined(QT_CHECK_STATE)
+ qWarning( "QSettings::insertSearchPath: Invalid key: '%s'", path.isNull() ? "(null)" : path.latin1() );
+#endif
+ return;
+ }
+
+#ifdef Q_WS_WIN
+ if ( d->sysd ) {
+ d->sysRemoveSearchPath( s, path );
+ return;
+ }
+#endif
+#if defined(Q_WS_WIN) || defined(Q_OS_MAC)
+ if ( d->sysd && s != Unix ) {
+#else
+ if ( s != Unix ) {
+#endif
+#ifdef Q_OS_MAC
+ if(s != Mac) //mac is respected on the mac as well
+#endif
+ return;
+ }
+
+ if (path == d->searchPaths.first() || path == d->searchPaths.last())
+ return;
+
+ d->searchPaths.remove(path);
+}
+
+
+/*!
+ Creates a settings object.
+*/
+QSettings::QSettings()
+{
+ d = new QSettingsPrivate( Native );
+ Q_CHECK_PTR(d);
+
+#if defined(Q_WS_WIN) || defined(Q_OS_MAC)
+ d->sysd = 0;
+ d->sysInit();
+#endif
+}
+
+/*!
+ Creates a settings object. If \a format is 'Ini' the settings will
+ be stored in a text file, using the Unix strategy (see above). If \a format
+ is 'Native', the settings will be stored in a platform specific way
+ (ie. the Windows registry).
+*/
+QSettings::QSettings( Format format )
+{
+ d = new QSettingsPrivate( format );
+ Q_CHECK_PTR(d);
+
+#if defined(Q_WS_WIN) || defined(Q_OS_MAC)
+ d->sysd = 0;
+ if ( format == Native )
+ d->sysInit();
+#else
+ Q_UNUSED(format);
+#endif
+}
+
+/*!
+ Destroys the settings object. All modifications made to the settings
+ will automatically be saved.
+
+*/
+QSettings::~QSettings()
+{
+ sync();
+
+#if defined(Q_WS_WIN) || defined(Q_OS_MAC)
+ if ( d->sysd )
+ d->sysClear();
+#endif
+
+ delete d;
+}
+
+
+/*! \internal
+ Writes all modifications to the settings to disk. If any errors are
+ encountered, this function returns FALSE, otherwise it will return TRUE.
+*/
+bool QSettings::sync()
+{
+#if defined(Q_WS_WIN) || defined(Q_OS_MAC)
+ if ( d->sysd )
+ return d->sysSync();
+#endif
+ if (! d->modified)
+ // fake success
+ return TRUE;
+
+ bool success = TRUE;
+ QMap<QString,QSettingsHeading>::Iterator it = d->headings.begin();
+
+ while (it != d->headings.end()) {
+ // determine filename
+ QSettingsHeading hd(*it);
+ QSettingsHeading::Iterator hdit = hd.begin();
+ QFile file;
+
+ QStringList::Iterator pit = d->searchPaths.begin();
+ while (pit != d->searchPaths.end()) {
+ QString filebase = it.key().lower().replace(QRegExp("\\s+"), "_");
+ QFileInfo di(*pit);
+ QFileInfo fi((*pit++) + "/" + filebase + "rc");
+
+ if ((fi.exists() && fi.isFile() && fi.isWritable()) ||
+ (! fi.exists() && di.isDir() && di.isWritable())) {
+ file.setName(fi.filePath());
+ break;
+ }
+ }
+
+ it++;
+
+ if (file.name().isNull() || file.name().isEmpty()) {
+
+#ifdef QT_CHECK_STATE
+ qWarning("QSettings::sync: filename is null/empty");
+#endif // QT_CHECK_STATE
+
+ success = FALSE;
+ continue;
+ }
+
+ HANDLE lockfd = openlock( file.name(), Q_LOCKWRITE );
+
+ if (! file.open(IO_WriteOnly)) {
+
+#ifdef QT_CHECK_STATE
+ qWarning("QSettings::sync: failed to open '%s' for writing",
+ file.name().latin1());
+#endif // QT_CHECK_STATE
+
+ success = FALSE;
+ continue;
+ }
+
+ // spew to file
+ QTextStream stream(&file);
+ stream.setEncoding(QTextStream::UnicodeUTF8);
+
+ while (hdit != hd.end()) {
+ if ((*hdit).count() > 0) {
+ stream << "[" << hdit.key() << "]" << endl;
+
+ QSettingsGroup grp(*hdit);
+ QSettingsGroup::Iterator grpit = grp.begin();
+
+ while (grpit != grp.end()) {
+ QString v = grpit.data();
+ if ( v.isNull() ) {
+ v = "\\0"; // escape null string
+ } else {
+ v.replace("\\", "\\\\"); // escape backslash
+ v.replace("\n", "\\n"); // escape newlines
+ }
+
+ stream << grpit.key() << "=" << v << endl;
+ grpit++;
+ }
+
+ stream << endl;
+ }
+
+ hdit++;
+ }
+
+ if (file.status() != IO_Ok) {
+
+#ifdef QT_CHECK_STATE
+ qWarning("QSettings::sync: error at end of write");
+#endif // QT_CHECK_STATE
+
+ success = FALSE;
+ }
+
+ file.close();
+
+ closelock( lockfd );
+ }
+
+ d->modified = FALSE;
+
+ return success;
+}
+
+
+/*!
+ \fn bool QSettings::readBoolEntry(const QString &key, bool def, bool *ok ) const
+
+ Reads the entry specified by \a key, and returns a bool, or the
+ default value, \a def, if the entry couldn't be read.
+ If \a ok is non-null, *ok is set to TRUE if the key was read, FALSE
+ otherwise.
+
+ \sa readEntry(), readNumEntry(), readDoubleEntry(), writeEntry(), removeEntry()
+*/
+
+/*!
+ \internal
+*/
+bool QSettings::readBoolEntry(const QString &key, bool def, bool *ok )
+{
+ if ( !verifyKey( key ) ) {
+#if defined(QT_CHECK_STATE)
+ qWarning( "QSettings::readBoolEntry: Invalid key: '%s'", key.isNull() ? "(null)" : key.latin1() );
+#endif
+ if ( ok )
+ *ok = FALSE;
+
+ return def;
+ }
+
+ QString theKey = groupKey( group(), key );
+#if defined(Q_WS_WIN) || defined(Q_OS_MAC)
+ if ( d->sysd )
+ return d->sysReadBoolEntry( theKey, def, ok );
+#endif
+
+ QString value = readEntry( theKey, ( def ? "true" : "false" ), ok );
+
+ if (value.lower() == "true")
+ return TRUE;
+ else if (value.lower() == "false")
+ return FALSE;
+ else if (value == "1")
+ return TRUE;
+ else if (value == "0")
+ return FALSE;
+
+ if (! value.isEmpty())
+ qWarning("QSettings::readBoolEntry: '%s' is not 'true' or 'false'",
+ value.latin1());
+ if ( ok )
+ *ok = FALSE;
+ return def;
+}
+
+
+/*!
+ \fn double QSettings::readDoubleEntry(const QString &key, double def, bool *ok ) const
+
+ Reads the entry specified by \a key, and returns a double, or the
+ default value, \a def, if the entry couldn't be read.
+ If \a ok is non-null, *ok is set to TRUE if the key was read, FALSE
+ otherwise.
+
+ \sa readEntry(), readNumEntry(), readBoolEntry(), writeEntry(), removeEntry()
+*/
+
+/*!
+ \internal
+*/
+double QSettings::readDoubleEntry(const QString &key, double def, bool *ok )
+{
+ if ( !verifyKey( key ) ) {
+#if defined(QT_CHECK_STATE)
+ qWarning( "QSettings::readDoubleEntry: Invalid key: '%s'", key.isNull() ? "(null)" : key.latin1() );
+#endif
+ if ( ok )
+ *ok = FALSE;
+
+ return def;
+ }
+
+ QString theKey = groupKey( group(), key );
+#if defined(Q_WS_WIN) || defined(Q_OS_MAC)
+ if ( d->sysd )
+ return d->sysReadDoubleEntry( theKey, def, ok );
+#endif
+
+ QString value = readEntry( theKey, QString::number(def), ok );
+ bool conv_ok;
+ double retval = value.toDouble( &conv_ok );
+ if ( conv_ok )
+ return retval;
+ if ( ! value.isEmpty() )
+ qWarning( "QSettings::readDoubleEntry: '%s' is not a number",
+ value.latin1() );
+ if ( ok )
+ *ok = FALSE;
+ return def;
+}
+
+
+/*!
+ \fn int QSettings::readNumEntry(const QString &key, int def, bool *ok ) const
+
+ Reads the entry specified by \a key, and returns an integer, or the
+ default value, \a def, if the entry couldn't be read.
+ If \a ok is non-null, *ok is set to TRUE if the key was read, FALSE
+ otherwise.
+
+ \sa readEntry(), readDoubleEntry(), readBoolEntry(), writeEntry(), removeEntry()
+*/
+
+/*!
+ \internal
+*/
+int QSettings::readNumEntry(const QString &key, int def, bool *ok )
+{
+ if ( !verifyKey( key ) ) {
+#if defined(QT_CHECK_STATE)
+ qWarning( "QSettings::readNumEntry: Invalid key: '%s'", key.isNull() ? "(null)" : key.latin1() );
+#endif
+ if ( ok )
+ *ok = FALSE;
+ return def;
+ }
+
+ QString theKey = groupKey( group(), key );
+
+#if defined(Q_WS_WIN) || defined(Q_OS_MAC)
+ if ( d->sysd )
+ return d->sysReadNumEntry( theKey, def, ok );
+#endif
+
+ QString value = readEntry( theKey, QString::number( def ), ok );
+ bool conv_ok;
+ int retval = value.toInt( &conv_ok );
+ if ( conv_ok )
+ return retval;
+ if ( ! value.isEmpty() )
+ qWarning( "QSettings::readNumEntry: '%s' is not a number",
+ value.latin1() );
+ if ( ok )
+ *ok = FALSE;
+ return def;
+}
+
+
+/*!
+ \fn QString QSettings::readEntry(const QString &key, const QString &def, bool *ok ) const
+
+ Reads the entry specified by \a key, and returns a QString, or the
+ default value, \a def, if the entry couldn't be read.
+ If \a ok is non-null, *ok is set to TRUE if the key was read, FALSE
+ otherwise.
+
+ \sa readListEntry(), readNumEntry(), readDoubleEntry(), readBoolEntry(), writeEntry(), removeEntry()
+*/
+
+/*!
+ \internal
+*/
+QString QSettings::readEntry(const QString &key, const QString &def, bool *ok )
+{
+ if ( !verifyKey( key ) ) {
+#if defined(QT_CHECK_STATE)
+ qWarning( "QSettings::readEntry: Invalid key: '%s'", key.isNull() ? "(null)" : key.latin1() );
+#endif
+ if ( ok )
+ *ok = FALSE;
+
+ return def;
+ }
+
+ QString theKey = groupKey( group(), key );
+
+#if defined(Q_WS_WIN) || defined(Q_OS_MAC)
+ if ( d->sysd )
+ return d->sysReadEntry( theKey, def, ok );
+#endif
+
+ if ( ok ) // no, everything is not ok
+ *ok = FALSE;
+
+ QString realkey;
+
+ if (theKey[0] == '/') {
+ // parse our key
+ QStringList list(QStringList::split('/', theKey));
+
+ if (list.count() < 2) {
+#ifdef QT_CHECK_STATE
+ qWarning("QSettings::readEntry: invalid key '%s'", theKey.latin1());
+#endif // QT_CHECK_STATE
+ if ( ok )
+ *ok = FALSE;
+ return def;
+ }
+
+ if (list.count() == 2) {
+ d->heading = list[0];
+ d->group = "General";
+ realkey = list[1];
+ } else {
+ d->heading = list[0];
+ d->group = list[1];
+
+ // remove the group from the list
+ list.remove(list.at(1));
+ // remove the heading from the list
+ list.remove(list.at(0));
+
+ realkey = list.join("/");
+ }
+ } else
+ realkey = theKey;
+
+ QSettingsGroup grp = d->readGroup();
+ QString retval = grp[realkey];
+ if ( retval.isNull() )
+ retval = def;
+ else if ( ok ) // everything is ok
+ *ok = TRUE;
+ return retval;
+}
+
+
+#if !defined(Q_NO_BOOL_TYPE)
+/*!
+ Writes the boolean entry \a value into key \a key. The \a key is
+ created if it doesn't exist. Any previous value is overwritten by \a
+ value.
+
+ If an error occurs the settings are left unchanged and FALSE is
+ returned; otherwise TRUE is returned.
+
+ \sa readListEntry(), readNumEntry(), readDoubleEntry(), readBoolEntry(), removeEntry()
+*/
+bool QSettings::writeEntry(const QString &key, bool value)
+{
+ if ( !verifyKey( key ) ) {
+#if defined(QT_CHECK_STATE)
+ qWarning( "QSettings::writeEntry: Invalid key: '%s'", key.isNull() ? "(null)" : key.latin1() );
+#endif
+ return FALSE;
+ }
+
+ QString theKey = groupKey( group(), key );
+
+#if defined(Q_WS_WIN) || defined(Q_OS_MAC)
+ if ( d->sysd )
+ return d->sysWriteEntry( theKey, value );
+#endif
+ QString s(value ? "true" : "false");
+ return writeEntry(theKey, s);
+}
+#endif
+
+
+/*!
+ \overload
+ Writes the double entry \a value into key \a key. The \a key is
+ created if it doesn't exist. Any previous value is overwritten by \a
+ value.
+
+ If an error occurs the settings are left unchanged and FALSE is
+ returned; otherwise TRUE is returned.
+
+ \sa readListEntry(), readNumEntry(), readDoubleEntry(), readBoolEntry(), removeEntry()
+*/
+bool QSettings::writeEntry(const QString &key, double value)
+{
+ if ( !verifyKey( key ) ) {
+#if defined(QT_CHECK_STATE)
+ qWarning( "QSettings::writeEntry: Invalid key: '%s'", key.isNull() ? "(null)" : key.latin1() );
+#endif
+ return FALSE;
+ }
+
+ QString theKey = groupKey( group(), key );
+
+#if defined(Q_WS_WIN) || defined(Q_OS_MAC)
+ if ( d->sysd )
+ return d->sysWriteEntry( theKey, value );
+#endif
+ QString s(QString::number(value));
+ return writeEntry(theKey, s);
+}
+
+
+/*!
+ \overload
+ Writes the integer entry \a value into key \a key. The \a key is
+ created if it doesn't exist. Any previous value is overwritten by \a
+ value.
+
+ If an error occurs the settings are left unchanged and FALSE is
+ returned; otherwise TRUE is returned.
+
+ \sa readListEntry(), readNumEntry(), readDoubleEntry(), readBoolEntry(), removeEntry()
+*/
+bool QSettings::writeEntry(const QString &key, int value)
+{
+ if ( !verifyKey( key ) ) {
+#if defined(QT_CHECK_STATE)
+ qWarning( "QSettings::writeEntry: Invalid key: '%s'", key.isNull() ? "(null)" : key.latin1() );
+#endif
+ return FALSE;
+ }
+
+ QString theKey = groupKey( group(), key );
+
+#if defined(Q_WS_WIN) || defined(Q_OS_MAC)
+ if ( d->sysd )
+ return d->sysWriteEntry( theKey, value );
+#endif
+ QString s(QString::number(value));
+ return writeEntry(theKey, s);
+}
+
+
+/*!
+ \internal
+
+ Writes the entry specified by \a key with the string-literal \a value,
+ replacing any previous setting. If \a value is zero-length or null, the
+ entry is replaced by an empty setting.
+
+ \e NOTE: This function is provided because some compilers use the
+ writeEntry (const QString &, bool) overload for this code:
+ writeEntry ("/foo/bar", "baz")
+
+ If an error occurs, this functions returns FALSE and the object is left
+ unchanged.
+
+ \sa readEntry(), removeEntry()
+*/
+bool QSettings::writeEntry(const QString &key, const char *value)
+{
+ if ( !verifyKey( key ) ) {
+#if defined(QT_CHECK_STATE)
+ qWarning( "QSettings::writeEntry: Invalid key: '%s'", key.isNull() ? "(null)" : key.latin1() );
+#endif
+ return FALSE;
+ }
+
+ QString theKey = groupKey( group(), key );
+
+ return writeEntry(theKey, QString(value));
+}
+
+
+/*!
+ \overload
+ Writes the string entry \a value into key \a key. The \a key is
+ created if it doesn't exist. Any previous value is overwritten by \a
+ value. If \a value is an empty string or a null string the key's
+ value will be an empty string.
+
+ If an error occurs the settings are left unchanged and FALSE is
+ returned; otherwise TRUE is returned.
+
+ \sa readListEntry(), readNumEntry(), readDoubleEntry(), readBoolEntry(), removeEntry()
+*/
+bool QSettings::writeEntry(const QString &key, const QString &value)
+{
+ if ( !verifyKey( key ) ) {
+#if defined(QT_CHECK_STATE)
+ qWarning( "QSettings::writeEntry: Invalid key: '%s'", key.isNull() ? "(null)" : key.latin1() );
+#endif
+ return FALSE;
+ }
+
+ QString theKey = groupKey( group(), key );
+
+#if defined(Q_WS_WIN) || defined(Q_OS_MAC)
+ if ( d->sysd )
+ return d->sysWriteEntry( theKey, value );
+#endif
+ // NOTE: we *do* allow value to be a null/empty string
+
+ QString realkey;
+
+ if (theKey[0] == '/') {
+ // parse our key
+ QStringList list(QStringList::split('/', theKey));
+
+ if (list.count() < 2) {
+#ifdef QT_CHECK_STATE
+ qWarning("QSettings::writeEntry: invalid key '%s'", theKey.latin1());
+#endif // QT_CHECK_STATE
+
+ return FALSE;
+ }
+
+ if (list.count() == 2) {
+ d->heading = list[0];
+ d->group = "General";
+ realkey = list[1];
+ } else {
+ d->heading = list[0];
+ d->group = list[1];
+
+ // remove the group from the list
+ list.remove(list.at(1));
+ // remove the heading from the list
+ list.remove(list.at(0));
+
+ realkey = list.join("/");
+ }
+ } else
+ realkey = theKey;
+
+ d->writeGroup(realkey, value);
+ return TRUE;
+}
+
+
+/*!
+ Removes the entry specified by \a key.
+
+ Returns TRUE if the entry existed and was removed; otherwise returns FALSE.
+
+ \sa readEntry(), writeEntry()
+*/
+bool QSettings::removeEntry(const QString &key)
+{
+ if ( !verifyKey( key ) ) {
+#if defined(QT_CHECK_STATE)
+ qWarning( "QSettings::removeEntry: Invalid key: '%s'", key.isNull() ? "(null)" : key.latin1() );
+#endif
+ return FALSE;
+ }
+
+ QString theKey = groupKey( group(), key );
+
+#if defined(Q_WS_WIN) || defined(Q_OS_MAC)
+ if ( d->sysd )
+ return d->sysRemoveEntry( theKey );
+#endif
+
+ QString realkey;
+
+ if (theKey[0] == '/') {
+ // parse our key
+ QStringList list(QStringList::split('/', theKey));
+
+ if (list.count() < 2) {
+#ifdef QT_CHECK_STATE
+ qWarning("QSettings::removeEntry: invalid key '%s'", theKey.latin1());
+#endif // QT_CHECK_STATE
+
+ return FALSE;
+ }
+
+ if (list.count() == 2) {
+ d->heading = list[0];
+ d->group = "General";
+ realkey = list[1];
+ } else {
+ d->heading = list[0];
+ d->group = list[1];
+
+ // remove the group from the list
+ list.remove(list.at(1));
+ // remove the heading from the list
+ list.remove(list.at(0));
+
+ realkey = list.join("/");
+ }
+ } else
+ realkey = theKey;
+
+ d->removeGroup(realkey);
+ return TRUE;
+}
+
+
+/*!
+ Returns a list of the keys which contain entries under \a key. Does \e
+ not return any keys that contain keys.
+
+ Example settings:
+ \code
+ /MyCompany/MyApplication/background color
+ /MyCompany/MyApplication/foreground color
+ /MyCompany/MyApplication/geometry/x
+ /MyCompany/MyApplication/geometry/y
+ /MyCompany/MyApplication/geometry/width
+ /MyCompany/MyApplication/geometry/height
+ \endcode
+ \code
+ QStringList keys = entryList( "/MyCompany/MyApplication" );
+ \endcode
+ \c keys contains 'background color' and 'foreground color'. It does
+ not contain 'geometry' because this key contains keys not entries.
+
+ To access the geometry values could either use subkeyList() to read
+ the keys and then read each entry, or simply read each entry
+ directly by specifying its full key, e.g.
+ "/MyCompany/MyApplication/geometry/y".
+
+ \sa subkeyList()
+*/
+QStringList QSettings::entryList(const QString &key) const
+{
+ if ( !verifyKey( key ) ) {
+#if defined(QT_CHECK_STATE)
+ qWarning( "QSettings::entryList: Invalid key: %s", key.isNull() ? "(null)" : key.latin1() );
+#endif
+ return QStringList();
+ }
+
+ QString theKey = groupKey( group(), key );
+
+#if defined(Q_WS_WIN) || defined(Q_OS_MAC)
+ if ( d->sysd )
+ return d->sysEntryList( theKey );
+#endif
+
+ QString realkey;
+ if (theKey[0] == '/') {
+ // parse our key
+ QStringList list(QStringList::split('/', theKey));
+
+ if (list.count() < 1) {
+#ifdef QT_CHECK_STATE
+ qWarning("QSettings::listEntries: invalid key '%s'", theKey.latin1());
+#endif // QT_CHECK_STATE
+
+ return QStringList();
+ }
+
+ if (list.count() == 1) {
+ d->heading = list[0];
+ d->group = "General";
+ } else {
+ d->heading = list[0];
+ d->group = list[1];
+
+ // remove the group from the list
+ list.remove(list.at(1));
+ // remove the heading from the list
+ list.remove(list.at(0));
+
+ realkey = list.join("/");
+ }
+ } else
+ realkey = theKey;
+
+ QSettingsGroup grp = d->readGroup();
+ QSettingsGroup::Iterator it = grp.begin();
+ QStringList ret;
+ QString itkey;
+ while (it != grp.end()) {
+ itkey = it.key();
+ it++;
+
+ if ( realkey.length() > 0 ) {
+ if ( itkey.left( realkey.length() ) != realkey )
+ continue;
+ else
+ itkey.remove( 0, realkey.length() + 1 );
+ }
+
+ if ( itkey.find( '/' ) != -1 )
+ continue;
+
+ ret << itkey;
+ }
+
+ return ret;
+}
+
+
+/*!
+ Returns a list of the keys which contain keys under \a key. Does \e
+ not return any keys that contain entries.
+
+ Example settings:
+ \code
+ /MyCompany/MyApplication/background color
+ /MyCompany/MyApplication/foreground color
+ /MyCompany/MyApplication/geometry/x
+ /MyCompany/MyApplication/geometry/y
+ /MyCompany/MyApplication/geometry/width
+ /MyCompany/MyApplication/geometry/height
+ /MyCompany/MyApplication/recent files/1
+ /MyCompany/MyApplication/recent files/2
+ /MyCompany/MyApplication/recent files/3
+ \endcode
+ \code
+ QStringList keys = subkeyList( "/MyCompany/MyApplication" );
+ \endcode
+ \c keys contains 'geometry' and 'recent files'. It does not contain
+ 'background color' or 'foreground color' because they are keys which
+ contain entries not keys. To get a list of keys that have values
+ rather than subkeys use entryList().
+
+ \sa entryList()
+*/
+QStringList QSettings::subkeyList(const QString &key) const
+{
+ if ( !verifyKey( key ) ) {
+#if defined(QT_CHECK_STATE)
+ qWarning( "QSettings::subkeyList: Invalid key: %s", key.isNull() ? "(null)" : key.latin1() );
+#endif
+ return QStringList();
+ }
+
+ QString theKey = groupKey( group(), key );
+
+#if defined(Q_WS_WIN) || defined(Q_OS_MAC)
+ if ( d->sysd )
+ return d->sysSubkeyList( theKey );
+#endif
+
+ QString realkey;
+ if (theKey[0] == '/') {
+ // parse our key
+ QStringList list(QStringList::split('/', theKey));
+
+ if (list.count() < 1) {
+#ifdef QT_CHECK_STATE
+ qWarning("QSettings::subkeyList: invalid key '%s'", theKey.latin1());
+#endif // QT_CHECK_STATE
+
+ return QStringList();
+ }
+
+ if (list.count() == 1) {
+ d->heading = list[0];
+ d->group = "General";
+ } else {
+ d->heading = list[0];
+ d->group = list[1];
+
+ // remove the group from the list
+ list.remove(list.at(1));
+ // remove the heading from the list
+ list.remove(list.at(0));
+
+ realkey = list.join("/");
+ }
+ } else
+ realkey = theKey;
+
+ QSettingsGroup grp = d->readGroup();
+ QSettingsGroup::Iterator it = grp.begin();
+ QStringList ret;
+ QString itkey;
+ while (it != grp.end()) {
+ itkey = it.key();
+ it++;
+
+ if ( realkey.length() > 0 ) {
+ if ( itkey.left( realkey.length() ) != realkey )
+ continue;
+ else
+ itkey.remove( 0, realkey.length() + 1 );
+ }
+
+ int slash = itkey.find( '/' );
+ if ( slash == -1 )
+ continue;
+ itkey.truncate( slash );
+
+ if ( ! ret.contains( itkey ) )
+ ret << itkey;
+ }
+
+ return ret;
+}
+
+
+/*!
+ \internal
+
+ This function returns the time of last modification for \a key.
+*/
+QDateTime QSettings::lastModficationTime(const QString &key)
+{
+ if ( !verifyKey( key ) ) {
+#if defined(QT_CHECK_STATE)
+ qWarning( "QSettings::lastModficationTime: Invalid key: '%s'", key.isNull() ? "(null)" : key.latin1() );
+#endif
+ return QDateTime();
+ }
+
+ QString theKey = groupKey( group(), key );
+
+#if defined(Q_WS_WIN) || defined(Q_OS_MAC)
+ if ( d->sysd )
+ return QDateTime();
+#endif
+
+ if (theKey[0] == '/') {
+ // parse our key
+ QStringList list(QStringList::split('/', theKey));
+
+ if (list.count() < 2) {
+#ifdef QT_CHECK_STATE
+ qWarning("QSettings::lastModficationTime: invalid key '%s'", theKey.latin1());
+#endif // QT_CHECK_STATE
+
+ return QDateTime();
+ }
+
+ if (list.count() == 2) {
+ d->heading = list[0];
+ d->group = "General";
+ } else {
+ d->heading = list[0];
+ d->group = list[1];
+ }
+ }
+
+ return d->modificationTime();
+}
+
+
+/*!
+ \overload
+
+ Writes the string list entry \a value into key \a key. The \a key
+ is created if it doesn't exist. Any previous value is overwritten
+ by \a value. The list is stored as a sequence of strings separated
+ by \a separator, so none of the strings in the list should contain
+ the separator. If the list is empty or null the key's value will
+ be an empty string.
+
+ If an error occurs the settings are left unchanged and FALSE is
+ returned; otherwise returns TRUE.
+
+ \sa readListEntry(), readNumEntry(), readDoubleEntry(), readBoolEntry(), removeEntry()
+*/
+bool QSettings::writeEntry(const QString &key, const QStringList &value,
+ const QChar &separator)
+{
+ QString s(value.join(separator));
+ return writeEntry(key, s);
+}
+
+/*!
+ \overload
+
+ Writes the string list entry \a value into key \a key. The \a key
+ is created if it doesn't exist. Any previous value is overwritten
+ by \a value.
+
+ If an error occurs the settings are left unchanged and FALSE is
+ returned; otherwise returns TRUE.
+
+ \sa readListEntry(), readNumEntry(), readDoubleEntry(), readBoolEntry(), removeEntry()
+*/
+bool QSettings::writeEntry(const QString &key, const QStringList &value)
+{
+ QString s;
+ for (QStringList::ConstIterator it=value.begin(); it!=value.end(); ++it) {
+ QString el = *it;
+ if ( el.isNull() ) {
+ el = "^0";
+ } else {
+ el.replace("^", "^^");
+ }
+ s+=el;
+ s+="^e"; // end of element
+ }
+ return writeEntry(key, s);
+}
+
+
+/*!
+ \overload QStringList QSettings::readListEntry(const QString &key, const QChar &separator, bool *ok ) const
+
+ Reads the entry specified by \a key as a string. The \a separator
+ is used to create a QStringList by calling QStringList::split(\a
+ separator, entry). If \a ok is not 0: \a *ok is set to TRUE if the
+ key was read, otherwise \a *ok is set to FALSE.
+
+ Note that if you want to iterate over the list, you should iterate
+ over a copy, e.g.
+ \code
+ QStringList list = mySettings.readListEntry( "size", " " );
+ QStringList::Iterator it = list.begin();
+ while( it != list.end() ) {
+ myProcessing( *it );
+ ++it;
+ }
+ \endcode
+
+ \sa readEntry(), readDoubleEntry(), readBoolEntry(), writeEntry(), removeEntry(), QStringList::split()
+*/
+
+/*!
+ \internal
+*/
+QStringList QSettings::readListEntry(const QString &key, const QChar &separator, bool *ok )
+{
+ QString value = readEntry( key, QString::null, ok );
+ if ( ok && !*ok )
+ return QStringList();
+
+ return QStringList::split(separator, value);
+}
+
+/*!
+ \fn QStringList QSettings::readListEntry(const QString &key, bool *ok ) const
+ Reads the entry specified by \a key as a string. If \a ok is not
+ 0, \a *ok is set to TRUE if the key was read, otherwise \a *ok is
+ set to FALSE.
+
+ Note that if you want to iterate over the list, you should iterate
+ over a copy, e.g.
+ \code
+ QStringList list = mySettings.readListEntry( "recentfiles" );
+ QStringList::Iterator it = list.begin();
+ while( it != list.end() ) {
+ myProcessing( *it );
+ ++it;
+ }
+ \endcode
+
+ \sa readEntry(), readDoubleEntry(), readBoolEntry(), writeEntry(), removeEntry(), QStringList::split()
+*/
+
+/*!
+ \internal
+*/
+QStringList QSettings::readListEntry(const QString &key, bool *ok )
+{
+ QString value = readEntry( key, QString::null, ok );
+ if ( ok && !*ok )
+ return QStringList();
+ QStringList l;
+ QString s;
+ bool esc=FALSE;
+ for (int i=0; i<(int)value.length(); i++) {
+ if ( esc ) {
+ if ( value[i] == 'e' ) { // end-of-string
+ l.append(s);
+ s="";
+ } else if ( value[i] == '0' ) { // null string
+ s=QString::null;
+ } else {
+ s.append(value[i]);
+ }
+ esc=FALSE;
+ } else if ( value[i] == '^' ) {
+ esc = TRUE;
+ } else {
+ s.append(value[i]);
+ if ( i == (int)value.length()-1 )
+ l.append(s);
+ }
+ }
+ return l;
+}
+
+/*!
+ Insert platform-dependent paths from platform-independent information.
+
+ The \a domain should be an Internet domain name
+ controlled by the producer of the software, eg. Trolltech products
+ use "trolltech.com".
+
+ The \a product should be the official name of the product.
+
+ The \a scope should be
+ QSettings::User for user-specific settings, or
+ QSettings::Global for system-wide settings (generally
+ these will be read-only to many users).
+*/
+
+void QSettings::setPath( const QString &domain, const QString &product, Scope scope )
+{
+// On Windows, any trailing ".com(\..*)" is stripped from the domain. The
+// Global scope corresponds to HKEY_LOCAL_MACHINE, and User corresponds to
+// HKEY_CURRENT_USER. Note that on some installations, not all users can
+// write to the Global scope. On UNIX, any trailing ".com(\..*)" is stripped
+// from the domain. The Global scope corresponds to "/opt" (this would be
+// configurable at library build time - eg. to "/usr/local" or "/usr"),
+// while the User scope corresponds to $HOME/.*rc.
+// Note that on most installations, not all users can write to the System
+// scope.
+//
+// On MacOS X, if there is no "." in domain, append ".com", then reverse the
+// order of the elements (Mac OS uses "com.apple.finder" as domain+product).
+// The Global scope corresponds to /Library/Preferences/*.plist, while the
+// User scope corresponds to ~/Library/Preferences/*.plist.
+// Note that on most installations, not all users can write to the System
+// scope.
+ QString actualSearchPath;
+ int lastDot = domain.findRev( '.' );
+
+#if defined(Q_WS_WIN)
+ actualSearchPath = "/" + domain.mid( 0, lastDot ) + "/" + product;
+ insertSearchPath( Windows, actualSearchPath );
+#elif defined(Q_WS_MAC)
+ QString topLevelDomain = domain.right( domain.length() - lastDot - 1 ) + ".";
+ if ( topLevelDomain.isEmpty() )
+ topLevelDomain = "com.";
+ actualSearchPath = "/" + topLevelDomain + domain.left( lastDot ) + product;
+ insertSearchPath( Mac, actualSearchPath );
+#else
+ actualSearchPath = "/" + domain.mid( 0, lastDot ) + "/" + product;
+ insertSearchPath( Unix, actualSearchPath );
+#endif
+
+ d->globalScope = scope == Global;
+}
+
+/*!
+ Appends \a group to the current key prefix.
+*/
+void QSettings::beginGroup( const QString &group )
+{
+ d->groupStack.push( group );
+ d->groupDirty = TRUE;
+}
+
+/*!
+ Undo previous calls to beginGroup(). Note that a single beginGroup("a/b/c") is undone
+ by a single call to endGroup().
+*/
+void QSettings::endGroup()
+{
+ d->groupStack.pop();
+ d->groupDirty = TRUE;
+}
+
+/*!
+ Set the current key prefix to the empty string.
+*/
+void QSettings::resetGroup()
+{
+ d->groupStack.clear();
+ d->groupDirty = FALSE;
+ d->groupPrefix = QString::null;
+}
+
+/*!
+ Returns the current key prefix, or a null string if there is no key prefix set.
+
+ \sa beginGroup();
+*/
+QString QSettings::group() const
+{
+ if ( d->groupDirty ) {
+ d->groupDirty = FALSE;
+ d->groupPrefix = QString::null;
+
+ QValueStack<QString>::Iterator it = d->groupStack.begin();
+ while ( it != d->groupStack.end() ) {
+ QString group = *it;
+ ++it;
+ if ( group[0] != '/' )
+ group = "/" + group;
+ d->groupPrefix += group;
+ }
+ }
+ return d->groupPrefix;
+}
+
+#endif