📄 qsettings.cpp
字号:
/************************************************************************ Copyright (C) 2000-2005 Trolltech AS. All rights reserved.**** This file is part of the Qtopia Environment.** ** This program is free software; you can redistribute it and/or modify it** under the terms of the GNU General Public License as published by the** Free Software Foundation; either version 2 of the License, or (at your** option) any later version.** ** A copy of the GNU GPL license version 2 is included in this package as ** LICENSE.GPL.**** This program is distributed in the hope that it will be useful, but** WITHOUT ANY WARRANTY; without even the implied warranty of** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ** See the GNU General Public License for more details.**** In addition, as a special exception Trolltech gives permission to link** the code of this program with Qtopia applications copyrighted, developed** and distributed by Trolltech under the terms of the Qtopia Personal Use** License Agreement. You must comply with the GNU General Public License** in all respects for all of the code used other than the applications** licensed under the Qtopia Personal Use License Agreement. If you modify** this file, you may extend this exception to your version of the file,** but you are not obligated to do so. If you do not wish to do so, delete** this exception statement from your version.** ** 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 -> open64static 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>#ifndef NO_ERRNO_H#include <errno.h>#endif/*! \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 uses the Carbon preferences API. 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 reading settings at application startup: \code QSettings settings; settings.setPath( "MyCompany.com", "MyApplication" ); QString bgColor = settings.readEntry( "/colors/background", "white" ); int width = settings.readNumEntry( "/geometry/width", 640 ); // ... \endcode A typical usage pattern for saving settings at application exit or 'save preferences': \code QSettings settings; settings.setPath( "MyCompany.com", "MyApplication" ); settings.writeEntry( "/colors/background", bgColor ); settings.writeEntry( "/geometry/width", width ); // ... \endcode A key prefix can be prepended to all keys using beginGroup(). The application of the prefix is stopped using endGroup(). For example: \code QSettings settings; settings.beginGroup( "/MainWindow" ); settings.beginGroup( "/Geometry" ); int x = settings.readEntry( "/x" ); // ... settings.endGroup(); settings.beginGroup( "/Toolbars" ); // ... settings.endGroup(); settings.endGroup(); \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 Since settings for Windows are stored in the registry there are some size limitations 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 or Mac OS X. \section1 Notes for Mac OS X Applications The location where settings are stored is not formally defined by the CFPreferences API (for the sake of Mac OS 9 support). At the time of writing settings are stored (either on a global or user basis, preferring locally) into a plist file in \c $ROOT/System/Library/Preferences (in XML format). QSettings will create an appropriate plist file (\c{com.<first group name>.plist}) out of the full path to a key. For further information on CFPreferences see \link http://developer.apple.com/techpubs/macosx/CoreFoundation/PreferenceServices/preferenceservices_carbon.html Apple's Specifications\endlink \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 \c SYSCONF - the default value is \c INSTALL/etc/settings \i \c /opt/MyCompany/share/etc \i \c /opt/MyCompany/share/MyApplication/etc \i \c $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 \link #sizelimit Windows size limitations \endlink 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 2static HANDLE openlock( const QString &name, int type ){ return 0; // ### if ( !QFile::exists( name ) ) return 0; HANDLE fd = 0; DWORD shareFlag = (type & Q_LOCKREAD) ? 0 : FILE_SHARE_READ; shareFlag |= (type & Q_LOCKWRITE) ? 0 : FILE_SHARE_WRITE; QT_WA( { fd = CreateFileW( (TCHAR*)name.ucs2(), GENERIC_READ, shareFlag, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); } , { fd = CreateFileA( name.local8Bit(), GENERIC_READ, shareFlag, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); } );#ifdef QT_CHECK_STATE if ( !fd ) qWarning( "QSettings: openlock failed!" );#endif return fd;}static void closelock( HANDLE fd ){ if ( !fd ) return; CloseHandle( fd );}#endifQSettingsGroup::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((uint)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#endifQSettingsPrivate::QSettingsPrivate( QSettings::Format format ) : groupDirty( TRUE ), modified(FALSE), globalScope(TRUE){#if !defined(QWS) && (defined(Q_WS_WIN) || defined(Q_OS_MAC)) if ( format != QSettings::Ini ) return;#else Q_UNUSED( format );#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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -