/* * 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 "configxml.h" #include #include #include #include #include #include #include #include namespace Plasma { class ConfigXmlPrivate { public: ~ConfigXmlPrivate() { qDeleteAll(bools); qDeleteAll(strings); qDeleteAll(stringlists); qDeleteAll(colors); qDeleteAll(fonts); qDeleteAll(ints); qDeleteAll(uints); qDeleteAll(urls); qDeleteAll(dateTimes); qDeleteAll(doubles); qDeleteAll(intlists); qDeleteAll(longlongs); qDeleteAll(points); qDeleteAll(rects); qDeleteAll(sizes); qDeleteAll(ulonglongs); qDeleteAll(urllists); } bool* newBool() { bool* v = new bool; bools.append(v); return v; } QString* newString() { QString* v = new QString; strings.append(v); return v; } QStringList* newStringList() { QStringList* v = new QStringList; stringlists.append(v); return v; } QColor* newColor() { QColor* v = new QColor; colors.append(v); return v; } QFont* newFont() { QFont* v = new QFont; fonts.append(v); return v; } qint32* newInt() { qint32* v = new qint32; ints.append(v); return v; } quint32* newUint() { quint32* v = new quint32; uints.append(v); return v; } KUrl* newUrl() { KUrl* v = new KUrl; urls.append(v); return v; } QDateTime* newDateTime() { QDateTime* v = new QDateTime; dateTimes.append(v); return v; } double* newDouble() { double* v = new double; doubles.append(v); return v; } QList* newIntList() { QList* v = new QList; intlists.append(v); return v; } qint64* newLongLong() { qint64* v = new qint64; longlongs.append(v); return v; } QPoint* newPoint() { QPoint* v = new QPoint; points.append(v); return v; } QRect* newRect() { QRect* v = new QRect; rects.append(v); return v; } QSize* newSize() { QSize* v = new QSize; sizes.append(v); return v; } quint64* newULongLong() { quint64* v = new quint64; ulonglongs.append(v); return v; } KUrl::List* newUrlList() { KUrl::List* v = new KUrl::List; urllists.append(v); return v; } void parse(ConfigXml *configXml, QIODevice *xml); QList bools; QList strings; QList stringlists; QList colors; QList fonts; QList ints; QList uints; QList urls; QList dateTimes; QList doubles; QList*> intlists; QList longlongs; QList points; QList rects; QList sizes; QList ulonglongs; QList urllists; QStringList groups; QHash keysToNames; }; class ConfigXmlHandler : public QXmlDefaultHandler { public: ConfigXmlHandler(ConfigXml* config, ConfigXmlPrivate* d); bool startElement(const QString &namespaceURI, const QString & localName, const QString &qName, const QXmlAttributes &atts); bool endElement(const QString &namespaceURI, const QString &localName, const QString &qName); bool characters(const QString &ch); private: void addItem(); void resetState(); ConfigXml* m_config; ConfigXmlPrivate* 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; }; void ConfigXmlPrivate::parse(ConfigXml *configXml, QIODevice *xml) { QXmlInputSource source(xml); QXmlSimpleReader reader; ConfigXmlHandler handler(configXml, this); reader.setContentHandler(&handler); reader.parse(&source, false); } ConfigXmlHandler::ConfigXmlHandler(ConfigXml* config, ConfigXmlPrivate* d) : QXmlDefaultHandler(), m_config(config), d(d) { resetState(); } bool ConfigXmlHandler::startElement(const QString &namespaceURI, const QString &localName, const QString &qName, const QXmlAttributes &attrs) { Q_UNUSED(namespaceURI) Q_UNUSED(qName) // kDebug() << "ConfigXmlHandler::startElement(" << localName << qName; int numAttrs = attrs.count(); QString tag = localName.toLower(); if (tag == "group") { for (int i = 0; i < numAttrs; ++i) { QString name = attrs.localName(i).toLower(); if (name == "name") { kDebug() << "set group to " << attrs.value(i); d->groups.append(attrs.value(i)); m_config->setCurrentGroup(attrs.value(i)); } } } else if (tag == "entry") { for (int i = 0; i < numAttrs; ++i) { QString name = attrs.localName(i).toLower(); if (name == "name") { m_name = attrs.value(i); } else if (name == "type") { m_type = attrs.value(i).toLower(); } else if (name == "key") { m_key = attrs.value(i); } } } else if (tag == "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 == "name") { m_choice.name = attrs.value(i); } } m_inChoice = true; } return true; } bool ConfigXmlHandler::characters(const QString &ch) { m_cdata.append(ch); return true; } bool ConfigXmlHandler::endElement(const QString &namespaceURI, const QString &localName, const QString &qName) { Q_UNUSED(namespaceURI) Q_UNUSED(qName) // kDebug() << "ConfigXmlHandler::endElement(" << localName << qName; QString tag = localName.toLower(); if (tag == "entry") { addItem(); resetState(); } else if (tag == "label") { if (m_inChoice) { m_choice.label = m_cdata.trimmed(); } else { m_label = m_cdata.trimmed(); } } else if (tag == "whatsthis") { if (m_inChoice) { m_choice.whatsThis = m_cdata.trimmed(); } else { m_whatsThis = m_cdata.trimmed(); } } else if (tag == "default") { m_default = m_cdata.trimmed(); } else if (tag == "min") { m_min = m_cdata.toInt(&m_haveMin); } else if (tag == "max") { m_max = m_cdata.toInt(&m_haveMax); } else if (tag == "choice") { m_enumChoices.append(m_choice); m_inChoice = false; } m_cdata.clear(); return true; } void ConfigXmlHandler::addItem() { if (m_name.isEmpty()) { return; } KConfigSkeletonItem* item = 0; if (m_type == "bool") { bool defaultValue = m_default.toLower() == "true"; item = m_config->addItemBool(m_name, *d->newBool(), defaultValue, m_key); } else if (m_type == "color") { item = m_config->addItemColor(m_name, *d->newColor(), QColor(m_default), m_key); } else if (m_type == "datetime") { item = m_config->addItemDateTime(m_name, *d->newDateTime(), QDateTime::fromString(m_default), m_key); } else if (m_type == "enum") { KConfigSkeleton::ItemEnum* enumItem = new KConfigSkeleton::ItemEnum(m_config->currentGroup(), m_key, *d->newInt(), m_enumChoices, m_default.toUInt()); enumItem->setName(m_name); m_config->addItem(enumItem, m_name); item = enumItem; } else if (m_type == "font") { item = m_config->addItemFont(m_name, *d->newFont(), QFont(m_default), m_key); } else if (m_type == "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 == "password") { item = m_config->addItemPassword(m_name, *d->newString(), m_default, m_key); } else if (m_type == "path") { item = m_config->addItemPath(m_name, *d->newString(), m_default, m_key); } else if (m_type == "string") { item = m_config->addItemString(m_name, *d->newString(), m_default, m_key); } else if (m_type == "stringlist") { //FIXME: the split() is naive and will break on lists with ,'s in them item = m_config->addItemStringList(m_name, *d->newStringList(), m_default.split(","), m_key); } else if (m_type == "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 == "url") { KConfigSkeleton::ItemUrl* urlItem = new KConfigSkeleton::ItemUrl(m_config->currentGroup(), m_key, *d->newUrl(), m_default); urlItem->setName(m_name); m_config->addItem(urlItem, m_name); item = urlItem; } else if (m_type == "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 == "intlist") { QStringList tmpList = m_default.split(","); QList defaultList; foreach (const QString &tmp, tmpList) { defaultList.append(tmp.toInt()); } item = m_config->addItemIntList(m_name, *d->newIntList(), defaultList, m_key); } else if (m_type == "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 == "point") { QPoint defaultPoint; QStringList tmpList = m_default.split(","); while (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 == "rect") { QRect defaultRect; QStringList tmpList = m_default.split(","); while (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 == "size") { QSize defaultSize; QStringList tmpList = m_default.split(","); while (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 == "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(","); KUrl::List defaultList; foreach (const QString& tmp, tmpList) { defaultList.append(KUrl(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 ConfigXmlHandler::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; } ConfigXml::ConfigXml(const QString &configFile, QIODevice *xml, QObject *parent) : KConfigSkeleton(configFile, parent), d(new ConfigXmlPrivate) { d->parse(this, xml); } ConfigXml::ConfigXml(KSharedConfigPtr config, QIODevice *xml, QObject *parent) : KConfigSkeleton(config, parent), d(new ConfigXmlPrivate) { 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 ConfigXml::ConfigXml(const KConfigGroup *config, QIODevice *xml, QObject *parent) : KConfigSkeleton(KSharedConfig::openConfig(config->config()->name()), parent), d(new ConfigXmlPrivate) { d->parse(this, xml); } ConfigXml::~ConfigXml() { delete d; } KConfigSkeletonItem* ConfigXml::findItem(const QString &group, const QString &key) { return KConfigSkeleton::findItem(d->keysToNames[group + key]); } bool ConfigXml::hasGroup(const QString &group) const { return d->groups.contains(group); } QStringList ConfigXml::groupList() const { return d->groups; } } // Plasma namespace