kconfig.cpp

00001 /*
00002   This file is part of the KDE libraries
00003   Copyright (c) 1999 Preston Brown <pbrown@kde.org>
00004   Copyright (C) 1997-1999 Matthias Kalle Dalheimer (kalle@kde.org)
00005 
00006   This library is free software; you can redistribute it and/or
00007   modify it under the terms of the GNU Library General Public
00008   License as published by the Free Software Foundation; either
00009   version 2 of the License, or (at your option) any later version.
00010 
00011   This library is distributed in the hope that it will be useful,
00012   but WITHOUT ANY WARRANTY; without even the implied warranty of
00013   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014   Library General Public License for more details.
00015 
00016   You should have received a copy of the GNU Library General Public License
00017   along with this library; see the file COPYING.LIB.  If not, write to
00018   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019   Boston, MA 02110-1301, USA.
00020 */
00021 
00022 // $Id$
00023 
00024 #include <config.h>
00025 
00026 #ifdef HAVE_SYS_STAT_H
00027 #include <sys/stat.h>
00028 #endif
00029 
00030 #include <stdlib.h>
00031 #include <unistd.h>
00032 
00033 #include <qfileinfo.h>
00034 
00035 #include <kapplication.h>
00036 #include "kconfigbackend.h"
00037 
00038 #include "kconfig.h"
00039 #include "kglobal.h"
00040 #include "kstandarddirs.h"
00041 #include "kstaticdeleter.h"
00042 #include <qtimer.h>
00043 
00044 KConfig::KConfig( const QString& fileName,
00045                  bool bReadOnly, bool bUseKderc, const char *resType )
00046   : KConfigBase(), bGroupImmutable(false), bFileImmutable(false),
00047     bForceGlobal(false)
00048 {
00049   // set the object's read-only status.
00050   setReadOnly(bReadOnly);
00051 
00052   // for right now we will hardcode that we are using the INI
00053   // back end driver.  In the future this should be converted over to
00054   // a object factory of some sorts.
00055   KConfigINIBackEnd *aBackEnd = new KConfigINIBackEnd(this,
00056                               fileName,
00057                                                       resType,
00058                               bUseKderc);
00059 
00060   // set the object's back end pointer to this new backend
00061   backEnd = aBackEnd;
00062 
00063   KGlobal::dirs()->addResourceDir( "config", "/etc/kde/config/");
00064   // read initial information off disk
00065   reparseConfiguration();
00066 
00067   // we let KStandardDirs add custom user config files. It will do
00068   // this only once. So only the first call ever to this constructor
00069   // will anything else than return here We have to reparse here as
00070   // configuration files may appear after customized directories have
00071   // been added. and the info they contain needs to be inserted into the
00072   // config object.
00073   // Since this makes only sense for config directories, addCustomized
00074   // returns true only if new config directories appeared.
00075   if (KGlobal::dirs()->addCustomized(this))
00076       reparseConfiguration();
00077 }
00078 
00079 KConfig::KConfig(KConfigBackEnd *aBackEnd, bool bReadOnly)
00080     : bGroupImmutable(false), bFileImmutable(false),
00081     bForceGlobal(false)
00082 {
00083   setReadOnly(bReadOnly);
00084   backEnd = aBackEnd;
00085   reparseConfiguration();
00086 }
00087 
00088 KConfig::~KConfig()
00089 {
00090   sync();
00091 
00092   delete backEnd;
00093 }
00094 
00095 void KConfig::rollback(bool bDeep)
00096 {
00097   KConfigBase::rollback(bDeep);
00098 
00099   if (!bDeep)
00100     return; // object's bDeep flag is set in KConfigBase method
00101 
00102   // clear any dirty flags that entries might have set
00103   for (KEntryMapIterator aIt = aEntryMap.begin();
00104        aIt != aEntryMap.end(); ++aIt)
00105     (*aIt).bDirty = false;
00106 }
00107 
00108 QStringList KConfig::groupList() const
00109 {
00110   QStringList retList;
00111 
00112   KEntryMapConstIterator aIt = aEntryMap.begin();
00113   KEntryMapConstIterator aEnd = aEntryMap.end();
00114   for (; aIt != aEnd; ++aIt)
00115   {
00116     while(aIt.key().mKey.isEmpty())
00117     {
00118       QCString group = aIt.key().mGroup;
00119       ++aIt;
00120       while (true)
00121       {
00122          if (aIt == aEnd)
00123             return retList; // done
00124 
00125          if (aIt.key().mKey.isEmpty())
00126             break; // Group is empty, next group
00127 
00128          if (!aIt.key().bDefault && !(*aIt).bDeleted)
00129          {
00130             if (group != "$Version") // Special case!
00131                retList.append(QString::fromUtf8(group));
00132             break; // Group is non-empty, added, next group
00133          }
00134          ++aIt;
00135       }
00136     }
00137   }
00138 
00139   return retList;
00140 }
00141 
00142 QMap<QString, QString> KConfig::entryMap(const QString &pGroup) const
00143 {
00144   QCString pGroup_utf = pGroup.utf8();
00145   KEntryKey groupKey( pGroup_utf, 0 );
00146   QMap<QString, QString> tmpMap;
00147 
00148   KEntryMapConstIterator aIt = aEntryMap.find(groupKey);
00149   if (aIt == aEntryMap.end())
00150      return tmpMap;
00151   ++aIt; // advance past special group entry marker
00152   for (; aIt.key().mGroup == pGroup_utf && aIt != aEntryMap.end(); ++aIt)
00153   {
00154     // Leave the default values out && leave deleted entries out
00155     if (!aIt.key().bDefault && !(*aIt).bDeleted)
00156       tmpMap.insert(QString::fromUtf8(aIt.key().mKey), QString::fromUtf8((*aIt).mValue.data(), (*aIt).mValue.length()));
00157   }
00158 
00159   return tmpMap;
00160 }
00161 
00162 void KConfig::reparseConfiguration()
00163 {
00164   // Don't lose pending changes
00165   if (!isReadOnly() && backEnd && bDirty)
00166     backEnd->sync();
00167 
00168   aEntryMap.clear();
00169 
00170   // add the "default group" marker to the map
00171   KEntryKey groupKey("<default>", 0);
00172   aEntryMap.insert(groupKey, KEntry());
00173 
00174   bFileImmutable = false;
00175   parseConfigFiles();
00176   bFileImmutable = bReadOnly;
00177 }
00178 
00179 KEntryMap KConfig::internalEntryMap(const QString &pGroup) const
00180 {
00181   QCString pGroup_utf = pGroup.utf8();
00182   KEntry aEntry;
00183   KEntryMapConstIterator aIt;
00184   KEntryKey aKey(pGroup_utf, 0);
00185   KEntryMap tmpEntryMap;
00186 
00187   aIt = aEntryMap.find(aKey);
00188   if (aIt == aEntryMap.end()) {
00189     // the special group key is not in the map,
00190     // so it must be an invalid group.  Return
00191     // an empty map.
00192     return tmpEntryMap;
00193   }
00194   // we now have a pointer to the nodes we want to copy.
00195   for (; aIt.key().mGroup == pGroup_utf && aIt != aEntryMap.end(); ++aIt)
00196   {
00197     tmpEntryMap.insert(aIt.key(), *aIt);
00198   }
00199 
00200   return tmpEntryMap;
00201 }
00202 
00203 void KConfig::putData(const KEntryKey &_key, const KEntry &_data, bool _checkGroup)
00204 {
00205   if (bFileImmutable && !_key.bDefault)
00206     return;
00207 
00208   // check to see if the special group key is present,
00209   // and if not, put it in.
00210   if (_checkGroup)
00211   {
00212     KEntryKey groupKey( _key.mGroup, 0);
00213     KEntry &entry = aEntryMap[groupKey];
00214     bGroupImmutable = entry.bImmutable;
00215   }
00216   if (bGroupImmutable && !_key.bDefault)
00217     return;
00218 
00219   // now either add or replace the data
00220   KEntry &entry = aEntryMap[_key];
00221   bool immutable = entry.bImmutable;
00222   if (immutable && !_key.bDefault)
00223     return;
00224 
00225   entry = _data;
00226   entry.bImmutable |= immutable;
00227   entry.bGlobal |= bForceGlobal; // force to kdeglobals
00228 
00229   if (_key.bDefault)
00230   {
00231      // We have added the data as default value,
00232      // add it as normal value as well.
00233      KEntryKey key(_key);
00234      key.bDefault = false;
00235      aEntryMap[key] = _data;
00236   }
00237 }
00238 
00239 KEntry KConfig::lookupData(const KEntryKey &_key) const
00240 {
00241   KEntryMapConstIterator aIt = aEntryMap.find(_key);
00242   if (aIt != aEntryMap.end())
00243   {
00244     const KEntry &entry = *aIt;
00245     if (entry.bDeleted)
00246        return KEntry();
00247     else
00248        return entry;
00249   }
00250   else {
00251     return KEntry();
00252   }
00253 }
00254 
00255 bool KConfig::internalHasGroup(const QCString &group) const
00256 {
00257   KEntryKey groupKey( group, 0);
00258 
00259   KEntryMapConstIterator aIt = aEntryMap.find(groupKey);
00260   KEntryMapConstIterator aEnd = aEntryMap.end();
00261 
00262   if (aIt == aEnd)
00263      return false;
00264   ++aIt;
00265   for(; (aIt != aEnd); ++aIt)
00266   {
00267      if (aIt.key().mKey.isEmpty())
00268         break;
00269 
00270      if (!aIt.key().bDefault && !(*aIt).bDeleted)
00271         return true;
00272   }
00273   return false;
00274 }
00275 
00276 void KConfig::setFileWriteMode(int mode)
00277 {
00278   backEnd->setFileWriteMode(mode);
00279 }
00280 
00281 KLockFile::Ptr KConfig::lockFile(bool bGlobal)
00282 {
00283   KConfigINIBackEnd *aBackEnd = dynamic_cast<KConfigINIBackEnd*>(backEnd);
00284   if (!aBackEnd) return 0;
00285   return aBackEnd->lockFile(bGlobal);
00286 }
00287 
00288 void KConfig::checkUpdate(const QString &id, const QString &updateFile)
00289 {
00290   QString oldGroup = group();
00291   setGroup("$Version");
00292   QString cfg_id = updateFile+":"+id;
00293   QStringList ids = readListEntry("update_info");
00294   if (!ids.contains(cfg_id))
00295   {
00296      QStringList args;
00297      args << "--check" << updateFile;
00298      KApplication::kdeinitExecWait("kconf_update", args);
00299      reparseConfiguration();
00300   }
00301   setGroup(oldGroup);
00302 }
00303 
00304 KConfig* KConfig::copyTo(const QString &file, KConfig *config) const
00305 {
00306   if (!config)
00307      config = new KConfig(QString::null, false, false);
00308   config->backEnd->changeFileName(file, "config", false);
00309   config->setReadOnly(false);
00310   config->bFileImmutable = false;
00311   config->backEnd->mConfigState = ReadWrite;
00312 
00313   QStringList groups = groupList();
00314   for(QStringList::ConstIterator it = groups.begin();
00315       it != groups.end(); ++it)
00316   {
00317      QMap<QString, QString> map = entryMap(*it);
00318      config->setGroup(*it);
00319      for (QMap<QString,QString>::Iterator it2  = map.begin();
00320           it2 != map.end(); ++it2)
00321      {
00322         config->writeEntry(it2.key(), it2.data());
00323      }
00324 
00325   }
00326   return config;
00327 }
00328 
00329 void KConfig::virtual_hook( int id, void* data )
00330 { KConfigBase::virtual_hook( id, data ); }
00331 
00332 static KStaticDeleter< QValueList<KSharedConfig*> > sd;
00333 QValueList<KSharedConfig*> *KSharedConfig::s_list = 0;
00334 
00335 KSharedConfig::Ptr KSharedConfig::openConfig(const QString& fileName, bool readOnly, bool useKDEGlobals )
00336 {
00337   if (s_list)
00338   {
00339      for(QValueList<KSharedConfig*>::ConstIterator it = s_list->begin();
00340          it != s_list->end(); ++it)
00341      {
00342         if ((*it)->backEnd->fileName() == fileName &&
00343                 (*it)->bReadOnly == readOnly &&
00344                 (*it)->backEnd->useKDEGlobals == useKDEGlobals )
00345            return (*it);
00346      }
00347   }
00348   return new KSharedConfig(fileName, readOnly, useKDEGlobals);
00349 }
00350 
00351 KSharedConfig::KSharedConfig( const QString& fileName, bool readonly, bool usekdeglobals)
00352  : KConfig(fileName, readonly, usekdeglobals)
00353 {
00354   if (!s_list)
00355   {
00356     sd.setObject(s_list, new QValueList<KSharedConfig*>);
00357   }
00358 
00359   s_list->append(this);
00360 }
00361 
00362 KSharedConfig::~KSharedConfig()
00363 {
00364   if ( s_list )
00365     s_list->remove(this);
00366 }
00367 
00368 #include "kconfig.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys