KDECore
kconfig.cpp
Go to the documentation of this file.
00001 /* 00002 This file is part of the KDE libraries 00003 Copyright (c) 2006, 2007 Thomas Braxton <kde.braxton@gmail.com> 00004 Copyright (c) 1999 Preston Brown <pbrown@kde.org> 00005 Copyright (c) 1997-1999 Matthias Kalle Dalheimer <kalle@kde.org> 00006 00007 This library is free software; you can redistribute it and/or 00008 modify it under the terms of the GNU Library General Public 00009 License as published by the Free Software Foundation; either 00010 version 2 of the License, or (at your option) any later version. 00011 00012 This library is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 Library General Public License for more details. 00016 00017 You should have received a copy of the GNU Library General Public License 00018 along with this library; see the file COPYING.LIB. If not, write to 00019 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00020 Boston, MA 02110-1301, USA. 00021 */ 00022 00023 #include "kconfig.h" 00024 #include "kconfig_p.h" 00025 00026 #include <cstdlib> 00027 #include <fcntl.h> 00028 #include <unistd.h> 00029 00030 #include "kconfigbackend.h" 00031 #include "kconfiggroup.h" 00032 #include <kstringhandler.h> 00033 #include <klocale.h> 00034 #include <kstandarddirs.h> 00035 #include <kurl.h> 00036 #include <kcomponentdata.h> 00037 #include <ktoolinvocation.h> 00038 #include <kaboutdata.h> 00039 #include <kdebug.h> 00040 00041 #include <qbytearray.h> 00042 #include <qfile.h> 00043 #include <qdir.h> 00044 #include <qdatetime.h> 00045 #include <qrect.h> 00046 #include <qsize.h> 00047 #include <qcolor.h> 00048 #include <QtCore/QProcess> 00049 #include <QtCore/QPointer> 00050 #include <QtCore/QSet> 00051 #include <QtCore/QStack> 00052 00053 bool KConfigPrivate::mappingsRegistered=false; 00054 00055 KConfigPrivate::KConfigPrivate(const KComponentData &componentData_, KConfig::OpenFlags flags, 00056 const char* resource) 00057 : openFlags(flags), resourceType(resource), mBackend(0), 00058 bDynamicBackend(true), bDirty(false), bReadDefaults(false), 00059 bFileImmutable(false), bForceGlobal(false), bSuppressGlobal(false), 00060 componentData(componentData_), configState(KConfigBase::NoAccess) 00061 { 00062 sGlobalFileName = componentData.dirs()->saveLocation("config", QString(), false) + QLatin1String("kdeglobals"); 00063 00064 static int use_etc_kderc = -1; 00065 if (use_etc_kderc < 0) 00066 use_etc_kderc = getenv("KDE_SKIP_KDERC") != 0 ? 0 : 1; // for unit tests 00067 if (use_etc_kderc) { 00068 00069 etc_kderc = 00070 #ifdef Q_WS_WIN 00071 QFile::decodeName( qgetenv("WINDIR") + "/kde4rc" ); 00072 #else 00073 QLatin1String("/etc/kde4rc"); 00074 #endif 00075 if (!KStandardDirs::checkAccess(etc_kderc, R_OK)) { 00076 etc_kderc.clear(); 00077 } 00078 } 00079 00080 // if (!mappingsRegistered) { 00081 // KEntryMap tmp; 00082 // if (!etc_kderc.isEmpty()) { 00083 // KSharedPtr<KConfigBackend> backend = KConfigBackend::create(componentData, etc_kderc, QLatin1String("INI")); 00084 // backend->parseConfig( "en_US", tmp, KConfigBackend::ParseDefaults); 00085 // } 00086 // const QString kde4rc(QDir::home().filePath(".kde4rc")); 00087 // if (KStandardDirs::checkAccess(kde4rc, R_OK)) { 00088 // KSharedPtr<KConfigBackend> backend = KConfigBackend::create(componentData, kde4rc, QLatin1String("INI")); 00089 // backend->parseConfig( "en_US", tmp, KConfigBackend::ParseOptions()); 00090 // } 00091 // KConfigBackend::registerMappings(tmp); 00092 // mappingsRegistered = true; 00093 // } 00094 00095 setLocale(KGlobal::hasLocale() ? KGlobal::locale()->language() : KLocale::defaultLanguage()); 00096 } 00097 00098 00099 bool KConfigPrivate::lockLocal() 00100 { 00101 if (mBackend) { 00102 return mBackend->lock(componentData); 00103 } 00104 // anonymous object - pretend we locked it 00105 return true; 00106 } 00107 00108 void KConfigPrivate::copyGroup(const QByteArray& source, const QByteArray& destination, 00109 KConfigGroup *otherGroup, KConfigBase::WriteConfigFlags flags) const 00110 { 00111 KEntryMap& otherMap = otherGroup->config()->d_ptr->entryMap; 00112 const int len = source.length(); 00113 const bool sameName = (destination == source); 00114 00115 // we keep this bool outside the foreach loop so that if 00116 // the group is empty, we don't end up marking the other config 00117 // as dirty erroneously 00118 bool dirtied = false; 00119 00120 for (KEntryMap::ConstIterator entryMapIt( entryMap.constBegin() ); entryMapIt != entryMap.constEnd(); ++entryMapIt) { 00121 const QByteArray& group = entryMapIt.key().mGroup; 00122 00123 if (!group.startsWith(source)) // nothing to do 00124 continue; 00125 00126 // don't copy groups that start with the same prefix, but are not sub-groups 00127 if (group.length() > len && group[len] != '\x1d') 00128 continue; 00129 00130 KEntryKey newKey = entryMapIt.key(); 00131 00132 if (flags & KConfigBase::Localized) { 00133 newKey.bLocal = true; 00134 } 00135 00136 if (!sameName) 00137 newKey.mGroup.replace(0, len, destination); 00138 00139 KEntry entry = entryMap[ entryMapIt.key() ]; 00140 dirtied = entry.bDirty = flags & KConfigBase::Persistent; 00141 00142 if (flags & KConfigBase::Global) { 00143 entry.bGlobal = true; 00144 } 00145 00146 otherMap[newKey] = entry; 00147 } 00148 00149 if (dirtied) { 00150 otherGroup->config()->d_ptr->bDirty = true; 00151 } 00152 } 00153 00154 KConfig::KConfig( const QString& file, OpenFlags mode, 00155 const char* resourceType) 00156 : d_ptr(new KConfigPrivate(KGlobal::mainComponent(), mode, resourceType)) 00157 { 00158 d_ptr->changeFileName(file, resourceType); // set the local file name 00159 00160 // read initial information off disk 00161 reparseConfiguration(); 00162 } 00163 00164 KConfig::KConfig( const KComponentData& componentData, const QString& file, OpenFlags mode, 00165 const char* resourceType) 00166 : d_ptr(new KConfigPrivate(componentData, mode, resourceType)) 00167 { 00168 d_ptr->changeFileName(file, resourceType); // set the local file name 00169 00170 // read initial information off disk 00171 reparseConfiguration(); 00172 } 00173 00174 KConfig::KConfig(const QString& file, const QString& backend, const char* resourceType) 00175 : d_ptr(new KConfigPrivate(KGlobal::mainComponent(), SimpleConfig, resourceType)) 00176 { 00177 d_ptr->mBackend = KConfigBackend::create(d_ptr->componentData, file, backend); 00178 d_ptr->bDynamicBackend = false; 00179 d_ptr->changeFileName(file, ""); // set the local file name 00180 00181 // read initial information off disk 00182 reparseConfiguration(); 00183 } 00184 00185 KConfig::KConfig(KConfigPrivate &d) 00186 : d_ptr(&d) 00187 { 00188 } 00189 00190 KConfig::~KConfig() 00191 { 00192 Q_D(KConfig); 00193 if (d->bDirty && d->mBackend.isUnique()) 00194 sync(); 00195 delete d; 00196 } 00197 00198 const KComponentData& KConfig::componentData() const 00199 { 00200 Q_D(const KConfig); 00201 return d->componentData; 00202 } 00203 00204 QStringList KConfig::groupList() const 00205 { 00206 Q_D(const KConfig); 00207 QSet<QString> groups; 00208 00209 for (KEntryMap::ConstIterator entryMapIt( d->entryMap.constBegin() ); entryMapIt != d->entryMap.constEnd(); ++entryMapIt) { 00210 const KEntryKey& key = entryMapIt.key(); 00211 const QByteArray group = key.mGroup; 00212 if (key.mKey.isNull() && !group.isEmpty() && group != "<default>" && group != "$Version") { 00213 const QString groupname = QString::fromUtf8(group); 00214 groups << groupname.left(groupname.indexOf(QLatin1Char('\x1d'))); 00215 } 00216 } 00217 00218 return groups.toList(); 00219 } 00220 00221 QStringList KConfigPrivate::groupList(const QByteArray& group) const 00222 { 00223 QByteArray theGroup = group + '\x1d'; 00224 QSet<QString> groups; 00225 00226 for (KEntryMap::ConstIterator entryMapIt( entryMap.constBegin() ); entryMapIt != entryMap.constEnd(); ++entryMapIt) { 00227 const KEntryKey& key = entryMapIt.key(); 00228 if (key.mKey.isNull() && key.mGroup.startsWith(theGroup)) { 00229 const QString groupname = QString::fromUtf8(key.mGroup.mid(theGroup.length())); 00230 groups << groupname.left(groupname.indexOf(QLatin1Char('\x1d'))); 00231 } 00232 } 00233 00234 return groups.toList(); 00235 } 00236 00237 // List all sub groups, including subsubgroups 00238 QSet<QByteArray> KConfigPrivate::allSubGroups(const QByteArray& parentGroup) const 00239 { 00240 QSet<QByteArray> groups; 00241 QByteArray theGroup = parentGroup + '\x1d'; 00242 groups << parentGroup; 00243 00244 for (KEntryMap::const_iterator entryMapIt = entryMap.begin(); entryMapIt != entryMap.end(); ++entryMapIt) { 00245 const KEntryKey& key = entryMapIt.key(); 00246 if (key.mKey.isNull() && key.mGroup.startsWith(theGroup)) { 00247 groups << key.mGroup; 00248 } 00249 } 00250 return groups; 00251 } 00252 00253 bool KConfigPrivate::hasNonDeletedEntries(const QByteArray& group) const 00254 { 00255 const QSet<QByteArray> allGroups = allSubGroups(group); 00256 00257 Q_FOREACH(const QByteArray& aGroup, allGroups) { 00258 // Could be optimized, let's use the slow way for now 00259 // Check for any non-deleted entry 00260 if (!keyListImpl(aGroup).isEmpty()) 00261 return true; 00262 } 00263 return false; 00264 } 00265 00266 00267 QStringList KConfigPrivate::keyListImpl(const QByteArray& theGroup) const 00268 { 00269 QStringList keys; 00270 00271 const KEntryMapConstIterator theEnd = entryMap.constEnd(); 00272 KEntryMapConstIterator it = entryMap.findEntry(theGroup); 00273 if (it != theEnd) { 00274 ++it; // advance past the special group entry marker 00275 00276 QSet<QString> tmp; 00277 for (; it != theEnd && it.key().mGroup == theGroup; ++it) { 00278 const KEntryKey& key = it.key(); 00279 if (key.mGroup == theGroup && !key.mKey.isNull() && !it->bDeleted) 00280 tmp << QString::fromUtf8(key.mKey); 00281 } 00282 keys = tmp.toList(); 00283 } 00284 00285 return keys; 00286 } 00287 00288 QStringList KConfig::keyList(const QString& aGroup) const 00289 { 00290 Q_D(const KConfig); 00291 const QByteArray theGroup(aGroup.isEmpty() ? "<default>" : aGroup.toUtf8()); 00292 return d->keyListImpl(theGroup); 00293 } 00294 00295 QMap<QString,QString> KConfig::entryMap(const QString& aGroup) const 00296 { 00297 Q_D(const KConfig); 00298 QMap<QString, QString> theMap; 00299 const QByteArray theGroup(aGroup.isEmpty() ? "<default>" : aGroup.toUtf8()); 00300 00301 const KEntryMapConstIterator theEnd = d->entryMap.constEnd(); 00302 KEntryMapConstIterator it = d->entryMap.findEntry(theGroup, 0, 0); 00303 if (it != theEnd) { 00304 ++it; // advance past the special group entry marker 00305 00306 for (; it != theEnd && it.key().mGroup == theGroup; ++it) { 00307 // leave the default values and deleted entries out 00308 if (!it->bDeleted && !it.key().bDefault) { 00309 const QString key = QString::fromUtf8(it.key().mKey.constData()); 00310 // the localized entry should come first, so don't overwrite it 00311 // with the non-localized entry 00312 if (!theMap.contains(key)) 00313 theMap.insert(key,QString::fromUtf8(it->mValue.constData())); 00314 } 00315 } 00316 } 00317 00318 return theMap; 00319 } 00320 00321 // TODO KDE5: return a bool value 00322 void KConfig::sync() 00323 { 00324 Q_D(KConfig); 00325 00326 if (isImmutable() || name().isEmpty()) { 00327 // can't write to an immutable or anonymous file. 00328 return; 00329 } 00330 00331 if (d->bDirty && d->mBackend) { 00332 const QByteArray utf8Locale(locale().toUtf8()); 00333 00334 // Create the containing dir, maybe it wasn't there 00335 d->mBackend->createEnclosing(); 00336 00337 // lock the local file 00338 if (d->configState == ReadWrite && !d->lockLocal()) { 00339 qWarning() << "couldn't lock local file"; 00340 return; 00341 } 00342 00343 // Rewrite global/local config only if there is a dirty entry in it. 00344 bool writeGlobals = false; 00345 bool writeLocals = false; 00346 foreach (const KEntry& e, d->entryMap) { 00347 if (e.bDirty) { 00348 if (e.bGlobal) { 00349 writeGlobals = true; 00350 } else { 00351 writeLocals = true; 00352 } 00353 00354 if (writeGlobals && writeLocals) { 00355 break; 00356 } 00357 } 00358 } 00359 00360 d->bDirty = false; // will revert to true if a config write fails 00361 00362 if (d->wantGlobals() && writeGlobals) { 00363 KSharedPtr<KConfigBackend> tmp = KConfigBackend::create(componentData(), d->sGlobalFileName); 00364 if (d->configState == ReadWrite && !tmp->lock(componentData())) { 00365 qWarning() << "couldn't lock global file"; 00366 return; 00367 } 00368 if (!tmp->writeConfig(utf8Locale, d->entryMap, KConfigBackend::WriteGlobal, d->componentData)) { 00369 d->bDirty = true; 00370 // TODO KDE5: return false? (to tell the app that writing wasn't possible, e.g. 00371 // config file is immutable or disk full) 00372 } 00373 if (tmp->isLocked()) { 00374 tmp->unlock(); 00375 } 00376 } 00377 00378 if (writeLocals) { 00379 if (!d->mBackend->writeConfig(utf8Locale, d->entryMap, KConfigBackend::WriteOptions(), d->componentData)) { 00380 d->bDirty = true; 00381 // TODO KDE5: return false? (to tell the app that writing wasn't possible, e.g. 00382 // config file is immutable or disk full) 00383 } 00384 } 00385 if (d->mBackend->isLocked()) { 00386 d->mBackend->unlock(); 00387 } 00388 } 00389 } 00390 00391 void KConfig::markAsClean() 00392 { 00393 Q_D(KConfig); 00394 d->bDirty = false; 00395 00396 // clear any dirty flags that entries might have set 00397 const KEntryMapIterator theEnd = d->entryMap.end(); 00398 for (KEntryMapIterator it = d->entryMap.begin(); it != theEnd; ++it) 00399 it->bDirty = false; 00400 } 00401 00402 void KConfig::checkUpdate(const QString &id, const QString &updateFile) 00403 { 00404 const KConfigGroup cg(this, "$Version"); 00405 const QString cfg_id = updateFile+QLatin1Char(':')+id; 00406 const QStringList ids = cg.readEntry("update_info", QStringList()); 00407 if (!ids.contains(cfg_id)) { 00408 KToolInvocation::kdeinitExecWait(QString::fromLatin1("kconf_update"), QStringList() << QString::fromLatin1("--check") << updateFile); 00409 reparseConfiguration(); 00410 } 00411 } 00412 00413 KConfig* KConfig::copyTo(const QString &file, KConfig *config) const 00414 { 00415 Q_D(const KConfig); 00416 if (!config) 00417 config = new KConfig(componentData(), QString(), SimpleConfig); 00418 config->d_func()->changeFileName(file, d->resourceType); 00419 config->d_func()->entryMap = d->entryMap; 00420 config->d_func()->bFileImmutable = false; 00421 00422 const KEntryMapIterator theEnd = config->d_func()->entryMap.end(); 00423 for (KEntryMapIterator it = config->d_func()->entryMap.begin(); it != theEnd; ++it) 00424 it->bDirty = true; 00425 config->d_ptr->bDirty = true; 00426 00427 return config; 00428 } 00429 00430 QString KConfig::name() const 00431 { 00432 Q_D(const KConfig); 00433 return d->fileName; 00434 } 00435 00436 void KConfigPrivate::changeFileName(const QString& name, const char* type) 00437 { 00438 fileName = name; 00439 00440 QString file; 00441 if (name.isEmpty()) { 00442 if (wantDefaults()) { // accessing default app-specific config "appnamerc" 00443 const QString appName = componentData.aboutData()->appName(); 00444 if (!appName.isEmpty()) { 00445 fileName = appName + QLatin1String("rc"); 00446 if (type && *type) 00447 resourceType = type; // only change it if it's not empty 00448 file = KStandardDirs::locateLocal(resourceType, fileName, false, componentData); 00449 } 00450 } else if (wantGlobals()) { // accessing "kdeglobals" - XXX used anywhere? 00451 resourceType = "config"; 00452 fileName = QLatin1String("kdeglobals"); 00453 file = sGlobalFileName; 00454 } // else anonymous config. 00455 // KDE5: remove these magic overloads 00456 } else if (QDir::isAbsolutePath(fileName)) { 00457 fileName = KStandardDirs::realFilePath(fileName); 00458 file = fileName; 00459 } else { 00460 if (type && *type) 00461 resourceType = type; // only change it if it's not empty 00462 file = KStandardDirs::locateLocal(resourceType, fileName, false, componentData); 00463 } 00464 00465 if (file.isEmpty()) { 00466 openFlags = KConfig::SimpleConfig; 00467 return; 00468 } 00469 00470 bSuppressGlobal = (file == sGlobalFileName); 00471 00472 if (bDynamicBackend || !mBackend) // allow dynamic changing of backend 00473 mBackend = KConfigBackend::create(componentData, file); 00474 else 00475 mBackend->setFilePath(file); 00476 00477 configState = mBackend->accessMode(); 00478 } 00479 00480 void KConfig::reparseConfiguration() 00481 { 00482 Q_D(KConfig); 00483 if (d->fileName.isEmpty()) { 00484 return; 00485 } 00486 00487 // Don't lose pending changes 00488 if (!d->isReadOnly() && d->bDirty) 00489 sync(); 00490 00491 d->entryMap.clear(); 00492 00493 d->bFileImmutable = false; 00494 00495 // Parse all desired files from the least to the most specific. 00496 if (d->wantGlobals()) 00497 d->parseGlobalFiles(); 00498 00499 d->parseConfigFiles(); 00500 } 00501 00502 00503 QStringList KConfigPrivate::getGlobalFiles() const 00504 { 00505 const KStandardDirs *const dirs = componentData.dirs(); 00506 QStringList globalFiles; 00507 foreach (const QString& dir1, dirs->findAllResources("config", QLatin1String("kdeglobals"))) 00508 globalFiles.push_front(dir1); 00509 foreach (const QString& dir2, dirs->findAllResources("config", QLatin1String("system.kdeglobals"))) 00510 globalFiles.push_front(dir2); 00511 if (!etc_kderc.isEmpty()) 00512 globalFiles.push_front(etc_kderc); 00513 return globalFiles; 00514 } 00515 00516 void KConfigPrivate::parseGlobalFiles() 00517 { 00518 const QStringList globalFiles = getGlobalFiles(); 00519 // qDebug() << "parsing global files" << globalFiles; 00520 00521 // TODO: can we cache the values in etc_kderc / other global files 00522 // on a per-application basis? 00523 const QByteArray utf8Locale = locale.toUtf8(); 00524 foreach(const QString& file, globalFiles) { 00525 KConfigBackend::ParseOptions parseOpts = KConfigBackend::ParseGlobal|KConfigBackend::ParseExpansions; 00526 if (file != sGlobalFileName) 00527 parseOpts |= KConfigBackend::ParseDefaults; 00528 00529 KSharedPtr<KConfigBackend> backend = KConfigBackend::create(componentData, file); 00530 if ( backend->parseConfig( utf8Locale, entryMap, parseOpts) == KConfigBackend::ParseImmutable) 00531 break; 00532 } 00533 } 00534 00535 void KConfigPrivate::parseConfigFiles() 00536 { 00537 // can only read the file if there is a backend and a file name 00538 if (mBackend && !fileName.isEmpty()) { 00539 00540 bFileImmutable = false; 00541 00542 QList<QString> files; 00543 if (wantDefaults()) { 00544 if (bSuppressGlobal) { 00545 files = getGlobalFiles(); 00546 } else { 00547 foreach (const QString& f, componentData.dirs()->findAllResources( 00548 resourceType, fileName)) 00549 files.prepend(f); 00550 } 00551 } else { 00552 files << mBackend->filePath(); 00553 } 00554 if (!isSimple()) 00555 files = extraFiles.toList() + files; 00556 00557 // qDebug() << "parsing local files" << files; 00558 00559 const QByteArray utf8Locale = locale.toUtf8(); 00560 foreach(const QString& file, files) { 00561 if (file == mBackend->filePath()) { 00562 switch (mBackend->parseConfig(utf8Locale, entryMap, KConfigBackend::ParseExpansions)) { 00563 case KConfigBackend::ParseOk: 00564 break; 00565 case KConfigBackend::ParseImmutable: 00566 bFileImmutable = true; 00567 break; 00568 case KConfigBackend::ParseOpenError: 00569 configState = KConfigBase::NoAccess; 00570 break; 00571 } 00572 } else { 00573 KSharedPtr<KConfigBackend> backend = KConfigBackend::create(componentData, file); 00574 bFileImmutable = (backend->parseConfig(utf8Locale, entryMap, 00575 KConfigBackend::ParseDefaults|KConfigBackend::ParseExpansions) 00576 == KConfigBackend::ParseImmutable); 00577 } 00578 00579 if (bFileImmutable) 00580 break; 00581 } 00582 if (componentData.dirs()->isRestrictedResource(resourceType, fileName)) 00583 bFileImmutable = true; 00584 } 00585 } 00586 00587 KConfig::AccessMode KConfig::accessMode() const 00588 { 00589 Q_D(const KConfig); 00590 return d->configState; 00591 } 00592 00593 void KConfig::addConfigSources(const QStringList& files) 00594 { 00595 Q_D(KConfig); 00596 foreach(const QString& file, files) { 00597 d->extraFiles.push(file); 00598 } 00599 00600 if (!files.isEmpty()) { 00601 reparseConfiguration(); 00602 } 00603 } 00604 00605 QString KConfig::locale() const 00606 { 00607 Q_D(const KConfig); 00608 return d->locale; 00609 } 00610 00611 bool KConfigPrivate::setLocale(const QString& aLocale) 00612 { 00613 if (aLocale != locale) { 00614 locale = aLocale; 00615 return true; 00616 } 00617 return false; 00618 } 00619 00620 bool KConfig::setLocale(const QString& locale) 00621 { 00622 Q_D(KConfig); 00623 if (d->setLocale(locale)) { 00624 reparseConfiguration(); 00625 return true; 00626 } 00627 return false; 00628 } 00629 00630 void KConfig::setReadDefaults(bool b) 00631 { 00632 Q_D(KConfig); 00633 d->bReadDefaults = b; 00634 } 00635 00636 bool KConfig::readDefaults() const 00637 { 00638 Q_D(const KConfig); 00639 return d->bReadDefaults; 00640 } 00641 00642 bool KConfig::isImmutable() const 00643 { 00644 Q_D(const KConfig); 00645 return d->bFileImmutable; 00646 } 00647 00648 bool KConfig::isGroupImmutableImpl(const QByteArray& aGroup) const 00649 { 00650 Q_D(const KConfig); 00651 return isImmutable() || d->entryMap.getEntryOption(aGroup, 0, 0, KEntryMap::EntryImmutable); 00652 } 00653 00654 #ifndef KDE_NO_DEPRECATED 00655 void KConfig::setForceGlobal(bool b) 00656 { 00657 Q_D(KConfig); 00658 d->bForceGlobal = b; 00659 } 00660 #endif 00661 00662 #ifndef KDE_NO_DEPRECATED 00663 bool KConfig::forceGlobal() const 00664 { 00665 Q_D(const KConfig); 00666 return d->bForceGlobal; 00667 } 00668 #endif 00669 00670 KConfigGroup KConfig::groupImpl(const QByteArray &group) 00671 { 00672 return KConfigGroup(this, group.constData()); 00673 } 00674 00675 const KConfigGroup KConfig::groupImpl(const QByteArray &group) const 00676 { 00677 return KConfigGroup(this, group.constData()); 00678 } 00679 00680 KEntryMap::EntryOptions convertToOptions(KConfig::WriteConfigFlags flags) 00681 { 00682 KEntryMap::EntryOptions options=0; 00683 00684 if (flags&KConfig::Persistent) 00685 options |= KEntryMap::EntryDirty; 00686 if (flags&KConfig::Global) 00687 options |= KEntryMap::EntryGlobal; 00688 if (flags&KConfig::Localized) 00689 options |= KEntryMap::EntryLocalized; 00690 return options; 00691 } 00692 00693 void KConfig::deleteGroupImpl(const QByteArray &aGroup, WriteConfigFlags flags) 00694 { 00695 Q_D(KConfig); 00696 KEntryMap::EntryOptions options = convertToOptions(flags)|KEntryMap::EntryDeleted; 00697 00698 const QSet<QByteArray> groups = d->allSubGroups(aGroup); 00699 foreach (const QByteArray& group, groups) { 00700 const QStringList keys = d->keyListImpl(group); 00701 foreach (const QString& _key, keys) { 00702 const QByteArray &key = _key.toUtf8(); 00703 if (d->canWriteEntry(group, key.constData())) { 00704 d->entryMap.setEntry(group, key, QByteArray(), options); 00705 d->bDirty = true; 00706 } 00707 } 00708 } 00709 } 00710 00711 bool KConfig::isConfigWritable(bool warnUser) 00712 { 00713 Q_D(KConfig); 00714 bool allWritable = (d->mBackend.isNull()? false: d->mBackend->isWritable()); 00715 00716 if (warnUser && !allWritable) { 00717 QString errorMsg; 00718 if (!d->mBackend.isNull()) // TODO how can be it be null? Set errorMsg appropriately 00719 errorMsg = d->mBackend->nonWritableErrorMessage(); 00720 00721 // Note: We don't ask the user if we should not ask this question again because we can't save the answer. 00722 errorMsg += i18n("Please contact your system administrator."); 00723 QString cmdToExec = KStandardDirs::findExe(QString::fromLatin1("kdialog")); 00724 if (!cmdToExec.isEmpty() && componentData().isValid()) 00725 { 00726 QProcess::execute(cmdToExec, QStringList() 00727 << QString::fromLatin1("--title") << componentData().componentName() 00728 << QString::fromLatin1("--msgbox") << errorMsg); 00729 } 00730 } 00731 00732 d->configState = allWritable ? ReadWrite : ReadOnly; // update the read/write status 00733 00734 return allWritable; 00735 } 00736 00737 bool KConfig::hasGroupImpl(const QByteArray& aGroup) const 00738 { 00739 Q_D(const KConfig); 00740 00741 // No need to look for the actual group entry anymore, or for subgroups: 00742 // a group exists if it contains any non-deleted entry. 00743 00744 return d->hasNonDeletedEntries(aGroup); 00745 } 00746 00747 bool KConfigPrivate::canWriteEntry(const QByteArray& group, const char* key, bool isDefault) const 00748 { 00749 if (bFileImmutable || 00750 entryMap.getEntryOption(group, key, KEntryMap::SearchLocalized, KEntryMap::EntryImmutable)) 00751 return isDefault; 00752 return true; 00753 } 00754 00755 void KConfigPrivate::putData( const QByteArray& group, const char* key, 00756 const QByteArray& value, KConfigBase::WriteConfigFlags flags, bool expand) 00757 { 00758 KEntryMap::EntryOptions options = convertToOptions(flags); 00759 00760 if (bForceGlobal) 00761 options |= KEntryMap::EntryGlobal; 00762 if (expand) 00763 options |= KEntryMap::EntryExpansion; 00764 00765 if (value.isNull()) // deleting entry 00766 options |= KEntryMap::EntryDeleted; 00767 00768 bool dirtied = entryMap.setEntry(group, key, value, options); 00769 if (dirtied && (flags & KConfigBase::Persistent)) 00770 bDirty = true; 00771 } 00772 00773 QByteArray KConfigPrivate::lookupData(const QByteArray& group, const char* key, 00774 KEntryMap::SearchFlags flags) const 00775 { 00776 if (bReadDefaults) 00777 flags |= KEntryMap::SearchDefaults; 00778 const KEntryMapConstIterator it = entryMap.findEntry(group, key, flags); 00779 if (it == entryMap.constEnd()) 00780 return QByteArray(); 00781 return it->mValue; 00782 } 00783 00784 QString KConfigPrivate::lookupData(const QByteArray& group, const char* key, 00785 KEntryMap::SearchFlags flags, bool *expand) const 00786 { 00787 if (bReadDefaults) 00788 flags |= KEntryMap::SearchDefaults; 00789 return entryMap.getEntry(group, key, QString(), flags, expand); 00790 } 00791 00792 void KConfig::virtual_hook(int /*id*/, void* /*data*/) 00793 { 00794 /* nothing */ 00795 } 00796
KDE 4.6 API Reference