📄 qsettings.cpp
字号:
/******************************************************************************** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved.**** This file is part of the QtCore module of the Qt Toolkit.**** This file may be used under the terms of the GNU General Public** License version 2.0 as published by the Free Software Foundation** and appearing in the file LICENSE.GPL included in the packaging of** this file. Please review the following information to ensure GNU** General Public Licensing requirements will be met:** http://www.trolltech.com/products/qt/opensource.html**** If you are unsure which license is appropriate for your use, please** review the following information:** http://www.trolltech.com/products/qt/licensing.html or contact the** sales department at sales@trolltech.com.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.******************************************************************************/#include <qdebug.h>#include "qplatformdefs.h"#include "qsettings.h"#ifndef QT_NO_SETTINGS#include "qsettings_p.h"#include "qcache.h"#include "qfile.h"#include "qdir.h"#include "qfileinfo.h"#include "qmutex.h"#include "qlibraryinfo.h"#include "qtemporaryfile.h"#ifndef QT_NO_GEOM_VARIANT#include "qsize.h"#include "qpoint.h"#include "qrect.h"#endif // !QT_NO_GEOM_VARIANT#ifndef QT_NO_QOBJECT#include "qcoreapplication.h"#ifdef Q_OS_WIN // for homedirpath reading from registry#include "qt_windows.h"#include "qlibrary.h"#endif // Q_OS_WIN#endif // QT_NO_QOBJECT#include <stdlib.h>#ifndef CSIDL_COMMON_APPDATA#define CSIDL_COMMON_APPDATA 0x0023 // All Users\Application Data#endif#ifndef CSIDL_APPDATA#define CSIDL_APPDATA 0x001a // <username>\Application Data#endif// ************************************************************************// QConfFile/* QConfFile objects are explicitly shared within the application. This ensures that modification to the settings done through one QSettings object are immediately reflected in other setting objects of the same application.*/struct QConfFileCustomFormat{ QString extension; QSettings::ReadFunc readFunc; QSettings::WriteFunc writeFunc; Qt::CaseSensitivity caseSensitivity;};typedef QHash<QString, QConfFile *> ConfFileHash;typedef QCache<QString, QConfFile> ConfFileCache;typedef QHash<int, QString> PathHash;typedef QVector<QConfFileCustomFormat> CustomFormatVector;Q_GLOBAL_STATIC(ConfFileHash, usedHashFunc)Q_GLOBAL_STATIC(ConfFileCache, unusedCacheFunc)Q_GLOBAL_STATIC(PathHash, pathHashFunc)Q_GLOBAL_STATIC(CustomFormatVector, customFormatVectorFunc)Q_GLOBAL_STATIC(QMutex, globalMutex)#ifndef Q_OS_WINstatic bool unixLock(int handle, int lockType){ struct flock fl; fl.l_whence = SEEK_SET; fl.l_start = 0; fl.l_len = 0; fl.l_type = lockType; return !fcntl(handle, F_SETLKW, &fl);}#endifQConfFile::QConfFile(const QString &fileName, bool _userPerms) : name(fileName), size(0), ref(1), userPerms(_userPerms){ usedHashFunc()->insert(name, this);}InternalSettingsMap QConfFile::mergedKeyMap() const{ InternalSettingsMap result = originalKeys; InternalSettingsMap::const_iterator i; for (i = removedKeys.begin(); i != removedKeys.end(); ++i) result.remove(i.key()); for (i = addedKeys.begin(); i != addedKeys.end(); ++i) result.insert(i.key(), i.value()); return result;}QConfFile *QConfFile::fromName(const QString &fileName, bool _userPerms){ QString absPath = QFileInfo(fileName).absoluteFilePath(); ConfFileHash *usedHash = usedHashFunc(); ConfFileCache *unusedCache = unusedCacheFunc(); QConfFile *confFile; QMutexLocker locker(globalMutex()); if (!(confFile = usedHash->value(absPath))) { if ((confFile = unusedCache->take(absPath))) usedHash->insert(absPath, confFile); } if (confFile) { confFile->ref.ref(); return confFile; } return new QConfFile(absPath, _userPerms);}void QConfFile::clearCache(){ QMutexLocker locker(globalMutex()); unusedCacheFunc()->clear();}// ************************************************************************// QSettingsPrivateQSettingsPrivate::QSettingsPrivate() : spec(0), fallbacks(true), pendingChanges(false), status(QSettings::NoError){}QSettingsPrivate::~QSettingsPrivate(){}QString QSettingsPrivate::actualKey(const QString &key) const{ QString n = normalizedKey(key); Q_ASSERT_X(!n.isEmpty(), "QSettings", "empty key"); n.prepend(groupPrefix); return n;}/* Returns a string that never starts nor ends with a slash (or an empty string). Examples: "foo" becomes "foo" "/foo//bar///" becomes "foo/bar" "///" becomes "" This function is optimized to avoid a QString deep copy in the common case where the key is already normalized.*/QString QSettingsPrivate::normalizedKey(const QString &key){ QString result = key; int i = 0; while (i < result.size()) { while (result.at(i) == QLatin1Char('/')) { result.remove(i, 1); if (i == result.size()) goto after_loop; } while (result.at(i) != QLatin1Char('/')) { ++i; if (i == result.size()) return result; } ++i; // leave the slash alone }after_loop: if (!result.isEmpty()) result.truncate(i - 1); // remove the trailing slash return result;}// see also qsettings_win.cpp and qsettings_mac.cpp#if !defined(Q_OS_WIN) && !defined(Q_OS_MAC)QSettingsPrivate *QSettingsPrivate::create(QSettings::Format format, QSettings::Scope scope, const QString &organization, const QString &application){ return new QConfFileSettingsPrivate(format, scope, organization, application);}#endif#if !defined(Q_OS_WIN)QSettingsPrivate *QSettingsPrivate::create(const QString &fileName, QSettings::Format format){ return new QConfFileSettingsPrivate(fileName, format);}#endifvoid QSettingsPrivate::processChild(QString key, ChildSpec spec, QMap<QString, QString> &result){ if (spec != AllKeys) { int slashPos = key.indexOf(QLatin1Char('/')); if (slashPos == -1) { if (spec != ChildKeys) return; } else { if (spec != ChildGroups) return; key.truncate(slashPos); } } result.insert(key, QString());}void QSettingsPrivate::beginGroupOrArray(const QSettingsGroup &group){ groupStack.push(group); if (!group.name().isEmpty()) { groupPrefix += group.name(); groupPrefix += QLatin1Char('/'); }}/* We only set an error if there isn't one set already. This way the user always gets the first error that occurred. We always allow clearing errors.*/void QSettingsPrivate::setStatus(QSettings::Status status){ if (status == QSettings::NoError || this->status == QSettings::NoError) this->status = status;}void QSettingsPrivate::update(){ flush(); pendingChanges = false;}void QSettingsPrivate::requestUpdate(){ if (!pendingChanges) { pendingChanges = true;#ifndef QT_NO_QOBJECT Q_Q(QSettings); QCoreApplication::postEvent(q, new QEvent(QEvent::UpdateRequest));#else update();#endif }}QStringList QSettingsPrivate::variantListToStringList(const QVariantList &l){ QStringList result; QVariantList::const_iterator it = l.constBegin(); for (; it != l.constEnd(); ++it) result.append(variantToString(*it)); return result;}QVariant QSettingsPrivate::stringListToVariantList(const QStringList &l){ QVariantList variantList; bool foundNonStringItem = false; bool foundEscapedStringItem = false; QStringList::const_iterator it = l.constBegin(); for (; it != l.constEnd(); ++it) { QVariant variant = stringToVariant(*it); variantList.append(variant); if (variant.type() != QVariant::String) foundNonStringItem = true; else if (variant.toString() != *it) foundEscapedStringItem = true; } if (foundNonStringItem) { return variantList; } else if (foundEscapedStringItem) { return QVariant(variantList).toStringList(); } return l;}QString &QSettingsPrivate::escapedLeadingAt(QString &s){ if (s.length() > 0 && s.at(0) == QLatin1Char('@')) s.prepend(QLatin1Char('@')); return s;}QString &QSettingsPrivate::unescapedLeadingAt(QString &s){ if (s.startsWith(QLatin1String("@@"))) s.remove(0, 1); return s;}QString QSettingsPrivate::variantToString(const QVariant &v){ QString result; switch (v.type()) { case QVariant::Invalid: result = QLatin1String("@Invalid()"); break; case QVariant::ByteArray: { QByteArray a = v.toByteArray(); result = QLatin1String("@ByteArray("); result += QString::fromLatin1(a.constData(), a.size()); result += QLatin1Char(')'); break; } case QVariant::String: case QVariant::LongLong: case QVariant::ULongLong: case QVariant::Int: case QVariant::UInt: case QVariant::Bool: case QVariant::Double: { result = v.toString(); result = escapedLeadingAt(result); break; }#ifndef QT_NO_GEOM_VARIANT case QVariant::Rect: { QRect r = qvariant_cast<QRect>(v); result += QLatin1String("@Rect("); result += QString::number(r.x()); result += QLatin1Char(' '); result += QString::number(r.y()); result += QLatin1Char(' '); result += QString::number(r.width()); result += QLatin1Char(' '); result += QString::number(r.height()); result += QLatin1Char(')'); break; } case QVariant::Size: { QSize s = qvariant_cast<QSize>(v); result += QLatin1String("@Size("); result += QString::number(s.width()); result += QLatin1Char(' '); result += QString::number(s.height()); result += QLatin1Char(')'); break; } case QVariant::Point: { QPoint p = qvariant_cast<QPoint>(v); result += QLatin1String("@Point("); result += QString::number(p.x()); result += QLatin1Char(' '); result += QString::number(p.y()); result += QLatin1Char(')'); break; }#endif // !QT_NO_GEOM_VARIANT default: {#ifndef QT_NO_DATASTREAM QByteArray a; { QDataStream s(&a, QIODevice::WriteOnly); s << v; } result = QLatin1String("@Variant("); result += QString::fromLatin1(a.constData(), a.size()); result += QLatin1Char(')');#else Q_ASSERT("QSettings: Cannot save custom types without QDataStream support");#endif break; } } return result;}QVariant QSettingsPrivate::stringToVariant(const QString &s){ if (s.length() > 3 && s.at(0) == QLatin1Char('@') && s.at(s.length() - 1) == QLatin1Char(')')) { if (s.startsWith(QLatin1String("@ByteArray("))) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -