• Skip to content
  • Skip to link menu
KDE 4.7 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • Contact Us
 

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 

KDECore

Skip menu "KDECore"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Modules
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.5
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal