fix logic
[personal-kdelibs.git] / kdecore / config / kconfiggroup.cpp
blobe0c2675cd3bb6a2c0a08c6dcd743dcabf033a908
1 /*
2 This file is part of the KDE libraries
3 Copyright (c) 2006, 2007 Thomas Braxton <kde.braxton@gmail.com>
4 Copyright (c) 1999 Preston Brown <pbrown@kde.org>
5 Copyright (c) 1997 Matthias Kalle Dalheimer <kalle@kde.org>
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details.
17 You should have received a copy of the GNU Library General Public License
18 along with this library; see the file COPYING.LIB. If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA.
23 #include "kconfiggroup.h"
24 #include "kconfiggroup_p.h"
26 #include <config.h>
28 #include "kconfig.h"
29 #include "kconfig_p.h"
30 #include "ksharedconfig.h"
31 #include "kstringhandler.h"
32 #include "kcomponentdata.h"
33 #include "kstandarddirs.h"
34 #include "kconfigdata.h"
35 #include "kde_file.h"
36 #include <kdebug.h>
38 #include <QtCore/QDate>
39 #include <QtCore/QSharedData>
40 #include <QtCore/QFile>
41 #include <QtCore/QPoint>
42 #include <QtCore/QRect>
43 #include <QtCore/QString>
44 #include <QtCore/QTextStream>
45 #include <QtCore/QDir>
47 #include <stdlib.h>
49 class KConfigGroupPrivate : public QSharedData
51 public:
52 KConfigGroupPrivate(KConfig* owner, bool isImmutable, bool isConst, const QByteArray &name)
53 : mOwner(owner), mName(name), bImmutable(isImmutable), bConst(isConst)
57 KConfigGroupPrivate(const KSharedConfigPtr &owner, const QByteArray& name)
58 : sOwner(owner), mOwner(sOwner.data()), mName(name),
59 bImmutable(name.isEmpty()? owner->isImmutable(): owner->isGroupImmutable(name)), bConst(false)
63 KConfigGroupPrivate(KConfigGroup* parent, bool isImmutable, bool isConst, const QByteArray& name)
64 : sOwner(parent->d->sOwner), mOwner(parent->d->mOwner), mName(name),
65 bImmutable(isImmutable), bConst(isConst)
67 if (!parent->d->mName.isEmpty())
68 mParent = parent->d;
71 KConfigGroupPrivate(const KConfigGroupPrivate* other, bool isImmutable, const QByteArray &name)
72 : sOwner(other->sOwner), mOwner(other->mOwner), mName(name),
73 bImmutable(isImmutable), bConst(other->bConst)
75 if (!other->mName.isEmpty())
76 mParent = const_cast<KConfigGroupPrivate *>(other);
79 KSharedConfig::Ptr sOwner;
80 KConfig *mOwner;
81 QExplicitlySharedDataPointer<KConfigGroupPrivate> mParent;
82 QByteArray mName;
84 /* bitfield */
85 const bool bImmutable:1; // is this group immutable?
86 const bool bConst:1; // is this group read-only?
88 QByteArray fullName() const
90 if (!mParent) {
91 return name();
93 return mParent->fullName(mName);
96 QByteArray name() const
98 if (mName.isEmpty())
99 return "<default>";
100 return mName;
103 QByteArray fullName(const QByteArray& aGroup) const
105 if (mName.isEmpty())
106 return aGroup;
107 return fullName() + '\x1d' + aGroup;
110 static QString expandString(const QString& value);
112 static QExplicitlySharedDataPointer<KConfigGroupPrivate> create(KConfigBase *master,
113 const QByteArray &name,
114 bool isImmutable,
115 bool isConst)
117 QExplicitlySharedDataPointer<KConfigGroupPrivate> data;
118 if (dynamic_cast<KConfigGroup*>(master))
119 data = new KConfigGroupPrivate(dynamic_cast<KConfigGroup*>(master), isImmutable, isConst, name);
120 else
121 data = new KConfigGroupPrivate(dynamic_cast<KConfig*>(master), isImmutable, isConst, name);
122 return data;
125 static QByteArray serializeList(const QList<QByteArray> &list);
126 static QStringList deserializeList(const QString &data);
129 QByteArray KConfigGroupPrivate::serializeList(const QList<QByteArray> &list)
131 QByteArray value = "";
133 if (!list.isEmpty()) {
134 QList<QByteArray>::ConstIterator it = list.constBegin();
135 const QList<QByteArray>::ConstIterator end = list.constEnd();
137 value = QByteArray(*it).replace('\\', "\\\\").replace(',', "\\,");
139 while (++it != end) {
140 // In the loop, so it is not done when there is only one element.
141 // Doing it repeatedly is a pretty cheap operation.
142 value.reserve(4096);
144 value += ',';
145 value += QByteArray(*it).replace('\\', "\\\\").replace(',', "\\,");
148 // To be able to distinguish an empty list from a list with one empty element.
149 if (value.isEmpty())
150 value = "\\0";
153 return value;
156 QStringList KConfigGroupPrivate::deserializeList(const QString &data)
158 if (data.isEmpty())
159 return QStringList();
160 if (data == "\\0")
161 return QStringList(QString());
162 QStringList value;
163 QString val;
164 val.reserve(data.size());
165 bool quoted = false;
166 for (int p = 0; p < data.length(); p++) {
167 if (quoted) {
168 val += data[p];
169 quoted = false;
170 } else if (data[p] == '\\') {
171 quoted = true;
172 } else if (data[p] == ',') {
173 val.squeeze(); // release any unused memory
174 value.append(val);
175 val.clear();
176 val.reserve(data.size() - p);
177 } else {
178 val += data[p];
181 value.append(val);
182 return value;
185 static QList<int> asIntList(const QByteArray& string)
187 QList<int> list;
188 Q_FOREACH(const QByteArray& s, string.split(','))
189 list << s.toInt();
190 return list;
193 static QList<qreal> asRealList(const QByteArray& string)
195 QList<qreal> list;
196 Q_FOREACH(const QByteArray& s, string.split(','))
197 list << s.toDouble();
198 return list;
201 static QString errString( const char * pKey, const QByteArray & value, const QVariant & aDefault ) {
202 return QString::fromLatin1("\"%1\" - conversion of \"%3\" to %2 failed")
203 .arg(pKey).arg(QVariant::typeToName(aDefault.type())).arg(value.constData());
206 static QString formatError( int expected, int got ) {
207 return QString::fromLatin1(" (wrong format: expected %1 items, got %2)").arg( expected ).arg( got );
210 QVariant KConfigGroup::convertToQVariant(const char *pKey, const QByteArray& value, const QVariant& aDefault)
212 // if a type handler is added here you must add a QVConversions definition
213 // to conversion_check.h, or ConversionCheck::to_QVariant will not allow
214 // readEntry<T> to convert to QVariant.
215 switch( aDefault.type() ) {
216 case QVariant::Invalid:
217 return QVariant();
218 case QVariant::String:
219 // this should return the raw string not the dollar expanded string.
220 // imho if processed string is wanted should call
221 // readEntry(key, QString) not readEntry(key, QVariant)
222 return QString::fromUtf8(value);
223 case QVariant::List:
224 case QVariant::StringList:
225 return KConfigGroupPrivate::deserializeList(QString::fromUtf8(value));
226 case QVariant::ByteArray:
227 return value;
228 case QVariant::Bool: {
229 const QByteArray lower(value.toLower());
230 if (lower == "false" || lower == "no" || lower == "off" || lower == "0")
231 return false;
232 return true;
234 case QVariant::Double:
235 case QMetaType::Float:
236 case QVariant::Int:
237 case QVariant::UInt:
238 case QVariant::LongLong:
239 case QVariant::ULongLong: {
240 QVariant tmp = value;
241 if ( !tmp.convert(aDefault.type()) )
242 tmp = aDefault;
243 return tmp;
245 case QVariant::Point: {
246 const QList<int> list = asIntList(value);
248 if ( list.count() != 2 ) {
249 kError() << errString( pKey, value, aDefault )
250 << formatError( 2, list.count() );
251 return aDefault;
253 return QPoint(list.at( 0 ), list.at( 1 ));
255 case QVariant::PointF: {
256 const QList<qreal> list = asRealList(value);
258 if ( list.count() != 2 ) {
259 kError() << errString( pKey, value, aDefault )
260 << formatError( 2, list.count() );
261 return aDefault;
263 return QPointF(list.at( 0 ), list.at( 1 ));
265 case QVariant::Rect: {
266 const QList<int> list = asIntList(value);
268 if ( list.count() != 4 ) {
269 kError() << errString( pKey, value, aDefault )
270 << formatError( 4, list.count() );
271 return aDefault;
273 const QRect rect(list.at( 0 ), list.at( 1 ), list.at( 2 ), list.at( 3 ));
274 if ( !rect.isValid() ) {
275 kError() << errString( pKey, value, aDefault );
276 return aDefault;
278 return rect;
280 case QVariant::RectF: {
281 const QList<qreal> list = asRealList(value);
283 if ( list.count() != 4 ) {
284 kError() << errString( pKey, value, aDefault )
285 << formatError( 4, list.count() );
286 return aDefault;
288 const QRectF rect(list.at( 0 ), list.at( 1 ), list.at( 2 ), list.at( 3 ));
289 if ( !rect.isValid() ) {
290 kError() << errString( pKey, value, aDefault );
291 return aDefault;
293 return rect;
295 case QVariant::Size: {
296 const QList<int> list = asIntList(value);
298 if ( list.count() != 2 ) {
299 kError() << errString( pKey, value, aDefault )
300 << formatError( 2, list.count() );
301 return aDefault;
303 const QSize size(list.at( 0 ), list.at( 1 ));
304 if ( !size.isValid() ) {
305 kError() << errString( pKey, value, aDefault );
306 return aDefault;
308 return size;
310 case QVariant::SizeF: {
311 const QList<qreal> list = asRealList(value);
313 if ( list.count() != 2 ) {
314 kError() << errString( pKey, value, aDefault )
315 << formatError( 2, list.count() );
316 return aDefault;
318 const QSizeF size(list.at( 0 ), list.at( 1 ));
319 if ( !size.isValid() ) {
320 kError() << errString( pKey, value, aDefault );
321 return aDefault;
323 return size;
325 case QVariant::DateTime: {
326 const QList<int> list = asIntList(value);
327 if ( list.count() != 6 ) {
328 kError() << errString( pKey, value, aDefault )
329 << formatError( 6, list.count() );
330 return aDefault;
332 const QDate date( list.at( 0 ), list.at( 1 ), list.at( 2 ) );
333 const QTime time( list.at( 3 ), list.at( 4 ), list.at( 5 ) );
334 const QDateTime dt( date, time );
335 if ( !dt.isValid() ) {
336 kError() << errString( pKey, value, aDefault );
337 return aDefault;
339 return dt;
341 case QVariant::Date: {
342 QList<int> list = asIntList(value);
343 if ( list.count() == 6 )
344 list = list.mid(0, 3); // don't break config files that stored QDate as QDateTime
345 if ( list.count() != 3 ) {
346 kError() << errString( pKey, value, aDefault )
347 << formatError( 3, list.count() );
348 return aDefault;
350 const QDate date( list.at( 0 ), list.at( 1 ), list.at( 2 ) );
351 if ( !date.isValid() ) {
352 kError() << errString( pKey, value, aDefault );
353 return aDefault;
355 return date;
357 case QVariant::Color:
358 case QVariant::Font:
359 kWarning() << "KConfigGroup::readEntry was passed GUI type '"
360 << aDefault.typeName()
361 << "' but kdeui isn't linked! If it is linked to your program, "
362 "this is a platform bug. Please inform the KDE developers";
363 break;
364 case QVariant::Url:
365 return QUrl(QString::fromUtf8(value));
367 default:
368 if( aDefault.canConvert<KUrl>() ) {
369 const KUrl url(QString::fromUtf8(value));
370 return qVariantFromValue<KUrl>( url );
372 break;
375 kWarning() << "unhandled type " << aDefault.typeName();
376 return QVariant();
379 QString KConfigGroupPrivate::expandString(const QString& value)
381 QString aValue = value;
383 // check for environment variables and make necessary translations
384 int nDollarPos = aValue.indexOf( '$' );
385 while( nDollarPos != -1 && nDollarPos+1 < aValue.length()) {
386 // there is at least one $
387 if( aValue[nDollarPos+1] == '(' ) {
388 int nEndPos = nDollarPos+1;
389 // the next character is not $
390 while ( (nEndPos <= aValue.length()) && (aValue[nEndPos]!=')') )
391 nEndPos++;
392 nEndPos++;
393 QString cmd = aValue.mid( nDollarPos+2, nEndPos-nDollarPos-3 );
395 QString result;
396 QByteArray oldpath = qgetenv( "PATH" );
397 QByteArray newpath;
398 if (KGlobal::hasMainComponent()) {
399 newpath = QFile::encodeName( KGlobal::dirs()->resourceDirs( "exe" ).join( QChar( KPATH_SEPARATOR ) ) );
400 if (!newpath.isEmpty() && !oldpath.isEmpty())
401 newpath += KPATH_SEPARATOR;
403 newpath += oldpath;
404 setenv( "PATH", newpath, 1/*overwrite*/ );
405 FILE *fs = popen(QFile::encodeName(cmd).data(), "r");
406 if (fs) {
407 QTextStream ts(fs, QIODevice::ReadOnly);
408 result = ts.readAll().trimmed();
409 pclose(fs);
411 setenv( "PATH", oldpath, 1/*overwrite*/ );
412 aValue.replace( nDollarPos, nEndPos-nDollarPos, result );
413 nDollarPos += result.length();
414 } else if( aValue[nDollarPos+1] != '$' ) {
415 int nEndPos = nDollarPos+1;
416 // the next character is not $
417 QString aVarName;
418 if ( aValue[nEndPos]=='{' ) {
419 while ( (nEndPos <= aValue.length()) && (aValue[nEndPos]!='}') )
420 nEndPos++;
421 nEndPos++;
422 aVarName = aValue.mid( nDollarPos+2, nEndPos-nDollarPos-3 );
423 } else {
424 while ( nEndPos <= aValue.length() &&
425 (aValue[nEndPos].isNumber() ||
426 aValue[nEndPos].isLetter() ||
427 aValue[nEndPos]=='_' ) )
428 nEndPos++;
429 aVarName = aValue.mid( nDollarPos+1, nEndPos-nDollarPos-1 );
431 QString env;
432 if (!aVarName.isEmpty()) {
433 #ifdef Q_OS_WIN
434 if (aVarName == "HOME")
435 env = QDir::homePath();
436 else
437 #endif
439 QByteArray pEnv = qgetenv( aVarName.toAscii() );
440 if( !pEnv.isEmpty() )
441 // !!! Sergey A. Sukiyazov <corwin@micom.don.ru> !!!
442 // An environment variable may contain values in 8bit
443 // locale specified encoding or UTF8 encoding
444 env = KStringHandler::from8Bit( pEnv );
446 aValue.replace(nDollarPos, nEndPos-nDollarPos, env);
447 nDollarPos += env.length();
448 } else
449 aValue.remove( nDollarPos, nEndPos-nDollarPos );
450 } else {
451 // remove one of the dollar signs
452 aValue.remove( nDollarPos, 1 );
453 nDollarPos++;
455 nDollarPos = aValue.indexOf( '$', nDollarPos );
458 return aValue;
461 #ifdef Q_WS_WIN
462 # include <QtCore/QDir>
463 #endif
465 static bool cleanHomeDirPath( QString &path, const QString &homeDir )
467 #ifdef Q_WS_WIN //safer
468 if (!QDir::convertSeparators(path).startsWith(QDir::convertSeparators(homeDir)))
469 return false;
470 #else
471 if (!path.startsWith(homeDir))
472 return false;
473 #endif
475 int len = homeDir.length();
476 // replace by "$HOME" if possible
477 if (len && (path.length() == len || path[len] == '/')) {
478 path.replace(0, len, QString::fromLatin1("$HOME"));
479 return true;
480 } else
481 return false;
484 static QString translatePath( QString path ) // krazy:exclude=passbyvalue
486 if (path.isEmpty())
487 return path;
489 // only "our" $HOME should be interpreted
490 path.replace('$', "$$");
492 bool startsWithFile = path.startsWith(QLatin1String("file:"), Qt::CaseInsensitive);
494 // return original path, if it refers to another type of URL (e.g. http:/), or
495 // if the path is already relative to another directory
496 if ((!startsWithFile && QFileInfo(path).isRelative()) ||
497 (startsWithFile && QFileInfo(path.mid(5)).isRelative()))
498 return path;
500 if (startsWithFile)
501 path.remove(0,5); // strip leading "file:/" off the string
503 // keep only one single '/' at the beginning - needed for cleanHomeDirPath()
504 while (path[0] == '/' && path[1] == '/')
505 path.remove(0,1);
507 // we can not use KGlobal::dirs()->relativeLocation("home", path) here,
508 // since it would not recognize paths without a trailing '/'.
509 // All of the 3 following functions to return the user's home directory
510 // can return different paths. We have to test all them.
511 const QString homeDir0 = QFile::decodeName(qgetenv("HOME"));
512 const QString homeDir1 = QDir::homePath();
513 const QString homeDir2 = QDir(homeDir1).canonicalPath();
514 if (cleanHomeDirPath(path, homeDir0) ||
515 cleanHomeDirPath(path, homeDir1) ||
516 cleanHomeDirPath(path, homeDir2) ) {
517 // kDebug() << "Path was replaced\n";
520 if (startsWithFile)
521 path.prepend( "file://" );
523 return path;
527 KConfigGroup::KConfigGroup() : d(0)
531 bool KConfigGroup::isValid() const
533 return 0 != d.constData();
536 KConfigGroupGui _kde_internal_KConfigGroupGui;
537 static inline bool readEntryGui(const QByteArray& data, const char* key, const QVariant &input,
538 QVariant &output)
540 if (_kde_internal_KConfigGroupGui.readEntryGui)
541 return _kde_internal_KConfigGroupGui.readEntryGui(data, key, input, output);
542 return false;
545 static inline bool writeEntryGui(KConfigGroup *cg, const char* key, const QVariant &input,
546 KConfigGroup::WriteConfigFlags flags)
548 if (_kde_internal_KConfigGroupGui.writeEntryGui)
549 return _kde_internal_KConfigGroupGui.writeEntryGui(cg, key, input, flags);
550 return false;
553 KConfigGroup::KConfigGroup(KConfigBase *master, const QString &_group)
554 : d(KConfigGroupPrivate::create(master, _group.toUtf8(), master->isGroupImmutable(_group), false))
558 KConfigGroup::KConfigGroup(KConfigBase *master, const char *_group)
559 : d(KConfigGroupPrivate::create(master, _group, master->isGroupImmutable(_group), false))
563 KConfigGroup::KConfigGroup(const KConfigBase *master, const QString &_group)
564 : d(KConfigGroupPrivate::create(const_cast<KConfigBase*>(master), _group.toUtf8(), master->isGroupImmutable(_group), true))
568 KConfigGroup::KConfigGroup(const KConfigBase *master, const char * _group)
569 : d(KConfigGroupPrivate::create(const_cast<KConfigBase*>(master), _group, master->isGroupImmutable(_group), true))
573 KConfigGroup::KConfigGroup(const KSharedConfigPtr &master, const QString &_group)
574 : d(new KConfigGroupPrivate(master, _group.toUtf8()))
578 KConfigGroup::KConfigGroup(const KSharedConfigPtr &master, const char * _group)
579 : d(new KConfigGroupPrivate(master, _group))
583 KConfigGroup &KConfigGroup::operator=(const KConfigGroup &rhs)
585 d = rhs.d;
586 return *this;
589 KConfigGroup::KConfigGroup(const KConfigGroup &rhs)
590 : KConfigBase(), d(rhs.d)
594 KConfigGroup::~KConfigGroup()
596 d = 0;
599 KConfigGroup KConfigGroup::groupImpl(const QByteArray& aGroup)
601 Q_ASSERT_X(isValid(), "KConfigGroup::groupImpl", "accessing an invalid group");
602 Q_ASSERT_X(!aGroup.isEmpty(), "KConfigGroup::groupImpl", "can not have an unnamed child group");
604 KConfigGroup newGroup;
606 newGroup.d = new KConfigGroupPrivate(this, isGroupImmutableImpl(aGroup), d->bConst, aGroup);
608 return newGroup;
611 const KConfigGroup KConfigGroup::groupImpl(const QByteArray& aGroup) const
613 Q_ASSERT_X(isValid(), "KConfigGroup::groupImpl", "accessing an invalid group");
614 Q_ASSERT_X(!aGroup.isEmpty(), "KConfigGroup::groupImpl", "can not have an unnamed child group");
616 KConfigGroup newGroup;
618 newGroup.d = new KConfigGroupPrivate(const_cast<KConfigGroup*>(this), isGroupImmutableImpl(aGroup),
619 true, aGroup);
621 return newGroup;
624 KConfigGroup KConfigGroup::parent() const
626 Q_ASSERT_X(isValid(), "KConfigGroup::parent", "accessing an invalid group");
628 KConfigGroup parentGroup;
630 if (d->mParent) {
631 parentGroup.d = d->mParent;
632 } else {
633 parentGroup.d = new KConfigGroupPrivate(d->mOwner, d->mOwner->isImmutable(), d->bConst, "");
634 // make sure we keep the refcount up on the KConfig object
635 parentGroup.d->sOwner = d->sOwner;
638 return parentGroup;
641 void KConfigGroup::deleteGroup(WriteConfigFlags flags)
643 Q_ASSERT_X(isValid(), "KConfigGroup::deleteGroup", "accessing an invalid group");
644 Q_ASSERT_X(!d->bConst, "KConfigGroup::deleteGroup", "deleting a read-only group");
646 config()->deleteGroup(d->fullName(), flags);
649 void KConfigGroup::changeGroup( const QString &group )
651 changeGroup(group.toUtf8().constData());
654 void KConfigGroup::changeGroup( const char *group )
656 Q_ASSERT_X(isValid(), "KConfigGroup::changeGroup", "accessing an invalid group");
658 KConfigGroup pnt(parent());
659 // detach (QExplicitlySharedDataPointer takes care of deleting the old d if necessary)
660 // ### temporary solution until QExplicitlySharedDataPointer has detach()
661 d = new KConfigGroupPrivate(&pnt, pnt.isGroupImmutable(group), d->bConst, group);
664 QString KConfigGroup::name() const
666 Q_ASSERT_X(isValid(), "KConfigGroup::name", "accessing an invalid group");
668 return QString::fromUtf8(d->name());
671 bool KConfigGroup::exists() const
673 Q_ASSERT_X(isValid(), "KConfigGroup::exists", "accessing an invalid group");
675 return config()->hasGroup( d->fullName() );
678 void KConfigGroup::sync()
680 Q_ASSERT_X(isValid(), "KConfigGroup::sync", "accessing an invalid group");
682 if (!d->bConst)
683 config()->sync();
686 QMap<QString, QString> KConfigGroup::entryMap() const
688 Q_ASSERT_X(isValid(), "KConfigGroup::entryMap", "accessing an invalid group");
690 return config()->entryMap(d->fullName());
693 KConfig* KConfigGroup::config()
695 Q_ASSERT_X(isValid(), "KConfigGroup::config", "accessing an invalid group");
697 return d->mOwner;
700 const KConfig* KConfigGroup::config() const
702 Q_ASSERT_X(isValid(), "KConfigGroup::config", "accessing an invalid group");
704 return d->mOwner;
707 bool KConfigGroup::isEntryImmutable(const char* key) const
709 Q_ASSERT_X(isValid(), "KConfigGroup::isEntryImmutable", "accessing an invalid group");
711 return (isImmutable() ||
712 !config()->d_func()->canWriteEntry(d->fullName(), key, config()->readDefaults()));
715 bool KConfigGroup::isEntryImmutable(const QString& key) const
717 return isEntryImmutable(key.toUtf8().constData());
720 QString KConfigGroup::readEntryUntranslated(const QString& pKey, const QString& aDefault) const
722 return readEntryUntranslated(pKey.toUtf8().constData(), aDefault);
725 QString KConfigGroup::readEntryUntranslated(const char *key, const QString& aDefault) const
727 Q_ASSERT_X(isValid(), "KConfigGroup::readEntryUntranslated", "accessing an invalid group");
729 QString result = config()->d_func()->lookupData(d->fullName(), key, KEntryMap::SearchFlags(), 0);
730 if (result.isNull())
731 return aDefault;
732 return result;
735 QString KConfigGroup::readEntry(const char *key, const char* aDefault) const
737 return readEntry(key, QString::fromUtf8(aDefault));
740 QString KConfigGroup::readEntry(const QString &key, const char* aDefault) const
742 return readEntry(key.toUtf8().constData(), aDefault);
745 QString KConfigGroup::readEntry(const char* key, const QString& aDefault) const
747 Q_ASSERT_X(isValid(), "KConfigGroup::readEntry", "accessing an invalid group");
749 bool expand = false;
751 // read value from the entry map
752 QString aValue = config()->d_func()->lookupData(d->fullName(), key, KEntryMap::SearchLocalized,
753 &expand);
754 if (aValue.isNull())
755 aValue = aDefault;
757 if (expand)
758 return KConfigGroupPrivate::expandString(aValue);
760 return aValue;
763 QString KConfigGroup::readEntry(const QString &key, const QString& aDefault) const
765 return readEntry(key.toUtf8().constData(), aDefault);
768 QStringList KConfigGroup::readEntry(const char* key, const QStringList& aDefault) const
770 Q_ASSERT_X(isValid(), "KConfigGroup::readEntry", "accessing an invalid group");
772 const QString data = readEntry(key, QString());
773 if (data.isNull())
774 return aDefault;
776 return KConfigGroupPrivate::deserializeList(data);
779 QStringList KConfigGroup::readEntry( const QString& key, const QStringList& aDefault) const
781 return readEntry( key.toUtf8().constData(), aDefault );
784 QVariant KConfigGroup::readEntry( const char* key, const QVariant &aDefault ) const
786 Q_ASSERT_X(isValid(), "KConfigGroup::readEntry", "accessing an invalid group");
788 const QByteArray data = config()->d_func()->lookupData(d->fullName(), key, KEntryMap::SearchLocalized);
789 if (data.isNull())
790 return aDefault;
792 QVariant value;
793 if (!readEntryGui( data, key, aDefault, value ))
794 return convertToQVariant(key, data, aDefault);
796 return value;
799 QVariant KConfigGroup::readEntry( const QString& key, const QVariant& aDefault) const
801 return readEntry( key.toUtf8().constData(), aDefault );
804 QVariantList KConfigGroup::readEntry( const char* key, const QVariantList& aDefault) const
806 Q_ASSERT_X(isValid(), "KConfigGroup::readEntry", "accessing an invalid group");
808 const QString data = readEntry(key, QString());
809 if (data.isNull())
810 return aDefault;
812 QVariantList value;
813 foreach(const QString& v, KConfigGroupPrivate::deserializeList(data))
814 value << v;
816 return value;
819 QVariantList KConfigGroup::readEntry( const QString& key, const QVariantList& aDefault) const
821 return readEntry( key.toUtf8().constData(), aDefault );
824 QStringList KConfigGroup::readXdgListEntry(const QString& key, const QStringList& aDefault) const
826 return readXdgListEntry(key.toUtf8().constData(), aDefault);
829 QStringList KConfigGroup::readXdgListEntry(const char *key, const QStringList& aDefault) const
831 Q_ASSERT_X(isValid(), "KConfigGroup::readXdgListEntry", "accessing an invalid group");
833 const QString data = readEntry(key, QString());
834 if (data.isNull())
835 return aDefault;
837 QStringList value;
838 QString val;
839 val.reserve(data.size());
840 // XXX List serialization being a separate layer from low-level parsing is
841 // probably a bug. No affected entries are defined, though.
842 bool quoted = false;
843 for (int p = 0; p < data.length(); p++) {
844 if (quoted) {
845 val += data[p];
846 quoted = false;
847 } else if (data[p] == '\\') {
848 quoted = true;
849 } else if (data[p] == ';') {
850 value.append(val);
851 val.clear();
852 val.reserve(data.size() - p);
853 } else {
854 val += data[p];
857 if (!val.isEmpty()) {
858 kWarning() << "List entry" << key << "in" << config()->name() << "is not compliant with XDG standard (missing trailing semicolon).";
859 value.append(val);
861 return value;
864 QString KConfigGroup::readPathEntry(const QString& pKey, const QString & aDefault) const
866 return readPathEntry(pKey.toUtf8().constData(), aDefault);
869 QString KConfigGroup::readPathEntry(const char *key, const QString & aDefault) const
871 Q_ASSERT_X(isValid(), "KConfigGroup::readPathEntry", "accessing an invalid group");
873 bool expand = false;
875 QString aValue = config()->d_func()->lookupData(d->fullName(), key, KEntryMap::SearchLocalized,
876 &expand);
877 if (aValue.isNull())
878 aValue = aDefault;
880 return KConfigGroupPrivate::expandString(aValue);
883 QStringList KConfigGroup::readPathEntry(const QString& pKey, const QStringList& aDefault) const
885 return readPathEntry(pKey.toUtf8().constData(), aDefault);
888 QStringList KConfigGroup::readPathEntry(const char *key, const QStringList& aDefault) const
890 Q_ASSERT_X(isValid(), "KConfigGroup::readPathEntry", "accessing an invalid group");
892 const QString data = readPathEntry(key, QString());
893 if (data.isNull())
894 return aDefault;
896 return KConfigGroupPrivate::deserializeList(data);
899 void KConfigGroup::writeEntry( const char* key, const QString& value, WriteConfigFlags flags )
901 Q_ASSERT_X(isValid(), "KConfigGroup::writeEntry", "accessing an invalid group");
902 Q_ASSERT_X(!d->bConst, "KConfigGroup::writeEntry", "writing to a read-only group");
904 writeEntry(key, value.toUtf8(), flags);
907 void KConfigGroup::writeEntry( const QString& key, const QString& value, WriteConfigFlags flags )
909 writeEntry(key.toUtf8().constData(), value, flags);
912 void KConfigGroup::writeEntry(const QString &key, const char *value, WriteConfigFlags pFlags)
914 Q_ASSERT_X(isValid(), "KConfigGroup::writeEntry", "accessing an invalid group");
915 Q_ASSERT_X(!d->bConst, "KConfigGroup::writeEntry", "writing to a read-only group");
917 writeEntry(key.toUtf8().constData(), QVariant(value), pFlags);
920 void KConfigGroup::writeEntry(const char *key, const char *value, WriteConfigFlags pFlags)
922 writeEntry(key, QVariant(value), pFlags);
925 void KConfigGroup::writeEntry( const char* key, const QByteArray& value,
926 WriteConfigFlags flags )
928 Q_ASSERT_X(isValid(), "KConfigGroup::writeEntry", "accessing an invalid group");
929 Q_ASSERT_X(!d->bConst, "KConfigGroup::writeEntry", "writing to a read-only group");
931 config()->d_func()->putData(d->fullName(), key, value.isNull()? QByteArray(""): value, flags);
934 void KConfigGroup::writeEntry(const QString& key, const QByteArray& value,
935 WriteConfigFlags pFlags)
937 writeEntry(key.toUtf8().constData(), value, pFlags);
940 void KConfigGroup::writeEntry(const char* key, const QStringList &list, WriteConfigFlags flags)
942 Q_ASSERT_X(isValid(), "KConfigGroup::writeEntry", "accessing an invalid group");
943 Q_ASSERT_X(!d->bConst, "KConfigGroup::writeEntry", "writing to a read-only group");
945 QList<QByteArray> balist;
947 foreach(const QString &entry, list)
948 balist.append(entry.toUtf8());
950 writeEntry(key, KConfigGroupPrivate::serializeList(balist), flags);
953 void KConfigGroup::writeEntry(const QString& key, const QStringList &list, WriteConfigFlags flags)
955 writeEntry(key.toUtf8().constData(), list, flags);
958 void KConfigGroup::writeEntry( const char* key, const QVariantList& list, WriteConfigFlags flags )
960 Q_ASSERT_X(isValid(), "KConfigGroup::writeEntry", "accessing an invalid group");
961 Q_ASSERT_X(!d->bConst, "KConfigGroup::writeEntry", "writing to a read-only group");
963 QList<QByteArray> data;
965 foreach(const QVariant& v, list) {
966 if (v.type() == QVariant::ByteArray)
967 data << v.toByteArray();
968 else
969 data << v.toString().toUtf8();
972 writeEntry(key, KConfigGroupPrivate::serializeList(data), flags);
975 void KConfigGroup::writeEntry( const char* key, const QVariant &value,
976 WriteConfigFlags flags )
978 Q_ASSERT_X(isValid(), "KConfigGroup::writeEntry", "accessing an invalid group");
979 Q_ASSERT_X(!d->bConst, "KConfigGroup::writeEntry", "writing to a read-only group");
981 if ( writeEntryGui( this, key, value, flags ) )
982 return; // GUI type that was handled
984 QByteArray data;
985 // if a type handler is added here you must add a QVConversions definition
986 // to conversion_check.h, or ConversionCheck::to_QVariant will not allow
987 // writeEntry<T> to convert to QVariant.
988 switch( value.type() ) {
989 case QVariant::Invalid:
990 data = "";
991 break;
992 case QVariant::ByteArray:
993 data = value.toByteArray();
994 break;
995 case QVariant::String:
996 case QVariant::Int:
997 case QVariant::UInt:
998 case QVariant::Double:
999 case QMetaType::Float:
1000 case QVariant::Bool:
1001 case QVariant::LongLong:
1002 case QVariant::ULongLong:
1003 data = value.toString().toUtf8();
1004 break;
1005 case QVariant::List:
1006 kError(!value.canConvert(QVariant::StringList))
1007 << "not all types in \"" << key << "\" can convert to QString,"
1008 " information will be lost";
1009 case QVariant::StringList:
1010 writeEntry( key, value.toList(), flags );
1011 return;
1012 case QVariant::Point: {
1013 QVariantList list;
1014 const QPoint rPoint = value.toPoint();
1015 list.insert( 0, rPoint.x() );
1016 list.insert( 1, rPoint.y() );
1018 writeEntry( key, list, flags );
1019 return;
1021 case QVariant::PointF: {
1022 QVariantList list;
1023 const QPointF point = value.toPointF();
1024 list.insert( 0, point.x() );
1025 list.insert( 1, point.y() );
1027 writeEntry( key, list, flags );
1028 return;
1030 case QVariant::Rect:{
1031 QVariantList list;
1032 const QRect rRect = value.toRect();
1033 list.insert( 0, rRect.left() );
1034 list.insert( 1, rRect.top() );
1035 list.insert( 2, rRect.width() );
1036 list.insert( 3, rRect.height() );
1038 writeEntry( key, list, flags );
1039 return;
1041 case QVariant::RectF:{
1042 QVariantList list;
1043 const QRectF rRectF = value.toRectF();
1044 list.insert(0, rRectF.left());
1045 list.insert(1, rRectF.top());
1046 list.insert(2, rRectF.width());
1047 list.insert(3, rRectF.height());
1049 writeEntry(key, list, flags);
1050 return;
1052 case QVariant::Size:{
1053 QVariantList list;
1054 const QSize rSize = value.toSize();
1055 list.insert( 0, rSize.width() );
1056 list.insert( 1, rSize.height() );
1058 writeEntry( key, list, flags );
1059 return;
1061 case QVariant::SizeF:{
1062 QVariantList list;
1063 const QSizeF rSizeF = value.toSizeF();
1064 list.insert(0, rSizeF.width());
1065 list.insert(1, rSizeF.height());
1067 writeEntry(key, list, flags);
1068 return;
1070 case QVariant::Date: {
1071 QVariantList list;
1072 const QDate date = value.toDate();
1074 list.insert( 0, date.year() );
1075 list.insert( 1, date.month() );
1076 list.insert( 2, date.day() );
1078 writeEntry( key, list, flags );
1079 return;
1081 case QVariant::DateTime: {
1082 QVariantList list;
1083 const QDateTime rDateTime = value.toDateTime();
1085 const QTime time = rDateTime.time();
1086 const QDate date = rDateTime.date();
1088 list.insert( 0, date.year() );
1089 list.insert( 1, date.month() );
1090 list.insert( 2, date.day() );
1092 list.insert( 3, time.hour() );
1093 list.insert( 4, time.minute() );
1094 list.insert( 5, time.second() );
1096 writeEntry( key, list, flags );
1097 return;
1100 case QVariant::Color:
1101 case QVariant::Font:
1102 kWarning() << "KConfigGroup::writeEntry was passed GUI type '"
1103 << value.typeName()
1104 << "' but kdeui isn't linked! If it is linked to your program, this is a platform bug. "
1105 "Please inform the KDE developers";
1106 break;
1107 case QVariant::Url:
1108 data = KUrl(value.toUrl()).url().toUtf8();
1109 break;
1110 default:
1111 if( value.canConvert<KUrl>() ) {
1112 data = qvariant_cast<KUrl>(value).url().toUtf8();
1113 break;
1115 kWarning() << "KConfigGroup::writeEntry - unhandled type" << value.typeName() << "in group" << name();
1118 writeEntry(key, data, flags);
1121 void KConfigGroup::writeEntry( const QString& key, const QVariant& value, WriteConfigFlags flags )
1123 writeEntry(key.toUtf8().constData(), value, flags);
1126 void KConfigGroup::writeEntry(const QString& key, const QVariantList &list, WriteConfigFlags flags)
1128 writeEntry(key.toUtf8().constData(), list, flags);
1131 void KConfigGroup::writeXdgListEntry(const QString& key, const QStringList &value, WriteConfigFlags pFlags)
1133 writeXdgListEntry(key.toUtf8().constData(), value, pFlags);
1136 void KConfigGroup::writeXdgListEntry(const char *key, const QStringList &list, WriteConfigFlags flags)
1138 Q_ASSERT_X(isValid(), "KConfigGroup::writeXdgListEntry", "accessing an invalid group");
1139 Q_ASSERT_X(!d->bConst, "KConfigGroup::writeXdgListEntry", "writing to a read-only group");
1141 QString value;
1142 value.reserve(4096);
1144 // XXX List serialization being a separate layer from low-level escaping is
1145 // probably a bug. No affected entries are defined, though.
1146 QStringList::ConstIterator it = list.constBegin();
1147 const QStringList::ConstIterator end = list.constEnd();
1148 for (; it != end; ++it) {
1149 QString val(*it);
1150 val.replace('\\', "\\\\").replace(';', "\\;");
1151 value += val;
1152 value += ';';
1155 writeEntry(key, value, flags);
1158 void KConfigGroup::writePathEntry(const QString& pKey, const QString & path, WriteConfigFlags pFlags)
1160 writePathEntry(pKey.toUtf8().constData(), path, pFlags);
1163 void KConfigGroup::writePathEntry(const char *pKey, const QString & path, WriteConfigFlags pFlags)
1165 Q_ASSERT_X(isValid(), "KConfigGroup::writePathEntry", "accessing an invalid group");
1166 Q_ASSERT_X(!d->bConst, "KConfigGroup::writePathEntry", "writing to a read-only group");
1168 config()->d_func()->putData(d->fullName(), pKey, translatePath(path).toUtf8(), pFlags, true);
1171 void KConfigGroup::writePathEntry(const QString& pKey, const QStringList &value, WriteConfigFlags pFlags)
1173 writePathEntry(pKey.toUtf8().constData(), value, pFlags);
1176 void KConfigGroup::writePathEntry(const char *pKey, const QStringList &value, WriteConfigFlags pFlags)
1178 Q_ASSERT_X(isValid(), "KConfigGroup::writePathEntry", "accessing an invalid group");
1179 Q_ASSERT_X(!d->bConst, "KConfigGroup::writePathEntry", "writing to a read-only group");
1181 QList<QByteArray> list;
1182 foreach(const QString& path, value)
1183 list << translatePath(path).toUtf8();
1185 config()->d_func()->putData(d->fullName(), pKey, KConfigGroupPrivate::serializeList(list), pFlags, true);
1188 void KConfigGroup::deleteEntry( const char *key, WriteConfigFlags flags)
1190 Q_ASSERT_X(isValid(), "KConfigGroup::deleteEntry", "accessing an invalid group");
1191 Q_ASSERT_X(!d->bConst, "KConfigGroup::deleteEntry", "deleting from a read-only group");
1193 config()->d_func()->putData(d->fullName(), key, QByteArray(), flags);
1196 void KConfigGroup::deleteEntry( const QString& key, WriteConfigFlags flags)
1198 deleteEntry(key.toUtf8().constData(), flags);
1201 void KConfigGroup::revertToDefault(const char *key)
1203 Q_ASSERT_X(isValid(), "KConfigGroup::revertToDefault", "accessing an invalid group");
1204 Q_ASSERT_X(!d->bConst, "KConfigGroup::revertToDefault", "writing to a read-only group");
1206 const QByteArray theDefault = config()->d_func()->lookupData(d->fullName(), key,
1207 KEntryMap::SearchDefaults|KEntryMap::SearchLocalized);
1209 config()->d_func()->putData(d->fullName(), key, theDefault, KConfig::Normal);
1212 void KConfigGroup::revertToDefault(const QString &key)
1214 revertToDefault(key.toUtf8().constData());
1217 bool KConfigGroup::hasDefault(const char *key) const
1219 Q_ASSERT_X(isValid(), "KConfigGroup::hasDefault", "accessing an invalid group");
1221 KEntryMap::SearchFlags flags = KEntryMap::SearchDefaults|KEntryMap::SearchLocalized;
1223 return !config()->d_func()->lookupData(d->fullName(), key, flags).isNull();
1226 bool KConfigGroup::hasDefault(const QString &key) const
1228 return hasDefault(key.toUtf8().constData());
1231 bool KConfigGroup::hasKey(const char *key) const
1233 Q_ASSERT_X(isValid(), "KConfigGroup::hasKey", "accessing an invalid group");
1235 KEntryMap::SearchFlags flags = KEntryMap::SearchLocalized;
1236 if ( config()->readDefaults() )
1237 flags |= KEntryMap::SearchDefaults;
1239 return !config()->d_func()->lookupData(d->fullName(), key, flags).isNull();
1242 bool KConfigGroup::hasKey(const QString &key) const
1244 return hasKey(key.toUtf8().constData());
1247 bool KConfigGroup::isImmutable() const
1249 Q_ASSERT_X(isValid(), "KConfigGroup::isImmutable", "accessing an invalid group");
1251 return d->bImmutable;
1254 QStringList KConfigGroup::groupList() const
1256 Q_ASSERT_X(isValid(), "KConfigGroup::groupList", "accessing an invalid group");
1258 return config()->d_func()->groupList(d->fullName());
1261 QStringList KConfigGroup::keyList() const
1263 Q_ASSERT_X(isValid(), "KConfigGroup::keyList", "accessing an invalid group");
1265 return entryMap().keys();
1268 void KConfigGroup::markAsClean()
1270 Q_ASSERT_X(isValid(), "KConfigGroup::markAsClean", "accessing an invalid group");
1272 config()->markAsClean();
1275 KConfigGroup::AccessMode KConfigGroup::accessMode() const
1277 Q_ASSERT_X(isValid(), "KConfigGroup::accessMode", "accessing an invalid group");
1279 return config()->accessMode();
1282 bool KConfigGroup::hasGroupImpl(const QByteArray & b) const
1284 Q_ASSERT_X(isValid(), "KConfigGroup::hasGroupImpl", "accessing an invalid group");
1286 return config()->hasGroup(d->fullName(b));
1289 void KConfigGroup::deleteGroupImpl(const QByteArray &b, WriteConfigFlags flags)
1291 Q_ASSERT_X(isValid(), "KConfigGroup::deleteGroupImpl", "accessing an invalid group");
1292 Q_ASSERT_X(!d->bConst,"KConfigGroup::deleteGroupImpl", "deleting from a read-only group");
1294 config()->deleteGroup(d->fullName(b), flags);
1297 bool KConfigGroup::isGroupImmutableImpl(const QByteArray& b) const
1299 Q_ASSERT_X(isValid(), "KConfigGroup::isGroupImmutableImpl", "accessing an invalid group");
1301 if (!hasGroupImpl(b)) // group doesn't exist yet
1302 return d->bImmutable; // child groups are immutable if the parent is immutable.
1304 return config()->isGroupImmutable(d->fullName(b));
1307 void KConfigGroup::copyTo(KConfigBase* other, WriteConfigFlags pFlags) const
1309 Q_ASSERT_X(isValid(), "KConfigGroup::copyTo", "accessing an invalid group");
1310 Q_ASSERT(other != 0);
1312 if (KConfigGroup *otherGroup = dynamic_cast<KConfigGroup*>(other)) {
1313 config()->d_func()->copyGroup(d->fullName(), otherGroup->d->fullName(), otherGroup, pFlags);
1314 } else if (KConfig* otherConfig = dynamic_cast<KConfig*>(other)) {
1315 KConfigGroup newGroup = otherConfig->group(d->fullName());
1316 otherConfig->d_func()->copyGroup(d->fullName(), d->fullName(), &newGroup, pFlags);
1317 } else {
1318 Q_ASSERT_X(false, "KConfigGroup::copyTo", "unknown type of KConfigBase");
1322 void KConfigGroup::reparent(KConfigBase* parent, WriteConfigFlags pFlags)
1324 Q_ASSERT_X(isValid(), "KConfigGroup::reparent", "accessing an invalid group");
1325 Q_ASSERT_X(!d->bConst, "KConfigGroup::reparent", "reparenting a read-only group");
1326 Q_ASSERT_X(!d->bImmutable, "KConfigGroup::reparent", "reparenting an immutable group");
1327 Q_ASSERT(parent != 0);
1329 KConfigGroup oldGroup(*this);
1331 d = KConfigGroupPrivate::create(parent, d->mName, false, false);
1332 oldGroup.copyTo(this, pFlags);
1333 oldGroup.deleteGroup(); // so that the entries with the old group name are deleted on sync