diff options
author | Jarek Kobus <jkobus@trolltech.com> | 2011-08-16 10:45:23 +0200 |
---|---|---|
committer | Jarek Kobus <jaroslaw.kobus@nokia.com> | 2011-09-23 10:23:15 +0200 |
commit | 224491182666840def3a551a840c8fa840bfe5c2 (patch) | |
tree | 0c75ae3cc76819f373c1642ffd598e57568dac54 /src/libs/utils | |
parent | 3955df7855c9d27d8d470f509578bd9004b72ea1 (diff) | |
download | qt-creator-224491182666840def3a551a840c8fa840bfe5c2.tar.gz |
Implement Code Style schemes
Task-number: QTCREATORBUG-5092
Change-Id: I218cef02f7c242e4dfae59b1b8021ea618e60d07
Reviewed-on: http://codereview.qt-project.org/5160
Reviewed-by: Leandro T. C. Melo <leandro.melo@nokia.com>
Diffstat (limited to 'src/libs/utils')
-rw-r--r-- | src/libs/utils/persistentsettings.cpp | 410 | ||||
-rw-r--r-- | src/libs/utils/persistentsettings.h | 72 | ||||
-rw-r--r-- | src/libs/utils/utils-lib.pri | 6 |
3 files changed, 486 insertions, 2 deletions
diff --git a/src/libs/utils/persistentsettings.cpp b/src/libs/utils/persistentsettings.cpp new file mode 100644 index 0000000000..f4d0eefda1 --- /dev/null +++ b/src/libs/utils/persistentsettings.cpp @@ -0,0 +1,410 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at info@qt.nokia.com. +** +**************************************************************************/ + +#include "persistentsettings.h" + +#include <app/app_version.h> + +#include <utils/fileutils.h> + +#include <QtCore/QDebug> +#include <QtCore/QFile> +#include <QtCore/QVariant> +#include <QtCore/QStack> +#include <QtCore/QXmlStreamAttributes> +#include <QtCore/QXmlStreamReader> +#include <QtCore/QXmlStreamWriter> +#include <QtCore/QDateTime> + +#include <utils/qtcassert.h> + + +/*! + \class Utils::PersistentSettingsReader + + \brief Reads a QVariantMap of arbitrary, nested data structures from a XML file. + + Handles all string-serializable simple types and QVariantList and QVariantMap. Example: + \code +<qtcreator> + <data> + <variable>ProjectExplorer.Project.ActiveTarget</variable> + <value type="int">0</value> + </data> + <data> + <variable>ProjectExplorer.Project.EditorSettings</variable> + <valuemap type="QVariantMap"> + <value type="bool" key="EditorConfiguration.AutoIndent">true</value> + </valuemap> + </data> + \endcode + + When parsing the structure, a parse stack of ParseValueStackEntry is used for each + <data> element. ParseValueStackEntry is a variant/union of: + \list + \o simple value + \o map + \o list + \endlist + + When entering a value element ( \c <value> / \c <valuelist> , \c <valuemap> ), entry is pushed + accordingly. When leaving the element, the QVariant-value of the entry is taken off the stack + and added to the stack entry below (added to list or inserted into map). The first element + of the stack is the value of the <data> element. + + \sa Utils::PersistentSettingsWriter +*/ + +namespace Utils { + +struct Context // Basic context containing element name string constants. +{ + Context(); + + const QString qtCreatorElement; + const QString dataElement; + const QString variableElement; + const QString typeAttribute; + const QString valueElement; + const QString valueListElement; + const QString valueMapElement; + const QString keyAttribute; +}; + +Context::Context() : + qtCreatorElement(QLatin1String("qtcreator")), + dataElement(QLatin1String("data")), + variableElement(QLatin1String("variable")), + typeAttribute(QLatin1String("type")), + valueElement(QLatin1String("value")), + valueListElement(QLatin1String("valuelist")), + valueMapElement(QLatin1String("valuemap")), + keyAttribute(QLatin1String("key")) +{ +} + +struct ParseValueStackEntry +{ + explicit ParseValueStackEntry(QVariant::Type t = QVariant::Invalid, const QString &k = QString()) : type(t), key(k) {} + explicit ParseValueStackEntry(const QVariant &aSimpleValue, const QString &k); + + QVariant value() const; + void addChild(const QString &key, const QVariant &v); + + QVariant::Type type; + QString key; + QVariant simpleValue; + QVariantList listValue; + QVariantMap mapValue; +}; + +ParseValueStackEntry::ParseValueStackEntry(const QVariant &aSimpleValue, const QString &k) : + type(aSimpleValue.type()), key(k), simpleValue(aSimpleValue) +{ + QTC_ASSERT(simpleValue.isValid(), return ; ) +} + +QVariant ParseValueStackEntry::value() const +{ + switch (type) { + case QVariant::Invalid: + return QVariant(); + case QVariant::Map: + return QVariant(mapValue); + case QVariant::List: + return QVariant(listValue); + default: + break; + } + return simpleValue; +} + +void ParseValueStackEntry::addChild(const QString &key, const QVariant &v) +{ + switch (type) { + case QVariant::Map: + mapValue.insert(key, v); + break; + case QVariant::List: + listValue.push_back(v); + break; + default: + qWarning() << "ParseValueStackEntry::Internal error adding " << key << v << " to " + << QVariant::typeToName(type) << value(); + break; + } +} + +class ParseContext : public Context +{ +public: + QVariantMap parse(QFile &file); + +private: + enum Element { QtCreatorElement, DataElement, VariableElement, + SimpleValueElement, ListValueElement, MapValueElement, UnknownElement }; + + Element element(const QStringRef &r) const; + static inline bool isValueElement(Element e) + { return e == SimpleValueElement || e == ListValueElement || e == MapValueElement; } + QVariant readSimpleValue(QXmlStreamReader &r, const QXmlStreamAttributes &attributes) const; + + bool handleStartElement(QXmlStreamReader &r); + bool handleEndElement(const QStringRef &name); + + QStack<ParseValueStackEntry> m_valueStack; + QVariantMap m_result; + QString m_currentVariableName; +}; + +QVariantMap ParseContext::parse(QFile &file) +{ + QXmlStreamReader r(&file); + + m_result.clear(); + m_currentVariableName.clear(); + + while (!r.atEnd()) { + switch (r.readNext()) { + case QXmlStreamReader::StartElement: + if (handleStartElement(r)) + return m_result; + break; + case QXmlStreamReader::EndElement: + if (handleEndElement(r.name())) + return m_result; + break; + case QXmlStreamReader::Invalid: + qWarning("Error reading %s:%d: %s", qPrintable(file.fileName()), + int(r.lineNumber()), qPrintable(r.errorString())); + return QVariantMap(); + break; + default: + break; + } // switch token + } // while (!r.atEnd()) + return m_result; +} + +bool ParseContext::handleStartElement(QXmlStreamReader &r) +{ + const QStringRef name = r.name(); + const Element e = element(name); + if (e == VariableElement) { + m_currentVariableName = r.readElementText(); + return false; + } + if (!ParseContext::isValueElement(e)) + return false; + + const QXmlStreamAttributes attributes = r.attributes(); + const QString key = attributes.hasAttribute(keyAttribute) ? + attributes.value(keyAttribute).toString() : QString(); + switch (e) { + case SimpleValueElement: + // This reads away the end element, so, handle end element right here. + m_valueStack.push_back(ParseValueStackEntry(readSimpleValue(r, attributes), key)); + return handleEndElement(name); + case ListValueElement: + m_valueStack.push_back(ParseValueStackEntry(QVariant::List, key)); + break; + case MapValueElement: + m_valueStack.push_back(ParseValueStackEntry(QVariant::Map, key)); + break; + default: + break; + } + return false; +} + +bool ParseContext::handleEndElement(const QStringRef &name) +{ + const Element e = element(name); + if (ParseContext::isValueElement(e)) { + QTC_ASSERT(!m_valueStack.isEmpty(), return true; ) + const ParseValueStackEntry top = m_valueStack.pop(); + if (m_valueStack.isEmpty()) { // Last element? -> Done with that variable. + QTC_ASSERT(!m_currentVariableName.isEmpty(), return true; ) + m_result.insert(m_currentVariableName, top.value()); + m_currentVariableName.clear(); + return false; + } + m_valueStack.top().addChild(top.key, top.value()); + } + return e == QtCreatorElement; +} + +ParseContext::Element ParseContext::element(const QStringRef &r) const +{ + if (r == valueElement) + return SimpleValueElement; + if (r == valueListElement) + return ListValueElement; + if (r == valueMapElement) + return MapValueElement; + if (r == qtCreatorElement) + return QtCreatorElement; + if (r == dataElement) + return DataElement; + if (r == variableElement) + return VariableElement; + return UnknownElement; +} + +QVariant ParseContext::readSimpleValue(QXmlStreamReader &r, const QXmlStreamAttributes &attributes) const +{ + // Simple value + const QString type = attributes.value(typeAttribute).toString(); + const QString text = r.readElementText(); + if (type == QLatin1String("QChar")) { // Workaround: QTBUG-12345 + QTC_ASSERT(text.size() == 1, return QVariant(); ) + return QVariant(QChar(text.at(0))); + } + QVariant value; + value.setValue(text); + value.convert(QVariant::nameToType(type.toLatin1().data())); + return value; +} + +// =================================== PersistentSettingsReader + +PersistentSettingsReader::PersistentSettingsReader() +{ +} + +QVariant PersistentSettingsReader::restoreValue(const QString &variable) const +{ + if (m_valueMap.contains(variable)) + return m_valueMap.value(variable); + return QVariant(); +} + +QVariantMap PersistentSettingsReader::restoreValues() const +{ + return m_valueMap; +} + +bool PersistentSettingsReader::load(const QString &fileName) +{ + m_valueMap.clear(); + + QFile file(fileName); + if (!file.open(QIODevice::ReadOnly|QIODevice::Text)) + return false; + ParseContext ctx; + m_valueMap = ctx.parse(file); + file.close(); + return true; +} + +/*! + \class Utils::PersistentSettingsWriter + + \brief Serializes a QVariantMap of arbitrary, nested data structures to a XML file. + \sa Utils::PersistentSettingsReader +*/ + +PersistentSettingsWriter::PersistentSettingsWriter() +{ +} + +static void writeVariantValue(QXmlStreamWriter &w, const Context &ctx, + const QVariant &variant, const QString &key = QString()) +{ + switch (variant.type()) { + case QVariant::StringList: + case QVariant::List: + w.writeStartElement(ctx.valueListElement); + w.writeAttribute(ctx.typeAttribute, QVariant::typeToName(QVariant::List)); + if (!key.isEmpty()) + w.writeAttribute(ctx.keyAttribute, key); + foreach (const QVariant &var, variant.toList()) + writeVariantValue(w, ctx, var); + w.writeEndElement(); + break; + case QVariant::Map: { + w.writeStartElement(ctx.valueMapElement); + w.writeAttribute(ctx.typeAttribute, QVariant::typeToName(QVariant::Map)); + if (!key.isEmpty()) + w.writeAttribute(ctx.keyAttribute, key); + const QVariantMap varMap = variant.toMap(); + const QVariantMap::const_iterator cend = varMap.constEnd(); + for (QVariantMap::const_iterator i = varMap.constBegin(); i != cend; ++i) + writeVariantValue(w, ctx, i.value(), i.key()); + w.writeEndElement(); + } + break; + default: + w.writeStartElement(ctx.valueElement); + w.writeAttribute(ctx.typeAttribute, QLatin1String(variant.typeName())); + if (!key.isEmpty()) + w.writeAttribute(ctx.keyAttribute, key); + w.writeCharacters(variant.toString()); + w.writeEndElement(); + break; + } +} + +void PersistentSettingsWriter::saveValue(const QString &variable, const QVariant &value) +{ + m_valueMap.insert(variable, value); +} + +bool PersistentSettingsWriter::save(const QString &fileName, const QString &docType, + QWidget *parent) const +{ + Utils::FileSaver saver(fileName, QIODevice::Text); + if (!saver.hasError()) { + const Context ctx; + QXmlStreamWriter w(saver.file()); + w.setAutoFormatting(true); + w.setAutoFormattingIndent(1); // Historical, used to be QDom. + w.writeStartDocument(); + w.writeDTD(QLatin1String("<!DOCTYPE ") + docType + QLatin1Char('>')); + w.writeComment(QString::fromAscii(" Written by Qt Creator %1, %2. "). + arg(QLatin1String(Core::Constants::IDE_VERSION_LONG), + QDateTime::currentDateTime().toString(Qt::ISODate))); + w.writeStartElement(ctx.qtCreatorElement); + const QVariantMap::const_iterator cend = m_valueMap.constEnd(); + for (QVariantMap::const_iterator it = m_valueMap.constBegin(); it != cend; ++it) { + w.writeStartElement(ctx.dataElement); + w.writeTextElement(ctx.variableElement, it.key()); + writeVariantValue(w, ctx, it.value()); + w.writeEndElement(); + } + w.writeEndDocument(); + + saver.setResult(&w); + } + return saver.finalize(parent); +} +} // namespace Utils diff --git a/src/libs/utils/persistentsettings.h b/src/libs/utils/persistentsettings.h new file mode 100644 index 0000000000..f116a94893 --- /dev/null +++ b/src/libs/utils/persistentsettings.h @@ -0,0 +1,72 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at info@qt.nokia.com. +** +**************************************************************************/ + +#ifndef PERSISTENTSETTINGS_H +#define PERSISTENTSETTINGS_H + +#include "utils_global.h" + +#include <QtCore/QMap> +#include <QtCore/QVariant> + +QT_BEGIN_NAMESPACE +class QWidget; +QT_END_NAMESPACE + +namespace Utils { + +class QTCREATOR_UTILS_EXPORT PersistentSettingsReader +{ +public: + PersistentSettingsReader(); + QVariant restoreValue(const QString &variable) const; + QVariantMap restoreValues() const; + bool load(const QString &fileName); + +private: + QMap<QString, QVariant> m_valueMap; +}; + +class QTCREATOR_UTILS_EXPORT PersistentSettingsWriter +{ +public: + PersistentSettingsWriter(); + void saveValue(const QString &variable, const QVariant &value); + bool save(const QString &fileName, const QString &docType, QWidget *parent) const; + +private: + QMap<QString, QVariant> m_valueMap; +}; + +} // namespace Utils + +#endif // PERSISTENTSETTINGS_H diff --git a/src/libs/utils/utils-lib.pri b/src/libs/utils/utils-lib.pri index 512249bfa0..187f0ba852 100644 --- a/src/libs/utils/utils-lib.pri +++ b/src/libs/utils/utils-lib.pri @@ -90,7 +90,8 @@ SOURCES += $$PWD/environment.cpp \ $$PWD/ssh/sshkeypasswordretriever.cpp \ $$PWD/outputformatter.cpp \ $$PWD/flowlayout.cpp \ - $$PWD/networkaccessmanager.cpp + $$PWD/networkaccessmanager.cpp \ + $$PWD/persistentsettings.cpp win32 { SOURCES += \ @@ -194,7 +195,8 @@ HEADERS += \ $$PWD/outputformatter.h \ $$PWD/outputformat.h \ $$PWD/flowlayout.h \ - $$PWD/networkaccessmanager.h + $$PWD/networkaccessmanager.h \ + $$PWD/persistentsettings.h FORMS += $$PWD/filewizardpage.ui \ $$PWD/projectintropage.ui \ |