1 /*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 2006, 2007 Thomas Braxton <kde.braxton@gmail.com>
4 SPDX-FileCopyrightText: 1999 Preston Brown <pbrown@kde.org>
5 SPDX-FileCopyrightText: 1997 Matthias Kalle Dalheimer <kalle@kde.org>
6
7 SPDX-License-Identifier: LGPL-2.0-or-later
8 */
9
10 #include "kconfiggroup.h"
11 #include "kconfiggroup_p.h"
12
13 #include "kconfig.h"
14 #include "kconfig_core_log_settings.h"
15 #include "kconfig_p.h"
16 #include "kconfigdata_p.h"
17 #include "ksharedconfig.h"
18
19 #include <QDate>
20 #include <QDir>
21 #include <QFile>
22 #include <QPoint>
23 #include <QRect>
24 #include <QSharedData>
25 #include <QString>
26 #include <QTextStream>
27 #include <QUrl>
28
29 #include <algorithm>
30 #include <array>
31 #include <math.h>
32 #include <stdlib.h>
33
34 class KConfigGroupPrivate : public QSharedData
35 {
36 public:
KConfigGroupPrivate(KConfig * owner,bool isImmutable,bool isConst,const QByteArray & name)37 KConfigGroupPrivate(KConfig *owner, bool isImmutable, bool isConst, const QByteArray &name)
38 : mOwner(owner)
39 , mName(name)
40 , bImmutable(isImmutable)
41 , bConst(isConst)
42 {
43 }
44
KConfigGroupPrivate(const KSharedConfigPtr & owner,const QByteArray & name)45 KConfigGroupPrivate(const KSharedConfigPtr &owner, const QByteArray &name)
46 : sOwner(owner)
47 , mOwner(sOwner.data())
48 , mName(name)
49 , bImmutable(name.isEmpty() ? owner->isImmutable() : owner->isGroupImmutable(name))
50 , bConst(false)
51 {
52 }
53
KConfigGroupPrivate(KConfigGroup * parent,bool isImmutable,bool isConst,const QByteArray & name)54 KConfigGroupPrivate(KConfigGroup *parent, bool isImmutable, bool isConst, const QByteArray &name)
55 : sOwner(parent->d->sOwner)
56 , mOwner(parent->d->mOwner)
57 , mName(name)
58 , bImmutable(isImmutable)
59 , bConst(isConst)
60 {
61 if (!parent->d->mName.isEmpty()) {
62 mParent = parent->d;
63 }
64 }
65
KConfigGroupPrivate(const KConfigGroupPrivate * other,bool isImmutable,const QByteArray & name)66 KConfigGroupPrivate(const KConfigGroupPrivate *other, bool isImmutable, const QByteArray &name)
67 : sOwner(other->sOwner)
68 , mOwner(other->mOwner)
69 , mName(name)
70 , bImmutable(isImmutable)
71 , bConst(other->bConst)
72 {
73 if (!other->mName.isEmpty()) {
74 mParent = const_cast<KConfigGroupPrivate *>(other);
75 }
76 }
77
78 KSharedConfig::Ptr sOwner;
79 KConfig *mOwner;
80 QExplicitlySharedDataPointer<KConfigGroupPrivate> mParent;
81 QByteArray mName;
82
83 /* bitfield */
84 const bool bImmutable : 1; // is this group immutable?
85 const bool bConst : 1; // is this group read-only?
86
fullName() const87 QByteArray fullName() const
88 {
89 if (!mParent) {
90 return name();
91 }
92 return mParent->fullName(mName);
93 }
94
name() const95 QByteArray name() const
96 {
97 if (mName.isEmpty()) {
98 return QByteArrayLiteral("<default>");
99 }
100 return mName;
101 }
102
fullName(const QByteArray & aGroup) const103 QByteArray fullName(const QByteArray &aGroup) const
104 {
105 if (mName.isEmpty()) {
106 return aGroup;
107 }
108 return fullName() + '\x1d' + aGroup;
109 }
110
create(KConfigBase * master,const QByteArray & name,bool isImmutable,bool isConst)111 static QExplicitlySharedDataPointer<KConfigGroupPrivate> create(KConfigBase *master, const QByteArray &name, bool isImmutable, bool isConst)
112 {
113 QExplicitlySharedDataPointer<KConfigGroupPrivate> data;
114 if (dynamic_cast<KConfigGroup *>(master)) {
115 data = new KConfigGroupPrivate(static_cast<KConfigGroup *>(master), isImmutable, isConst, name);
116 } else {
117 data = new KConfigGroupPrivate(dynamic_cast<KConfig *>(master), isImmutable, isConst, name);
118 }
119 return data;
120 }
121
122 static QByteArray serializeList(const QList<QByteArray> &list);
123 static QStringList deserializeList(const QString &data);
124 };
125
serializeList(const QList<QByteArray> & list)126 QByteArray KConfigGroupPrivate::serializeList(const QList<QByteArray> &list)
127 {
128 QByteArray value;
129
130 if (!list.isEmpty()) {
131 auto it = list.cbegin();
132 const auto end = list.cend();
133
134 value = QByteArray(*it).replace('\\', QByteArrayLiteral("\\\\")).replace(',', QByteArrayLiteral("\\,"));
135
136 while (++it != end) {
137 // In the loop, so it is not done when there is only one element.
138 // Doing it repeatedly is a pretty cheap operation.
139 value.reserve(4096);
140
141 value += ',';
142 value += QByteArray(*it).replace('\\', QByteArrayLiteral("\\\\")).replace(',', QByteArrayLiteral("\\,"));
143 }
144
145 // To be able to distinguish an empty list from a list with one empty element.
146 if (value.isEmpty()) {
147 value = QByteArrayLiteral("\\0");
148 }
149 }
150
151 return value;
152 }
153
deserializeList(const QString & data)154 QStringList KConfigGroupPrivate::deserializeList(const QString &data)
155 {
156 if (data.isEmpty()) {
157 return QStringList();
158 }
159 if (data == QLatin1String("\\0")) {
160 return QStringList(QString());
161 }
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].unicode() == '\\') {
171 quoted = true;
172 } else if (data[p].unicode() == ',') {
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];
179 }
180 }
181 value.append(val);
182 return value;
183 }
184
asIntList(const QByteArray & string)185 static QVector<int> asIntList(const QByteArray &string)
186 {
187 const auto &splitString = string.split(',');
188
189 QVector<int> list;
190 list.reserve(splitString.count());
191 for (const QByteArray &s : splitString) {
192 list << s.toInt();
193 }
194 return list;
195 }
196
asRealList(const QByteArray & string)197 static QVector<qreal> asRealList(const QByteArray &string)
198 {
199 const auto &splitString = string.split(',');
200
201 QVector<qreal> list;
202 list.reserve(splitString.count());
203 for (const QByteArray &s : splitString) {
204 list << s.toDouble();
205 }
206 return list;
207 }
208
errString(const char * pKey,const QByteArray & value,const QVariant & aDefault)209 static QString errString(const char *pKey, const QByteArray &value, const QVariant &aDefault)
210 {
211 return QStringLiteral("\"%1\" - conversion of \"%3\" to %2 failed")
212 .arg(QString::fromLatin1(pKey), QString::fromLatin1(QVariant::typeToName(aDefault.type())), QString::fromLatin1(value));
213 }
214
formatError(int expected,int got)215 static QString formatError(int expected, int got)
216 {
217 return QStringLiteral(" (wrong format: expected %1 items, got %2)").arg(expected).arg(got);
218 }
219
convertToQVariant(const char * pKey,const QByteArray & value,const QVariant & aDefault)220 QVariant KConfigGroup::convertToQVariant(const char *pKey, const QByteArray &value, const QVariant &aDefault)
221 {
222 // if a type handler is added here you must add a QVConversions definition
223 // to conversioncheck.h, or ConversionCheck::to_QVariant will not allow
224 // readEntry<T> to convert to QVariant.
225 switch (static_cast<QMetaType::Type>(aDefault.type())) {
226 case QMetaType::UnknownType:
227 return QVariant();
228 case QMetaType::QString:
229 // this should return the raw string not the dollar expanded string.
230 // imho if processed string is wanted should call
231 // readEntry(key, QString) not readEntry(key, QVariant)
232 return QString::fromUtf8(value);
233 case QMetaType::QVariantList:
234 case QMetaType::QStringList:
235 return KConfigGroupPrivate::deserializeList(QString::fromUtf8(value));
236 case QMetaType::QByteArray:
237 return value;
238 case QMetaType::Bool: {
239 static const std::array<const char *, 4> negatives = {"false", "no", "off", "0"};
240
241 return std::all_of(negatives.begin(), negatives.end(), [value](const char *negativeString) {
242 return value.compare(negativeString, Qt::CaseInsensitive) != 0;
243 });
244 }
245 case QMetaType::Double:
246 case QMetaType::Float:
247 case QMetaType::Int:
248 case QMetaType::UInt:
249 case QMetaType::LongLong:
250 case QMetaType::ULongLong: {
251 QVariant tmp = value;
252 if (!tmp.convert(aDefault.type())) {
253 tmp = aDefault;
254 }
255 return tmp;
256 }
257 case QMetaType::QPoint: {
258 const auto list = asIntList(value);
259
260 if (list.count() != 2) {
261 qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault) << formatError(2, list.count());
262 return aDefault;
263 }
264 return QPoint(list.at(0), list.at(1));
265 }
266 case QMetaType::QPointF: {
267 const auto list = asRealList(value);
268
269 if (list.count() != 2) {
270 qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault) << formatError(2, list.count());
271 return aDefault;
272 }
273 return QPointF(list.at(0), list.at(1));
274 }
275 case QMetaType::QRect: {
276 const auto list = asIntList(value);
277
278 if (list.count() != 4) {
279 qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault) << formatError(4, list.count());
280 return aDefault;
281 }
282 const QRect rect(list.at(0), list.at(1), list.at(2), list.at(3));
283 if (!rect.isValid()) {
284 qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault);
285 return aDefault;
286 }
287 return rect;
288 }
289 case QMetaType::QRectF: {
290 const auto list = asRealList(value);
291
292 if (list.count() != 4) {
293 qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault) << formatError(4, list.count());
294 return aDefault;
295 }
296 const QRectF rect(list.at(0), list.at(1), list.at(2), list.at(3));
297 if (!rect.isValid()) {
298 qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault);
299 return aDefault;
300 }
301 return rect;
302 }
303 case QMetaType::QSize: {
304 const auto list = asIntList(value);
305
306 if (list.count() != 2) {
307 qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault) << formatError(2, list.count());
308 return aDefault;
309 }
310 const QSize size(list.at(0), list.at(1));
311 if (!size.isValid()) {
312 qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault);
313 return aDefault;
314 }
315 return size;
316 }
317 case QMetaType::QSizeF: {
318 const auto list = asRealList(value);
319
320 if (list.count() != 2) {
321 qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault) << formatError(2, list.count());
322 return aDefault;
323 }
324 const QSizeF size(list.at(0), list.at(1));
325 if (!size.isValid()) {
326 qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault);
327 return aDefault;
328 }
329 return size;
330 }
331 case QMetaType::QDateTime: {
332 const auto list = asRealList(value);
333 if (list.count() < 6) {
334 qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault) << formatError(6, list.count());
335 return aDefault;
336 }
337 const QDate date(list.at(0), list.at(1), list.at(2));
338 const qreal totalSeconds = list.at(5);
339 qreal seconds;
340 const qreal fractional = modf(totalSeconds, &seconds);
341 const qreal milliseconds = round(fractional * 1000.0);
342 const QTime time(list.at(3), list.at(4), seconds, milliseconds);
343 const QDateTime dt(date, time);
344 if (!dt.isValid()) {
345 qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault);
346 return aDefault;
347 }
348 return dt;
349 }
350 case QMetaType::QDate: {
351 auto list = asIntList(value);
352 if (list.count() == 6) {
353 list = list.mid(0, 3); // don't break config files that stored QDate as QDateTime
354 }
355 if (list.count() != 3) {
356 qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault) << formatError(3, list.count());
357 return aDefault;
358 }
359 const QDate date(list.at(0), list.at(1), list.at(2));
360 if (!date.isValid()) {
361 qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault);
362 return aDefault;
363 }
364 return date;
365 }
366 case QMetaType::QColor:
367 case QMetaType::QFont:
368 qCWarning(KCONFIG_CORE_LOG) << "KConfigGroup::readEntry was passed GUI type '" << aDefault.typeName()
369 << "' but KConfigGui isn't linked! If it is linked to your program, "
370 "this is a platform bug. Please inform the KDE developers";
371 break;
372 case QMetaType::QUrl:
373 return QUrl(QString::fromUtf8(value));
374
375 default:
376 break;
377 }
378
379 qCWarning(KCONFIG_CORE_LOG) << "unhandled type " << aDefault.typeName();
380 return QVariant();
381 }
382
383 #ifdef Q_OS_WIN
384 #include <QDir>
385 #endif
386
cleanHomeDirPath(QString & path,const QString & homeDir)387 static bool cleanHomeDirPath(QString &path, const QString &homeDir)
388 {
389 #ifdef Q_OS_WIN // safer
390 if (!QDir::toNativeSeparators(path).startsWith(QDir::toNativeSeparators(homeDir))) {
391 return false;
392 }
393 #else
394 if (!path.startsWith(homeDir)) {
395 return false;
396 }
397 #endif
398
399 int len = homeDir.length();
400 // replace by "$HOME" if possible
401 if (len && (path.length() == len || path[len] == QLatin1Char('/'))) {
402 path.replace(0, len, QStringLiteral("$HOME"));
403 return true;
404 }
405
406 return false;
407 }
408
translatePath(QString path)409 static QString translatePath(QString path) // krazy:exclude=passbyvalue
410 {
411 if (path.isEmpty()) {
412 return path;
413 }
414
415 // only "our" $HOME should be interpreted
416 path.replace(QLatin1Char('$'), QLatin1String("$$"));
417
418 const bool startsWithFile = path.startsWith(QLatin1String("file:"), Qt::CaseInsensitive);
419 path = startsWithFile ? QUrl(path).toLocalFile() : path;
420
421 if (QDir::isRelativePath(path)) {
422 return path;
423 }
424
425 // we can not use KGlobal::dirs()->relativeLocation("home", path) here,
426 // since it would not recognize paths without a trailing '/'.
427 // All of the 3 following functions to return the user's home directory
428 // can return different paths. We have to test all them.
429 const QString homeDir0 = QFile::decodeName(qgetenv("HOME"));
430 const QString homeDir1 = QDir::homePath();
431 const QString homeDir2 = QDir(homeDir1).canonicalPath();
432 if (cleanHomeDirPath(path, homeDir0) || cleanHomeDirPath(path, homeDir1) || cleanHomeDirPath(path, homeDir2)) {
433 // qDebug() << "Path was replaced\n";
434 }
435
436 if (startsWithFile) {
437 path = QUrl::fromLocalFile(path).toString();
438 }
439
440 return path;
441 }
442
KConfigGroup()443 KConfigGroup::KConfigGroup()
444 : d()
445 {
446 }
447
isValid() const448 bool KConfigGroup::isValid() const
449 {
450 return bool(d);
451 }
452
453 KConfigGroupGui _kde_internal_KConfigGroupGui;
readEntryGui(const QByteArray & data,const char * key,const QVariant & input,QVariant & output)454 static inline bool readEntryGui(const QByteArray &data, const char *key, const QVariant &input, QVariant &output)
455 {
456 if (_kde_internal_KConfigGroupGui.readEntryGui) {
457 return _kde_internal_KConfigGroupGui.readEntryGui(data, key, input, output);
458 }
459 return false;
460 }
461
writeEntryGui(KConfigGroup * cg,const char * key,const QVariant & input,KConfigGroup::WriteConfigFlags flags)462 static inline bool writeEntryGui(KConfigGroup *cg, const char *key, const QVariant &input, KConfigGroup::WriteConfigFlags flags)
463 {
464 if (_kde_internal_KConfigGroupGui.writeEntryGui) {
465 return _kde_internal_KConfigGroupGui.writeEntryGui(cg, key, input, flags);
466 }
467 return false;
468 }
469
KConfigGroup(KConfigBase * master,const QString & _group)470 KConfigGroup::KConfigGroup(KConfigBase *master, const QString &_group)
471 : d(KConfigGroupPrivate::create(master, _group.toUtf8(), master->isGroupImmutable(_group), false))
472 {
473 }
474
KConfigGroup(KConfigBase * master,const char * _group)475 KConfigGroup::KConfigGroup(KConfigBase *master, const char *_group)
476 : d(KConfigGroupPrivate::create(master, _group, master->isGroupImmutable(_group), false))
477 {
478 }
479
KConfigGroup(const KConfigBase * master,const QString & _group)480 KConfigGroup::KConfigGroup(const KConfigBase *master, const QString &_group)
481 : d(KConfigGroupPrivate::create(const_cast<KConfigBase *>(master), _group.toUtf8(), master->isGroupImmutable(_group), true))
482 {
483 }
484
KConfigGroup(const KConfigBase * master,const char * _group)485 KConfigGroup::KConfigGroup(const KConfigBase *master, const char *_group)
486 : d(KConfigGroupPrivate::create(const_cast<KConfigBase *>(master), _group, master->isGroupImmutable(_group), true))
487 {
488 }
489
KConfigGroup(const KSharedConfigPtr & master,const QString & _group)490 KConfigGroup::KConfigGroup(const KSharedConfigPtr &master, const QString &_group)
491 : d(new KConfigGroupPrivate(master, _group.toUtf8()))
492 {
493 }
494
KConfigGroup(const KSharedConfigPtr & master,const char * _group)495 KConfigGroup::KConfigGroup(const KSharedConfigPtr &master, const char *_group)
496 : d(new KConfigGroupPrivate(master, _group))
497 {
498 }
499
operator =(const KConfigGroup & rhs)500 KConfigGroup &KConfigGroup::operator=(const KConfigGroup &rhs)
501 {
502 d = rhs.d;
503 return *this;
504 }
505
KConfigGroup(const KConfigGroup & rhs)506 KConfigGroup::KConfigGroup(const KConfigGroup &rhs)
507 : d(rhs.d)
508 {
509 }
510
~KConfigGroup()511 KConfigGroup::~KConfigGroup()
512 {
513 d.reset();
514 }
515
groupImpl(const QByteArray & aGroup)516 KConfigGroup KConfigGroup::groupImpl(const QByteArray &aGroup)
517 {
518 Q_ASSERT_X(isValid(), "KConfigGroup::groupImpl", "accessing an invalid group");
519 Q_ASSERT_X(!aGroup.isEmpty(), "KConfigGroup::groupImpl", "can not have an unnamed child group");
520
521 KConfigGroup newGroup;
522
523 newGroup.d = new KConfigGroupPrivate(this, isGroupImmutableImpl(aGroup), d->bConst, aGroup);
524
525 return newGroup;
526 }
527
groupImpl(const QByteArray & aGroup) const528 const KConfigGroup KConfigGroup::groupImpl(const QByteArray &aGroup) const
529 {
530 Q_ASSERT_X(isValid(), "KConfigGroup::groupImpl", "accessing an invalid group");
531 Q_ASSERT_X(!aGroup.isEmpty(), "KConfigGroup::groupImpl", "can not have an unnamed child group");
532
533 KConfigGroup newGroup;
534
535 newGroup.d = new KConfigGroupPrivate(const_cast<KConfigGroup *>(this), isGroupImmutableImpl(aGroup), true, aGroup);
536
537 return newGroup;
538 }
539
parent() const540 KConfigGroup KConfigGroup::parent() const
541 {
542 Q_ASSERT_X(isValid(), "KConfigGroup::parent", "accessing an invalid group");
543
544 KConfigGroup parentGroup;
545
546 if (d->mParent) {
547 parentGroup.d = d->mParent;
548 } else {
549 parentGroup.d = new KConfigGroupPrivate(d->mOwner, d->mOwner->isImmutable(), d->bConst, "");
550 // make sure we keep the refcount up on the KConfig object
551 parentGroup.d->sOwner = d->sOwner;
552 }
553
554 return parentGroup;
555 }
556
deleteGroup(WriteConfigFlags flags)557 void KConfigGroup::deleteGroup(WriteConfigFlags flags)
558 {
559 Q_ASSERT_X(isValid(), "KConfigGroup::deleteGroup", "accessing an invalid group");
560 Q_ASSERT_X(!d->bConst, "KConfigGroup::deleteGroup", "deleting a read-only group");
561
562 config()->deleteGroup(d->fullName(), flags);
563 }
564
565 #if KCONFIGCORE_BUILD_DEPRECATED_SINCE(5, 0)
changeGroup(const QString & group)566 void KConfigGroup::changeGroup(const QString &group)
567 {
568 Q_ASSERT_X(isValid(), "KConfigGroup::changeGroup", "accessing an invalid group");
569 d.detach();
570 d->mName = group.toUtf8();
571 }
572 #endif
573
574 #if KCONFIGCORE_BUILD_DEPRECATED_SINCE(5, 0)
changeGroup(const char * group)575 void KConfigGroup::changeGroup(const char *group)
576 {
577 Q_ASSERT_X(isValid(), "KConfigGroup::changeGroup", "accessing an invalid group");
578 d.detach();
579 d->mName = group;
580 }
581 #endif
582
name() const583 QString KConfigGroup::name() const
584 {
585 Q_ASSERT_X(isValid(), "KConfigGroup::name", "accessing an invalid group");
586
587 return QString::fromUtf8(d->name());
588 }
589
exists() const590 bool KConfigGroup::exists() const
591 {
592 Q_ASSERT_X(isValid(), "KConfigGroup::exists", "accessing an invalid group");
593
594 return config()->hasGroup(d->fullName());
595 }
596
sync()597 bool KConfigGroup::sync()
598 {
599 Q_ASSERT_X(isValid(), "KConfigGroup::sync", "accessing an invalid group");
600
601 if (!d->bConst) {
602 return config()->sync();
603 }
604
605 return false;
606 }
607
entryMap() const608 QMap<QString, QString> KConfigGroup::entryMap() const
609 {
610 Q_ASSERT_X(isValid(), "KConfigGroup::entryMap", "accessing an invalid group");
611
612 return config()->entryMap(QString::fromUtf8(d->fullName()));
613 }
614
config()615 KConfig *KConfigGroup::config()
616 {
617 Q_ASSERT_X(isValid(), "KConfigGroup::config", "accessing an invalid group");
618
619 return d->mOwner;
620 }
621
config() const622 const KConfig *KConfigGroup::config() const
623 {
624 Q_ASSERT_X(isValid(), "KConfigGroup::config", "accessing an invalid group");
625
626 return d->mOwner;
627 }
628
isEntryImmutable(const char * key) const629 bool KConfigGroup::isEntryImmutable(const char *key) const
630 {
631 Q_ASSERT_X(isValid(), "KConfigGroup::isEntryImmutable", "accessing an invalid group");
632
633 return (isImmutable() || !config()->d_func()->canWriteEntry(d->fullName(), key, config()->readDefaults()));
634 }
635
isEntryImmutable(const QString & key) const636 bool KConfigGroup::isEntryImmutable(const QString &key) const
637 {
638 return isEntryImmutable(key.toUtf8().constData());
639 }
640
readEntryUntranslated(const QString & pKey,const QString & aDefault) const641 QString KConfigGroup::readEntryUntranslated(const QString &pKey, const QString &aDefault) const
642 {
643 return readEntryUntranslated(pKey.toUtf8().constData(), aDefault);
644 }
645
readEntryUntranslated(const char * key,const QString & aDefault) const646 QString KConfigGroup::readEntryUntranslated(const char *key, const QString &aDefault) const
647 {
648 Q_ASSERT_X(isValid(), "KConfigGroup::readEntryUntranslated", "accessing an invalid group");
649
650 QString result = config()->d_func()->lookupData(d->fullName(), key, KEntryMap::SearchFlags(), nullptr);
651 if (result.isNull()) {
652 return aDefault;
653 }
654 return result;
655 }
656
readEntry(const char * key,const char * aDefault) const657 QString KConfigGroup::readEntry(const char *key, const char *aDefault) const
658 {
659 return readEntry(key, QString::fromUtf8(aDefault));
660 }
661
readEntry(const QString & key,const char * aDefault) const662 QString KConfigGroup::readEntry(const QString &key, const char *aDefault) const
663 {
664 return readEntry(key.toUtf8().constData(), aDefault);
665 }
666
readEntry(const char * key,const QString & aDefault) const667 QString KConfigGroup::readEntry(const char *key, const QString &aDefault) const
668 {
669 Q_ASSERT_X(isValid(), "KConfigGroup::readEntry", "accessing an invalid group");
670
671 bool expand = false;
672
673 // read value from the entry map
674 QString aValue = config()->d_func()->lookupData(d->fullName(), key, KEntryMap::SearchLocalized, &expand);
675 if (aValue.isNull()) {
676 aValue = aDefault;
677 }
678
679 if (expand) {
680 return KConfigPrivate::expandString(aValue);
681 }
682
683 return aValue;
684 }
685
readEntry(const QString & key,const QString & aDefault) const686 QString KConfigGroup::readEntry(const QString &key, const QString &aDefault) const
687 {
688 return readEntry(key.toUtf8().constData(), aDefault);
689 }
690
readEntry(const char * key,const QStringList & aDefault) const691 QStringList KConfigGroup::readEntry(const char *key, const QStringList &aDefault) const
692 {
693 Q_ASSERT_X(isValid(), "KConfigGroup::readEntry", "accessing an invalid group");
694
695 const QString data = readEntry(key, QString());
696 if (data.isNull()) {
697 return aDefault;
698 }
699
700 return KConfigGroupPrivate::deserializeList(data);
701 }
702
readEntry(const QString & key,const QStringList & aDefault) const703 QStringList KConfigGroup::readEntry(const QString &key, const QStringList &aDefault) const
704 {
705 return readEntry(key.toUtf8().constData(), aDefault);
706 }
707
readEntry(const char * key,const QVariant & aDefault) const708 QVariant KConfigGroup::readEntry(const char *key, const QVariant &aDefault) const
709 {
710 Q_ASSERT_X(isValid(), "KConfigGroup::readEntry", "accessing an invalid group");
711
712 const QByteArray data = config()->d_func()->lookupData(d->fullName(), key, KEntryMap::SearchLocalized);
713 if (data.isNull()) {
714 return aDefault;
715 }
716
717 QVariant value;
718 if (!readEntryGui(data, key, aDefault, value)) {
719 return convertToQVariant(key, data, aDefault);
720 }
721
722 return value;
723 }
724
readEntry(const QString & key,const QVariant & aDefault) const725 QVariant KConfigGroup::readEntry(const QString &key, const QVariant &aDefault) const
726 {
727 return readEntry(key.toUtf8().constData(), aDefault);
728 }
729
readEntry(const char * key,const QVariantList & aDefault) const730 QVariantList KConfigGroup::readEntry(const char *key, const QVariantList &aDefault) const
731 {
732 Q_ASSERT_X(isValid(), "KConfigGroup::readEntry", "accessing an invalid group");
733
734 const QString data = readEntry(key, QString());
735 if (data.isNull()) {
736 return aDefault;
737 }
738
739 const auto &list = KConfigGroupPrivate::deserializeList(data);
740
741 QVariantList value;
742 value.reserve(list.count());
743 for (const QString &v : list) {
744 value << v;
745 }
746
747 return value;
748 }
749
readEntry(const QString & key,const QVariantList & aDefault) const750 QVariantList KConfigGroup::readEntry(const QString &key, const QVariantList &aDefault) const
751 {
752 return readEntry(key.toUtf8().constData(), aDefault);
753 }
754
readXdgListEntry(const QString & key,const QStringList & aDefault) const755 QStringList KConfigGroup::readXdgListEntry(const QString &key, const QStringList &aDefault) const
756 {
757 return readXdgListEntry(key.toUtf8().constData(), aDefault);
758 }
759
readXdgListEntry(const char * key,const QStringList & aDefault) const760 QStringList KConfigGroup::readXdgListEntry(const char *key, const QStringList &aDefault) const
761 {
762 Q_ASSERT_X(isValid(), "KConfigGroup::readXdgListEntry", "accessing an invalid group");
763
764 const QString data = readEntry(key, QString());
765 if (data.isNull()) {
766 return aDefault;
767 }
768
769 QStringList value;
770 QString val;
771 val.reserve(data.size());
772 // XXX List serialization being a separate layer from low-level parsing is
773 // probably a bug. No affected entries are defined, though.
774 bool quoted = false;
775 for (int p = 0; p < data.length(); p++) {
776 if (quoted) {
777 val += data[p];
778 quoted = false;
779 } else if (data[p] == QLatin1Char('\\')) {
780 quoted = true;
781 } else if (data[p] == QLatin1Char(';')) {
782 value.append(val);
783 val.clear();
784 val.reserve(data.size() - p);
785 } else {
786 val += data[p];
787 }
788 }
789 if (!val.isEmpty()) {
790 value.append(val);
791 }
792 return value;
793 }
794
readPathEntry(const QString & pKey,const QString & aDefault) const795 QString KConfigGroup::readPathEntry(const QString &pKey, const QString &aDefault) const
796 {
797 return readPathEntry(pKey.toUtf8().constData(), aDefault);
798 }
799
readPathEntry(const char * key,const QString & aDefault) const800 QString KConfigGroup::readPathEntry(const char *key, const QString &aDefault) const
801 {
802 Q_ASSERT_X(isValid(), "KConfigGroup::readPathEntry", "accessing an invalid group");
803
804 bool expand = false;
805
806 QString aValue = config()->d_func()->lookupData(d->fullName(), key, KEntryMap::SearchLocalized, &expand);
807 if (aValue.isNull()) {
808 aValue = aDefault;
809 }
810
811 return KConfigPrivate::expandString(aValue);
812 }
813
readPathEntry(const QString & pKey,const QStringList & aDefault) const814 QStringList KConfigGroup::readPathEntry(const QString &pKey, const QStringList &aDefault) const
815 {
816 return readPathEntry(pKey.toUtf8().constData(), aDefault);
817 }
818
readPathEntry(const char * key,const QStringList & aDefault) const819 QStringList KConfigGroup::readPathEntry(const char *key, const QStringList &aDefault) const
820 {
821 Q_ASSERT_X(isValid(), "KConfigGroup::readPathEntry", "accessing an invalid group");
822
823 const QString data = readPathEntry(key, QString());
824 if (data.isNull()) {
825 return aDefault;
826 }
827
828 return KConfigGroupPrivate::deserializeList(data);
829 }
830
writeEntry(const char * key,const QString & value,WriteConfigFlags flags)831 void KConfigGroup::writeEntry(const char *key, const QString &value, WriteConfigFlags flags)
832 {
833 Q_ASSERT_X(isValid(), "KConfigGroup::writeEntry", "accessing an invalid group");
834 Q_ASSERT_X(!d->bConst, "KConfigGroup::writeEntry", "writing to a read-only group");
835
836 writeEntry(key, value.toUtf8(), flags);
837 }
838
writeEntry(const QString & key,const QString & value,WriteConfigFlags flags)839 void KConfigGroup::writeEntry(const QString &key, const QString &value, WriteConfigFlags flags)
840 {
841 writeEntry(key.toUtf8().constData(), value, flags);
842 }
843
writeEntry(const QString & key,const char * value,WriteConfigFlags pFlags)844 void KConfigGroup::writeEntry(const QString &key, const char *value, WriteConfigFlags pFlags)
845 {
846 Q_ASSERT_X(isValid(), "KConfigGroup::writeEntry", "accessing an invalid group");
847 Q_ASSERT_X(!d->bConst, "KConfigGroup::writeEntry", "writing to a read-only group");
848
849 writeEntry(key.toUtf8().constData(), QVariant(QString::fromLatin1(value)), pFlags);
850 }
851
writeEntry(const char * key,const char * value,WriteConfigFlags pFlags)852 void KConfigGroup::writeEntry(const char *key, const char *value, WriteConfigFlags pFlags)
853 {
854 writeEntry(key, QVariant(QString::fromLatin1(value)), pFlags);
855 }
856
writeEntry(const char * key,const QByteArray & value,WriteConfigFlags flags)857 void KConfigGroup::writeEntry(const char *key, const QByteArray &value, WriteConfigFlags flags)
858 {
859 Q_ASSERT_X(isValid(), "KConfigGroup::writeEntry", "accessing an invalid group");
860 Q_ASSERT_X(!d->bConst, "KConfigGroup::writeEntry", "writing to a read-only group");
861
862 config()->d_func()->putData(d->fullName(), key, value.isNull() ? QByteArray("") : value, flags);
863 }
864
writeEntry(const QString & key,const QByteArray & value,WriteConfigFlags pFlags)865 void KConfigGroup::writeEntry(const QString &key, const QByteArray &value, WriteConfigFlags pFlags)
866 {
867 writeEntry(key.toUtf8().constData(), value, pFlags);
868 }
869
writeEntry(const char * key,const QStringList & list,WriteConfigFlags flags)870 void KConfigGroup::writeEntry(const char *key, const QStringList &list, WriteConfigFlags flags)
871 {
872 Q_ASSERT_X(isValid(), "KConfigGroup::writeEntry", "accessing an invalid group");
873 Q_ASSERT_X(!d->bConst, "KConfigGroup::writeEntry", "writing to a read-only group");
874
875 QList<QByteArray> balist;
876 balist.reserve(list.count());
877
878 for (const QString &entry : list) {
879 balist.append(entry.toUtf8());
880 }
881
882 writeEntry(key, KConfigGroupPrivate::serializeList(balist), flags);
883 }
884
writeEntry(const QString & key,const QStringList & list,WriteConfigFlags flags)885 void KConfigGroup::writeEntry(const QString &key, const QStringList &list, WriteConfigFlags flags)
886 {
887 writeEntry(key.toUtf8().constData(), list, flags);
888 }
889
writeEntry(const char * key,const QVariantList & list,WriteConfigFlags flags)890 void KConfigGroup::writeEntry(const char *key, const QVariantList &list, WriteConfigFlags flags)
891 {
892 Q_ASSERT_X(isValid(), "KConfigGroup::writeEntry", "accessing an invalid group");
893 Q_ASSERT_X(!d->bConst, "KConfigGroup::writeEntry", "writing to a read-only group");
894
895 QList<QByteArray> data;
896 data.reserve(list.count());
897
898 for (const QVariant &v : list) {
899 if (v.type() == QVariant::ByteArray) {
900 data << v.toByteArray();
901 } else {
902 data << v.toString().toUtf8();
903 }
904 }
905
906 writeEntry(key, KConfigGroupPrivate::serializeList(data), flags);
907 }
908
writeEntry(const char * key,const QVariant & value,WriteConfigFlags flags)909 void KConfigGroup::writeEntry(const char *key, const QVariant &value, WriteConfigFlags flags)
910 {
911 Q_ASSERT_X(isValid(), "KConfigGroup::writeEntry", "accessing an invalid group");
912 Q_ASSERT_X(!d->bConst, "KConfigGroup::writeEntry", "writing to a read-only group");
913
914 if (writeEntryGui(this, key, value, flags)) {
915 return; // GUI type that was handled
916 }
917
918 QByteArray data;
919 // if a type handler is added here you must add a QVConversions definition
920 // to conversioncheck.h, or ConversionCheck::to_QVariant will not allow
921 // writeEntry<T> to convert to QVariant.
922 switch (static_cast<QMetaType::Type>(value.type())) {
923 case QMetaType::UnknownType:
924 data = "";
925 break;
926 case QMetaType::QByteArray:
927 data = value.toByteArray();
928 break;
929 case QMetaType::QString:
930 case QMetaType::Int:
931 case QMetaType::UInt:
932 case QMetaType::Double:
933 case QMetaType::Float:
934 case QMetaType::Bool:
935 case QMetaType::LongLong:
936 case QMetaType::ULongLong:
937 data = value.toString().toUtf8();
938 break;
939 case QMetaType::QVariantList:
940 if (!value.canConvert(QMetaType::QStringList)) {
941 qCWarning(KCONFIG_CORE_LOG) << "not all types in \"" << key
942 << "\" can convert to QString,"
943 " information will be lost";
944 }
945 Q_FALLTHROUGH();
946 case QMetaType::QStringList:
947 writeEntry(key, value.toList(), flags);
948 return;
949 case QMetaType::QPoint: {
950 const QPoint rPoint = value.toPoint();
951
952 const QVariantList list{rPoint.x(), rPoint.y()};
953
954 writeEntry(key, list, flags);
955 return;
956 }
957 case QMetaType::QPointF: {
958 const QPointF point = value.toPointF();
959
960 const QVariantList list{point.x(), point.y()};
961
962 writeEntry(key, list, flags);
963 return;
964 }
965 case QMetaType::QRect: {
966 const QRect rRect = value.toRect();
967
968 const QVariantList list{rRect.left(), rRect.top(), rRect.width(), rRect.height()};
969
970 writeEntry(key, list, flags);
971 return;
972 }
973 case QMetaType::QRectF: {
974 const QRectF rRectF = value.toRectF();
975
976 const QVariantList list{rRectF.left(), rRectF.top(), rRectF.width(), rRectF.height()};
977
978 writeEntry(key, list, flags);
979 return;
980 }
981 case QMetaType::QSize: {
982 const QSize rSize = value.toSize();
983
984 const QVariantList list{rSize.width(), rSize.height()};
985
986 writeEntry(key, list, flags);
987 return;
988 }
989 case QMetaType::QSizeF: {
990 const QSizeF rSizeF = value.toSizeF();
991
992 const QVariantList list{rSizeF.width(), rSizeF.height()};
993
994 writeEntry(key, list, flags);
995 return;
996 }
997 case QMetaType::QDate: {
998 const QDate date = value.toDate();
999
1000 const QVariantList list{date.year(), date.month(), date.day()};
1001
1002 writeEntry(key, list, flags);
1003 return;
1004 }
1005 case QMetaType::QDateTime: {
1006 const QDateTime rDateTime = value.toDateTime();
1007
1008 const QTime time = rDateTime.time();
1009 const QDate date = rDateTime.date();
1010
1011 const QVariantList list{
1012 date.year(),
1013 date.month(),
1014 date.day(),
1015
1016 time.hour(),
1017 time.minute(),
1018 time.second() + time.msec() / 1000.0,
1019 };
1020
1021 writeEntry(key, list, flags);
1022 return;
1023 }
1024
1025 case QMetaType::QColor:
1026 case QMetaType::QFont:
1027 qCWarning(KCONFIG_CORE_LOG) << "KConfigGroup::writeEntry was passed GUI type '" << value.typeName()
1028 << "' but KConfigGui isn't linked! If it is linked to your program, this is a platform bug. "
1029 "Please inform the KDE developers";
1030 break;
1031 case QMetaType::QUrl:
1032 data = QUrl(value.toUrl()).toString().toUtf8();
1033 break;
1034 default:
1035 qCWarning(KCONFIG_CORE_LOG) << "KConfigGroup::writeEntry - unhandled type" << value.typeName() << "in group" << name();
1036 }
1037
1038 writeEntry(key, data, flags);
1039 }
1040
writeEntry(const QString & key,const QVariant & value,WriteConfigFlags flags)1041 void KConfigGroup::writeEntry(const QString &key, const QVariant &value, WriteConfigFlags flags)
1042 {
1043 writeEntry(key.toUtf8().constData(), value, flags);
1044 }
1045
writeEntry(const QString & key,const QVariantList & list,WriteConfigFlags flags)1046 void KConfigGroup::writeEntry(const QString &key, const QVariantList &list, WriteConfigFlags flags)
1047 {
1048 writeEntry(key.toUtf8().constData(), list, flags);
1049 }
1050
writeXdgListEntry(const QString & key,const QStringList & value,WriteConfigFlags pFlags)1051 void KConfigGroup::writeXdgListEntry(const QString &key, const QStringList &value, WriteConfigFlags pFlags)
1052 {
1053 writeXdgListEntry(key.toUtf8().constData(), value, pFlags);
1054 }
1055
writeXdgListEntry(const char * key,const QStringList & list,WriteConfigFlags flags)1056 void KConfigGroup::writeXdgListEntry(const char *key, const QStringList &list, WriteConfigFlags flags)
1057 {
1058 Q_ASSERT_X(isValid(), "KConfigGroup::writeXdgListEntry", "accessing an invalid group");
1059 Q_ASSERT_X(!d->bConst, "KConfigGroup::writeXdgListEntry", "writing to a read-only group");
1060
1061 QString value;
1062 value.reserve(4096);
1063
1064 // XXX List serialization being a separate layer from low-level escaping is
1065 // probably a bug. No affected entries are defined, though.
1066 for (QString val : list) { // clazy:exclude=range-loop
1067 val.replace(QLatin1Char('\\'), QLatin1String("\\\\")).replace(QLatin1Char(';'), QLatin1String("\\;"));
1068 value += val + QLatin1Char(';');
1069 }
1070
1071 writeEntry(key, value, flags);
1072 }
1073
writePathEntry(const QString & pKey,const QString & path,WriteConfigFlags pFlags)1074 void KConfigGroup::writePathEntry(const QString &pKey, const QString &path, WriteConfigFlags pFlags)
1075 {
1076 writePathEntry(pKey.toUtf8().constData(), path, pFlags);
1077 }
1078
writePathEntry(const char * pKey,const QString & path,WriteConfigFlags pFlags)1079 void KConfigGroup::writePathEntry(const char *pKey, const QString &path, WriteConfigFlags pFlags)
1080 {
1081 Q_ASSERT_X(isValid(), "KConfigGroup::writePathEntry", "accessing an invalid group");
1082 Q_ASSERT_X(!d->bConst, "KConfigGroup::writePathEntry", "writing to a read-only group");
1083
1084 config()->d_func()->putData(d->fullName(), pKey, translatePath(path).toUtf8(), pFlags, true);
1085 }
1086
writePathEntry(const QString & pKey,const QStringList & value,WriteConfigFlags pFlags)1087 void KConfigGroup::writePathEntry(const QString &pKey, const QStringList &value, WriteConfigFlags pFlags)
1088 {
1089 writePathEntry(pKey.toUtf8().constData(), value, pFlags);
1090 }
1091
writePathEntry(const char * pKey,const QStringList & value,WriteConfigFlags pFlags)1092 void KConfigGroup::writePathEntry(const char *pKey, const QStringList &value, WriteConfigFlags pFlags)
1093 {
1094 Q_ASSERT_X(isValid(), "KConfigGroup::writePathEntry", "accessing an invalid group");
1095 Q_ASSERT_X(!d->bConst, "KConfigGroup::writePathEntry", "writing to a read-only group");
1096
1097 QList<QByteArray> list;
1098 list.reserve(value.length());
1099 for (const QString &path : value) {
1100 list << translatePath(path).toUtf8();
1101 }
1102
1103 config()->d_func()->putData(d->fullName(), pKey, KConfigGroupPrivate::serializeList(list), pFlags, true);
1104 }
1105
deleteEntry(const char * key,WriteConfigFlags flags)1106 void KConfigGroup::deleteEntry(const char *key, WriteConfigFlags flags)
1107 {
1108 Q_ASSERT_X(isValid(), "KConfigGroup::deleteEntry", "accessing an invalid group");
1109 Q_ASSERT_X(!d->bConst, "KConfigGroup::deleteEntry", "deleting from a read-only group");
1110
1111 config()->d_func()->putData(d->fullName(), key, QByteArray(), flags);
1112 }
1113
deleteEntry(const QString & key,WriteConfigFlags flags)1114 void KConfigGroup::deleteEntry(const QString &key, WriteConfigFlags flags)
1115 {
1116 deleteEntry(key.toUtf8().constData(), flags);
1117 }
1118
revertToDefault(const char * key)1119 void KConfigGroup::revertToDefault(const char *key)
1120 {
1121 revertToDefault(key, WriteConfigFlags());
1122 }
1123
revertToDefault(const char * key,WriteConfigFlags flags)1124 void KConfigGroup::revertToDefault(const char *key, WriteConfigFlags flags)
1125 {
1126 Q_ASSERT_X(isValid(), "KConfigGroup::revertToDefault", "accessing an invalid group");
1127 Q_ASSERT_X(!d->bConst, "KConfigGroup::revertToDefault", "writing to a read-only group");
1128
1129 config()->d_func()->revertEntry(d->fullName(), key, flags);
1130 }
1131
revertToDefault(const QString & key)1132 void KConfigGroup::revertToDefault(const QString &key)
1133 {
1134 revertToDefault(key, WriteConfigFlags());
1135 }
1136
revertToDefault(const QString & key,WriteConfigFlags flags)1137 void KConfigGroup::revertToDefault(const QString &key, WriteConfigFlags flags)
1138 {
1139 revertToDefault(key.toUtf8().constData(), flags);
1140 }
1141
hasDefault(const char * key) const1142 bool KConfigGroup::hasDefault(const char *key) const
1143 {
1144 Q_ASSERT_X(isValid(), "KConfigGroup::hasDefault", "accessing an invalid group");
1145
1146 KEntryMap::SearchFlags flags = KEntryMap::SearchDefaults | KEntryMap::SearchLocalized;
1147
1148 return !config()->d_func()->lookupData(d->fullName(), key, flags).isNull();
1149 }
1150
hasDefault(const QString & key) const1151 bool KConfigGroup::hasDefault(const QString &key) const
1152 {
1153 return hasDefault(key.toUtf8().constData());
1154 }
1155
hasKey(const char * key) const1156 bool KConfigGroup::hasKey(const char *key) const
1157 {
1158 Q_ASSERT_X(isValid(), "KConfigGroup::hasKey", "accessing an invalid group");
1159
1160 KEntryMap::SearchFlags flags = KEntryMap::SearchLocalized;
1161 if (config()->readDefaults()) {
1162 flags |= KEntryMap::SearchDefaults;
1163 }
1164
1165 return !config()->d_func()->lookupData(d->fullName(), key, flags).isNull();
1166 }
1167
hasKey(const QString & key) const1168 bool KConfigGroup::hasKey(const QString &key) const
1169 {
1170 return hasKey(key.toUtf8().constData());
1171 }
1172
isImmutable() const1173 bool KConfigGroup::isImmutable() const
1174 {
1175 Q_ASSERT_X(isValid(), "KConfigGroup::isImmutable", "accessing an invalid group");
1176
1177 return d->bImmutable;
1178 }
1179
groupList() const1180 QStringList KConfigGroup::groupList() const
1181 {
1182 Q_ASSERT_X(isValid(), "KConfigGroup::groupList", "accessing an invalid group");
1183
1184 return config()->d_func()->groupList(d->fullName());
1185 }
1186
keyList() const1187 QStringList KConfigGroup::keyList() const
1188 {
1189 Q_ASSERT_X(isValid(), "KConfigGroup::keyList", "accessing an invalid group");
1190
1191 return entryMap().keys();
1192 }
1193
markAsClean()1194 void KConfigGroup::markAsClean()
1195 {
1196 Q_ASSERT_X(isValid(), "KConfigGroup::markAsClean", "accessing an invalid group");
1197
1198 config()->markAsClean();
1199 }
1200
accessMode() const1201 KConfigGroup::AccessMode KConfigGroup::accessMode() const
1202 {
1203 Q_ASSERT_X(isValid(), "KConfigGroup::accessMode", "accessing an invalid group");
1204
1205 return config()->accessMode();
1206 }
1207
hasGroupImpl(const QByteArray & b) const1208 bool KConfigGroup::hasGroupImpl(const QByteArray &b) const
1209 {
1210 Q_ASSERT_X(isValid(), "KConfigGroup::hasGroupImpl", "accessing an invalid group");
1211
1212 return config()->hasGroup(d->fullName(b));
1213 }
1214
deleteGroupImpl(const QByteArray & b,WriteConfigFlags flags)1215 void KConfigGroup::deleteGroupImpl(const QByteArray &b, WriteConfigFlags flags)
1216 {
1217 Q_ASSERT_X(isValid(), "KConfigGroup::deleteGroupImpl", "accessing an invalid group");
1218 Q_ASSERT_X(!d->bConst, "KConfigGroup::deleteGroupImpl", "deleting from a read-only group");
1219
1220 config()->deleteGroup(d->fullName(b), flags);
1221 }
1222
isGroupImmutableImpl(const QByteArray & b) const1223 bool KConfigGroup::isGroupImmutableImpl(const QByteArray &b) const
1224 {
1225 Q_ASSERT_X(isValid(), "KConfigGroup::isGroupImmutableImpl", "accessing an invalid group");
1226
1227 if (!hasGroupImpl(b)) { // group doesn't exist yet
1228 return d->bImmutable; // child groups are immutable if the parent is immutable.
1229 }
1230
1231 return config()->isGroupImmutable(d->fullName(b));
1232 }
1233
copyTo(KConfigBase * other,WriteConfigFlags pFlags) const1234 void KConfigGroup::copyTo(KConfigBase *other, WriteConfigFlags pFlags) const
1235 {
1236 Q_ASSERT_X(isValid(), "KConfigGroup::copyTo", "accessing an invalid group");
1237 Q_ASSERT(other != nullptr);
1238
1239 if (KConfigGroup *otherGroup = dynamic_cast<KConfigGroup *>(other)) {
1240 config()->d_func()->copyGroup(d->fullName(), otherGroup->d->fullName(), otherGroup, pFlags);
1241 } else if (KConfig *otherConfig = dynamic_cast<KConfig *>(other)) {
1242 KConfigGroup newGroup = otherConfig->group(d->fullName());
1243 otherConfig->d_func()->copyGroup(d->fullName(), d->fullName(), &newGroup, pFlags);
1244 } else {
1245 Q_ASSERT_X(false, "KConfigGroup::copyTo", "unknown type of KConfigBase");
1246 }
1247 }
1248
reparent(KConfigBase * parent,WriteConfigFlags pFlags)1249 void KConfigGroup::reparent(KConfigBase *parent, WriteConfigFlags pFlags)
1250 {
1251 Q_ASSERT_X(isValid(), "KConfigGroup::reparent", "accessing an invalid group");
1252 Q_ASSERT_X(!d->bConst, "KConfigGroup::reparent", "reparenting a read-only group");
1253 Q_ASSERT_X(!d->bImmutable, "KConfigGroup::reparent", "reparenting an immutable group");
1254 Q_ASSERT(parent != nullptr);
1255
1256 KConfigGroup oldGroup(*this);
1257
1258 d = KConfigGroupPrivate::create(parent, d->mName, false, false);
1259 oldGroup.copyTo(this, pFlags);
1260 oldGroup.deleteGroup(); // so that the entries with the old group name are deleted on sync
1261 }
1262
moveValuesTo(const QList<const char * > & keys,KConfigGroup & other,WriteConfigFlags pFlags)1263 void KConfigGroup::moveValuesTo(const QList<const char *> &keys, KConfigGroup &other, WriteConfigFlags pFlags)
1264 {
1265 Q_ASSERT(isValid());
1266 Q_ASSERT(other.isValid());
1267
1268 for (const auto key : keys) {
1269 const QByteArray groupName = name().toLocal8Bit();
1270 const auto entry = config()->d_ptr->lookupInternalEntry(groupName, key, KEntryMap::SearchLocalized);
1271
1272 // Only write the entry if it is not null, if it is a global enry there is no point in moving it
1273 if (!entry.mValue.isNull() && !entry.bGlobal) {
1274 deleteEntry(key, pFlags);
1275 KEntryMap::EntryOptions options = KEntryMap::EntryOption::EntryDirty;
1276 if (entry.bDeleted) {
1277 options |= KEntryMap::EntryDeleted;
1278 }
1279
1280 if (entry.bExpand) {
1281 options |= KEntryMap::EntryExpansion;
1282 }
1283
1284 other.config()->d_ptr->setEntryData(other.name().toLocal8Bit(), key, entry.mValue, options);
1285 }
1286 }
1287 }
1288