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