File indexing completed on 2024-05-12 03:54:25
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 2006, 2007 Thomas Braxton <kde.braxton@gmail.com> 0004 SPDX-FileCopyrightText: 1999 Preston Brown <pbrown@kde.org> 0005 SPDX-FileCopyrightText: 1997 Matthias Kalle Dalheimer <kalle@kde.org> 0006 0007 SPDX-License-Identifier: LGPL-2.0-or-later 0008 */ 0009 0010 #include "kconfiggroup.h" 0011 #include "kconfiggroup_p.h" 0012 0013 #include "kconfig.h" 0014 #include "kconfig_core_log_settings.h" 0015 #include "kconfig_p.h" 0016 #include "kconfigdata_p.h" 0017 #include "ksharedconfig.h" 0018 0019 #include <QDate> 0020 #include <QDir> 0021 #include <QFile> 0022 #include <QPoint> 0023 #include <QRect> 0024 #include <QSharedData> 0025 #include <QString> 0026 #include <QTextStream> 0027 #include <QUrl> 0028 #include <QUuid> 0029 0030 #include <algorithm> 0031 #include <array> 0032 #include <math.h> 0033 #include <stdlib.h> 0034 0035 class KConfigGroupPrivate : public QSharedData 0036 { 0037 public: 0038 KConfigGroupPrivate(KConfig *owner, bool isImmutable, bool isConst, const QString &name) 0039 : mOwner(owner) 0040 , mName(name) 0041 , bImmutable(isImmutable) 0042 , bConst(isConst) 0043 { 0044 if (Q_UNLIKELY(!mOwner->name().isEmpty() && mOwner->accessMode() == KConfigBase::NoAccess)) { 0045 qCWarning(KCONFIG_CORE_LOG) << "Created a KConfigGroup on an inaccessible config location" << mOwner->name() << name; 0046 } 0047 } 0048 0049 KConfigGroupPrivate(const KSharedConfigPtr &owner, const QString &name) 0050 : sOwner(owner) 0051 , mOwner(sOwner.data()) 0052 , mName(name) 0053 , bImmutable(name.isEmpty() ? owner->isImmutable() : owner->isGroupImmutable(name)) 0054 , bConst(false) 0055 { 0056 if (Q_UNLIKELY(!mOwner->name().isEmpty() && mOwner->accessMode() == KConfigBase::NoAccess)) { 0057 qCWarning(KCONFIG_CORE_LOG) << "Created a KConfigGroup on an inaccessible config location" << mOwner->name() << name; 0058 } 0059 } 0060 0061 KConfigGroupPrivate(KConfigGroup *parent, bool isImmutable, bool isConst, const QString &name) 0062 : sOwner(parent->d->sOwner) 0063 , mOwner(parent->d->mOwner) 0064 , mName(name) 0065 , bImmutable(isImmutable) 0066 , bConst(isConst) 0067 { 0068 if (!parent->d->mName.isEmpty()) { 0069 mParent = parent->d; 0070 } 0071 } 0072 0073 KConfigGroupPrivate(const KConfigGroupPrivate *other, bool isImmutable, const QString &name) 0074 : sOwner(other->sOwner) 0075 , mOwner(other->mOwner) 0076 , mName(name) 0077 , bImmutable(isImmutable) 0078 , bConst(other->bConst) 0079 { 0080 if (!other->mName.isEmpty()) { 0081 mParent = const_cast<KConfigGroupPrivate *>(other); 0082 } 0083 } 0084 0085 KSharedConfig::Ptr sOwner; 0086 KConfig *mOwner; 0087 QExplicitlySharedDataPointer<KConfigGroupPrivate> mParent; 0088 QString mName; 0089 0090 /* bitfield */ 0091 const bool bImmutable : 1; // is this group immutable? 0092 const bool bConst : 1; // is this group read-only? 0093 0094 QString fullName() const 0095 { 0096 if (!mParent) { 0097 return name(); 0098 } 0099 return mParent->fullName(mName); 0100 } 0101 0102 QString name() const 0103 { 0104 if (mName.isEmpty()) { 0105 return QStringLiteral("<default>"); 0106 } 0107 return mName; 0108 } 0109 0110 QString fullName(const QString &aGroup) const 0111 { 0112 if (mName.isEmpty()) { 0113 return aGroup; 0114 } 0115 return fullName() + QLatin1Char('\x1d') + aGroup; 0116 } 0117 0118 static QExplicitlySharedDataPointer<KConfigGroupPrivate> create(KConfigBase *master, const QString &name, bool isImmutable, bool isConst) 0119 { 0120 QExplicitlySharedDataPointer<KConfigGroupPrivate> data; 0121 if (dynamic_cast<KConfigGroup *>(master)) { 0122 data = new KConfigGroupPrivate(static_cast<KConfigGroup *>(master), isImmutable, isConst, name); 0123 } else { 0124 data = new KConfigGroupPrivate(dynamic_cast<KConfig *>(master), isImmutable, isConst, name); 0125 } 0126 return data; 0127 } 0128 0129 static QByteArray serializeList(const QList<QByteArray> &list); 0130 static QStringList deserializeList(const QString &data); 0131 }; 0132 0133 QByteArray KConfigGroupPrivate::serializeList(const QList<QByteArray> &list) 0134 { 0135 QByteArray value; 0136 0137 if (!list.isEmpty()) { 0138 auto it = list.cbegin(); 0139 const auto end = list.cend(); 0140 0141 value = QByteArray(*it).replace('\\', QByteArrayLiteral("\\\\")).replace(',', QByteArrayLiteral("\\,")); 0142 0143 while (++it != end) { 0144 // In the loop, so it is not done when there is only one element. 0145 // Doing it repeatedly is a pretty cheap operation. 0146 value.reserve(4096); 0147 0148 value += ','; 0149 value += QByteArray(*it).replace('\\', QByteArrayLiteral("\\\\")).replace(',', QByteArrayLiteral("\\,")); 0150 } 0151 0152 // To be able to distinguish an empty list from a list with one empty element. 0153 if (value.isEmpty()) { 0154 value = QByteArrayLiteral("\\0"); 0155 } 0156 } 0157 0158 return value; 0159 } 0160 0161 QStringList KConfigGroupPrivate::deserializeList(const QString &data) 0162 { 0163 if (data.isEmpty()) { 0164 return QStringList(); 0165 } 0166 if (data == QLatin1String("\\0")) { 0167 return QStringList(QString()); 0168 } 0169 QStringList value; 0170 QString val; 0171 val.reserve(data.size()); 0172 bool quoted = false; 0173 for (int p = 0; p < data.length(); p++) { 0174 if (quoted) { 0175 val += data[p]; 0176 quoted = false; 0177 } else if (data[p].unicode() == '\\') { 0178 quoted = true; 0179 } else if (data[p].unicode() == ',') { 0180 val.squeeze(); // release any unused memory 0181 value.append(val); 0182 val.clear(); 0183 val.reserve(data.size() - p); 0184 } else { 0185 val += data[p]; 0186 } 0187 } 0188 value.append(val); 0189 return value; 0190 } 0191 0192 static QList<int> asIntList(const QByteArray &string) 0193 { 0194 const auto &splitString = string.split(','); 0195 0196 QList<int> list; 0197 list.reserve(splitString.count()); 0198 for (const QByteArray &s : splitString) { 0199 list << s.toInt(); 0200 } 0201 return list; 0202 } 0203 0204 static QList<qreal> asRealList(const QByteArray &string) 0205 { 0206 const auto &splitString = string.split(','); 0207 0208 QList<qreal> list; 0209 list.reserve(splitString.count()); 0210 for (const QByteArray &s : splitString) { 0211 list << s.toDouble(); 0212 } 0213 return list; 0214 } 0215 0216 static QString errString(const char *pKey, const QByteArray &value, const QVariant &aDefault) 0217 { 0218 return QStringLiteral("\"%1\" - conversion of \"%3\" to %2 failed") 0219 .arg(QString::fromLatin1(pKey), QString::fromLatin1(aDefault.typeName()), QString::fromLatin1(value)); 0220 } 0221 0222 static QString formatError(int expected, int got) 0223 { 0224 return QStringLiteral(" (wrong format: expected %1 items, got %2)").arg(expected).arg(got); 0225 } 0226 0227 QVariant KConfigGroup::convertToQVariant(const char *pKey, const QByteArray &value, const QVariant &aDefault) 0228 { 0229 // if a type handler is added here you must add a QVConversions definition 0230 // to kconfigconversioncheck_p.h, or KConfigConversionCheck::to_QVariant will not allow 0231 // readEntry<T> to convert to QVariant. 0232 switch (static_cast<QMetaType::Type>(aDefault.userType())) { 0233 case QMetaType::UnknownType: 0234 return QVariant(); 0235 case QMetaType::QString: 0236 // this should return the raw string not the dollar expanded string. 0237 // imho if processed string is wanted should call 0238 // readEntry(key, QString) not readEntry(key, QVariant) 0239 return QString::fromUtf8(value); 0240 case QMetaType::QUuid: 0241 return QUuid::fromString(value); 0242 case QMetaType::QVariantList: 0243 case QMetaType::QStringList: 0244 return KConfigGroupPrivate::deserializeList(QString::fromUtf8(value)); 0245 case QMetaType::QByteArray: 0246 return value; 0247 case QMetaType::Bool: { 0248 static const std::array<const char *, 4> negatives = {"false", "no", "off", "0"}; 0249 0250 return std::all_of(negatives.begin(), negatives.end(), [value](const char *negativeString) { 0251 return value.compare(negativeString, Qt::CaseInsensitive) != 0; 0252 }); 0253 } 0254 case QMetaType::Double: 0255 case QMetaType::Float: 0256 case QMetaType::Int: 0257 case QMetaType::UInt: 0258 case QMetaType::LongLong: 0259 case QMetaType::ULongLong: { 0260 QVariant tmp = value; 0261 if (!tmp.convert(aDefault.metaType())) { 0262 tmp = aDefault; 0263 } 0264 return tmp; 0265 } 0266 case QMetaType::QPoint: { 0267 const auto list = asIntList(value); 0268 0269 if (list.count() != 2) { 0270 qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault) << formatError(2, list.count()); 0271 return aDefault; 0272 } 0273 return QPoint(list.at(0), list.at(1)); 0274 } 0275 case QMetaType::QPointF: { 0276 const auto list = asRealList(value); 0277 0278 if (list.count() != 2) { 0279 qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault) << formatError(2, list.count()); 0280 return aDefault; 0281 } 0282 return QPointF(list.at(0), list.at(1)); 0283 } 0284 case QMetaType::QRect: { 0285 const auto list = asIntList(value); 0286 0287 if (list.count() != 4) { 0288 qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault) << formatError(4, list.count()); 0289 return aDefault; 0290 } 0291 const QRect rect(list.at(0), list.at(1), list.at(2), list.at(3)); 0292 if (!rect.isValid()) { 0293 qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault); 0294 return aDefault; 0295 } 0296 return rect; 0297 } 0298 case QMetaType::QRectF: { 0299 const auto list = asRealList(value); 0300 0301 if (list.count() != 4) { 0302 qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault) << formatError(4, list.count()); 0303 return aDefault; 0304 } 0305 const QRectF rect(list.at(0), list.at(1), list.at(2), list.at(3)); 0306 if (!rect.isValid()) { 0307 qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault); 0308 return aDefault; 0309 } 0310 return rect; 0311 } 0312 case QMetaType::QSize: { 0313 const auto list = asIntList(value); 0314 0315 if (list.count() != 2) { 0316 qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault) << formatError(2, list.count()); 0317 return aDefault; 0318 } 0319 const QSize size(list.at(0), list.at(1)); 0320 if (!size.isValid()) { 0321 qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault); 0322 return aDefault; 0323 } 0324 return size; 0325 } 0326 case QMetaType::QSizeF: { 0327 const auto list = asRealList(value); 0328 0329 if (list.count() != 2) { 0330 qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault) << formatError(2, list.count()); 0331 return aDefault; 0332 } 0333 const QSizeF size(list.at(0), list.at(1)); 0334 if (!size.isValid()) { 0335 qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault); 0336 return aDefault; 0337 } 0338 return size; 0339 } 0340 case QMetaType::QDateTime: { 0341 const auto list = asRealList(value); 0342 if (list.count() < 6) { 0343 qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault) << formatError(6, list.count()); 0344 return aDefault; 0345 } 0346 const QDate date(list.at(0), list.at(1), list.at(2)); 0347 const qreal totalSeconds = list.at(5); 0348 qreal seconds; 0349 const qreal fractional = modf(totalSeconds, &seconds); 0350 const qreal milliseconds = round(fractional * 1000.0); 0351 const QTime time(list.at(3), list.at(4), seconds, milliseconds); 0352 const QDateTime dt(date, time); 0353 if (!dt.isValid()) { 0354 qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault); 0355 return aDefault; 0356 } 0357 return dt; 0358 } 0359 case QMetaType::QDate: { 0360 auto list = asIntList(value); 0361 if (list.count() == 6) { 0362 list = list.mid(0, 3); // don't break config files that stored QDate as QDateTime 0363 } 0364 if (list.count() != 3) { 0365 qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault) << formatError(3, list.count()); 0366 return aDefault; 0367 } 0368 const QDate date(list.at(0), list.at(1), list.at(2)); 0369 if (!date.isValid()) { 0370 qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault); 0371 return aDefault; 0372 } 0373 return date; 0374 } 0375 case QMetaType::QColor: 0376 case QMetaType::QFont: 0377 qCWarning(KCONFIG_CORE_LOG) << "KConfigGroup::readEntry was passed GUI type '" << aDefault.typeName() 0378 << "' but KConfigGui isn't linked! If it is linked to your program, " 0379 "this is a platform bug. Please inform the KDE developers"; 0380 break; 0381 case QMetaType::QUrl: 0382 return QUrl(QString::fromUtf8(value)); 0383 0384 default: 0385 break; 0386 } 0387 0388 qCWarning(KCONFIG_CORE_LOG) << "unhandled type " << aDefault.typeName(); 0389 return QVariant(); 0390 } 0391 0392 static bool cleanHomeDirPath(QString &path, const QString &homeDir) 0393 { 0394 #ifdef Q_OS_WIN // safer 0395 if (!QDir::toNativeSeparators(path).startsWith(QDir::toNativeSeparators(homeDir))) { 0396 return false; 0397 } 0398 #else 0399 if (!path.startsWith(homeDir)) { 0400 return false; 0401 } 0402 #endif 0403 0404 int len = homeDir.length(); 0405 // replace by "$HOME" if possible 0406 if (len && (path.length() == len || path[len] == QLatin1Char('/'))) { 0407 path.replace(0, len, QStringLiteral("$HOME")); 0408 return true; 0409 } 0410 0411 return false; 0412 } 0413 0414 static QString translatePath(QString path) // krazy:exclude=passbyvalue 0415 { 0416 if (path.isEmpty()) { 0417 return path; 0418 } 0419 0420 // only "our" $HOME should be interpreted 0421 path.replace(QLatin1Char('$'), QLatin1String("$$")); 0422 0423 const bool startsWithFile = path.startsWith(QLatin1String("file:"), Qt::CaseInsensitive); 0424 path = startsWithFile ? QUrl(path).toLocalFile() : path; 0425 0426 if (QDir::isRelativePath(path)) { 0427 return path; 0428 } 0429 0430 // Use the same thing as what expandString() will do, to keep data intact 0431 #ifdef Q_OS_WIN 0432 const QString homeDir = QDir::homePath(); 0433 #else 0434 const QString homeDir = QFile::decodeName(qgetenv("HOME")); 0435 #endif 0436 (void)cleanHomeDirPath(path, homeDir); 0437 0438 if (startsWithFile) { 0439 path = QUrl::fromLocalFile(path).toString(); 0440 } 0441 0442 return path; 0443 } 0444 0445 KConfigGroup::KConfigGroup() 0446 : d() 0447 { 0448 } 0449 0450 bool KConfigGroup::isValid() const 0451 { 0452 return bool(d); 0453 } 0454 0455 KConfigGroupGui _kde_internal_KConfigGroupGui; 0456 static inline bool readEntryGui(const QByteArray &data, const char *key, const QVariant &input, QVariant &output) 0457 { 0458 if (_kde_internal_KConfigGroupGui.readEntryGui) { 0459 return _kde_internal_KConfigGroupGui.readEntryGui(data, key, input, output); 0460 } 0461 return false; 0462 } 0463 0464 static inline bool writeEntryGui(KConfigGroup *cg, const char *key, const QVariant &input, KConfigGroup::WriteConfigFlags flags) 0465 { 0466 if (_kde_internal_KConfigGroupGui.writeEntryGui) { 0467 return _kde_internal_KConfigGroupGui.writeEntryGui(cg, key, input, flags); 0468 } 0469 return false; 0470 } 0471 0472 KConfigGroup::KConfigGroup(KConfigBase *master, const QString &_group) 0473 : d(KConfigGroupPrivate::create(master, _group, master->isGroupImmutable(_group), false)) 0474 { 0475 } 0476 0477 KConfigGroup::KConfigGroup(const KConfigBase *master, const QString &_group) 0478 : d(KConfigGroupPrivate::create(const_cast<KConfigBase *>(master), _group, master->isGroupImmutable(_group), true)) 0479 { 0480 } 0481 0482 KConfigGroup::KConfigGroup(const KSharedConfigPtr &master, const QString &_group) 0483 : d(new KConfigGroupPrivate(master, _group)) 0484 { 0485 } 0486 0487 KConfigGroup &KConfigGroup::operator=(const KConfigGroup &rhs) 0488 { 0489 d = rhs.d; 0490 return *this; 0491 } 0492 0493 KConfigGroup::KConfigGroup(const KConfigGroup &rhs) 0494 : d(rhs.d) 0495 { 0496 } 0497 0498 KConfigGroup::~KConfigGroup() 0499 { 0500 d.reset(); 0501 } 0502 0503 KConfigGroup KConfigGroup::groupImpl(const QString &aGroup) 0504 { 0505 Q_ASSERT_X(isValid(), "KConfigGroup::groupImpl", "accessing an invalid group"); 0506 Q_ASSERT_X(!aGroup.isEmpty(), "KConfigGroup::groupImpl", "can not have an unnamed child group"); 0507 0508 KConfigGroup newGroup; 0509 0510 newGroup.d = new KConfigGroupPrivate(this, isGroupImmutableImpl(aGroup), d->bConst, aGroup); 0511 0512 return newGroup; 0513 } 0514 0515 const KConfigGroup KConfigGroup::groupImpl(const QString &aGroup) const 0516 { 0517 Q_ASSERT_X(isValid(), "KConfigGroup::groupImpl", "accessing an invalid group"); 0518 Q_ASSERT_X(!aGroup.isEmpty(), "KConfigGroup::groupImpl", "can not have an unnamed child group"); 0519 0520 KConfigGroup newGroup; 0521 0522 newGroup.d = new KConfigGroupPrivate(const_cast<KConfigGroup *>(this), isGroupImmutableImpl(aGroup), true, aGroup); 0523 0524 return newGroup; 0525 } 0526 0527 KConfigGroup KConfigGroup::parent() const 0528 { 0529 Q_ASSERT_X(isValid(), "KConfigGroup::parent", "accessing an invalid group"); 0530 0531 KConfigGroup parentGroup; 0532 0533 if (d->mParent) { 0534 parentGroup.d = d->mParent; 0535 } else { 0536 parentGroup.d = new KConfigGroupPrivate(d->mOwner, d->mOwner->isImmutable(), d->bConst, QString()); 0537 // make sure we keep the refcount up on the KConfig object 0538 parentGroup.d->sOwner = d->sOwner; 0539 } 0540 0541 return parentGroup; 0542 } 0543 0544 void KConfigGroup::deleteGroup(WriteConfigFlags flags) 0545 { 0546 Q_ASSERT_X(isValid(), "KConfigGroup::deleteGroup", "accessing an invalid group"); 0547 Q_ASSERT_X(!d->bConst, "KConfigGroup::deleteGroup", "deleting a read-only group"); 0548 0549 config()->deleteGroup(d->fullName(), flags); 0550 } 0551 0552 QString KConfigGroup::name() const 0553 { 0554 Q_ASSERT_X(isValid(), "KConfigGroup::name", "accessing an invalid group"); 0555 0556 return d->name(); 0557 } 0558 0559 bool KConfigGroup::exists() const 0560 { 0561 Q_ASSERT_X(isValid(), "KConfigGroup::exists", "accessing an invalid group"); 0562 0563 return config()->hasGroup(d->fullName()); 0564 } 0565 0566 bool KConfigGroup::sync() 0567 { 0568 Q_ASSERT_X(isValid(), "KConfigGroup::sync", "accessing an invalid group"); 0569 0570 if (!d->bConst) { 0571 return config()->sync(); 0572 } 0573 0574 return false; 0575 } 0576 0577 QMap<QString, QString> KConfigGroup::entryMap() const 0578 { 0579 Q_ASSERT_X(isValid(), "KConfigGroup::entryMap", "accessing an invalid group"); 0580 0581 return config()->entryMap(d->fullName()); 0582 } 0583 0584 KConfig *KConfigGroup::config() 0585 { 0586 Q_ASSERT_X(isValid(), "KConfigGroup::config", "accessing an invalid group"); 0587 0588 return d->mOwner; 0589 } 0590 0591 const KConfig *KConfigGroup::config() const 0592 { 0593 Q_ASSERT_X(isValid(), "KConfigGroup::config", "accessing an invalid group"); 0594 0595 return d->mOwner; 0596 } 0597 0598 bool KConfigGroup::isEntryImmutable(const char *key) const 0599 { 0600 Q_ASSERT_X(isValid(), "KConfigGroup::isEntryImmutable", "accessing an invalid group"); 0601 0602 return (isImmutable() || !config()->d_func()->canWriteEntry(d->fullName(), key, config()->readDefaults())); 0603 } 0604 0605 bool KConfigGroup::isEntryImmutable(const QString &key) const 0606 { 0607 return isEntryImmutable(key.toUtf8().constData()); 0608 } 0609 0610 QString KConfigGroup::readEntryUntranslated(const QString &pKey, const QString &aDefault) const 0611 { 0612 return readEntryUntranslated(pKey.toUtf8().constData(), aDefault); 0613 } 0614 0615 QString KConfigGroup::readEntryUntranslated(const char *key, const QString &aDefault) const 0616 { 0617 Q_ASSERT_X(isValid(), "KConfigGroup::readEntryUntranslated", "accessing an invalid group"); 0618 0619 QString result = config()->d_func()->lookupData(d->fullName(), key, KEntryMap::SearchFlags(), nullptr); 0620 if (result.isNull()) { 0621 return aDefault; 0622 } 0623 return result; 0624 } 0625 0626 QString KConfigGroup::readEntry(const char *key, const char *aDefault) const 0627 { 0628 return readEntry(key, QString::fromUtf8(aDefault)); 0629 } 0630 0631 QString KConfigGroup::readEntry(const QString &key, const char *aDefault) const 0632 { 0633 return readEntry(key.toUtf8().constData(), aDefault); 0634 } 0635 0636 QString KConfigGroup::readEntry(const char *key, const QString &aDefault) const 0637 { 0638 Q_ASSERT_X(isValid(), "KConfigGroup::readEntry", "accessing an invalid group"); 0639 0640 bool expand = false; 0641 0642 // read value from the entry map 0643 QString aValue = config()->d_func()->lookupData(d->fullName(), key, KEntryMap::SearchLocalized, &expand); 0644 if (aValue.isNull()) { 0645 aValue = aDefault; 0646 } 0647 0648 if (expand) { 0649 return KConfigPrivate::expandString(aValue); 0650 } 0651 0652 return aValue; 0653 } 0654 0655 QString KConfigGroup::readEntry(const QString &key, const QString &aDefault) const 0656 { 0657 return readEntry(key.toUtf8().constData(), aDefault); 0658 } 0659 0660 QStringList KConfigGroup::readEntry(const char *key, const QStringList &aDefault) const 0661 { 0662 Q_ASSERT_X(isValid(), "KConfigGroup::readEntry", "accessing an invalid group"); 0663 0664 const QString data = readEntry(key, QString()); 0665 if (data.isNull()) { 0666 return aDefault; 0667 } 0668 0669 return KConfigGroupPrivate::deserializeList(data); 0670 } 0671 0672 QStringList KConfigGroup::readEntry(const QString &key, const QStringList &aDefault) const 0673 { 0674 return readEntry(key.toUtf8().constData(), aDefault); 0675 } 0676 0677 QVariant KConfigGroup::readEntry(const char *key, const QVariant &aDefault) const 0678 { 0679 Q_ASSERT_X(isValid(), "KConfigGroup::readEntry", "accessing an invalid group"); 0680 0681 const QByteArray data = config()->d_func()->lookupData(d->fullName(), key, KEntryMap::SearchLocalized); 0682 if (data.isNull()) { 0683 return aDefault; 0684 } 0685 0686 QVariant value; 0687 if (!readEntryGui(data, key, aDefault, value)) { 0688 return convertToQVariant(key, data, aDefault); 0689 } 0690 0691 return value; 0692 } 0693 0694 QVariant KConfigGroup::readEntry(const QString &key, const QVariant &aDefault) const 0695 { 0696 return readEntry(key.toUtf8().constData(), aDefault); 0697 } 0698 0699 QVariantList KConfigGroup::readEntry(const char *key, const QVariantList &aDefault) const 0700 { 0701 Q_ASSERT_X(isValid(), "KConfigGroup::readEntry", "accessing an invalid group"); 0702 0703 const QString data = readEntry(key, QString()); 0704 if (data.isNull()) { 0705 return aDefault; 0706 } 0707 0708 const auto &list = KConfigGroupPrivate::deserializeList(data); 0709 0710 QVariantList value; 0711 value.reserve(list.count()); 0712 for (const QString &v : list) { 0713 value << v; 0714 } 0715 0716 return value; 0717 } 0718 0719 QVariantList KConfigGroup::readEntry(const QString &key, const QVariantList &aDefault) const 0720 { 0721 return readEntry(key.toUtf8().constData(), aDefault); 0722 } 0723 0724 QStringList KConfigGroup::readXdgListEntry(const QString &key, const QStringList &aDefault) const 0725 { 0726 return readXdgListEntry(key.toUtf8().constData(), aDefault); 0727 } 0728 0729 QStringList KConfigGroup::readXdgListEntry(const char *key, const QStringList &aDefault) const 0730 { 0731 Q_ASSERT_X(isValid(), "KConfigGroup::readXdgListEntry", "accessing an invalid group"); 0732 0733 const QString data = readEntry(key, QString()); 0734 if (data.isNull()) { 0735 return aDefault; 0736 } 0737 0738 QStringList value; 0739 QString val; 0740 val.reserve(data.size()); 0741 // XXX List serialization being a separate layer from low-level parsing is 0742 // probably a bug. No affected entries are defined, though. 0743 bool quoted = false; 0744 for (int p = 0; p < data.length(); p++) { 0745 if (quoted) { 0746 val += data[p]; 0747 quoted = false; 0748 } else if (data[p] == QLatin1Char('\\')) { 0749 quoted = true; 0750 } else if (data[p] == QLatin1Char(';')) { 0751 value.append(val); 0752 val.clear(); 0753 val.reserve(data.size() - p); 0754 } else { 0755 val += data[p]; 0756 } 0757 } 0758 if (!val.isEmpty()) { 0759 value.append(val); 0760 } 0761 return value; 0762 } 0763 0764 QString KConfigGroup::readPathEntry(const QString &pKey, const QString &aDefault) const 0765 { 0766 return readPathEntry(pKey.toUtf8().constData(), aDefault); 0767 } 0768 0769 QString KConfigGroup::readPathEntry(const char *key, const QString &aDefault) const 0770 { 0771 Q_ASSERT_X(isValid(), "KConfigGroup::readPathEntry", "accessing an invalid group"); 0772 0773 bool expand = false; 0774 0775 QString aValue = config()->d_func()->lookupData(d->fullName(), key, KEntryMap::SearchLocalized, &expand); 0776 if (aValue.isNull()) { 0777 aValue = aDefault; 0778 } 0779 0780 return KConfigPrivate::expandString(aValue); 0781 } 0782 0783 QStringList KConfigGroup::readPathEntry(const QString &pKey, const QStringList &aDefault) const 0784 { 0785 return readPathEntry(pKey.toUtf8().constData(), aDefault); 0786 } 0787 0788 QStringList KConfigGroup::readPathEntry(const char *key, const QStringList &aDefault) const 0789 { 0790 Q_ASSERT_X(isValid(), "KConfigGroup::readPathEntry", "accessing an invalid group"); 0791 0792 const QString data = readPathEntry(key, QString()); 0793 if (data.isNull()) { 0794 return aDefault; 0795 } 0796 0797 return KConfigGroupPrivate::deserializeList(data); 0798 } 0799 0800 void KConfigGroup::writeEntry(const char *key, const QString &value, WriteConfigFlags flags) 0801 { 0802 Q_ASSERT_X(isValid(), "KConfigGroup::writeEntry", "accessing an invalid group"); 0803 Q_ASSERT_X(!d->bConst, "KConfigGroup::writeEntry", "writing to a read-only group"); 0804 0805 writeEntry(key, value.toUtf8(), flags); 0806 } 0807 0808 void KConfigGroup::writeEntry(const QString &key, const QString &value, WriteConfigFlags flags) 0809 { 0810 writeEntry(key.toUtf8().constData(), value, flags); 0811 } 0812 0813 void KConfigGroup::writeEntry(const QString &key, const char *value, WriteConfigFlags pFlags) 0814 { 0815 Q_ASSERT_X(isValid(), "KConfigGroup::writeEntry", "accessing an invalid group"); 0816 Q_ASSERT_X(!d->bConst, "KConfigGroup::writeEntry", "writing to a read-only group"); 0817 0818 writeEntry(key.toUtf8().constData(), QVariant(QString::fromLatin1(value)), pFlags); 0819 } 0820 0821 void KConfigGroup::writeEntry(const char *key, const char *value, WriteConfigFlags pFlags) 0822 { 0823 writeEntry(key, QVariant(QString::fromLatin1(value)), pFlags); 0824 } 0825 0826 void KConfigGroup::writeEntry(const char *key, const QByteArray &value, WriteConfigFlags flags) 0827 { 0828 Q_ASSERT_X(isValid(), "KConfigGroup::writeEntry", "accessing an invalid group"); 0829 Q_ASSERT_X(!d->bConst, "KConfigGroup::writeEntry", "writing to a read-only group"); 0830 0831 config()->d_func()->putData(d->fullName(), key, value.isNull() ? QByteArray("") : value, flags); 0832 } 0833 0834 void KConfigGroup::writeEntry(const QString &key, const QByteArray &value, WriteConfigFlags pFlags) 0835 { 0836 writeEntry(key.toUtf8().constData(), value, pFlags); 0837 } 0838 0839 void KConfigGroup::writeEntry(const char *key, const QStringList &list, WriteConfigFlags flags) 0840 { 0841 Q_ASSERT_X(isValid(), "KConfigGroup::writeEntry", "accessing an invalid group"); 0842 Q_ASSERT_X(!d->bConst, "KConfigGroup::writeEntry", "writing to a read-only group"); 0843 0844 QList<QByteArray> balist; 0845 balist.reserve(list.count()); 0846 0847 for (const QString &entry : list) { 0848 balist.append(entry.toUtf8()); 0849 } 0850 0851 writeEntry(key, KConfigGroupPrivate::serializeList(balist), flags); 0852 } 0853 0854 void KConfigGroup::writeEntry(const QString &key, const QStringList &list, WriteConfigFlags flags) 0855 { 0856 writeEntry(key.toUtf8().constData(), list, flags); 0857 } 0858 0859 void KConfigGroup::writeEntry(const char *key, const QVariantList &list, WriteConfigFlags flags) 0860 { 0861 Q_ASSERT_X(isValid(), "KConfigGroup::writeEntry", "accessing an invalid group"); 0862 Q_ASSERT_X(!d->bConst, "KConfigGroup::writeEntry", "writing to a read-only group"); 0863 0864 QList<QByteArray> data; 0865 data.reserve(list.count()); 0866 0867 for (const QVariant &v : list) { 0868 if (v.userType() == QMetaType::QByteArray) { 0869 data << v.toByteArray(); 0870 } else { 0871 data << v.toString().toUtf8(); 0872 } 0873 } 0874 0875 writeEntry(key, KConfigGroupPrivate::serializeList(data), flags); 0876 } 0877 0878 void KConfigGroup::writeEntry(const char *key, const QVariant &value, WriteConfigFlags flags) 0879 { 0880 Q_ASSERT_X(isValid(), "KConfigGroup::writeEntry", "accessing an invalid group"); 0881 Q_ASSERT_X(!d->bConst, "KConfigGroup::writeEntry", "writing to a read-only group"); 0882 0883 if (writeEntryGui(this, key, value, flags)) { 0884 return; // GUI type that was handled 0885 } 0886 0887 QByteArray data; 0888 // if a type handler is added here you must add a QVConversions definition 0889 // to kconfigconversioncheck_p.h, or KConfigConversionCheck::to_QVariant will not allow 0890 // writeEntry<T> to convert to QVariant. 0891 switch (static_cast<QMetaType::Type>(value.userType())) { 0892 case QMetaType::UnknownType: 0893 data = ""; 0894 break; 0895 case QMetaType::QByteArray: 0896 data = value.toByteArray(); 0897 break; 0898 case QMetaType::QString: 0899 case QMetaType::Int: 0900 case QMetaType::UInt: 0901 case QMetaType::Double: 0902 case QMetaType::Float: 0903 case QMetaType::Bool: 0904 case QMetaType::LongLong: 0905 case QMetaType::ULongLong: 0906 data = value.toString().toUtf8(); 0907 break; 0908 case QMetaType::QVariantList: 0909 if (!value.canConvert<QStringList>()) { 0910 qCWarning(KCONFIG_CORE_LOG) << "not all types in \"" << key 0911 << "\" can convert to QString," 0912 " information will be lost"; 0913 } 0914 Q_FALLTHROUGH(); 0915 case QMetaType::QStringList: 0916 writeEntry(key, value.toList(), flags); 0917 return; 0918 case QMetaType::QPoint: { 0919 const QPoint rPoint = value.toPoint(); 0920 0921 const QVariantList list{rPoint.x(), rPoint.y()}; 0922 0923 writeEntry(key, list, flags); 0924 return; 0925 } 0926 case QMetaType::QPointF: { 0927 const QPointF point = value.toPointF(); 0928 0929 const QVariantList list{point.x(), point.y()}; 0930 0931 writeEntry(key, list, flags); 0932 return; 0933 } 0934 case QMetaType::QRect: { 0935 const QRect rRect = value.toRect(); 0936 0937 const QVariantList list{rRect.left(), rRect.top(), rRect.width(), rRect.height()}; 0938 0939 writeEntry(key, list, flags); 0940 return; 0941 } 0942 case QMetaType::QRectF: { 0943 const QRectF rRectF = value.toRectF(); 0944 0945 const QVariantList list{rRectF.left(), rRectF.top(), rRectF.width(), rRectF.height()}; 0946 0947 writeEntry(key, list, flags); 0948 return; 0949 } 0950 case QMetaType::QSize: { 0951 const QSize rSize = value.toSize(); 0952 0953 const QVariantList list{rSize.width(), rSize.height()}; 0954 0955 writeEntry(key, list, flags); 0956 return; 0957 } 0958 case QMetaType::QUuid: { 0959 writeEntry(key, value.toString(), flags); 0960 return; 0961 } 0962 case QMetaType::QSizeF: { 0963 const QSizeF rSizeF = value.toSizeF(); 0964 0965 const QVariantList list{rSizeF.width(), rSizeF.height()}; 0966 0967 writeEntry(key, list, flags); 0968 return; 0969 } 0970 case QMetaType::QDate: { 0971 const QDate date = value.toDate(); 0972 0973 const QVariantList list{date.year(), date.month(), date.day()}; 0974 0975 writeEntry(key, list, flags); 0976 return; 0977 } 0978 case QMetaType::QDateTime: { 0979 const QDateTime rDateTime = value.toDateTime(); 0980 0981 const QTime time = rDateTime.time(); 0982 const QDate date = rDateTime.date(); 0983 0984 const QVariantList list{ 0985 date.year(), 0986 date.month(), 0987 date.day(), 0988 0989 time.hour(), 0990 time.minute(), 0991 time.second() + time.msec() / 1000.0, 0992 }; 0993 0994 writeEntry(key, list, flags); 0995 return; 0996 } 0997 0998 case QMetaType::QColor: 0999 case QMetaType::QFont: 1000 qCWarning(KCONFIG_CORE_LOG) << "KConfigGroup::writeEntry was passed GUI type '" << value.typeName() 1001 << "' but KConfigGui isn't linked! If it is linked to your program, this is a platform bug. " 1002 "Please inform the KDE developers"; 1003 break; 1004 case QMetaType::QUrl: 1005 data = QUrl(value.toUrl()).toString().toUtf8(); 1006 break; 1007 default: 1008 qCWarning(KCONFIG_CORE_LOG) << "KConfigGroup::writeEntry - unhandled type" << value.typeName() << "in group" << name(); 1009 } 1010 1011 writeEntry(key, data, flags); 1012 } 1013 1014 void KConfigGroup::writeEntry(const QString &key, const QVariant &value, WriteConfigFlags flags) 1015 { 1016 writeEntry(key.toUtf8().constData(), value, flags); 1017 } 1018 1019 void KConfigGroup::writeEntry(const QString &key, const QVariantList &list, WriteConfigFlags flags) 1020 { 1021 writeEntry(key.toUtf8().constData(), list, flags); 1022 } 1023 1024 void KConfigGroup::writeXdgListEntry(const QString &key, const QStringList &value, WriteConfigFlags pFlags) 1025 { 1026 writeXdgListEntry(key.toUtf8().constData(), value, pFlags); 1027 } 1028 1029 void KConfigGroup::writeXdgListEntry(const char *key, const QStringList &list, WriteConfigFlags flags) 1030 { 1031 Q_ASSERT_X(isValid(), "KConfigGroup::writeXdgListEntry", "accessing an invalid group"); 1032 Q_ASSERT_X(!d->bConst, "KConfigGroup::writeXdgListEntry", "writing to a read-only group"); 1033 1034 QString value; 1035 value.reserve(4096); 1036 1037 // XXX List serialization being a separate layer from low-level escaping is 1038 // probably a bug. No affected entries are defined, though. 1039 for (QString val : list) { // clazy:exclude=range-loop 1040 val.replace(QLatin1Char('\\'), QLatin1String("\\\\")).replace(QLatin1Char(';'), QLatin1String("\\;")); 1041 value += val + QLatin1Char(';'); 1042 } 1043 1044 writeEntry(key, value, flags); 1045 } 1046 1047 void KConfigGroup::writePathEntry(const QString &pKey, const QString &path, WriteConfigFlags pFlags) 1048 { 1049 writePathEntry(pKey.toUtf8().constData(), path, pFlags); 1050 } 1051 1052 void KConfigGroup::writePathEntry(const char *pKey, const QString &path, WriteConfigFlags pFlags) 1053 { 1054 Q_ASSERT_X(isValid(), "KConfigGroup::writePathEntry", "accessing an invalid group"); 1055 Q_ASSERT_X(!d->bConst, "KConfigGroup::writePathEntry", "writing to a read-only group"); 1056 1057 config()->d_func()->putData(d->fullName(), pKey, translatePath(path).toUtf8(), pFlags, true); 1058 } 1059 1060 void KConfigGroup::writePathEntry(const QString &pKey, const QStringList &value, WriteConfigFlags pFlags) 1061 { 1062 writePathEntry(pKey.toUtf8().constData(), value, pFlags); 1063 } 1064 1065 void KConfigGroup::writePathEntry(const char *pKey, const QStringList &value, WriteConfigFlags pFlags) 1066 { 1067 Q_ASSERT_X(isValid(), "KConfigGroup::writePathEntry", "accessing an invalid group"); 1068 Q_ASSERT_X(!d->bConst, "KConfigGroup::writePathEntry", "writing to a read-only group"); 1069 1070 QList<QByteArray> list; 1071 list.reserve(value.length()); 1072 for (const QString &path : value) { 1073 list << translatePath(path).toUtf8(); 1074 } 1075 1076 config()->d_func()->putData(d->fullName(), pKey, KConfigGroupPrivate::serializeList(list), pFlags, true); 1077 } 1078 1079 void KConfigGroup::deleteEntry(const char *key, WriteConfigFlags flags) 1080 { 1081 Q_ASSERT_X(isValid(), "KConfigGroup::deleteEntry", "accessing an invalid group"); 1082 Q_ASSERT_X(!d->bConst, "KConfigGroup::deleteEntry", "deleting from a read-only group"); 1083 1084 config()->d_func()->putData(d->fullName(), key, QByteArray(), flags); 1085 } 1086 1087 void KConfigGroup::deleteEntry(const QString &key, WriteConfigFlags flags) 1088 { 1089 deleteEntry(key.toUtf8().constData(), flags); 1090 } 1091 1092 void KConfigGroup::revertToDefault(const char *key, WriteConfigFlags flags) 1093 { 1094 Q_ASSERT_X(isValid(), "KConfigGroup::revertToDefault", "accessing an invalid group"); 1095 Q_ASSERT_X(!d->bConst, "KConfigGroup::revertToDefault", "writing to a read-only group"); 1096 1097 config()->d_func()->revertEntry(d->fullName(), key, flags); 1098 } 1099 1100 void KConfigGroup::revertToDefault(const QString &key, WriteConfigFlags flags) 1101 { 1102 revertToDefault(key.toUtf8().constData(), flags); 1103 } 1104 1105 bool KConfigGroup::hasDefault(const char *key) const 1106 { 1107 Q_ASSERT_X(isValid(), "KConfigGroup::hasDefault", "accessing an invalid group"); 1108 1109 KEntryMap::SearchFlags flags = KEntryMap::SearchDefaults | KEntryMap::SearchLocalized; 1110 1111 return !config()->d_func()->lookupData(d->fullName(), key, flags).isNull(); 1112 } 1113 1114 bool KConfigGroup::hasDefault(const QString &key) const 1115 { 1116 return hasDefault(key.toUtf8().constData()); 1117 } 1118 1119 bool KConfigGroup::hasKey(const char *key) const 1120 { 1121 Q_ASSERT_X(isValid(), "KConfigGroup::hasKey", "accessing an invalid group"); 1122 1123 KEntryMap::SearchFlags flags = KEntryMap::SearchLocalized; 1124 if (config()->readDefaults()) { 1125 flags |= KEntryMap::SearchDefaults; 1126 } 1127 1128 return !config()->d_func()->lookupData(d->fullName(), key, flags).isNull(); 1129 } 1130 1131 bool KConfigGroup::hasKey(const QString &key) const 1132 { 1133 return hasKey(key.toUtf8().constData()); 1134 } 1135 1136 bool KConfigGroup::isImmutable() const 1137 { 1138 Q_ASSERT_X(isValid(), "KConfigGroup::isImmutable", "accessing an invalid group"); 1139 1140 return d->bImmutable; 1141 } 1142 1143 QStringList KConfigGroup::groupList() const 1144 { 1145 Q_ASSERT_X(isValid(), "KConfigGroup::groupList", "accessing an invalid group"); 1146 1147 return config()->d_func()->groupList(d->fullName()); 1148 } 1149 1150 QStringList KConfigGroup::keyList() const 1151 { 1152 Q_ASSERT_X(isValid(), "KConfigGroup::keyList", "accessing an invalid group"); 1153 1154 return config()->d_func()->usedKeyList(d->fullName()); 1155 } 1156 1157 void KConfigGroup::markAsClean() 1158 { 1159 Q_ASSERT_X(isValid(), "KConfigGroup::markAsClean", "accessing an invalid group"); 1160 1161 config()->markAsClean(); 1162 } 1163 1164 KConfigGroup::AccessMode KConfigGroup::accessMode() const 1165 { 1166 Q_ASSERT_X(isValid(), "KConfigGroup::accessMode", "accessing an invalid group"); 1167 1168 return config()->accessMode(); 1169 } 1170 1171 bool KConfigGroup::hasGroupImpl(const QString &b) const 1172 { 1173 Q_ASSERT_X(isValid(), "KConfigGroup::hasGroupImpl", "accessing an invalid group"); 1174 1175 return config()->hasGroup(d->fullName(b)); 1176 } 1177 1178 void KConfigGroup::deleteGroupImpl(const QString &b, WriteConfigFlags flags) 1179 { 1180 Q_ASSERT_X(isValid(), "KConfigGroup::deleteGroupImpl", "accessing an invalid group"); 1181 Q_ASSERT_X(!d->bConst, "KConfigGroup::deleteGroupImpl", "deleting from a read-only group"); 1182 1183 config()->deleteGroup(d->fullName(b), flags); 1184 } 1185 1186 bool KConfigGroup::isGroupImmutableImpl(const QString &groupName) const 1187 { 1188 Q_ASSERT_X(isValid(), "KConfigGroup::isGroupImmutableImpl", "accessing an invalid group"); 1189 1190 if (!hasGroupImpl(groupName)) { // group doesn't exist yet 1191 return d->bImmutable; // child groups are immutable if the parent is immutable. 1192 } 1193 1194 return config()->isGroupImmutable(d->fullName(groupName)); 1195 } 1196 1197 void KConfigGroup::copyTo(KConfigBase *other, WriteConfigFlags pFlags) const 1198 { 1199 Q_ASSERT_X(isValid(), "KConfigGroup::copyTo", "accessing an invalid group"); 1200 Q_ASSERT(other != nullptr); 1201 1202 if (KConfigGroup *otherGroup = dynamic_cast<KConfigGroup *>(other)) { 1203 config()->d_func()->copyGroup(d->fullName(), otherGroup->d->fullName(), otherGroup, pFlags); 1204 } else if (KConfig *otherConfig = dynamic_cast<KConfig *>(other)) { 1205 KConfigGroup newGroup = otherConfig->group(d->fullName()); 1206 otherConfig->d_func()->copyGroup(d->fullName(), d->fullName(), &newGroup, pFlags); 1207 } else { 1208 Q_ASSERT_X(false, "KConfigGroup::copyTo", "unknown type of KConfigBase"); 1209 } 1210 } 1211 1212 void KConfigGroup::reparent(KConfigBase *parent, WriteConfigFlags pFlags) 1213 { 1214 Q_ASSERT_X(isValid(), "KConfigGroup::reparent", "accessing an invalid group"); 1215 Q_ASSERT_X(!d->bConst, "KConfigGroup::reparent", "reparenting a read-only group"); 1216 Q_ASSERT_X(!d->bImmutable, "KConfigGroup::reparent", "reparenting an immutable group"); 1217 Q_ASSERT(parent != nullptr); 1218 1219 KConfigGroup oldGroup(*this); 1220 1221 d = KConfigGroupPrivate::create(parent, d->mName, false, false); 1222 oldGroup.copyTo(this, pFlags); 1223 oldGroup.deleteGroup(); // so that the entries with the old group name are deleted on sync 1224 } 1225 1226 void KConfigGroup::moveValuesTo(const QList<const char *> &keys, KConfigGroup &other, WriteConfigFlags pFlags) 1227 { 1228 Q_ASSERT(isValid()); 1229 Q_ASSERT(other.isValid()); 1230 1231 for (const auto key : keys) { 1232 const QString groupName = name(); 1233 const auto entry = config()->d_ptr->lookupInternalEntry(groupName, key, KEntryMap::SearchLocalized); 1234 1235 // Only write the entry if it is not null, if it is a global enry there is no point in moving it 1236 if (!entry.mValue.isNull() && !entry.bGlobal) { 1237 deleteEntry(key, pFlags); 1238 KEntryMap::EntryOptions options = KEntryMap::EntryOption::EntryDirty; 1239 if (entry.bDeleted) { 1240 options |= KEntryMap::EntryDeleted; 1241 } 1242 1243 if (entry.bExpand) { 1244 options |= KEntryMap::EntryExpansion; 1245 } 1246 1247 other.config()->d_ptr->setEntryData(other.name(), key, entry.mValue, options); 1248 } 1249 } 1250 }