File indexing completed on 2024-04-28 03:53:15
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-2000 Preston Brown <pbrown@kde.org> 0005 SPDX-FileCopyrightText: 1996-2000 Matthias Kalle Dalheimer <kalle@kde.org> 0006 0007 SPDX-License-Identifier: LGPL-2.0-or-later 0008 */ 0009 0010 #ifndef KCONFIGDATA_P_H 0011 #define KCONFIGDATA_P_H 0012 0013 #include <QByteArray> 0014 #include <QDebug> 0015 #include <QString> 0016 #include <map> 0017 0018 /** 0019 * map/dict/list config node entry. 0020 * @internal 0021 */ 0022 struct KEntry { 0023 /** Constructor. @internal */ 0024 KEntry() 0025 : mValue() 0026 , bDirty(false) 0027 , bGlobal(false) 0028 , bImmutable(false) 0029 , bDeleted(false) 0030 , bExpand(false) 0031 , bReverted(false) 0032 , bLocalizedCountry(false) 0033 , bNotify(false) 0034 , bOverridesGlobal(false) 0035 { 0036 } 0037 /** @internal */ 0038 QByteArray mValue; 0039 /** 0040 * Must the entry be written back to disk? 0041 */ 0042 bool bDirty : 1; 0043 /** 0044 * Entry should be written to the global config file 0045 */ 0046 bool bGlobal : 1; 0047 /** 0048 * Entry can not be modified. 0049 */ 0050 bool bImmutable : 1; 0051 /** 0052 * Entry has been deleted. 0053 */ 0054 bool bDeleted : 1; 0055 /** 0056 * Whether to apply dollar expansion or not. 0057 */ 0058 bool bExpand : 1; 0059 /** 0060 * Entry has been reverted to its default value (from a more global file). 0061 */ 0062 bool bReverted : 1; 0063 /** 0064 * Entry is for a localized key. If @c false the value references just language e.g. "de", 0065 * if @c true the value references language and country, e.g. "de_DE". 0066 **/ 0067 bool bLocalizedCountry : 1; 0068 0069 bool bNotify : 1; 0070 0071 /** 0072 * Entry will need to be written on a non global file even if it matches default value 0073 */ 0074 bool bOverridesGlobal : 1; 0075 }; 0076 0077 Q_DECLARE_TYPEINFO(KEntry, Q_RELOCATABLE_TYPE); 0078 0079 // These operators are used to check whether an entry which is about 0080 // to be written equals the previous value. As such, this intentionally 0081 // omits the dirty/notify flag from the comparison. 0082 inline bool operator==(const KEntry &k1, const KEntry &k2) 0083 { 0084 /* clang-format off */ 0085 return k1.bGlobal == k2.bGlobal 0086 && k1.bImmutable == k2.bImmutable 0087 && k1.bDeleted == k2.bDeleted 0088 && k1.bExpand == k2.bExpand 0089 && k1.mValue == k2.mValue; 0090 /* clang-format on */ 0091 } 0092 0093 inline bool operator!=(const KEntry &k1, const KEntry &k2) 0094 { 0095 return !(k1 == k2); 0096 } 0097 0098 /** 0099 * key structure holding both the actual key and the group 0100 * to which it belongs. 0101 * @internal 0102 */ 0103 struct KEntryKey { 0104 /** Constructor. @internal */ 0105 KEntryKey(const QString &_group = QString(), const QByteArray &_key = QByteArray(), bool isLocalized = false, bool isDefault = false) 0106 : mGroup(_group) 0107 , mKey(_key) 0108 , bLocal(isLocalized) 0109 , bDefault(isDefault) 0110 , bRaw(false) 0111 { 0112 } 0113 /** 0114 * The "group" to which this EntryKey belongs 0115 */ 0116 QString mGroup; 0117 /** 0118 * The _actual_ key of the entry in question 0119 */ 0120 QByteArray mKey; 0121 /** 0122 * Entry is localised or not 0123 */ 0124 bool bLocal : 1; 0125 /** 0126 * Entry indicates if this is a default value. 0127 */ 0128 bool bDefault : 1; 0129 /** @internal 0130 * Key is a raw unprocessed key. 0131 * @warning this should only be set during merging, never for normal use. 0132 */ 0133 bool bRaw : 1; 0134 }; 0135 0136 Q_DECLARE_TYPEINFO(KEntryKey, Q_RELOCATABLE_TYPE); 0137 0138 /** 0139 * Compares two KEntryKeys (needed for std::map). The order is localized, localized-default, 0140 * non-localized, non-localized-default 0141 * @internal 0142 */ 0143 inline bool operator<(const KEntryKey &k1, const KEntryKey &k2) 0144 { 0145 int result = k1.mGroup.compare(k2.mGroup); 0146 if (result != 0) { 0147 return result < 0; 0148 } 0149 0150 result = k1.mKey.compare(k2.mKey); 0151 if (result != 0) { 0152 return result < 0; 0153 } 0154 0155 if (k1.bLocal != k2.bLocal) { 0156 return k1.bLocal; 0157 } 0158 return (!k1.bDefault && k2.bDefault); 0159 } 0160 0161 /** 0162 * Light-weight view variant of KEntryKey. 0163 * Used for look-up in the map. 0164 * @internal 0165 */ 0166 struct KEntryKeyView { 0167 /** Constructor. @internal */ 0168 KEntryKeyView(QStringView _group, QAnyStringView _key, bool isLocalized = false, bool isDefault = false) 0169 : mGroup(_group) 0170 , mKey(_key) 0171 , bLocal(isLocalized) 0172 , bDefault(isDefault) 0173 { 0174 } 0175 /** 0176 * The "group" to which this EntryKey belongs 0177 */ 0178 const QStringView mGroup; 0179 /** 0180 * The _actual_ key of the entry in question 0181 */ 0182 const QAnyStringView mKey; 0183 /** 0184 * Entry is localised or not 0185 */ 0186 bool bLocal : 1; 0187 /** 0188 * Entry indicates if this is a default value. 0189 */ 0190 bool bDefault : 1; 0191 }; 0192 0193 template<typename TEntryKey1, typename TEntryKey2> 0194 bool compareEntryKeyViews(const TEntryKey1 &k1, const TEntryKey2 &k2) 0195 { 0196 int result = k1.mGroup.compare(k2.mGroup); 0197 if (result != 0) { 0198 return result < 0; 0199 } 0200 0201 result = QAnyStringView::compare(k1.mKey, k2.mKey); 0202 if (result != 0) { 0203 return result < 0; 0204 } 0205 0206 if (k1.bLocal != k2.bLocal) { 0207 return k1.bLocal; 0208 } 0209 return (!k1.bDefault && k2.bDefault); 0210 } 0211 0212 inline bool operator<(const KEntryKeyView &k1, const KEntryKey &k2) 0213 { 0214 return compareEntryKeyViews(k1, k2); 0215 } 0216 0217 inline bool operator<(const KEntryKey &k1, const KEntryKeyView &k2) 0218 { 0219 return compareEntryKeyViews(k1, k2); 0220 } 0221 0222 /** 0223 * Struct to use as Compare type with std::map. 0224 * To enable usage of KEntryKeyView for look-up in the map 0225 * via the template find() overloads. 0226 * @internal 0227 */ 0228 struct KEntryKeyCompare { 0229 using is_transparent = void; 0230 0231 bool operator()(const KEntryKey &k1, const KEntryKey &k2) const 0232 { 0233 return (k1 < k2); 0234 } 0235 0236 bool operator()(const KEntryKeyView &k1, const KEntryKey &k2) const 0237 { 0238 return (k1 < k2); 0239 } 0240 0241 bool operator()(const KEntryKey &k1, const KEntryKeyView &k2) const 0242 { 0243 return (k1 < k2); 0244 } 0245 }; 0246 0247 /** 0248 * Returns the minimum key that has @a mGroup == @p group. 0249 * 0250 * @note The returned "minimum key" is consistent with KEntryKey's operator<(). 0251 * The return value of this function can be passed to KEntryMap::lowerBound(). 0252 */ 0253 inline KEntryKeyView minimumGroupKeyView(const QString &group) 0254 { 0255 return KEntryKeyView(group, QAnyStringView{}, true, false); 0256 } 0257 0258 QDebug operator<<(QDebug dbg, const KEntryKey &key); 0259 QDebug operator<<(QDebug dbg, const KEntry &entry); 0260 0261 /** 0262 * \relates KEntry 0263 * type specifying a map of entries (key,value pairs). 0264 * The keys are actually a key in a particular config file group together 0265 * with the group name. 0266 * @internal 0267 */ 0268 class KEntryMap : public std::map<KEntryKey, KEntry, KEntryKeyCompare> 0269 { 0270 public: 0271 enum SearchFlag { 0272 SearchDefaults = 1, 0273 SearchLocalized = 2, 0274 }; 0275 Q_DECLARE_FLAGS(SearchFlags, SearchFlag) 0276 0277 enum EntryOption { 0278 EntryDirty = 1, 0279 EntryGlobal = 2, 0280 EntryImmutable = 4, 0281 EntryDeleted = 8, 0282 EntryExpansion = 16, 0283 EntryRawKey = 32, 0284 EntryLocalizedCountry = 64, 0285 EntryNotify = 128, 0286 EntryDefault = (SearchDefaults << 16), 0287 EntryLocalized = (SearchLocalized << 16), 0288 }; 0289 Q_DECLARE_FLAGS(EntryOptions, EntryOption) 0290 0291 iterator findExactEntry(const QString &group, QAnyStringView key = QAnyStringView(), SearchFlags flags = SearchFlags()); 0292 0293 iterator findEntry(const QString &group, QAnyStringView key = QAnyStringView(), SearchFlags flags = SearchFlags()); 0294 0295 const_iterator findEntry(const QString &group, QAnyStringView key = QAnyStringView(), SearchFlags flags = SearchFlags()) const 0296 { 0297 return constFindEntry(group, key, flags); 0298 } 0299 0300 const_iterator constFindEntry(const QString &group, QAnyStringView key = QAnyStringView(), SearchFlags flags = SearchFlags()) const; 0301 0302 /** 0303 * Returns true if the entry gets dirtied or false in other case 0304 */ 0305 bool setEntry(const QString &group, const QByteArray &key, const QByteArray &value, EntryOptions options); 0306 0307 void setEntry(const QString &group, const QByteArray &key, const QString &value, EntryOptions options) 0308 { 0309 setEntry(group, key, value.toUtf8(), options); 0310 } 0311 0312 QString getEntry(const QString &group, 0313 QAnyStringView key, 0314 const QString &defaultValue = QString(), 0315 SearchFlags flags = SearchFlags(), 0316 bool *expand = nullptr) const; 0317 0318 bool hasEntry(const QString &group, QAnyStringView key = QAnyStringView(), SearchFlags flags = SearchFlags()) const; 0319 0320 bool getEntryOption(const const_iterator &it, EntryOption option) const; 0321 bool getEntryOption(const QString &group, QAnyStringView key, SearchFlags flags, EntryOption option) const 0322 { 0323 return getEntryOption(findEntry(group, key, flags), option); 0324 } 0325 0326 void setEntryOption(iterator it, EntryOption option, bool bf); 0327 void setEntryOption(const QString &group, QAnyStringView key, SearchFlags flags, EntryOption option, bool bf) 0328 { 0329 setEntryOption(findEntry(group, key, flags), option, bf); 0330 } 0331 0332 bool revertEntry(const QString &group, QAnyStringView key, EntryOptions options, SearchFlags flags = SearchFlags()); 0333 0334 template<typename ConstIteratorUser> 0335 void forEachEntryWhoseGroupStartsWith(const QString &groupPrefix, ConstIteratorUser callback) const 0336 { 0337 for (auto it = lower_bound(minimumGroupKeyView(groupPrefix)), end = cend(); it != end && it->first.mGroup.startsWith(groupPrefix); ++it) { 0338 callback(it); 0339 } 0340 } 0341 0342 template<typename ConstIteratorPredicate> 0343 bool anyEntryWhoseGroupStartsWith(const QString &groupPrefix, ConstIteratorPredicate predicate) const 0344 { 0345 for (auto it = lower_bound(minimumGroupKeyView(groupPrefix)), end = cend(); it != end && it->first.mGroup.startsWith(groupPrefix); ++it) { 0346 if (predicate(it)) { 0347 return true; 0348 } 0349 } 0350 return false; 0351 } 0352 0353 template<typename ConstIteratorUser> 0354 void forEachEntryOfGroup(const QString &theGroup, ConstIteratorUser callback) const 0355 { 0356 const auto theEnd = cend(); 0357 auto it = constFindEntry(theGroup); 0358 if (it != theEnd) { 0359 ++it; // advance past the special group entry marker 0360 0361 for (; (it != theEnd) && (it->first.mGroup == theGroup); ++it) { 0362 callback(it); 0363 } 0364 } 0365 } 0366 }; 0367 Q_DECLARE_OPERATORS_FOR_FLAGS(KEntryMap::SearchFlags) 0368 Q_DECLARE_OPERATORS_FOR_FLAGS(KEntryMap::EntryOptions) 0369 0370 /** 0371 * \relates KEntry 0372 * type for iterating over keys in a KEntryMap in sorted order. 0373 * @internal 0374 */ 0375 typedef KEntryMap::iterator KEntryMapIterator; 0376 0377 /** 0378 * \relates KEntry 0379 * type for iterating over keys in a KEntryMap in sorted order. 0380 * It is const, thus you cannot change the entries in the iterator, 0381 * only examine them. 0382 * @internal 0383 */ 0384 typedef KEntryMap::const_iterator KEntryMapConstIterator; 0385 0386 #endif