kdelibs/kdecore/config/kconfiggroup.cpp
Ivailo Monev 91174d40d0 kdecore: drop support for config backends
there was only one now backend (INI) and changing it on the fly
(as was supported before) can cause serious issues with
applications misbihaving and such

Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
2016-03-28 07:00:48 +00:00

1217 lines
40 KiB
C++

/*
This file is part of the KDE libraries
Copyright (c) 2006, 2007 Thomas Braxton <kde.braxton@gmail.com>
Copyright (c) 1999 Preston Brown <pbrown@kde.org>
Copyright (c) 1997 Matthias Kalle Dalheimer <kalle@kde.org>
This library 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 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "kconfiggroup.h"
#include "kconfiggroup_p.h"
#include "kconfig.h"
#include "kconfig_p.h"
#include "ksharedconfig.h"
#include "kstringhandler.h"
#include "kcomponentdata.h"
#include "kconfigdata.h"
#include <kdebug.h>
#include <QtCore/QDateTime>
#include <QtCore/QSharedData>
#include <QtCore/QFile>
#include <QtCore/QPoint>
#include <QtCore/QRect>
#include <QtCore/QString>
#include <QtCore/QTextStream>
#include <QtCore/QDir>
#include <stdlib.h>
class KConfigGroupPrivate : public QSharedData
{
public:
KConfigGroupPrivate(KConfig* owner, bool isImmutable, bool isConst, const QByteArray &name)
: mOwner(owner), mName(name), bImmutable(isImmutable), bConst(isConst)
{
}
KConfigGroupPrivate(const KSharedConfigPtr &owner, const QByteArray& name)
: sOwner(owner), mOwner(sOwner.data()), mName(name),
bImmutable(name.isEmpty()? owner->isImmutable(): owner->isGroupImmutable(name)), bConst(false)
{
}
KConfigGroupPrivate(KConfigGroup* parent, bool isImmutable, bool isConst, const QByteArray& name)
: sOwner(parent->d->sOwner), mOwner(parent->d->mOwner), mName(name),
bImmutable(isImmutable), bConst(isConst)
{
if (!parent->d->mName.isEmpty())
mParent = parent->d;
}
KConfigGroupPrivate(const KConfigGroupPrivate* other, bool isImmutable, const QByteArray &name)
: sOwner(other->sOwner), mOwner(other->mOwner), mName(name),
bImmutable(isImmutable), bConst(other->bConst)
{
if (!other->mName.isEmpty())
mParent = const_cast<KConfigGroupPrivate *>(other);
}
KSharedConfig::Ptr sOwner;
KConfig *mOwner;
QExplicitlySharedDataPointer<KConfigGroupPrivate> mParent;
QByteArray mName;
/* bitfield */
const bool bImmutable:1; // is this group immutable?
const bool bConst:1; // is this group read-only?
QByteArray fullName() const
{
if (!mParent) {
return name();
}
return mParent->fullName(mName);
}
QByteArray name() const
{
if (mName.isEmpty())
return "<default>";
return mName;
}
QByteArray fullName(const QByteArray& aGroup) const
{
if (mName.isEmpty())
return aGroup;
return fullName() + '\x1d' + aGroup;
}
static QExplicitlySharedDataPointer<KConfigGroupPrivate> create(KConfigBase *master,
const QByteArray &name,
bool isImmutable,
bool isConst)
{
QExplicitlySharedDataPointer<KConfigGroupPrivate> data;
if (dynamic_cast<KConfigGroup*>(master))
data = new KConfigGroupPrivate(dynamic_cast<KConfigGroup*>(master), isImmutable, isConst, name);
else
data = new KConfigGroupPrivate(dynamic_cast<KConfig*>(master), isImmutable, isConst, name);
return data;
}
static QByteArray serializeList(const QList<QByteArray> &list);
static QStringList deserializeList(const QString &data);
};
QByteArray KConfigGroupPrivate::serializeList(const QList<QByteArray> &list)
{
QByteArray value = "";
if (!list.isEmpty()) {
QList<QByteArray>::ConstIterator it = list.constBegin();
const QList<QByteArray>::ConstIterator end = list.constEnd();
value = QByteArray(*it).replace('\\', "\\\\").replace(',', "\\,");
while (++it != end) {
// In the loop, so it is not done when there is only one element.
// Doing it repeatedly is a pretty cheap operation.
value.reserve(4096);
value += ',';
value += QByteArray(*it).replace('\\', "\\\\").replace(',', "\\,");
}
// To be able to distinguish an empty list from a list with one empty element.
if (value.isEmpty())
value = "\\0";
}
return value;
}
QStringList KConfigGroupPrivate::deserializeList(const QString &data)
{
if (data.isEmpty())
return QStringList();
if (data == QLatin1String("\\0"))
return QStringList(QString());
QStringList value;
QString val;
val.reserve(data.size());
bool quoted = false;
for (int p = 0; p < data.length(); p++) {
if (quoted) {
val += data[p];
quoted = false;
} else if (data[p].unicode() == '\\') {
quoted = true;
} else if (data[p].unicode() == ',') {
val.squeeze(); // release any unused memory
value.append(val);
val.clear();
val.reserve(data.size() - p);
} else {
val += data[p];
}
}
value.append(val);
return value;
}
static QList<int> asIntList(const QByteArray& string)
{
QList<int> list;
Q_FOREACH(const QByteArray& s, string.split(','))
list << s.toInt();
return list;
}
static QList<qreal> asRealList(const QByteArray& string)
{
QList<qreal> list;
Q_FOREACH(const QByteArray& s, string.split(','))
list << s.toDouble();
return list;
}
static QString errString( const char * pKey, const QByteArray & value, const QVariant & aDefault ) {
return QString::fromLatin1("\"%1\" - conversion of \"%3\" to %2 failed")
.arg(QString::fromLatin1(pKey))
.arg(QString::fromLatin1(QVariant::typeToName(aDefault.type())))
.arg(QString::fromLatin1(value));
}
static QString formatError( int expected, int got ) {
return QString::fromLatin1(" (wrong format: expected %1 items, got %2)").arg( expected ).arg( got );
}
QVariant KConfigGroup::convertToQVariant(const char *pKey, const QByteArray& value, const QVariant& aDefault)
{
switch( aDefault.type() ) {
case QVariant::Invalid:
return QVariant();
case QVariant::String:
// this should return the raw string not the dollar expanded string.
// imho if processed string is wanted should call
// readEntry(key, QString) not readEntry(key, QVariant)
return QString::fromUtf8(value);
case QVariant::List:
case QVariant::StringList:
return KConfigGroupPrivate::deserializeList(QString::fromUtf8(value));
case QVariant::ByteArray:
return value;
case QVariant::Bool: {
const QByteArray lower(value.toLower());
if (lower == "false" || lower == "no" || lower == "off" || lower == "0")
return false;
return true;
}
case QVariant::Double:
case QMetaType::Float:
case QVariant::Int:
case QVariant::UInt:
case QVariant::LongLong:
case QVariant::ULongLong: {
QVariant tmp = value;
if ( !tmp.convert(aDefault.type()) )
tmp = aDefault;
return tmp;
}
case QVariant::Point: {
const QList<int> list = asIntList(value);
if ( list.count() != 2 ) {
kError() << errString( pKey, value, aDefault )
<< formatError( 2, list.count() );
return aDefault;
}
return QPoint(list.at( 0 ), list.at( 1 ));
}
case QVariant::PointF: {
const QList<qreal> list = asRealList(value);
if ( list.count() != 2 ) {
kError() << errString( pKey, value, aDefault )
<< formatError( 2, list.count() );
return aDefault;
}
return QPointF(list.at( 0 ), list.at( 1 ));
}
case QVariant::Rect: {
const QList<int> list = asIntList(value);
if ( list.count() != 4 ) {
kError() << errString( pKey, value, aDefault )
<< formatError( 4, list.count() );
return aDefault;
}
const QRect rect(list.at( 0 ), list.at( 1 ), list.at( 2 ), list.at( 3 ));
if ( !rect.isValid() ) {
kError() << errString( pKey, value, aDefault );
return aDefault;
}
return rect;
}
case QVariant::RectF: {
const QList<qreal> list = asRealList(value);
if ( list.count() != 4 ) {
kError() << errString( pKey, value, aDefault )
<< formatError( 4, list.count() );
return aDefault;
}
const QRectF rect(list.at( 0 ), list.at( 1 ), list.at( 2 ), list.at( 3 ));
if ( !rect.isValid() ) {
kError() << errString( pKey, value, aDefault );
return aDefault;
}
return rect;
}
case QVariant::Size: {
const QList<int> list = asIntList(value);
if ( list.count() != 2 ) {
kError() << errString( pKey, value, aDefault )
<< formatError( 2, list.count() );
return aDefault;
}
const QSize size(list.at( 0 ), list.at( 1 ));
if ( !size.isValid() ) {
kError() << errString( pKey, value, aDefault );
return aDefault;
}
return size;
}
case QVariant::SizeF: {
const QList<qreal> list = asRealList(value);
if ( list.count() != 2 ) {
kError() << errString( pKey, value, aDefault )
<< formatError( 2, list.count() );
return aDefault;
}
const QSizeF size(list.at( 0 ), list.at( 1 ));
if ( !size.isValid() ) {
kError() << errString( pKey, value, aDefault );
return aDefault;
}
return size;
}
case QVariant::DateTime: {
const QList<int> list = asIntList(value);
if ( list.count() != 6 ) {
kError() << errString( pKey, value, aDefault )
<< formatError( 6, list.count() );
return aDefault;
}
const QDate date( list.at( 0 ), list.at( 1 ), list.at( 2 ) );
const QTime time( list.at( 3 ), list.at( 4 ), list.at( 5 ) );
const QDateTime dt( date, time );
if ( !dt.isValid() ) {
kError() << errString( pKey, value, aDefault );
return aDefault;
}
return dt;
}
case QVariant::Date: {
QList<int> list = asIntList(value);
if ( list.count() == 6 )
list = list.mid(0, 3); // don't break config files that stored QDate as QDateTime
if ( list.count() != 3 ) {
kError() << errString( pKey, value, aDefault )
<< formatError( 3, list.count() );
return aDefault;
}
const QDate date( list.at( 0 ), list.at( 1 ), list.at( 2 ) );
if ( !date.isValid() ) {
kError() << errString( pKey, value, aDefault );
return aDefault;
}
return date;
}
case QVariant::Color:
case QVariant::Font:
kWarning() << "KConfigGroup::readEntry was passed GUI type '"
<< aDefault.typeName()
<< "' but kdeui isn't linked! If it is linked to your program, "
"this is a platform bug. Please inform the KDE developers";
break;
case QVariant::Url:
return QUrl(QString::fromUtf8(value));
default:
if( aDefault.canConvert<KUrl>() ) {
const KUrl url(QString::fromUtf8(value));
return qVariantFromValue<KUrl>( url );
}
break;
}
kWarning() << "unhandled type " << aDefault.typeName();
return QVariant();
}
static bool cleanHomeDirPath( QString &path, const QString &homeDir )
{
if (!path.startsWith(homeDir))
return false;
int len = homeDir.length();
// replace by "$HOME" if possible
if (len && (path.length() == len || path[len] == QLatin1Char('/'))) {
path.replace(0, len, QString::fromLatin1("$HOME"));
return true;
} else
return false;
}
static QString translatePath( QString path ) // krazy:exclude=passbyvalue
{
if (path.isEmpty())
return path;
// only "our" $HOME should be interpreted
path.replace(QLatin1Char('$'), QLatin1String("$$"));
bool startsWithFile = path.startsWith(QLatin1String("file:"), Qt::CaseInsensitive);
// return original path, if it refers to another type of URL (e.g. http:/), or
// if the path is already relative to another directory
if ((!startsWithFile && QFileInfo(path).isRelative()) ||
(startsWithFile && QFileInfo(path.mid(5)).isRelative()))
return path;
if (startsWithFile)
path.remove(0,5); // strip leading "file:/" off the string
// keep only one single '/' at the beginning - needed for cleanHomeDirPath()
while (path[0] == QLatin1Char('/') && path[1] == QLatin1Char('/'))
path.remove(0,1);
// we can not use KGlobal::dirs()->relativeLocation("home", path) here,
// since it would not recognize paths without a trailing '/'.
// All of the 3 following functions to return the user's home directory
// can return different paths. We have to test all them.
const QString homeDir0 = QFile::decodeName(qgetenv("HOME"));
const QString homeDir1 = QDir::homePath();
const QString homeDir2 = QDir(homeDir1).canonicalPath();
if (cleanHomeDirPath(path, homeDir0) ||
cleanHomeDirPath(path, homeDir1) ||
cleanHomeDirPath(path, homeDir2) ) {
// kDebug() << "Path was replaced\n";
}
if (startsWithFile)
path.prepend(QString::fromLatin1("file://"));
return path;
}
KConfigGroup::KConfigGroup() : d(0)
{
}
bool KConfigGroup::isValid() const
{
return 0 != d.constData();
}
KConfigGroupGui _kde_internal_KConfigGroupGui;
static inline bool readEntryGui(const QByteArray& data, const char* key, const QVariant &input,
QVariant &output)
{
if (_kde_internal_KConfigGroupGui.readEntryGui)
return _kde_internal_KConfigGroupGui.readEntryGui(data, key, input, output);
return false;
}
static inline bool writeEntryGui(KConfigGroup *cg, const char* key, const QVariant &input,
KConfigGroup::WriteConfigFlags flags)
{
if (_kde_internal_KConfigGroupGui.writeEntryGui)
return _kde_internal_KConfigGroupGui.writeEntryGui(cg, key, input, flags);
return false;
}
KConfigGroup::KConfigGroup(KConfigBase *master, const QString &_group)
: d(KConfigGroupPrivate::create(master, _group.toUtf8(), master->isGroupImmutable(_group), false))
{
}
KConfigGroup::KConfigGroup(KConfigBase *master, const char *_group)
: d(KConfigGroupPrivate::create(master, _group, master->isGroupImmutable(_group), false))
{
}
KConfigGroup::KConfigGroup(const KConfigBase *master, const QString &_group)
: d(KConfigGroupPrivate::create(const_cast<KConfigBase*>(master), _group.toUtf8(), master->isGroupImmutable(_group), true))
{
}
KConfigGroup::KConfigGroup(const KConfigBase *master, const char * _group)
: d(KConfigGroupPrivate::create(const_cast<KConfigBase*>(master), _group, master->isGroupImmutable(_group), true))
{
}
KConfigGroup::KConfigGroup(const KSharedConfigPtr &master, const QString &_group)
: d(new KConfigGroupPrivate(master, _group.toUtf8()))
{
}
KConfigGroup::KConfigGroup(const KSharedConfigPtr &master, const char * _group)
: d(new KConfigGroupPrivate(master, _group))
{
}
KConfigGroup &KConfigGroup::operator=(const KConfigGroup &rhs)
{
d = rhs.d;
return *this;
}
KConfigGroup::KConfigGroup(const KConfigGroup &rhs)
: KConfigBase(), d(rhs.d)
{
}
KConfigGroup::~KConfigGroup()
{
d = 0;
}
KConfigGroup KConfigGroup::groupImpl(const QByteArray& aGroup)
{
Q_ASSERT_X(isValid(), "KConfigGroup::groupImpl", "accessing an invalid group");
Q_ASSERT_X(!aGroup.isEmpty(), "KConfigGroup::groupImpl", "can not have an unnamed child group");
KConfigGroup newGroup;
newGroup.d = new KConfigGroupPrivate(this, isGroupImmutableImpl(aGroup), d->bConst, aGroup);
return newGroup;
}
const KConfigGroup KConfigGroup::groupImpl(const QByteArray& aGroup) const
{
Q_ASSERT_X(isValid(), "KConfigGroup::groupImpl", "accessing an invalid group");
Q_ASSERT_X(!aGroup.isEmpty(), "KConfigGroup::groupImpl", "can not have an unnamed child group");
KConfigGroup newGroup;
newGroup.d = new KConfigGroupPrivate(const_cast<KConfigGroup*>(this), isGroupImmutableImpl(aGroup),
true, aGroup);
return newGroup;
}
KConfigGroup KConfigGroup::parent() const
{
Q_ASSERT_X(isValid(), "KConfigGroup::parent", "accessing an invalid group");
KConfigGroup parentGroup;
if (d->mParent) {
parentGroup.d = d->mParent;
} else {
parentGroup.d = new KConfigGroupPrivate(d->mOwner, d->mOwner->isImmutable(), d->bConst, "");
// make sure we keep the refcount up on the KConfig object
parentGroup.d->sOwner = d->sOwner;
}
return parentGroup;
}
void KConfigGroup::deleteGroup(WriteConfigFlags flags)
{
Q_ASSERT_X(isValid(), "KConfigGroup::deleteGroup", "accessing an invalid group");
Q_ASSERT_X(!d->bConst, "KConfigGroup::deleteGroup", "deleting a read-only group");
config()->deleteGroup(d->fullName(), flags);
}
QString KConfigGroup::name() const
{
Q_ASSERT_X(isValid(), "KConfigGroup::name", "accessing an invalid group");
return QString::fromUtf8(d->name());
}
bool KConfigGroup::exists() const
{
Q_ASSERT_X(isValid(), "KConfigGroup::exists", "accessing an invalid group");
return config()->hasGroup( d->fullName() );
}
void KConfigGroup::sync()
{
Q_ASSERT_X(isValid(), "KConfigGroup::sync", "accessing an invalid group");
if (!d->bConst)
config()->sync();
}
QMap<QString, QString> KConfigGroup::entryMap() const
{
Q_ASSERT_X(isValid(), "KConfigGroup::entryMap", "accessing an invalid group");
return config()->entryMap(QString::fromUtf8(d->fullName()));
}
KConfig* KConfigGroup::config()
{
Q_ASSERT_X(isValid(), "KConfigGroup::config", "accessing an invalid group");
return d->mOwner;
}
const KConfig* KConfigGroup::config() const
{
Q_ASSERT_X(isValid(), "KConfigGroup::config", "accessing an invalid group");
return d->mOwner;
}
bool KConfigGroup::isEntryImmutable(const char* key) const
{
Q_ASSERT_X(isValid(), "KConfigGroup::isEntryImmutable", "accessing an invalid group");
return (isImmutable() ||
!config()->d_func()->canWriteEntry(d->fullName(), key, config()->readDefaults()));
}
bool KConfigGroup::isEntryImmutable(const QString& key) const
{
return isEntryImmutable(key.toUtf8().constData());
}
QString KConfigGroup::readEntryUntranslated(const QString& pKey, const QString& aDefault) const
{
return readEntryUntranslated(pKey.toUtf8().constData(), aDefault);
}
QString KConfigGroup::readEntryUntranslated(const char *key, const QString& aDefault) const
{
Q_ASSERT_X(isValid(), "KConfigGroup::readEntryUntranslated", "accessing an invalid group");
QString result = config()->d_func()->lookupData(d->fullName(), key, KEntryMap::SearchFlags(), 0);
if (result.isNull())
return aDefault;
return result;
}
QString KConfigGroup::readEntry(const char *key, const char* aDefault) const
{
return readEntry(key, QString::fromUtf8(aDefault));
}
QString KConfigGroup::readEntry(const QString &key, const char* aDefault) const
{
return readEntry(key.toUtf8().constData(), aDefault);
}
QString KConfigGroup::readEntry(const char* key, const QString& aDefault) const
{
Q_ASSERT_X(isValid(), "KConfigGroup::readEntry", "accessing an invalid group");
bool expand = false;
// read value from the entry map
QString aValue = config()->d_func()->lookupData(d->fullName(), key, KEntryMap::SearchLocalized,
&expand);
if (aValue.isNull())
aValue = aDefault;
if (expand)
return KConfigPrivate::expandString(aValue);
return aValue;
}
QString KConfigGroup::readEntry(const QString &key, const QString& aDefault) const
{
return readEntry(key.toUtf8().constData(), aDefault);
}
QStringList KConfigGroup::readEntry(const char* key, const QStringList& aDefault) const
{
Q_ASSERT_X(isValid(), "KConfigGroup::readEntry", "accessing an invalid group");
const QString data = readEntry(key, QString());
if (data.isNull())
return aDefault;
return KConfigGroupPrivate::deserializeList(data);
}
QStringList KConfigGroup::readEntry( const QString& key, const QStringList& aDefault) const
{
return readEntry( key.toUtf8().constData(), aDefault );
}
QVariant KConfigGroup::readEntry( const char* key, const QVariant &aDefault ) const
{
Q_ASSERT_X(isValid(), "KConfigGroup::readEntry", "accessing an invalid group");
const QByteArray data = config()->d_func()->lookupData(d->fullName(), key, KEntryMap::SearchLocalized);
if (data.isNull())
return aDefault;
QVariant value;
if (!readEntryGui( data, key, aDefault, value ))
return convertToQVariant(key, data, aDefault);
return value;
}
QVariant KConfigGroup::readEntry( const QString& key, const QVariant& aDefault) const
{
return readEntry( key.toUtf8().constData(), aDefault );
}
QVariantList KConfigGroup::readEntry( const char* key, const QVariantList& aDefault) const
{
Q_ASSERT_X(isValid(), "KConfigGroup::readEntry", "accessing an invalid group");
const QString data = readEntry(key, QString());
if (data.isNull())
return aDefault;
QVariantList value;
foreach(const QString& v, KConfigGroupPrivate::deserializeList(data))
value << v;
return value;
}
QVariantList KConfigGroup::readEntry( const QString& key, const QVariantList& aDefault) const
{
return readEntry( key.toUtf8().constData(), aDefault );
}
QStringList KConfigGroup::readXdgListEntry(const QString& key, const QStringList& aDefault) const
{
return readXdgListEntry(key.toUtf8().constData(), aDefault);
}
QStringList KConfigGroup::readXdgListEntry(const char *key, const QStringList& aDefault) const
{
Q_ASSERT_X(isValid(), "KConfigGroup::readXdgListEntry", "accessing an invalid group");
const QString data = readEntry(key, QString());
if (data.isNull())
return aDefault;
QStringList value;
QString val;
val.reserve(data.size());
// XXX List serialization being a separate layer from low-level parsing is
// probably a bug. No affected entries are defined, though.
bool quoted = false;
for (int p = 0; p < data.length(); p++) {
if (quoted) {
val += data[p];
quoted = false;
} else if (data[p] == QLatin1Char('\\')) {
quoted = true;
} else if (data[p] == QLatin1Char(';')) {
value.append(val);
val.clear();
val.reserve(data.size() - p);
} else {
val += data[p];
}
}
if (!val.isEmpty()) {
value.append(val);
}
return value;
}
QString KConfigGroup::readPathEntry(const QString& pKey, const QString & aDefault) const
{
return readPathEntry(pKey.toUtf8().constData(), aDefault);
}
QString KConfigGroup::readPathEntry(const char *key, const QString & aDefault) const
{
Q_ASSERT_X(isValid(), "KConfigGroup::readPathEntry", "accessing an invalid group");
bool expand = false;
QString aValue = config()->d_func()->lookupData(d->fullName(), key, KEntryMap::SearchLocalized,
&expand);
if (aValue.isNull())
aValue = aDefault;
return KConfigPrivate::expandString(aValue);
}
QStringList KConfigGroup::readPathEntry(const QString& pKey, const QStringList& aDefault) const
{
return readPathEntry(pKey.toUtf8().constData(), aDefault);
}
QStringList KConfigGroup::readPathEntry(const char *key, const QStringList& aDefault) const
{
Q_ASSERT_X(isValid(), "KConfigGroup::readPathEntry", "accessing an invalid group");
const QString data = readPathEntry(key, QString());
if (data.isNull())
return aDefault;
return KConfigGroupPrivate::deserializeList(data);
}
void KConfigGroup::writeEntry( const char* key, const QString& value, WriteConfigFlags flags )
{
Q_ASSERT_X(isValid(), "KConfigGroup::writeEntry", "accessing an invalid group");
Q_ASSERT_X(!d->bConst, "KConfigGroup::writeEntry", "writing to a read-only group");
writeEntry(key, value.toUtf8(), flags);
}
void KConfigGroup::writeEntry( const QString& key, const QString& value, WriteConfigFlags flags )
{
writeEntry(key.toUtf8().constData(), value, flags);
}
void KConfigGroup::writeEntry(const QString &key, const char *value, WriteConfigFlags pFlags)
{
Q_ASSERT_X(isValid(), "KConfigGroup::writeEntry", "accessing an invalid group");
Q_ASSERT_X(!d->bConst, "KConfigGroup::writeEntry", "writing to a read-only group");
writeEntry(key.toUtf8().constData(), QVariant(QString::fromLatin1(value)), pFlags);
}
void KConfigGroup::writeEntry(const char *key, const char *value, WriteConfigFlags pFlags)
{
writeEntry(key, QVariant(QString::fromLatin1(value)), pFlags);
}
void KConfigGroup::writeEntry( const char* key, const QByteArray& value,
WriteConfigFlags flags )
{
Q_ASSERT_X(isValid(), "KConfigGroup::writeEntry", "accessing an invalid group");
Q_ASSERT_X(!d->bConst, "KConfigGroup::writeEntry", "writing to a read-only group");
config()->d_func()->putData(d->fullName(), key, value.isNull()? QByteArray(""): value, flags);
}
void KConfigGroup::writeEntry(const QString& key, const QByteArray& value,
WriteConfigFlags pFlags)
{
writeEntry(key.toUtf8().constData(), value, pFlags);
}
void KConfigGroup::writeEntry(const char* key, const QStringList &list, WriteConfigFlags flags)
{
Q_ASSERT_X(isValid(), "KConfigGroup::writeEntry", "accessing an invalid group");
Q_ASSERT_X(!d->bConst, "KConfigGroup::writeEntry", "writing to a read-only group");
QList<QByteArray> balist;
foreach(const QString &entry, list)
balist.append(entry.toUtf8());
writeEntry(key, KConfigGroupPrivate::serializeList(balist), flags);
}
void KConfigGroup::writeEntry(const QString& key, const QStringList &list, WriteConfigFlags flags)
{
writeEntry(key.toUtf8().constData(), list, flags);
}
void KConfigGroup::writeEntry( const char* key, const QVariantList& list, WriteConfigFlags flags )
{
Q_ASSERT_X(isValid(), "KConfigGroup::writeEntry", "accessing an invalid group");
Q_ASSERT_X(!d->bConst, "KConfigGroup::writeEntry", "writing to a read-only group");
QList<QByteArray> data;
foreach(const QVariant& v, list) {
if (v.type() == QVariant::ByteArray)
data << v.toByteArray();
else
data << v.toString().toUtf8();
}
writeEntry(key, KConfigGroupPrivate::serializeList(data), flags);
}
void KConfigGroup::writeEntry( const char* key, const QVariant &value,
WriteConfigFlags flags )
{
Q_ASSERT_X(isValid(), "KConfigGroup::writeEntry", "accessing an invalid group");
Q_ASSERT_X(!d->bConst, "KConfigGroup::writeEntry", "writing to a read-only group");
if ( writeEntryGui( this, key, value, flags ) )
return; // GUI type that was handled
QByteArray data;
switch( value.type() ) {
case QVariant::Invalid:
data = "";
break;
case QVariant::ByteArray:
data = value.toByteArray();
break;
case QVariant::String:
case QVariant::Int:
case QVariant::UInt:
case QVariant::Double:
case QMetaType::Float:
case QVariant::Bool:
case QVariant::LongLong:
case QVariant::ULongLong:
data = value.toString().toUtf8();
break;
case QVariant::List:
kError(!value.canConvert(QVariant::StringList))
<< "not all types in \"" << key << "\" can convert to QString,"
" information will be lost";
case QVariant::StringList:
writeEntry( key, value.toList(), flags );
return;
case QVariant::Point: {
QVariantList list;
const QPoint rPoint = value.toPoint();
list.insert( 0, rPoint.x() );
list.insert( 1, rPoint.y() );
writeEntry( key, list, flags );
return;
}
case QVariant::PointF: {
QVariantList list;
const QPointF point = value.toPointF();
list.insert( 0, point.x() );
list.insert( 1, point.y() );
writeEntry( key, list, flags );
return;
}
case QVariant::Rect:{
QVariantList list;
const QRect rRect = value.toRect();
list.insert( 0, rRect.left() );
list.insert( 1, rRect.top() );
list.insert( 2, rRect.width() );
list.insert( 3, rRect.height() );
writeEntry( key, list, flags );
return;
}
case QVariant::RectF:{
QVariantList list;
const QRectF rRectF = value.toRectF();
list.insert(0, rRectF.left());
list.insert(1, rRectF.top());
list.insert(2, rRectF.width());
list.insert(3, rRectF.height());
writeEntry(key, list, flags);
return;
}
case QVariant::Size:{
QVariantList list;
const QSize rSize = value.toSize();
list.insert( 0, rSize.width() );
list.insert( 1, rSize.height() );
writeEntry( key, list, flags );
return;
}
case QVariant::SizeF:{
QVariantList list;
const QSizeF rSizeF = value.toSizeF();
list.insert(0, rSizeF.width());
list.insert(1, rSizeF.height());
writeEntry(key, list, flags);
return;
}
case QVariant::Date: {
QVariantList list;
const QDate date = value.toDate();
list.insert( 0, date.year() );
list.insert( 1, date.month() );
list.insert( 2, date.day() );
writeEntry( key, list, flags );
return;
}
case QVariant::DateTime: {
QVariantList list;
const QDateTime rDateTime = value.toDateTime();
const QTime time = rDateTime.time();
const QDate date = rDateTime.date();
list.insert( 0, date.year() );
list.insert( 1, date.month() );
list.insert( 2, date.day() );
list.insert( 3, time.hour() );
list.insert( 4, time.minute() );
list.insert( 5, time.second() );
writeEntry( key, list, flags );
return;
}
case QVariant::Color:
case QVariant::Font:
kWarning() << "KConfigGroup::writeEntry was passed GUI type '"
<< value.typeName()
<< "' but kdeui isn't linked! If it is linked to your program, this is a platform bug. "
"Please inform the KDE developers";
break;
case QVariant::Url:
data = KUrl(value.toUrl()).url().toUtf8();
break;
default:
if( value.canConvert<KUrl>() ) {
data = qvariant_cast<KUrl>(value).url().toUtf8();
break;
}
kWarning() << "KConfigGroup::writeEntry - unhandled type" << value.typeName() << "in group" << name();
}
writeEntry(key, data, flags);
}
void KConfigGroup::writeEntry( const QString& key, const QVariant& value, WriteConfigFlags flags )
{
writeEntry(key.toUtf8().constData(), value, flags);
}
void KConfigGroup::writeEntry(const QString& key, const QVariantList &list, WriteConfigFlags flags)
{
writeEntry(key.toUtf8().constData(), list, flags);
}
void KConfigGroup::writeXdgListEntry(const QString& key, const QStringList &value, WriteConfigFlags pFlags)
{
writeXdgListEntry(key.toUtf8().constData(), value, pFlags);
}
void KConfigGroup::writeXdgListEntry(const char *key, const QStringList &list, WriteConfigFlags flags)
{
Q_ASSERT_X(isValid(), "KConfigGroup::writeXdgListEntry", "accessing an invalid group");
Q_ASSERT_X(!d->bConst, "KConfigGroup::writeXdgListEntry", "writing to a read-only group");
QString value;
value.reserve(4096);
// XXX List serialization being a separate layer from low-level escaping is
// probably a bug. No affected entries are defined, though.
QStringList::ConstIterator it = list.constBegin();
const QStringList::ConstIterator end = list.constEnd();
for (; it != end; ++it) {
QString val(*it);
val.replace(QLatin1Char('\\'), QLatin1String("\\\\")).replace(QLatin1Char(';'), QLatin1String("\\;"));
value += val;
value += QLatin1Char(';');
}
writeEntry(key, value, flags);
}
void KConfigGroup::writePathEntry(const QString& pKey, const QString & path, WriteConfigFlags pFlags)
{
writePathEntry(pKey.toUtf8().constData(), path, pFlags);
}
void KConfigGroup::writePathEntry(const char *pKey, const QString & path, WriteConfigFlags pFlags)
{
Q_ASSERT_X(isValid(), "KConfigGroup::writePathEntry", "accessing an invalid group");
Q_ASSERT_X(!d->bConst, "KConfigGroup::writePathEntry", "writing to a read-only group");
config()->d_func()->putData(d->fullName(), pKey, translatePath(path).toUtf8(), pFlags, true);
}
void KConfigGroup::writePathEntry(const QString& pKey, const QStringList &value, WriteConfigFlags pFlags)
{
writePathEntry(pKey.toUtf8().constData(), value, pFlags);
}
void KConfigGroup::writePathEntry(const char *pKey, const QStringList &value, WriteConfigFlags pFlags)
{
Q_ASSERT_X(isValid(), "KConfigGroup::writePathEntry", "accessing an invalid group");
Q_ASSERT_X(!d->bConst, "KConfigGroup::writePathEntry", "writing to a read-only group");
QList<QByteArray> list;
foreach(const QString& path, value)
list << translatePath(path).toUtf8();
config()->d_func()->putData(d->fullName(), pKey, KConfigGroupPrivate::serializeList(list), pFlags, true);
}
void KConfigGroup::deleteEntry( const char *key, WriteConfigFlags flags)
{
Q_ASSERT_X(isValid(), "KConfigGroup::deleteEntry", "accessing an invalid group");
Q_ASSERT_X(!d->bConst, "KConfigGroup::deleteEntry", "deleting from a read-only group");
config()->d_func()->putData(d->fullName(), key, QByteArray(), flags);
}
void KConfigGroup::deleteEntry( const QString& key, WriteConfigFlags flags)
{
deleteEntry(key.toUtf8().constData(), flags);
}
void KConfigGroup::revertToDefault(const char *key)
{
Q_ASSERT_X(isValid(), "KConfigGroup::revertToDefault", "accessing an invalid group");
Q_ASSERT_X(!d->bConst, "KConfigGroup::revertToDefault", "writing to a read-only group");
config()->d_func()->revertEntry(d->fullName(), key);
}
void KConfigGroup::revertToDefault(const QString &key)
{
revertToDefault(key.toUtf8().constData());
}
bool KConfigGroup::hasDefault(const char *key) const
{
Q_ASSERT_X(isValid(), "KConfigGroup::hasDefault", "accessing an invalid group");
KEntryMap::SearchFlags flags = KEntryMap::SearchDefaults|KEntryMap::SearchLocalized;
return !config()->d_func()->lookupData(d->fullName(), key, flags).isNull();
}
bool KConfigGroup::hasDefault(const QString &key) const
{
return hasDefault(key.toUtf8().constData());
}
bool KConfigGroup::hasKey(const char *key) const
{
Q_ASSERT_X(isValid(), "KConfigGroup::hasKey", "accessing an invalid group");
KEntryMap::SearchFlags flags = KEntryMap::SearchLocalized;
if ( config()->readDefaults() )
flags |= KEntryMap::SearchDefaults;
return !config()->d_func()->lookupData(d->fullName(), key, flags).isNull();
}
bool KConfigGroup::hasKey(const QString &key) const
{
return hasKey(key.toUtf8().constData());
}
bool KConfigGroup::isImmutable() const
{
Q_ASSERT_X(isValid(), "KConfigGroup::isImmutable", "accessing an invalid group");
return d->bImmutable;
}
QStringList KConfigGroup::groupList() const
{
Q_ASSERT_X(isValid(), "KConfigGroup::groupList", "accessing an invalid group");
return config()->d_func()->groupList(d->fullName());
}
QStringList KConfigGroup::keyList() const
{
Q_ASSERT_X(isValid(), "KConfigGroup::keyList", "accessing an invalid group");
return entryMap().keys();
}
void KConfigGroup::markAsClean()
{
Q_ASSERT_X(isValid(), "KConfigGroup::markAsClean", "accessing an invalid group");
config()->markAsClean();
}
KConfigGroup::AccessMode KConfigGroup::accessMode() const
{
Q_ASSERT_X(isValid(), "KConfigGroup::accessMode", "accessing an invalid group");
return config()->accessMode();
}
bool KConfigGroup::hasGroupImpl(const QByteArray & b) const
{
Q_ASSERT_X(isValid(), "KConfigGroup::hasGroupImpl", "accessing an invalid group");
return config()->hasGroup(d->fullName(b));
}
void KConfigGroup::deleteGroupImpl(const QByteArray &b, WriteConfigFlags flags)
{
Q_ASSERT_X(isValid(), "KConfigGroup::deleteGroupImpl", "accessing an invalid group");
Q_ASSERT_X(!d->bConst,"KConfigGroup::deleteGroupImpl", "deleting from a read-only group");
config()->deleteGroup(d->fullName(b), flags);
}
bool KConfigGroup::isGroupImmutableImpl(const QByteArray& b) const
{
Q_ASSERT_X(isValid(), "KConfigGroup::isGroupImmutableImpl", "accessing an invalid group");
if (!hasGroupImpl(b)) // group doesn't exist yet
return d->bImmutable; // child groups are immutable if the parent is immutable.
return config()->isGroupImmutable(d->fullName(b));
}
void KConfigGroup::copyTo(KConfigBase* other, WriteConfigFlags pFlags) const
{
Q_ASSERT_X(isValid(), "KConfigGroup::copyTo", "accessing an invalid group");
Q_ASSERT(other != 0);
if (KConfigGroup *otherGroup = dynamic_cast<KConfigGroup*>(other)) {
config()->d_func()->copyGroup(d->fullName(), otherGroup->d->fullName(), otherGroup, pFlags);
} else if (KConfig* otherConfig = dynamic_cast<KConfig*>(other)) {
KConfigGroup newGroup = otherConfig->group(d->fullName());
otherConfig->d_func()->copyGroup(d->fullName(), d->fullName(), &newGroup, pFlags);
} else {
Q_ASSERT_X(false, "KConfigGroup::copyTo", "unknown type of KConfigBase");
}
}
void KConfigGroup::reparent(KConfigBase* parent, WriteConfigFlags pFlags)
{
Q_ASSERT_X(isValid(), "KConfigGroup::reparent", "accessing an invalid group");
Q_ASSERT_X(!d->bConst, "KConfigGroup::reparent", "reparenting a read-only group");
Q_ASSERT_X(!d->bImmutable, "KConfigGroup::reparent", "reparenting an immutable group");
Q_ASSERT(parent != 0);
KConfigGroup oldGroup(*this);
d = KConfigGroupPrivate::create(parent, d->mName, false, false);
oldGroup.copyTo(this, pFlags);
oldGroup.deleteGroup(); // so that the entries with the old group name are deleted on sync
}