/************************************************************************** ** ** This file is part of Qt Creator ** ** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). ** ** Contact: Qt Software Information (qt-info@nokia.com) ** ** Commercial Usage ** ** Licensees holding valid Qt Commercial licenses may use this file in ** accordance with the Qt Commercial License Agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Nokia. ** ** GNU Lesser General Public License Usage ** ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** If you are unsure which license is appropriate for your use, please ** contact the sales department at qt-sales@nokia.com. ** **************************************************************************/ #include "settingsdatabase.h" #include #include #include #include using namespace Core; using namespace Core::Internal; enum { debug_settings = 1 }; namespace Core { namespace Internal { typedef QMap SettingsMap; class SettingsDatabasePrivate { public: QString effectiveGroup() const { return m_groups.join(QLatin1String("/")); } QString effectiveKey(const QString &key) const { QString g = effectiveGroup(); if (!g.isEmpty()) g += QLatin1Char('/'); g += key; return g; } SettingsMap m_settings; QStringList m_groups; QStringList m_dirtyKeys; QSqlDatabase m_db; }; } // namespace Internal } // namespace Core SettingsDatabase::SettingsDatabase(const QString &path, const QString &application, QObject *parent) : QObject(parent) , d(new SettingsDatabasePrivate) { const QLatin1Char slash('/'); // TODO: Don't rely on a path, but determine automatically QString fileName = path; if (!fileName.endsWith(slash)) fileName += slash; fileName += application; fileName += QLatin1String(".db"); d->m_db = QSqlDatabase::addDatabase("QSQLITE", QLatin1String("settings")); d->m_db.setDatabaseName(fileName); if (!d->m_db.open()) qWarning() << "Warning: Failed to open settings database!"; // Create the settings table if it doesn't exist yet QSqlQuery query(d->m_db); query.prepare(QLatin1String("CREATE TABLE IF NOT EXISTS settings (" "key PRIMARY KEY ON CONFLICT REPLACE, " "value)")); if (d->m_db.isOpen() && !query.exec()) qWarning() << "Warning: Failed to prepare settings database!"; // Retrieve all available keys (values are retrieved lazily) if (query.exec(QLatin1String("SELECT key FROM settings"))) { while (query.next()) { d->m_settings.insert(query.value(0).toString(), QVariant()); } } } SettingsDatabase::~SettingsDatabase() { sync(); delete d; QSqlDatabase::removeDatabase(QLatin1String("settings")); } void SettingsDatabase::setValue(const QString &key, const QVariant &value) { const QString effectiveKey = d->effectiveKey(key); // Add to cache d->m_settings.insert(effectiveKey, value); // Instant apply (TODO: Delay writing out settings) QSqlQuery query(d->m_db); query.prepare(QLatin1String("INSERT INTO settings VALUES (?, ?)")); query.addBindValue(effectiveKey); query.addBindValue(value); query.exec(); if (debug_settings) qDebug() << "Stored:" << effectiveKey << "=" << value; } QVariant SettingsDatabase::value(const QString &key, const QVariant &defaultValue) const { const QString effectiveKey = d->effectiveKey(key); QVariant value = defaultValue; SettingsMap::const_iterator i = d->m_settings.constFind(effectiveKey); if (i != d->m_settings.constEnd() && i.value().isValid()) { value = i.value(); } else { // Try to read the value from the database QSqlQuery query(d->m_db); query.prepare(QLatin1String("SELECT value FROM settings WHERE key = ?")); query.addBindValue(effectiveKey); query.exec(); if (query.next()) { value = query.value(0); if (debug_settings) qDebug() << "Retrieved:" << effectiveKey << "=" << value; } // Cache the result d->m_settings.insert(effectiveKey, value); } return value; } bool SettingsDatabase::contains(const QString &key) const { return d->m_settings.contains(d->effectiveKey(key)); } void SettingsDatabase::remove(const QString &key) { Q_UNUSED(key); // TODO: Remove key and all subkeys } void SettingsDatabase::beginGroup(const QString &prefix) { d->m_groups.append(prefix); } void SettingsDatabase::endGroup() { d->m_groups.removeLast(); } QString SettingsDatabase::group() const { return d->effectiveGroup(); } QStringList SettingsDatabase::childKeys() const { QStringList childs; const QString g = group(); QMapIterator i(d->m_settings); while (i.hasNext()) { const QString &key = i.next().key(); if (key.startsWith(g) && key.indexOf(QLatin1Char('/'), g.length() + 1) == -1) { childs.append(key.mid(g.length() + 1)); } } return childs; } void SettingsDatabase::sync() { // TODO: Delay writing of dirty keys and save them here }