diff --git a/src/gui/kconfigloader.cpp b/src/gui/kconfigloader.cpp index 760b150..181def6 100644 --- a/src/gui/kconfigloader.cpp +++ b/src/gui/kconfigloader.cpp @@ -1,441 +1,478 @@ /* * Copyright 2007 Aaron Seigo * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, or * (at your option) any later version. * * 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 * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kconfigloader.h" #include "kconfigloader_p.h" #include "kconfigloaderhandler_p.h" #include #include #include #include -#include -#include #include #include void ConfigLoaderPrivate::parse(KConfigLoader *loader, QIODevice *xml) { clearData(); loader->clearItems(); if (xml) { - QXmlInputSource source(xml); - QXmlSimpleReader reader; ConfigLoaderHandler handler(loader, this); - reader.setContentHandler(&handler); - reader.parse(&source, false); + handler.parse(xml); } } ConfigLoaderHandler::ConfigLoaderHandler(KConfigLoader *config, ConfigLoaderPrivate *d) - : QXmlDefaultHandler(), - m_config(config), + : m_config(config), d(d) { resetState(); } -bool ConfigLoaderHandler::startElement(const QString &namespaceURI, const QString &localName, - const QString &qName, const QXmlAttributes &attrs) +bool ConfigLoaderHandler::parse(QIODevice *input) +{ + if (!input->open(QIODevice::ReadOnly)) { + qWarning() << "Impossible to open device"; + return false; + } + QXmlStreamReader reader(input); + + while (!reader.atEnd()) { + reader.readNext(); + if (reader.hasError()) + return false; + + switch (reader.tokenType()) { + case QXmlStreamReader::StartElement: + if (!startElement(reader.namespaceUri(), reader.name(), + reader.qualifiedName(), reader.attributes())) { + return false; + } + break; + case QXmlStreamReader::EndElement: + if (!endElement(reader.namespaceUri(), reader.name(), + reader.qualifiedName())) { + return false; + } + break; + case QXmlStreamReader::Characters: + if (!reader.isWhitespace() && !reader.text().trimmed().isEmpty()) { + if (!characters(reader.text())) + return false; + } + break; + default: + break; + } + } + + if (reader.isEndDocument()) + return false; + + return true; +} + +bool ConfigLoaderHandler::startElement(const QStringRef &namespaceURI, const QStringRef &localName, + const QStringRef &qName, const QXmlStreamAttributes &attrs) { Q_UNUSED(namespaceURI) Q_UNUSED(qName) -// qDebug() << "ConfigLoaderHandler::startElement(" << localName << qName; - int numAttrs = attrs.count(); - QString tag = localName.toLower(); + // qDebug() << "ConfigLoaderHandler::startElement(" << localName << qName; + const int numAttrs = attrs.count(); + const QString tag = localName.toString().toLower(); if (tag == QLatin1String("group")) { QString group; for (int i = 0; i < numAttrs; ++i) { - QString name = attrs.localName(i).toLower(); - if (name == QLatin1String("name")) { + const QStringRef name = attrs.at(i).name(); + if (name.compare(QLatin1String("name"), Qt::CaseInsensitive) == 0) { //qDebug() << "set group to" << attrs.value(i); - group = attrs.value(i); + group = attrs.at(i).value().toString(); } } if (group.isEmpty()) { group = d->baseGroup; } else { d->groups.append(group); if (!d->baseGroup.isEmpty()) { group = d->baseGroup + QLatin1Char('\x1d') + group; } } if (m_config) { m_config->setCurrentGroup(group); } } else if (tag == QLatin1String("entry")) { for (int i = 0; i < numAttrs; ++i) { - QString name = attrs.localName(i).toLower(); - if (name == QLatin1String("name")) { - m_name = attrs.value(i).trimmed(); - } else if (name == QLatin1String("type")) { - m_type = attrs.value(i).toLower(); - } else if (name == QLatin1String("key")) { - m_key = attrs.value(i).trimmed(); + const QStringRef name = attrs.at(i).name(); + if (name.compare(QLatin1String("name"), Qt::CaseInsensitive) == 0) { + m_name = attrs.at(i).value().trimmed().toString(); + } else if (name.compare(QLatin1String("type"), Qt::CaseInsensitive) == 0) { + m_type = attrs.at(i).value().toString().toLower(); + } else if (name.compare(QLatin1String("key"), Qt::CaseInsensitive) == 0) { + m_key = attrs.at(i).value().trimmed().toString(); } } } else if (tag == QLatin1String("choice")) { m_choice.name.clear(); m_choice.label.clear(); m_choice.whatsThis.clear(); for (int i = 0; i < numAttrs; ++i) { - QString name = attrs.localName(i).toLower(); - if (name == QLatin1String("name")) { - m_choice.name = attrs.value(i); + const QStringRef name = attrs.at(i).name(); + if (name.compare(QLatin1String("name"), Qt::CaseInsensitive) == 0) { + m_choice.name = attrs.at(i).value().toString(); } } m_inChoice = true; } return true; } -bool ConfigLoaderHandler::characters(const QString &ch) +bool ConfigLoaderHandler::characters(const QStringRef &ch) { - m_cdata.append(ch); + m_cdata.append(ch.toString()); return true; } QString ConfigLoaderHandler::name() const { return m_name; } void ConfigLoaderHandler::setName(const QString &name) { m_name = name; } QString ConfigLoaderHandler::key() const { return m_key; } void ConfigLoaderHandler::setKey(const QString &key) { m_key = key; } QString ConfigLoaderHandler::type() const { return m_type; } QString ConfigLoaderHandler::defaultValue() const { return m_default; } -bool ConfigLoaderHandler::endElement(const QString &namespaceURI, - const QString &localName, const QString &qName) +bool ConfigLoaderHandler::endElement(const QStringRef &namespaceURI, + const QStringRef &localName, const QStringRef &qName) { Q_UNUSED(namespaceURI) Q_UNUSED(qName) // qDebug() << "ConfigLoaderHandler::endElement(" << localName << qName; - const QString tag = localName.toLower(); - if (tag == QLatin1String("entry")) { + const QStringRef tag = localName; + if (tag.compare(QLatin1String("entry"), Qt::CaseInsensitive) == 0) { addItem(); resetState(); - } else if (tag == QLatin1String("label")) { + } else if (tag.compare(QLatin1String("label"), Qt::CaseInsensitive) == 0) { if (m_inChoice) { m_choice.label = m_cdata.trimmed(); } else { m_label = m_cdata.trimmed(); } - } else if (tag == QLatin1String("whatsthis")) { + } else if (tag.compare(QLatin1String("whatsthis"), Qt::CaseInsensitive) == 0) { if (m_inChoice) { m_choice.whatsThis = m_cdata.trimmed(); } else { m_whatsThis = m_cdata.trimmed(); } - } else if (tag == QLatin1String("default")) { + } else if (tag.compare(QLatin1String("default"), Qt::CaseInsensitive) == 0) { m_default = m_cdata.trimmed(); - } else if (tag == QLatin1String("min")) { + } else if (tag.compare(QLatin1String("min"), Qt::CaseInsensitive) == 0) { m_min = m_cdata.toInt(&m_haveMin); - } else if (tag == QLatin1String("max")) { + } else if (tag.compare(QLatin1String("max"), Qt::CaseInsensitive) == 0) { m_max = m_cdata.toInt(&m_haveMax); - } else if (tag == QLatin1String("choice")) { + } else if (tag.compare(QLatin1String("choice"), Qt::CaseInsensitive) == 0) { m_enumChoices.append(m_choice); m_inChoice = false; } m_cdata.clear(); return true; } void ConfigLoaderHandler::addItem() { if (m_name.isEmpty()) { if (m_key.isEmpty()) { return; } m_name = m_key; } m_name.remove(QLatin1Char(' ')); KConfigSkeletonItem *item = nullptr; if (m_type == QLatin1String("bool")) { bool defaultValue = m_default.toLower() == QLatin1String("true"); item = m_config->addItemBool(m_name, *d->newBool(), defaultValue, m_key); } else if (m_type == QLatin1String("color")) { item = m_config->addItemColor(m_name, *d->newColor(), QColor(m_default), m_key); } else if (m_type == QLatin1String("datetime")) { item = m_config->addItemDateTime(m_name, *d->newDateTime(), QDateTime::fromString(m_default), m_key); } else if (m_type == QLatin1String("enum")) { m_key = (m_key.isEmpty()) ? m_name : m_key; KConfigSkeleton::ItemEnum *enumItem = new KConfigSkeleton::ItemEnum(m_config->currentGroup(), m_key, *d->newInt(), m_enumChoices, m_default.toUInt()); m_config->addItem(enumItem, m_name); item = enumItem; } else if (m_type == QLatin1String("font")) { item = m_config->addItemFont(m_name, *d->newFont(), QFont(m_default), m_key); } else if (m_type == QLatin1String("int")) { KConfigSkeleton::ItemInt *intItem = m_config->addItemInt(m_name, *d->newInt(), m_default.toInt(), m_key); if (m_haveMin) { intItem->setMinValue(m_min); } if (m_haveMax) { intItem->setMaxValue(m_max); } item = intItem; } else if (m_type == QLatin1String("password")) { item = m_config->addItemPassword(m_name, *d->newString(), m_default, m_key); } else if (m_type == QLatin1String("path")) { item = m_config->addItemPath(m_name, *d->newString(), m_default, m_key); } else if (m_type == QLatin1String("string")) { item = m_config->addItemString(m_name, *d->newString(), m_default, m_key); } else if (m_type == QLatin1String("stringlist")) { //FIXME: the split() is naive and will break on lists with ,'s in them //empty parts are not wanted in this case item = m_config->addItemStringList(m_name, *d->newStringList(), m_default.split(QLatin1Char(','), QString::SkipEmptyParts), m_key); } else if (m_type == QLatin1String("uint")) { KConfigSkeleton::ItemUInt *uintItem = m_config->addItemUInt(m_name, *d->newUint(), m_default.toUInt(), m_key); if (m_haveMin) { uintItem->setMinValue(m_min); } if (m_haveMax) { uintItem->setMaxValue(m_max); } item = uintItem; } else if (m_type == QLatin1String("url")) { m_key = (m_key.isEmpty()) ? m_name : m_key; KConfigSkeleton::ItemUrl *urlItem = new KConfigSkeleton::ItemUrl(m_config->currentGroup(), m_key, *d->newUrl(), QUrl::fromUserInput(m_default)); m_config->addItem(urlItem, m_name); item = urlItem; } else if (m_type == QLatin1String("double")) { KConfigSkeleton::ItemDouble *doubleItem = m_config->addItemDouble(m_name, *d->newDouble(), m_default.toDouble(), m_key); if (m_haveMin) { doubleItem->setMinValue(m_min); } if (m_haveMax) { doubleItem->setMaxValue(m_max); } item = doubleItem; } else if (m_type == QLatin1String("intlist")) { const QStringList tmpList = m_default.split(QLatin1Char(',')); QList defaultList; for (const QString &tmp : tmpList) { defaultList.append(tmp.toInt()); } item = m_config->addItemIntList(m_name, *d->newIntList(), defaultList, m_key); } else if (m_type == QLatin1String("longlong")) { KConfigSkeleton::ItemLongLong *longlongItem = m_config->addItemLongLong(m_name, *d->newLongLong(), m_default.toLongLong(), m_key); if (m_haveMin) { longlongItem->setMinValue(m_min); } if (m_haveMax) { longlongItem->setMaxValue(m_max); } item = longlongItem; /* No addItemPathList in KConfigSkeleton ? } else if (m_type == "PathList") { //FIXME: the split() is naive and will break on lists with ,'s in them item = m_config->addItemPathList(m_name, *d->newStringList(), m_default.split(","), m_key); */ } else if (m_type == QLatin1String("point")) { QPoint defaultPoint; QStringList tmpList = m_default.split(QLatin1Char(',')); if (tmpList.size() >= 2) { defaultPoint.setX(tmpList[0].toInt()); defaultPoint.setY(tmpList[1].toInt()); } item = m_config->addItemPoint(m_name, *d->newPoint(), defaultPoint, m_key); } else if (m_type == QLatin1String("rect")) { QRect defaultRect; QStringList tmpList = m_default.split(QLatin1Char(',')); if (tmpList.size() >= 4) { defaultRect.setCoords(tmpList[0].toInt(), tmpList[1].toInt(), tmpList[2].toInt(), tmpList[3].toInt()); } item = m_config->addItemRect(m_name, *d->newRect(), defaultRect, m_key); } else if (m_type == QLatin1String("size")) { QSize defaultSize; QStringList tmpList = m_default.split(QLatin1Char(',')); if (tmpList.size() >= 2) { defaultSize.setWidth(tmpList[0].toInt()); defaultSize.setHeight(tmpList[1].toInt()); } item = m_config->addItemSize(m_name, *d->newSize(), defaultSize, m_key); } else if (m_type == QLatin1String("ulonglong")) { KConfigSkeleton::ItemULongLong *ulonglongItem = m_config->addItemULongLong(m_name, *d->newULongLong(), m_default.toULongLong(), m_key); if (m_haveMin) { ulonglongItem->setMinValue(m_min); } if (m_haveMax) { ulonglongItem->setMaxValue(m_max); } item = ulonglongItem; /* No addItemUrlList in KConfigSkeleton ? } else if (m_type == "urllist") { //FIXME: the split() is naive and will break on lists with ,'s in them QStringList tmpList = m_default.split(","); QList defaultList; foreach (const QString& tmp, tmpList) { defaultList.append(QUrl(tmp)); } item = m_config->addItemUrlList(m_name, *d->newUrlList(), defaultList, m_key);*/ } if (item) { item->setLabel(m_label); item->setWhatsThis(m_whatsThis); d->keysToNames.insert(item->group() + item->key(), item->name()); } } void ConfigLoaderHandler::resetState() { m_haveMin = false; m_min = 0; m_haveMax = false; m_max = 0; m_name.clear(); m_type.clear(); m_label.clear(); m_default.clear(); m_key.clear(); m_whatsThis.clear(); m_enumChoices.clear(); m_inChoice = false; } KConfigLoader::KConfigLoader(const QString &configFile, QIODevice *xml, QObject *parent) : KConfigSkeleton(configFile, parent), d(new ConfigLoaderPrivate) { d->parse(this, xml); } KConfigLoader::KConfigLoader(KSharedConfigPtr config, QIODevice *xml, QObject *parent) : KConfigSkeleton(std::move(config), parent), d(new ConfigLoaderPrivate) { d->parse(this, xml); } //FIXME: obviously this is broken and should be using the group as the root, // but KConfigSkeleton does not currently support this. it will eventually though, // at which point this can be addressed properly KConfigLoader::KConfigLoader(const KConfigGroup &config, QIODevice *xml, QObject *parent) : KConfigSkeleton(KSharedConfig::openConfig(config.config()->name(), config.config()->openFlags()), parent), d(new ConfigLoaderPrivate) { KConfigGroup group = config.parent(); d->baseGroup = config.name(); while (group.isValid() && group.name() != QLatin1String("")) { d->baseGroup = group.name() + QLatin1Char('\x1d') + d->baseGroup; group = group.parent(); } d->parse(this, xml); } KConfigLoader::~KConfigLoader() { delete d; } KConfigSkeletonItem *KConfigLoader::findItem(const QString &group, const QString &key) const { return KConfigSkeleton::findItem(d->keysToNames[group + key]); } KConfigSkeletonItem *KConfigLoader::findItemByName(const QString &name) const { return KConfigSkeleton::findItem(name); } QVariant KConfigLoader::property(const QString &name) const { KConfigSkeletonItem *item = KConfigSkeleton::findItem(name); if (item) { return item->property(); } return QVariant(); } bool KConfigLoader::hasGroup(const QString &group) const { return d->groups.contains(group); } QStringList KConfigLoader::groupList() const { return d->groups; } #if KCONFIGCORE_BUILD_DEPRECATED_SINCE(5, 0) bool KConfigLoader::usrWriteConfig() #else bool KConfigLoader::usrSave() #endif { if (d->saveDefaults) { const auto listItems = items(); for (const auto& item : listItems) { config()->group(item->group()).writeEntry(item->key(), ""); } } return true; } diff --git a/src/gui/kconfigloaderhandler_p.h b/src/gui/kconfigloaderhandler_p.h index cae9249..fa313f5 100644 --- a/src/gui/kconfigloaderhandler_p.h +++ b/src/gui/kconfigloaderhandler_p.h @@ -1,66 +1,69 @@ /* * Copyright 2007-2008 Aaron Seigo * Copyright 2013 Marco Martin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, or * (at your option) any later version. * * 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 * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KCONFIGLOADERHANDLER_P_H #define KCONFIGLOADERHANDLER_P_H -#include +#include -class ConfigLoaderHandler : public QXmlDefaultHandler +class ConfigLoaderHandler { public: ConfigLoaderHandler(KConfigLoader *config, ConfigLoaderPrivate *d); - bool startElement(const QString &namespaceURI, const QString &localName, - const QString &qName, const QXmlAttributes &atts) override; - bool endElement(const QString &namespaceURI, const QString &localName, - const QString &qName) override; - bool characters(const QString &ch) override; + + bool parse(QIODevice *input); + + bool startElement(const QStringRef &namespaceURI, const QStringRef &localName, + const QStringRef &qName, const QXmlStreamAttributes &atts); + bool endElement(const QStringRef &namespaceURI, const QStringRef &localName, + const QStringRef &qName); + bool characters(const QStringRef &ch); QString name() const; void setName(const QString &name); QString key() const; void setKey(const QString &name); QString type() const; QString defaultValue() const; private: - virtual void addItem(); + void addItem(); void resetState(); KConfigLoader *m_config; ConfigLoaderPrivate *d; int m_min; int m_max; QString m_name; QString m_key; QString m_type; QString m_label; QString m_default; QString m_cdata; QString m_whatsThis; KConfigSkeleton::ItemEnum::Choice m_choice; QList m_enumChoices; bool m_haveMin; bool m_haveMax; bool m_inChoice; }; #endif