KConfig

kconfiggroup.cpp
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#include <QUuid>
29
30#include <algorithm>
31#include <array>
32#include <math.h>
33#include <stdlib.h>
34
35class KConfigGroupPrivate : public QSharedData
36{
37public:
38 KConfigGroupPrivate(KConfig *owner, bool isImmutable, bool isConst, const QString &name)
39 : mOwner(owner)
40 , mName(name)
41 , bImmutable(isImmutable)
42 , bConst(isConst)
43 {
44 if (Q_UNLIKELY(!mOwner->name().isEmpty() && mOwner->accessMode() == KConfigBase::NoAccess)) {
45 qCWarning(KCONFIG_CORE_LOG) << "Created a KConfigGroup on an inaccessible config location" << mOwner->name() << name;
46 }
47 }
48
49 KConfigGroupPrivate(const KSharedConfigPtr &owner, const QString &name)
50 : sOwner(owner)
51 , mOwner(sOwner.data())
52 , mName(name)
53 , bImmutable(name.isEmpty() ? owner->isImmutable() : owner->isGroupImmutable(name))
54 , bConst(false)
55 {
56 if (Q_UNLIKELY(!mOwner->name().isEmpty() && mOwner->accessMode() == KConfigBase::NoAccess)) {
57 qCWarning(KCONFIG_CORE_LOG) << "Created a KConfigGroup on an inaccessible config location" << mOwner->name() << name;
58 }
59 }
60
61 KConfigGroupPrivate(KConfigGroup *parent, bool isImmutable, bool isConst, const QString &name)
62 : sOwner(parent->d->sOwner)
63 , mOwner(parent->d->mOwner)
64 , mName(name)
65 , bImmutable(isImmutable)
66 , bConst(isConst)
67 {
68 if (!parent->d->mName.isEmpty()) {
69 mParent = parent->d;
70 }
71 }
72
73 KConfigGroupPrivate(const KConfigGroupPrivate *other, bool isImmutable, const QString &name)
74 : sOwner(other->sOwner)
75 , mOwner(other->mOwner)
76 , mName(name)
77 , bImmutable(isImmutable)
78 , bConst(other->bConst)
79 {
80 if (!other->mName.isEmpty()) {
81 mParent = const_cast<KConfigGroupPrivate *>(other);
82 }
83 }
84
85 KSharedConfig::Ptr sOwner;
86 KConfig *mOwner;
87 QExplicitlySharedDataPointer<KConfigGroupPrivate> mParent;
88 QString mName;
89
90 /* bitfield */
91 const bool bImmutable : 1; // is this group immutable?
92 const bool bConst : 1; // is this group read-only?
93
94 QString fullName() const
95 {
96 if (!mParent) {
97 return name();
98 }
99 return mParent->fullName(mName);
100 }
101
102 QString name() const
103 {
104 if (mName.isEmpty()) {
105 return QStringLiteral("<default>");
106 }
107 return mName;
108 }
109
110 QString fullName(const QString &aGroup) const
111 {
112 if (mName.isEmpty()) {
113 return aGroup;
114 }
115 return fullName() + QLatin1Char('\x1d') + aGroup;
116 }
117
118 static QExplicitlySharedDataPointer<KConfigGroupPrivate> create(KConfigBase *master, const QString &name, bool isImmutable, bool isConst)
119 {
120 QExplicitlySharedDataPointer<KConfigGroupPrivate> data;
121 if (dynamic_cast<KConfigGroup *>(master)) {
122 data = new KConfigGroupPrivate(static_cast<KConfigGroup *>(master), isImmutable, isConst, name);
123 } else {
124 data = new KConfigGroupPrivate(dynamic_cast<KConfig *>(master), isImmutable, isConst, name);
125 }
126 return data;
127 }
128
129 static QByteArray serializeList(const QList<QByteArray> &list);
130 static QStringList deserializeList(const QString &data);
131};
132
133QByteArray KConfigGroupPrivate::serializeList(const QList<QByteArray> &list)
134{
135 QByteArray value;
136
137 if (!list.isEmpty()) {
138 auto it = list.cbegin();
139 const auto end = list.cend();
140
141 value = QByteArray(*it).replace('\\', QByteArrayLiteral("\\\\")).replace(',', QByteArrayLiteral("\\,"));
142
143 while (++it != end) {
144 // In the loop, so it is not done when there is only one element.
145 // Doing it repeatedly is a pretty cheap operation.
146 value.reserve(4096);
147
148 value += ',';
149 value += QByteArray(*it).replace('\\', QByteArrayLiteral("\\\\")).replace(',', QByteArrayLiteral("\\,"));
150 }
151
152 // To be able to distinguish an empty list from a list with one empty element.
153 if (value.isEmpty()) {
154 value = QByteArrayLiteral("\\0");
155 }
156 }
157
158 return value;
159}
160
161QStringList KConfigGroupPrivate::deserializeList(const QString &data)
162{
163 if (data.isEmpty()) {
164 return QStringList();
165 }
166 if (data == QLatin1String("\\0")) {
167 return QStringList(QString());
168 }
169 QStringList value;
170 QString val;
171 val.reserve(data.size());
172 bool quoted = false;
173 for (int p = 0; p < data.length(); p++) {
174 if (quoted) {
175 val += data[p];
176 quoted = false;
177 } else if (data[p].unicode() == '\\') {
178 quoted = true;
179 } else if (data[p].unicode() == ',') {
180 val.squeeze(); // release any unused memory
181 value.append(val);
182 val.clear();
183 val.reserve(data.size() - p);
184 } else {
185 val += data[p];
186 }
187 }
188 value.append(val);
189 return value;
190}
191
192static QVarLengthArray<int, 8> asIntList(QByteArrayView string)
193{
194 int start = 0;
195 int next = start;
197 while ((next = string.indexOf(',', start)) != -1) {
198 ret.push_back(string.sliced(start, next - start).toInt());
199 start = next + 1;
200 }
201 ret.push_back(string.sliced(start, string.size() - start).toInt());
202 return ret;
203}
204
205static QVarLengthArray<qreal, 8> asRealList(QByteArrayView string)
206{
207 int start = 0;
208 int next = start;
210 while ((next = string.indexOf(',', start)) != -1) {
211 ret.push_back(string.sliced(start, next - start).toDouble());
212 start = next + 1;
213 }
214 ret.push_back(string.sliced(start, string.size() - start).toDouble());
215 return ret;
216}
217
218static QString errString(const char *pKey, const QByteArray &value, const QVariant &aDefault)
219{
220 return QStringLiteral("\"%1\" - conversion of \"%3\" to %2 failed")
222}
223
224static QString formatError(int expected, int got)
225{
226 return QStringLiteral(" (wrong format: expected %1 items, got %2)").arg(expected).arg(got);
227}
228
229QVariant KConfigGroup::convertToQVariant(const char *pKey, const QByteArray &value, const QVariant &aDefault)
230{
231 // if a type handler is added here you must add a QVConversions definition
232 // to kconfigconversioncheck_p.h, or KConfigConversionCheck::to_QVariant will not allow
233 // readEntry<T> to convert to QVariant.
234 switch (static_cast<QMetaType::Type>(aDefault.userType())) {
236 return QVariant();
238 // this should return the raw string not the dollar expanded string.
239 // imho if processed string is wanted should call
240 // readEntry(key, QString) not readEntry(key, QVariant)
241 return QString::fromUtf8(value);
242 case QMetaType::QUuid:
243 return QUuid::fromString(value);
246 return KConfigGroupPrivate::deserializeList(QString::fromUtf8(value));
248 return value;
249 case QMetaType::Bool: {
250 static const std::array<const char *, 4> negatives = {"false", "no", "off", "0"};
251
252 return std::all_of(negatives.begin(), negatives.end(), [value](const char *negativeString) {
253 return value.compare(negativeString, Qt::CaseInsensitive) != 0;
254 });
255 }
257 case QMetaType::Float:
258 case QMetaType::Int:
259 case QMetaType::UInt:
262 QVariant tmp = value;
263 if (!tmp.convert(aDefault.metaType())) {
264 tmp = aDefault;
265 }
266 return tmp;
267 }
268 case QMetaType::QPoint: {
269 const auto list = asIntList(value);
270
271 if (list.count() != 2) {
272 qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault) << formatError(2, list.count());
273 return aDefault;
274 }
275 return QPoint(list.at(0), list.at(1));
276 }
277 case QMetaType::QPointF: {
278 const auto list = asRealList(value);
279
280 if (list.count() != 2) {
281 qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault) << formatError(2, list.count());
282 return aDefault;
283 }
284 return QPointF(list.at(0), list.at(1));
285 }
286 case QMetaType::QRect: {
287 const auto list = asIntList(value);
288
289 if (list.count() != 4) {
290 qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault) << formatError(4, list.count());
291 return aDefault;
292 }
293 const QRect rect(list.at(0), list.at(1), list.at(2), list.at(3));
294 if (!rect.isValid()) {
295 qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault);
296 return aDefault;
297 }
298 return rect;
299 }
300 case QMetaType::QRectF: {
301 const auto list = asRealList(value);
302
303 if (list.count() != 4) {
304 qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault) << formatError(4, list.count());
305 return aDefault;
306 }
307 const QRectF rect(list.at(0), list.at(1), list.at(2), list.at(3));
308 if (!rect.isValid()) {
309 qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault);
310 return aDefault;
311 }
312 return rect;
313 }
314 case QMetaType::QSize: {
315 const auto list = asIntList(value);
316
317 if (list.count() != 2) {
318 qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault) << formatError(2, list.count());
319 return aDefault;
320 }
321 const QSize size(list.at(0), list.at(1));
322 if (!size.isValid()) {
323 qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault);
324 return aDefault;
325 }
326 return size;
327 }
328 case QMetaType::QSizeF: {
329 const auto list = asRealList(value);
330
331 if (list.count() != 2) {
332 qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault) << formatError(2, list.count());
333 return aDefault;
334 }
335 const QSizeF size(list.at(0), list.at(1));
336 if (!size.isValid()) {
337 qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault);
338 return aDefault;
339 }
340 return size;
341 }
343 const auto list = asRealList(value);
344 if (list.count() < 6) {
345 qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault) << formatError(6, list.count());
346 return aDefault;
347 }
348 const QDate date(list.at(0), list.at(1), list.at(2));
349 const qreal totalSeconds = list.at(5);
350 qreal seconds;
351 const qreal fractional = modf(totalSeconds, &seconds);
352 const qreal milliseconds = round(fractional * 1000.0);
353 const QTime time(list.at(3), list.at(4), seconds, milliseconds);
354
355 QDateTime dt(date, time);
356 if (list.count() == 7) { // Then the timezone, which was added later
357 const auto id = value.mid(value.lastIndexOf(',') + 1);
358 dt.setTimeZone(QTimeZone(id));
359 }
360 if (!dt.isValid()) {
361 qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault);
362 return aDefault;
363 }
364 return dt;
365 }
366 case QMetaType::QDate: {
367 auto list = asIntList(value);
368 // list.count == 6 -> don't break config files that stored QDate as QDateTime
369 if (list.count() != 3 && list.count() != 6) {
370 qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault) << formatError(3, list.count());
371 return aDefault;
372 }
373 const QDate date(list.at(0), list.at(1), list.at(2));
374 if (!date.isValid()) {
375 qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault);
376 return aDefault;
377 }
378 return date;
379 }
381 case QMetaType::QFont:
382 qCWarning(KCONFIG_CORE_LOG) << "KConfigGroup::readEntry was passed GUI type '" << aDefault.typeName()
383 << "' but KConfigGui isn't linked! If it is linked to your program, "
384 "this is a platform bug. Please inform the KDE developers";
385 break;
386 case QMetaType::QUrl:
387 return QUrl(QString::fromUtf8(value));
388
389 default:
390 break;
391 }
392
393 qCWarning(KCONFIG_CORE_LOG) << "unhandled type " << aDefault.typeName();
394 return QVariant();
395}
396
397static bool cleanHomeDirPath(QString &path, const QString &homeDir)
398{
399#ifdef Q_OS_WIN // safer
400 if (!QDir::toNativeSeparators(path).startsWith(QDir::toNativeSeparators(homeDir))) {
401 return false;
402 }
403#else
404 if (!path.startsWith(homeDir)) {
405 return false;
406 }
407#endif
408
409 int len = homeDir.length();
410 // replace by "$HOME" if possible
411 if (len && (path.length() == len || path[len] == QLatin1Char('/'))) {
412 path.replace(0, len, QStringLiteral("$HOME"));
413 return true;
414 }
415
416 return false;
417}
418
419static QString translatePath(QString path) // krazy:exclude=passbyvalue
420{
421 if (path.isEmpty()) {
422 return path;
423 }
424
425 // only "our" $HOME should be interpreted
427
428 const bool startsWithFile = path.startsWith(QLatin1String("file:"), Qt::CaseInsensitive);
429 path = startsWithFile ? QUrl(path).toLocalFile() : path;
430
431 if (QDir::isRelativePath(path)) {
432 return path;
433 }
434
435 // Use the same thing as what expandString() will do, to keep data intact
436#ifdef Q_OS_WIN
437 const QString homeDir = QDir::homePath();
438#else
439 const QString homeDir = QFile::decodeName(qgetenv("HOME"));
440#endif
441 (void)cleanHomeDirPath(path, homeDir);
442
443 if (startsWithFile) {
445 }
446
447 return path;
448}
449
451 : d()
452{
453}
454
456{
457 return bool(d);
458}
459
460KConfigGroupGui _kde_internal_KConfigGroupGui;
461static inline bool readEntryGui(const QByteArray &data, const char *key, const QVariant &input, QVariant &output)
462{
463 if (_kde_internal_KConfigGroupGui.readEntryGui) {
464 return _kde_internal_KConfigGroupGui.readEntryGui(data, key, input, output);
465 }
466 return false;
467}
468
469static inline bool writeEntryGui(KConfigGroup *cg, const char *key, const QVariant &input, KConfigGroup::WriteConfigFlags flags)
470{
471 if (_kde_internal_KConfigGroupGui.writeEntryGui) {
472 return _kde_internal_KConfigGroupGui.writeEntryGui(cg, key, input, flags);
473 }
474 return false;
475}
476
477KConfigGroup::KConfigGroup(KConfigBase *master, const QString &_group)
478 : d(KConfigGroupPrivate::create(master, _group, master->isGroupImmutable(_group), false))
479{
480}
481
482KConfigGroup::KConfigGroup(const KConfigBase *master, const QString &_group)
483 : d(KConfigGroupPrivate::create(const_cast<KConfigBase *>(master), _group, master->isGroupImmutable(_group), true))
484{
485}
486
487KConfigGroup::KConfigGroup(const KSharedConfigPtr &master, const QString &_group)
488 : d(new KConfigGroupPrivate(master, _group))
489{
490}
491
492KConfigGroup &KConfigGroup::operator=(const KConfigGroup &rhs)
493{
494 d = rhs.d;
495 return *this;
496}
497
499 : d(rhs.d)
500{
501}
502
503KConfigGroup::~KConfigGroup()
504{
505 d.reset();
506}
507
509{
510 Q_ASSERT_X(isValid(), "KConfigGroup::groupImpl", "accessing an invalid group");
511 Q_ASSERT_X(!aGroup.isEmpty(), "KConfigGroup::groupImpl", "can not have an unnamed child group");
512
513 KConfigGroup newGroup;
514
515 newGroup.d = new KConfigGroupPrivate(this, isGroupImmutableImpl(aGroup), d->bConst, aGroup);
516
517 return newGroup;
518}
519
521{
522 Q_ASSERT_X(isValid(), "KConfigGroup::groupImpl", "accessing an invalid group");
523 Q_ASSERT_X(!aGroup.isEmpty(), "KConfigGroup::groupImpl", "can not have an unnamed child group");
524
525 KConfigGroup newGroup;
526
527 newGroup.d = new KConfigGroupPrivate(const_cast<KConfigGroup *>(this), isGroupImmutableImpl(aGroup), true, aGroup);
528
529 return newGroup;
530}
531
533{
534 Q_ASSERT_X(isValid(), "KConfigGroup::parent", "accessing an invalid group");
535
536 KConfigGroup parentGroup;
537
538 if (d->mParent) {
539 parentGroup.d = d->mParent;
540 } else {
541 parentGroup.d = new KConfigGroupPrivate(d->mOwner, d->mOwner->isImmutable(), d->bConst, QString());
542 // make sure we keep the refcount up on the KConfig object
543 parentGroup.d->sOwner = d->sOwner;
544 }
545
546 return parentGroup;
547}
548
550{
551 Q_ASSERT_X(isValid(), "KConfigGroup::deleteGroup", "accessing an invalid group");
552 Q_ASSERT_X(!d->bConst, "KConfigGroup::deleteGroup", "deleting a read-only group");
553
554 config()->deleteGroup(d->fullName(), flags);
555}
556
558{
559 Q_ASSERT_X(isValid(), "KConfigGroup::name", "accessing an invalid group");
560
561 return d->name();
562}
563
565{
566 Q_ASSERT_X(isValid(), "KConfigGroup::exists", "accessing an invalid group");
567
568 return config()->hasGroup(d->fullName());
569}
570
572{
573 Q_ASSERT_X(isValid(), "KConfigGroup::sync", "accessing an invalid group");
574
575 if (!d->bConst) {
576 return config()->sync();
577 }
578
579 return false;
580}
581
583{
584 Q_ASSERT_X(isValid(), "KConfigGroup::entryMap", "accessing an invalid group");
585
586 return config()->entryMap(d->fullName());
587}
588
590{
591 Q_ASSERT_X(isValid(), "KConfigGroup::config", "accessing an invalid group");
592
593 return d->mOwner;
594}
595
597{
598 Q_ASSERT_X(isValid(), "KConfigGroup::config", "accessing an invalid group");
599
600 return d->mOwner;
601}
602
603bool KConfigGroup::isEntryImmutable(const char *key) const
604{
605 Q_ASSERT_X(isValid(), "KConfigGroup::isEntryImmutable", "accessing an invalid group");
606
607 return (isImmutable() || !config()->d_func()->canWriteEntry(d->fullName(), key, config()->readDefaults()));
608}
609
611{
612 return isEntryImmutable(key.toUtf8().constData());
613}
614
616{
617 return readEntryUntranslated(pKey.toUtf8().constData(), aDefault);
618}
619
620QString KConfigGroup::readEntryUntranslated(const char *key, const QString &aDefault) const
621{
622 Q_ASSERT_X(isValid(), "KConfigGroup::readEntryUntranslated", "accessing an invalid group");
623
624 QString result = config()->d_func()->lookupData(d->fullName(), key, KEntryMap::SearchFlags(), nullptr);
625 if (result.isNull()) {
626 return aDefault;
627 }
628 return result;
629}
630
631QString KConfigGroup::readEntry(const char *key, const char *aDefault) const
632{
633 return readEntry(key, QString::fromUtf8(aDefault));
634}
635
636QString KConfigGroup::readEntry(const QString &key, const char *aDefault) const
637{
638 return readEntry(key.toUtf8().constData(), aDefault);
639}
640
641QString KConfigGroup::readEntry(const char *key, const QString &aDefault) const
642{
643 Q_ASSERT_X(isValid(), "KConfigGroup::readEntry", "accessing an invalid group");
644
645 bool expand = false;
646
647 // read value from the entry map
648 QString aValue = config()->d_func()->lookupData(d->fullName(), key, KEntryMap::SearchLocalized, &expand);
649 if (aValue.isNull()) {
650 aValue = aDefault;
651 }
652
653 if (expand) {
654 return KConfigPrivate::expandString(aValue);
655 }
656
657 return aValue;
658}
659
660QString KConfigGroup::readEntry(const QString &key, const QString &aDefault) const
661{
662 return readEntry(key.toUtf8().constData(), aDefault);
663}
664
665QStringList KConfigGroup::readEntry(const char *key, const QStringList &aDefault) const
666{
667 Q_ASSERT_X(isValid(), "KConfigGroup::readEntry", "accessing an invalid group");
668
669 const QString data = readEntry(key, QString());
670 if (data.isNull()) {
671 return aDefault;
672 }
673
674 return KConfigGroupPrivate::deserializeList(data);
675}
676
677QStringList KConfigGroup::readEntry(const QString &key, const QStringList &aDefault) const
678{
679 return readEntry(key.toUtf8().constData(), aDefault);
680}
681
682QVariant KConfigGroup::readEntry(const char *key, const QVariant &aDefault) const
683{
684 Q_ASSERT_X(isValid(), "KConfigGroup::readEntry", "accessing an invalid group");
685
686 const QByteArray data = config()->d_func()->lookupData(d->fullName(), key, KEntryMap::SearchLocalized);
687 if (data.isNull()) {
688 return aDefault;
689 }
690
691 QVariant value;
692 if (!readEntryGui(data, key, aDefault, value)) {
693 return convertToQVariant(key, data, aDefault);
694 }
695
696 return value;
697}
698
699QVariant KConfigGroup::readEntry(const QString &key, const QVariant &aDefault) const
700{
701 return readEntry(key.toUtf8().constData(), aDefault);
702}
703
704QVariantList KConfigGroup::readEntry(const char *key, const QVariantList &aDefault) const
705{
706 Q_ASSERT_X(isValid(), "KConfigGroup::readEntry", "accessing an invalid group");
707
708 const QString data = readEntry(key, QString());
709 if (data.isNull()) {
710 return aDefault;
711 }
712
713 const auto &list = KConfigGroupPrivate::deserializeList(data);
714
715 QVariantList value;
716 value.reserve(list.count());
717 for (const QString &v : list) {
718 value << v;
719 }
720
721 return value;
722}
723
724QVariantList KConfigGroup::readEntry(const QString &key, const QVariantList &aDefault) const
725{
726 return readEntry(key.toUtf8().constData(), aDefault);
727}
728
730{
731 return readXdgListEntry(key.toUtf8().constData(), aDefault);
732}
733
734QStringList KConfigGroup::readXdgListEntry(const char *key, const QStringList &aDefault) const
735{
736 Q_ASSERT_X(isValid(), "KConfigGroup::readXdgListEntry", "accessing an invalid group");
737
738 const QString data = readEntry(key, QString());
739 if (data.isNull()) {
740 return aDefault;
741 }
742
743 QStringList value;
744 QString val;
745 val.reserve(data.size());
746 // XXX List serialization being a separate layer from low-level parsing is
747 // probably a bug. No affected entries are defined, though.
748 bool quoted = false;
749 for (int p = 0; p < data.length(); p++) {
750 if (quoted) {
751 val += data[p];
752 quoted = false;
753 } else if (data[p] == QLatin1Char('\\')) {
754 quoted = true;
755 } else if (data[p] == QLatin1Char(';')) {
756 value.append(val);
757 val.clear();
758 val.reserve(data.size() - p);
759 } else {
760 val += data[p];
761 }
762 }
763 if (!val.isEmpty()) {
764 value.append(val);
765 }
766 return value;
767}
768
769QString KConfigGroup::readPathEntry(const QString &pKey, const QString &aDefault) const
770{
771 return readPathEntry(pKey.toUtf8().constData(), aDefault);
772}
773
774QString KConfigGroup::readPathEntry(const char *key, const QString &aDefault) const
775{
776 Q_ASSERT_X(isValid(), "KConfigGroup::readPathEntry", "accessing an invalid group");
777
778 bool expand = false;
779
780 QString aValue = config()->d_func()->lookupData(d->fullName(), key, KEntryMap::SearchLocalized, &expand);
781 if (aValue.isNull()) {
782 aValue = aDefault;
783 }
784
785 return KConfigPrivate::expandString(aValue);
786}
787
789{
790 return readPathEntry(pKey.toUtf8().constData(), aDefault);
791}
792
793QStringList KConfigGroup::readPathEntry(const char *key, const QStringList &aDefault) const
794{
795 Q_ASSERT_X(isValid(), "KConfigGroup::readPathEntry", "accessing an invalid group");
796
797 const QString data = readPathEntry(key, QString());
798 if (data.isNull()) {
799 return aDefault;
800 }
801
802 return KConfigGroupPrivate::deserializeList(data);
803}
804
805void KConfigGroup::writeEntry(const char *key, const QString &value, WriteConfigFlags flags)
806{
807 Q_ASSERT_X(isValid(), "KConfigGroup::writeEntry", "accessing an invalid group");
808 Q_ASSERT_X(!d->bConst, "KConfigGroup::writeEntry", "writing to a read-only group");
809
810 writeEntry(key, value.toUtf8(), flags);
811}
812
813void KConfigGroup::writeEntry(const QString &key, const QString &value, WriteConfigFlags flags)
814{
815 writeEntry(key.toUtf8().constData(), value, flags);
816}
817
818void KConfigGroup::writeEntry(const QString &key, const char *value, WriteConfigFlags pFlags)
819{
820 Q_ASSERT_X(isValid(), "KConfigGroup::writeEntry", "accessing an invalid group");
821 Q_ASSERT_X(!d->bConst, "KConfigGroup::writeEntry", "writing to a read-only group");
822
823 writeEntry(key.toUtf8().constData(), QVariant(QString::fromLatin1(value)), pFlags);
824}
825
826void KConfigGroup::writeEntry(const char *key, const char *value, WriteConfigFlags pFlags)
827{
828 writeEntry(key, QVariant(QString::fromLatin1(value)), pFlags);
829}
830
831void KConfigGroup::writeEntry(const char *key, const QByteArray &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 config()->d_func()->putData(d->fullName(), key, value.isNull() ? QByteArray("") : value, flags);
837}
838
839void KConfigGroup::writeEntry(const QString &key, const QByteArray &value, WriteConfigFlags pFlags)
840{
841 writeEntry(key.toUtf8().constData(), value, pFlags);
842}
843
844void KConfigGroup::writeEntry(const char *key, const QStringList &list, WriteConfigFlags flags)
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 QList<QByteArray> balist;
850 balist.reserve(list.count());
851
852 for (const QString &entry : list) {
853 balist.append(entry.toUtf8());
854 }
855
856 writeEntry(key, KConfigGroupPrivate::serializeList(balist), flags);
857}
858
860{
861 writeEntry(key.toUtf8().constData(), list, flags);
862}
863
864void KConfigGroup::writeEntry(const char *key, const QVariantList &list, WriteConfigFlags flags)
865{
866 Q_ASSERT_X(isValid(), "KConfigGroup::writeEntry", "accessing an invalid group");
867 Q_ASSERT_X(!d->bConst, "KConfigGroup::writeEntry", "writing to a read-only group");
868
870 data.reserve(list.count());
871
872 for (const QVariant &v : list) {
873 if (v.userType() == QMetaType::QByteArray) {
874 data << v.toByteArray();
875 } else {
876 data << v.toString().toUtf8();
877 }
878 }
879
880 writeEntry(key, KConfigGroupPrivate::serializeList(data), flags);
881}
882
883void KConfigGroup::writeEntry(const char *key, const QVariant &value, WriteConfigFlags flags)
884{
885 Q_ASSERT_X(isValid(), "KConfigGroup::writeEntry", "accessing an invalid group");
886 Q_ASSERT_X(!d->bConst, "KConfigGroup::writeEntry", "writing to a read-only group");
887
888 if (writeEntryGui(this, key, value, flags)) {
889 return; // GUI type that was handled
890 }
891
892 QByteArray data;
893 // if a type handler is added here you must add a QVConversions definition
894 // to kconfigconversioncheck_p.h, or KConfigConversionCheck::to_QVariant will not allow
895 // writeEntry<T> to convert to QVariant.
896 switch (static_cast<QMetaType::Type>(value.userType())) {
898 data = "";
899 break;
901 data = value.toByteArray();
902 break;
904 case QMetaType::Int:
905 case QMetaType::UInt:
907 case QMetaType::Float:
908 case QMetaType::Bool:
911 data = value.toString().toUtf8();
912 break;
914 if (!value.canConvert<QStringList>()) {
915 qCWarning(KCONFIG_CORE_LOG) << "not all types in \"" << key
916 << "\" can convert to QString,"
917 " information will be lost";
918 }
919 Q_FALLTHROUGH();
921 writeEntry(key, value.toList(), flags);
922 return;
923 case QMetaType::QPoint: {
924 const QPoint rPoint = value.toPoint();
925
926 const QVariantList list{rPoint.x(), rPoint.y()};
927
928 writeEntry(key, list, flags);
929 return;
930 }
931 case QMetaType::QPointF: {
932 const QPointF point = value.toPointF();
933
934 const QVariantList list{point.x(), point.y()};
935
936 writeEntry(key, list, flags);
937 return;
938 }
939 case QMetaType::QRect: {
940 const QRect rRect = value.toRect();
941
942 const QVariantList list{rRect.left(), rRect.top(), rRect.width(), rRect.height()};
943
944 writeEntry(key, list, flags);
945 return;
946 }
947 case QMetaType::QRectF: {
948 const QRectF rRectF = value.toRectF();
949
950 const QVariantList list{rRectF.left(), rRectF.top(), rRectF.width(), rRectF.height()};
951
952 writeEntry(key, list, flags);
953 return;
954 }
955 case QMetaType::QSize: {
956 const QSize rSize = value.toSize();
957
958 const QVariantList list{rSize.width(), rSize.height()};
959
960 writeEntry(key, list, flags);
961 return;
962 }
963 case QMetaType::QUuid: {
964 writeEntry(key, value.toString(), flags);
965 return;
966 }
967 case QMetaType::QSizeF: {
968 const QSizeF rSizeF = value.toSizeF();
969
970 const QVariantList list{rSizeF.width(), rSizeF.height()};
971
972 writeEntry(key, list, flags);
973 return;
974 }
975 case QMetaType::QDate: {
976 const QDate date = value.toDate();
977
978 const QVariantList list{date.year(), date.month(), date.day()};
979
980 writeEntry(key, list, flags);
981 return;
982 }
984 const QDateTime rDateTime = value.toDateTime();
985
986 const QTime time = rDateTime.time();
987 const QDate date = rDateTime.date();
988
989 QVariantList list{
990 date.year(),
991 date.month(),
992 date.day(),
993
994 time.hour(),
995 time.minute(),
996 time.second() + time.msec() / 1000.0,
997 };
998 if (rDateTime.timeRepresentation().timeSpec() != Qt::LocalTime) {
999 list.append(rDateTime.timeZone().id());
1000 }
1001
1002 writeEntry(key, list, flags);
1003 return;
1004 }
1005
1006 case QMetaType::QColor:
1007 case QMetaType::QFont:
1008 qCWarning(KCONFIG_CORE_LOG) << "KConfigGroup::writeEntry was passed GUI type '" << value.typeName()
1009 << "' but KConfigGui isn't linked! If it is linked to your program, this is a platform bug. "
1010 "Please inform the KDE developers";
1011 break;
1012 case QMetaType::QUrl:
1013 data = QUrl(value.toUrl()).toString().toUtf8();
1014 break;
1015 default:
1016 qCWarning(KCONFIG_CORE_LOG) << "KConfigGroup::writeEntry - unhandled type" << value.typeName() << "in group" << name();
1017 }
1018
1019 writeEntry(key, data, flags);
1020}
1021
1022void KConfigGroup::writeEntry(const QString &key, const QVariant &value, WriteConfigFlags flags)
1023{
1024 writeEntry(key.toUtf8().constData(), value, flags);
1025}
1026
1027void KConfigGroup::writeEntry(const QString &key, const QVariantList &list, WriteConfigFlags flags)
1028{
1029 writeEntry(key.toUtf8().constData(), list, flags);
1030}
1031
1033{
1034 writeXdgListEntry(key.toUtf8().constData(), value, pFlags);
1035}
1036
1037void KConfigGroup::writeXdgListEntry(const char *key, const QStringList &list, WriteConfigFlags flags)
1038{
1039 Q_ASSERT_X(isValid(), "KConfigGroup::writeXdgListEntry", "accessing an invalid group");
1040 Q_ASSERT_X(!d->bConst, "KConfigGroup::writeXdgListEntry", "writing to a read-only group");
1041
1042 QString value;
1043 value.reserve(4096);
1044
1045 // XXX List serialization being a separate layer from low-level escaping is
1046 // probably a bug. No affected entries are defined, though.
1047 for (QString val : list) { // clazy:exclude=range-loop
1048 val.replace(QLatin1Char('\\'), QLatin1String("\\\\")).replace(QLatin1Char(';'), QLatin1String("\\;"));
1049 value += val + QLatin1Char(';');
1050 }
1051
1052 writeEntry(key, value, flags);
1053}
1054
1055void KConfigGroup::writePathEntry(const QString &pKey, const QString &path, WriteConfigFlags pFlags)
1056{
1057 writePathEntry(pKey.toUtf8().constData(), path, pFlags);
1058}
1059
1060void KConfigGroup::writePathEntry(const char *pKey, const QString &path, WriteConfigFlags pFlags)
1061{
1062 Q_ASSERT_X(isValid(), "KConfigGroup::writePathEntry", "accessing an invalid group");
1063 Q_ASSERT_X(!d->bConst, "KConfigGroup::writePathEntry", "writing to a read-only group");
1064
1065 config()->d_func()->putData(d->fullName(), pKey, translatePath(path).toUtf8(), pFlags, true);
1066}
1067
1069{
1070 writePathEntry(pKey.toUtf8().constData(), value, pFlags);
1071}
1072
1073void KConfigGroup::writePathEntry(const char *pKey, const QStringList &value, WriteConfigFlags pFlags)
1074{
1075 Q_ASSERT_X(isValid(), "KConfigGroup::writePathEntry", "accessing an invalid group");
1076 Q_ASSERT_X(!d->bConst, "KConfigGroup::writePathEntry", "writing to a read-only group");
1077
1078 QList<QByteArray> list;
1079 list.reserve(value.length());
1080 for (const QString &path : value) {
1081 list << translatePath(path).toUtf8();
1082 }
1083
1084 config()->d_func()->putData(d->fullName(), pKey, KConfigGroupPrivate::serializeList(list), pFlags, true);
1085}
1086
1088{
1089 Q_ASSERT_X(isValid(), "KConfigGroup::deleteEntry", "accessing an invalid group");
1090 Q_ASSERT_X(!d->bConst, "KConfigGroup::deleteEntry", "deleting from a read-only group");
1091
1092 config()->d_func()->putData(d->fullName(), key, QByteArray(), flags);
1093}
1094
1096{
1097 deleteEntry(key.toUtf8().constData(), flags);
1098}
1099
1101{
1102 Q_ASSERT_X(isValid(), "KConfigGroup::revertToDefault", "accessing an invalid group");
1103 Q_ASSERT_X(!d->bConst, "KConfigGroup::revertToDefault", "writing to a read-only group");
1104
1105 config()->d_func()->revertEntry(d->fullName(), key, flags);
1106}
1107
1109{
1110 revertToDefault(key.toUtf8().constData(), flags);
1111}
1112
1113bool KConfigGroup::hasDefault(const char *key) const
1114{
1115 Q_ASSERT_X(isValid(), "KConfigGroup::hasDefault", "accessing an invalid group");
1116
1117 KEntryMap::SearchFlags flags = KEntryMap::SearchDefaults | KEntryMap::SearchLocalized;
1118
1119 return !config()->d_func()->lookupData(d->fullName(), key, flags).isNull();
1120}
1121
1122bool KConfigGroup::hasDefault(const QString &key) const
1123{
1124 return hasDefault(key.toUtf8().constData());
1125}
1126
1127bool KConfigGroup::hasKey(const char *key) const
1128{
1129 Q_ASSERT_X(isValid(), "KConfigGroup::hasKey", "accessing an invalid group");
1130
1131 KEntryMap::SearchFlags flags = KEntryMap::SearchLocalized;
1132 if (config()->readDefaults()) {
1133 flags |= KEntryMap::SearchDefaults;
1134 }
1135
1136 return !config()->d_func()->lookupData(d->fullName(), key, flags).isNull();
1137}
1138
1139bool KConfigGroup::hasKey(const QString &key) const
1140{
1141 return hasKey(key.toUtf8().constData());
1142}
1143
1145{
1146 Q_ASSERT_X(isValid(), "KConfigGroup::isImmutable", "accessing an invalid group");
1147
1148 return d->bImmutable;
1149}
1150
1152{
1153 Q_ASSERT_X(isValid(), "KConfigGroup::groupList", "accessing an invalid group");
1154
1155 return config()->d_func()->groupList(d->fullName());
1156}
1157
1159{
1160 Q_ASSERT_X(isValid(), "KConfigGroup::keyList", "accessing an invalid group");
1161
1162 return config()->d_func()->usedKeyList(d->fullName());
1163}
1164
1166{
1167 Q_ASSERT_X(isValid(), "KConfigGroup::markAsClean", "accessing an invalid group");
1168
1169 config()->markAsClean();
1170}
1171
1173{
1174 Q_ASSERT_X(isValid(), "KConfigGroup::accessMode", "accessing an invalid group");
1175
1176 return config()->accessMode();
1177}
1178
1180{
1181 Q_ASSERT_X(isValid(), "KConfigGroup::hasGroupImpl", "accessing an invalid group");
1182
1183 return config()->hasGroup(d->fullName(b));
1184}
1185
1187{
1188 Q_ASSERT_X(isValid(), "KConfigGroup::deleteGroupImpl", "accessing an invalid group");
1189 Q_ASSERT_X(!d->bConst, "KConfigGroup::deleteGroupImpl", "deleting from a read-only group");
1190
1191 config()->deleteGroup(d->fullName(b), flags);
1192}
1193
1195{
1196 Q_ASSERT_X(isValid(), "KConfigGroup::isGroupImmutableImpl", "accessing an invalid group");
1197
1198 if (!hasGroupImpl(groupName)) { // group doesn't exist yet
1199 return d->bImmutable; // child groups are immutable if the parent is immutable.
1200 }
1201
1202 return config()->isGroupImmutable(d->fullName(groupName));
1203}
1204
1205void KConfigGroup::copyTo(KConfigBase *other, WriteConfigFlags pFlags) const
1206{
1207 Q_ASSERT_X(isValid(), "KConfigGroup::copyTo", "accessing an invalid group");
1208 Q_ASSERT(other != nullptr);
1209
1210 if (KConfigGroup *otherGroup = dynamic_cast<KConfigGroup *>(other)) {
1211 config()->d_func()->copyGroup(d->fullName(), otherGroup->d->fullName(), otherGroup, pFlags);
1212 } else if (KConfig *otherConfig = dynamic_cast<KConfig *>(other)) {
1213 KConfigGroup newGroup = otherConfig->group(d->fullName());
1214 otherConfig->d_func()->copyGroup(d->fullName(), d->fullName(), &newGroup, pFlags);
1215 } else {
1216 Q_ASSERT_X(false, "KConfigGroup::copyTo", "unknown type of KConfigBase");
1217 }
1218}
1219
1221{
1222 Q_ASSERT_X(isValid(), "KConfigGroup::reparent", "accessing an invalid group");
1223 Q_ASSERT_X(!d->bConst, "KConfigGroup::reparent", "reparenting a read-only group");
1224 Q_ASSERT_X(!d->bImmutable, "KConfigGroup::reparent", "reparenting an immutable group");
1225 Q_ASSERT(parent != nullptr);
1226
1227 KConfigGroup oldGroup(*this);
1228
1229 d = KConfigGroupPrivate::create(parent, d->mName, false, false);
1230 oldGroup.copyTo(this, pFlags);
1231 oldGroup.deleteGroup(); // so that the entries with the old group name are deleted on sync
1232}
1233
1234void KConfigGroup::moveValue(const char *key, KConfigGroup &other, WriteConfigFlags pFlags)
1235{
1236 const QString groupName = d->fullName();
1237 const auto entry = config()->d_ptr->lookupInternalEntry(groupName, key, KEntryMap::SearchLocalized);
1238
1239 // Only write the entry if it is not null, if it is a global enry there is no point in moving it
1240 if (!entry.mValue.isNull() && !entry.bGlobal) {
1241 deleteEntry(key, pFlags);
1242 KEntryMap::EntryOptions options = KEntryMap::EntryOption::EntryDirty;
1243 if (entry.bDeleted) {
1244 options |= KEntryMap::EntryDeleted;
1245 }
1246
1247 if (entry.bExpand) {
1248 options |= KEntryMap::EntryExpansion;
1249 }
1250
1251 other.config()->d_ptr->setEntryData(other.d->fullName(), key, entry.mValue, options);
1252 }
1253}
1254
1256{
1257 Q_ASSERT(isValid());
1258 Q_ASSERT(other.isValid());
1259
1260 for (const auto key : keys) {
1261 moveValue(key, other, pFlags);
1262 }
1263}
1264
1266{
1267 Q_ASSERT(isValid());
1268 Q_ASSERT(other.isValid());
1269
1270 const QStringList keys = keyList();
1271 for (const QString &key : keys) {
1272 moveValue(key.toUtf8().constData(), other, pFlags);
1273 }
1274}
void deleteGroup(const QString &group, WriteConfigFlags flags=Normal)
Delete group.
AccessMode
Possible return values for accessMode().
QFlags< WriteConfigFlag > WriteConfigFlags
Stores a combination of WriteConfigFlag values.
Definition kconfigbase.h:67
bool isGroupImmutable(const QString &group) const
Can changes be made to the entries in group?
bool hasGroup(const QString &group) const
Returns true if the specified group is known about.
A class for one specific group in a KConfig object.
void reparent(KConfigBase *parent, WriteConfigFlags pFlags=Normal)
Changes the configuration object that this group belongs to.
T readEntry(const QString &key, const T &aDefault) const
Reads the value of an entry specified by pKey in the current group.
void writeXdgListEntry(const QString &pKey, const QStringList &value, WriteConfigFlags pFlags=Normal)
Writes a list of strings to the config object, following XDG desktop entry spec separator semantics.
QString name() const
The name of this group.
bool hasDefault(const QString &key) const
Whether a default is specified for an entry in either the system wide configuration file or the globa...
bool hasKey(const QString &key) const
Checks whether the key has an entry in this group.
QString readPathEntry(const QString &pKey, const QString &aDefault) const
Reads a path.
bool hasGroupImpl(const QString &groupName) const override
void writePathEntry(const QString &pKey, const QString &path, WriteConfigFlags pFlags=Normal)
Writes a file path to the configuration.
void revertToDefault(const QString &key, WriteConfigFlags pFlag=WriteConfigFlags())
Reverts an entry to the default settings.
bool isEntryImmutable(const QString &key) const
Checks if it is possible to change the given entry.
void writeEntry(const QString &key, const QVariant &value, WriteConfigFlags pFlags=Normal)
Writes a value to the configuration object.
AccessMode accessMode() const override
void deleteGroup(WriteConfigFlags pFlags=Normal)
Delete all entries in the entire group.
void deleteGroupImpl(const QString &groupName, WriteConfigFlags flags) override
bool isValid() const
Whether the group is valid.
bool isGroupImmutableImpl(const QString &groupName) const override
void markAsClean() override
KConfigGroup()
Constructs an invalid group.
bool isImmutable() const override
Whether this group may be changed.
KConfig * config()
Return the config object that this group belongs to.
bool exists() const
Check whether the containing KConfig object actually contains a group with this name.
void deleteEntry(const QString &pKey, WriteConfigFlags pFlags=Normal)
Deletes the entry specified by pKey in the current group.
bool sync() override
void moveValuesTo(const QList< const char * > &keys, KConfigGroup &other, WriteConfigFlags pFlags=Normal)
Moves the key-value pairs from one config group to the other.
KConfigGroup parent() const
Returns the group that this group belongs to.
QMap< QString, QString > entryMap() const
Returns a map (tree) of entries for all entries in this group.
QStringList readXdgListEntry(const QString &pKey, const QStringList &aDefault=QStringList()) const
Reads a list of strings from the config object with semicolons separating them (i....
QStringList groupList() const override
QString readEntryUntranslated(const QString &pKey, const QString &aDefault=QString()) const
Reads an untranslated string entry.
KConfigGroup groupImpl(const QString &groupName) override
QStringList keyList() const
Returns a list of keys this group contains.
void copyTo(KConfigBase *other, WriteConfigFlags pFlags=Normal) const
Copies the entries in this group to another configuration object.
The central class of the KDE configuration data system.
Definition kconfig.h:56
AccessMode accessMode() const override
Definition kconfig.cpp:830
void markAsClean() override
Definition kconfig.cpp:515
QMap< QString, QString > entryMap(const QString &aGroup=QString()) const
Returns a map (tree) of entries in a particular group.
Definition kconfig.cpp:384
bool sync() override
Definition kconfig.cpp:409
QStringList groupList() const override
Definition kconfig.cpp:302
Q_SCRIPTABLE QString start(QString train="")
QAction * end(const QObject *recvr, const char *slot, QObject *parent)
QString path(const QString &relativePath)
KIOCORE_EXPORT QStringList list(const QString &fileClass)
QAction * next(const QObject *recvr, const char *slot, QObject *parent)
const char * constData() const const
bool isEmpty() const const
bool isNull() const const
qsizetype lastIndexOf(QByteArrayView bv) const const
QByteArray mid(qsizetype pos, qsizetype len) const const
QByteArray & replace(QByteArrayView before, QByteArrayView after)
void reserve(qsizetype size)
int day() const const
int month() const const
int year() const const
QDate date() const const
QTime time() const const
QTimeZone timeRepresentation() const const
QTimeZone timeZone() const const
QString homePath()
bool isRelativePath(const QString &path)
QString toNativeSeparators(const QString &pathName)
QString decodeName(const QByteArray &localFileName)
void append(QList< T > &&value)
const_reference at(qsizetype i) const const
const_iterator cbegin() const const
const_iterator cend() const const
qsizetype count() const const
bool isEmpty() const const
qsizetype length() const const
void reserve(qsizetype size)
int x() const const
int y() const const
qreal x() const const
qreal y() const const
int height() const const
int left() const const
int top() const const
int width() const const
qreal height() const const
qreal left() const const
qreal top() const const
qreal width() const const
int height() const const
int width() const const
qreal height() const const
qreal width() const const
QString arg(Args &&... args) const const
void clear()
QString fromLatin1(QByteArrayView str)
QString fromUtf8(QByteArrayView str)
bool isEmpty() const const
bool isNull() const const
qsizetype length() const const
QString & replace(QChar before, QChar after, Qt::CaseSensitivity cs)
void reserve(qsizetype size)
qsizetype size() const const
void squeeze()
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
QByteArray toUtf8() const const
CaseInsensitive
LocalTime
int hour() const const
int minute() const const
int msec() const const
int second() const const
QByteArray id() const const
Qt::TimeSpec timeSpec() const const
QUrl fromLocalFile(const QString &localFile)
QString toLocalFile() const const
QString toString(FormattingOptions options) const const
QUuid fromString(QAnyStringView string)
bool canConvert() const const
bool convert(QMetaType targetType)
QMetaType metaType() const const
QByteArray toByteArray() const const
QDate toDate() const const
QDateTime toDateTime() const const
QList< QVariant > toList() const const
QPoint toPoint() const const
QPointF toPointF() const const
QRect toRect() const const
QRectF toRectF() const const
QSize toSize() const const
QSizeF toSizeF() const const
QString toString() const const
QUrl toUrl() const const
const char * typeName() const const
int userType() const const
void push_back(T &&t)
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri Apr 18 2025 12:10:09 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.