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"
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"
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>
49 class KConfigGroupPrivate
: public QSharedData
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())
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
;
81 QExplicitlySharedDataPointer
<KConfigGroupPrivate
> mParent
;
85 const bool bImmutable
:1; // is this group immutable?
86 const bool bConst
:1; // is this group read-only?
88 QByteArray
fullName() const
93 return mParent
->fullName(mName
);
96 QByteArray
name() const
103 QByteArray
fullName(const QByteArray
& aGroup
) const
107 return fullName() + '\x1d' + aGroup
;
110 static QString
expandString(const QString
& value
);
112 static QExplicitlySharedDataPointer
<KConfigGroupPrivate
> create(KConfigBase
*master
,
113 const QByteArray
&name
,
117 QExplicitlySharedDataPointer
<KConfigGroupPrivate
> data
;
118 if (dynamic_cast<KConfigGroup
*>(master
))
119 data
= new KConfigGroupPrivate(dynamic_cast<KConfigGroup
*>(master
), isImmutable
, isConst
, name
);
121 data
= new KConfigGroupPrivate(dynamic_cast<KConfig
*>(master
), isImmutable
, isConst
, name
);
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.
145 value
+= QByteArray(*it
).replace('\\', "\\\\").replace(',', "\\,");
148 // To be able to distinguish an empty list from a list with one empty element.
156 QStringList
KConfigGroupPrivate::deserializeList(const QString
&data
)
159 return QStringList();
161 return QStringList(QString());
164 val
.reserve(data
.size());
166 for (int p
= 0; p
< data
.length(); p
++) {
170 } else if (data
[p
] == '\\') {
172 } else if (data
[p
] == ',') {
173 val
.squeeze(); // release any unused memory
176 val
.reserve(data
.size() - p
);
185 static QList
<int> asIntList(const QByteArray
& string
)
188 Q_FOREACH(const QByteArray
& s
, string
.split(','))
193 static QList
<qreal
> asRealList(const QByteArray
& string
)
196 Q_FOREACH(const QByteArray
& s
, string
.split(','))
197 list
<< s
.toDouble();
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
:
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
);
224 case QVariant::StringList
:
225 return KConfigGroupPrivate::deserializeList(QString::fromUtf8(value
));
226 case QVariant::ByteArray
:
228 case QVariant::Bool
: {
229 const QByteArray
lower(value
.toLower());
230 if (lower
== "false" || lower
== "no" || lower
== "off" || lower
== "0")
234 case QVariant::Double
:
235 case QMetaType::Float
:
238 case QVariant::LongLong
:
239 case QVariant::ULongLong
: {
240 QVariant tmp
= value
;
241 if ( !tmp
.convert(aDefault
.type()) )
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() );
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() );
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() );
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
);
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() );
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
);
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() );
303 const QSize
size(list
.at( 0 ), list
.at( 1 ));
304 if ( !size
.isValid() ) {
305 kError() << errString( pKey
, value
, aDefault
);
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() );
318 const QSizeF
size(list
.at( 0 ), list
.at( 1 ));
319 if ( !size
.isValid() ) {
320 kError() << errString( pKey
, value
, aDefault
);
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() );
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
);
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() );
350 const QDate
date( list
.at( 0 ), list
.at( 1 ), list
.at( 2 ) );
351 if ( !date
.isValid() ) {
352 kError() << errString( pKey
, value
, aDefault
);
357 case QVariant::Color
:
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";
365 return QUrl(QString::fromUtf8(value
));
368 if( aDefault
.canConvert
<KUrl
>() ) {
369 const KUrl
url(QString::fromUtf8(value
));
370 return qVariantFromValue
<KUrl
>( url
);
375 kWarning() << "unhandled type " << aDefault
.typeName();
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
]!=')') )
393 QString cmd
= aValue
.mid( nDollarPos
+2, nEndPos
-nDollarPos
-3 );
396 QByteArray oldpath
= qgetenv( "PATH" );
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
;
404 setenv( "PATH", newpath
, 1/*overwrite*/ );
405 FILE *fs
= popen(QFile::encodeName(cmd
).data(), "r");
407 QTextStream
ts(fs
, QIODevice::ReadOnly
);
408 result
= ts
.readAll().trimmed();
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 $
418 if ( aValue
[nEndPos
]=='{' ) {
419 while ( (nEndPos
<= aValue
.length()) && (aValue
[nEndPos
]!='}') )
422 aVarName
= aValue
.mid( nDollarPos
+2, nEndPos
-nDollarPos
-3 );
424 while ( nEndPos
<= aValue
.length() &&
425 (aValue
[nEndPos
].isNumber() ||
426 aValue
[nEndPos
].isLetter() ||
427 aValue
[nEndPos
]=='_' ) )
429 aVarName
= aValue
.mid( nDollarPos
+1, nEndPos
-nDollarPos
-1 );
432 if (!aVarName
.isEmpty()) {
434 if (aVarName
== "HOME")
435 env
= QDir::homePath();
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();
449 aValue
.remove( nDollarPos
, nEndPos
-nDollarPos
);
451 // remove one of the dollar signs
452 aValue
.remove( nDollarPos
, 1 );
455 nDollarPos
= aValue
.indexOf( '$', nDollarPos
);
462 # include <QtCore/QDir>
465 static bool cleanHomeDirPath( QString
&path
, const QString
&homeDir
)
467 #ifdef Q_WS_WIN //safer
468 if (!QDir::convertSeparators(path
).startsWith(QDir::convertSeparators(homeDir
)))
471 if (!path
.startsWith(homeDir
))
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"));
484 static QString
translatePath( QString path
) // krazy:exclude=passbyvalue
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()))
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] == '/')
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";
521 path
.prepend( "file://" );
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
,
540 if (_kde_internal_KConfigGroupGui
.readEntryGui
)
541 return _kde_internal_KConfigGroupGui
.readEntryGui(data
, key
, input
, output
);
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
);
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
)
589 KConfigGroup::KConfigGroup(const KConfigGroup
&rhs
)
590 : KConfigBase(), d(rhs
.d
)
594 KConfigGroup::~KConfigGroup()
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
);
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
),
624 KConfigGroup
KConfigGroup::parent() const
626 Q_ASSERT_X(isValid(), "KConfigGroup::parent", "accessing an invalid group");
628 KConfigGroup parentGroup
;
631 parentGroup
.d
= d
->mParent
;
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
;
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");
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");
700 const KConfig
* KConfigGroup::config() const
702 Q_ASSERT_X(isValid(), "KConfigGroup::config", "accessing an invalid group");
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);
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");
751 // read value from the entry map
752 QString aValue
= config()->d_func()->lookupData(d
->fullName(), key
, KEntryMap::SearchLocalized
,
758 return KConfigGroupPrivate::expandString(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());
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
);
793 if (!readEntryGui( data
, key
, aDefault
, value
))
794 return convertToQVariant(key
, data
, aDefault
);
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());
813 foreach(const QString
& v
, KConfigGroupPrivate::deserializeList(data
))
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());
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.
843 for (int p
= 0; p
< data
.length(); p
++) {
847 } else if (data
[p
] == '\\') {
849 } else if (data
[p
] == ';') {
852 val
.reserve(data
.size() - p
);
857 if (!val
.isEmpty()) {
858 kWarning() << "List entry" << key
<< "in" << config()->name() << "is not compliant with XDG standard (missing trailing semicolon).";
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");
875 QString aValue
= config()->d_func()->lookupData(d
->fullName(), key
, KEntryMap::SearchLocalized
,
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());
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();
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
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
:
992 case QVariant::ByteArray
:
993 data
= value
.toByteArray();
995 case QVariant::String
:
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();
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
);
1012 case QVariant::Point
: {
1014 const QPoint rPoint
= value
.toPoint();
1015 list
.insert( 0, rPoint
.x() );
1016 list
.insert( 1, rPoint
.y() );
1018 writeEntry( key
, list
, flags
);
1021 case QVariant::PointF
: {
1023 const QPointF point
= value
.toPointF();
1024 list
.insert( 0, point
.x() );
1025 list
.insert( 1, point
.y() );
1027 writeEntry( key
, list
, flags
);
1030 case QVariant::Rect
:{
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
);
1041 case QVariant::RectF
:{
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
);
1052 case QVariant::Size
:{
1054 const QSize rSize
= value
.toSize();
1055 list
.insert( 0, rSize
.width() );
1056 list
.insert( 1, rSize
.height() );
1058 writeEntry( key
, list
, flags
);
1061 case QVariant::SizeF
:{
1063 const QSizeF rSizeF
= value
.toSizeF();
1064 list
.insert(0, rSizeF
.width());
1065 list
.insert(1, rSizeF
.height());
1067 writeEntry(key
, list
, flags
);
1070 case QVariant::Date
: {
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
);
1081 case QVariant::DateTime
: {
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
);
1100 case QVariant::Color
:
1101 case QVariant::Font
:
1102 kWarning() << "KConfigGroup::writeEntry was passed GUI type '"
1104 << "' but kdeui isn't linked! If it is linked to your program, this is a platform bug. "
1105 "Please inform the KDE developers";
1108 data
= KUrl(value
.toUrl()).url().toUtf8();
1111 if( value
.canConvert
<KUrl
>() ) {
1112 data
= qvariant_cast
<KUrl
>(value
).url().toUtf8();
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");
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
) {
1150 val
.replace('\\', "\\\\").replace(';', "\\;");
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
);
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