tdeconfig.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 <tqfileinfo.h> 00034 00035 #include <tdeapplication.h> 00036 #include "tdeconfigbackend.h" 00037 00038 #include "tdeconfig.h" 00039 #include "tdeglobal.h" 00040 #include "kstandarddirs.h" 00041 #include "kstaticdeleter.h" 00042 #include <tqtimer.h> 00043 00044 TDEConfig::TDEConfig( const TQString& fileName, 00045 bool bReadOnly, bool bUseKderc, const char *resType ) 00046 : TDEConfigBase(), 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 TDEConfigINIBackEnd *aBackEnd = new TDEConfigINIBackEnd(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 // read initial information off disk 00064 reparseConfiguration(); 00065 00066 // we let TDEStandardDirs add custom user config files. It will do 00067 // this only once. So only the first call ever to this constructor 00068 // will anything else than return here We have to reparse here as 00069 // configuration files may appear after customized directories have 00070 // been added. and the info they contain needs to be inserted into the 00071 // config object. 00072 // Since this makes only sense for config directories, addCustomized 00073 // returns true only if new config directories appeared. 00074 if (TDEGlobal::dirs()->addCustomized(this)) 00075 reparseConfiguration(); 00076 } 00077 00078 TDEConfig::TDEConfig(TDEConfigBackEnd *aBackEnd, bool bReadOnly) 00079 : bGroupImmutable(false), bFileImmutable(false), 00080 bForceGlobal(false) 00081 { 00082 setReadOnly(bReadOnly); 00083 backEnd = aBackEnd; 00084 reparseConfiguration(); 00085 } 00086 00087 TDEConfig::~TDEConfig() 00088 { 00089 sync(); 00090 00091 delete backEnd; 00092 } 00093 00094 void TDEConfig::rollback(bool bDeep) 00095 { 00096 TDEConfigBase::rollback(bDeep); 00097 00098 if (!bDeep) 00099 return; // object's bDeep flag is set in TDEConfigBase method 00100 00101 // clear any dirty flags that entries might have set 00102 for (KEntryMapIterator aIt = aEntryMap.begin(); 00103 aIt != aEntryMap.end(); ++aIt) 00104 (*aIt).bDirty = false; 00105 } 00106 00107 TQStringList TDEConfig::groupList() const 00108 { 00109 TQStringList retList; 00110 00111 KEntryMapConstIterator aIt = aEntryMap.begin(); 00112 KEntryMapConstIterator aEnd = aEntryMap.end(); 00113 for (; aIt != aEnd; ++aIt) 00114 { 00115 while(aIt.key().mKey.isEmpty()) 00116 { 00117 TQCString group = aIt.key().mGroup; 00118 ++aIt; 00119 while (true) 00120 { 00121 if (aIt == aEnd) 00122 return retList; // done 00123 00124 if (aIt.key().mKey.isEmpty()) 00125 break; // Group is empty, next group 00126 00127 if (!aIt.key().bDefault && !(*aIt).bDeleted) 00128 { 00129 if (group != "$Version") // Special case! 00130 retList.append(TQString::fromUtf8(group)); 00131 break; // Group is non-empty, added, next group 00132 } 00133 ++aIt; 00134 } 00135 } 00136 } 00137 00138 return retList; 00139 } 00140 00141 TQMap<TQString, TQString> TDEConfig::entryMap(const TQString &pGroup) const 00142 { 00143 TQCString pGroup_utf = pGroup.utf8(); 00144 KEntryKey groupKey( pGroup_utf, 0 ); 00145 TQMap<TQString, TQString> tmpMap; 00146 00147 KEntryMapConstIterator aIt = aEntryMap.find(groupKey); 00148 if (aIt == aEntryMap.end()) 00149 return tmpMap; 00150 ++aIt; // advance past special group entry marker 00151 for (; aIt.key().mGroup == pGroup_utf && aIt != aEntryMap.end(); ++aIt) 00152 { 00153 // Leave the default values out && leave deleted entries out 00154 if (!aIt.key().bDefault && !(*aIt).bDeleted) 00155 tmpMap.insert(TQString::fromUtf8(aIt.key().mKey), TQString::fromUtf8((*aIt).mValue.data(), (*aIt).mValue.length())); 00156 } 00157 00158 return tmpMap; 00159 } 00160 00161 void TDEConfig::reparseConfiguration() 00162 { 00163 // Don't lose pending changes 00164 if (!isReadOnly() && backEnd && bDirty) 00165 backEnd->sync(); 00166 00167 aEntryMap.clear(); 00168 00169 // add the "default group" marker to the map 00170 KEntryKey groupKey("<default>", 0); 00171 aEntryMap.insert(groupKey, KEntry()); 00172 00173 bFileImmutable = false; 00174 parseConfigFiles(); 00175 bFileImmutable = bReadOnly; 00176 } 00177 00178 KEntryMap TDEConfig::internalEntryMap(const TQString &pGroup) const 00179 { 00180 TQCString pGroup_utf = pGroup.utf8(); 00181 KEntry aEntry; 00182 KEntryMapConstIterator aIt; 00183 KEntryKey aKey(pGroup_utf, 0); 00184 KEntryMap tmpEntryMap; 00185 00186 aIt = aEntryMap.find(aKey); 00187 if (aIt == aEntryMap.end()) { 00188 // the special group key is not in the map, 00189 // so it must be an invalid group. Return 00190 // an empty map. 00191 return tmpEntryMap; 00192 } 00193 // we now have a pointer to the nodes we want to copy. 00194 for (; aIt.key().mGroup == pGroup_utf && aIt != aEntryMap.end(); ++aIt) 00195 { 00196 tmpEntryMap.insert(aIt.key(), *aIt); 00197 } 00198 00199 return tmpEntryMap; 00200 } 00201 00202 void TDEConfig::putData(const KEntryKey &_key, const KEntry &_data, bool _checkGroup) 00203 { 00204 if (bFileImmutable && !_key.bDefault) 00205 return; 00206 00207 // check to see if the special group key is present, 00208 // and if not, put it in. 00209 if (_checkGroup) 00210 { 00211 KEntryKey groupKey( _key.mGroup, 0); 00212 KEntry &entry = aEntryMap[groupKey]; 00213 bGroupImmutable = entry.bImmutable; 00214 } 00215 if (bGroupImmutable && !_key.bDefault) 00216 return; 00217 00218 // now either add or replace the data 00219 KEntry &entry = aEntryMap[_key]; 00220 bool immutable = entry.bImmutable; 00221 if (immutable && !_key.bDefault) 00222 return; 00223 00224 entry = _data; 00225 entry.bImmutable |= immutable; 00226 entry.bGlobal |= bForceGlobal; // force to kdeglobals 00227 00228 if (_key.bDefault) 00229 { 00230 // We have added the data as default value, 00231 // add it as normal value as well. 00232 KEntryKey key(_key); 00233 key.bDefault = false; 00234 aEntryMap[key] = _data; 00235 } 00236 } 00237 00238 KEntry TDEConfig::lookupData(const KEntryKey &_key) const 00239 { 00240 KEntryMapConstIterator aIt = aEntryMap.find(_key); 00241 if (aIt != aEntryMap.end()) 00242 { 00243 const KEntry &entry = *aIt; 00244 if (entry.bDeleted) 00245 return KEntry(); 00246 else 00247 return entry; 00248 } 00249 else { 00250 return KEntry(); 00251 } 00252 } 00253 00254 bool TDEConfig::internalHasGroup(const TQCString &group) const 00255 { 00256 KEntryKey groupKey( group, 0); 00257 00258 KEntryMapConstIterator aIt = aEntryMap.find(groupKey); 00259 KEntryMapConstIterator aEnd = aEntryMap.end(); 00260 00261 if (aIt == aEnd) 00262 return false; 00263 ++aIt; 00264 for(; (aIt != aEnd); ++aIt) 00265 { 00266 if (aIt.key().mKey.isEmpty()) 00267 break; 00268 00269 if (!aIt.key().bDefault && !(*aIt).bDeleted) 00270 return true; 00271 } 00272 return false; 00273 } 00274 00275 void TDEConfig::setFileWriteMode(int mode) 00276 { 00277 backEnd->setFileWriteMode(mode); 00278 } 00279 00280 TDELockFile::Ptr TDEConfig::lockFile(bool bGlobal) 00281 { 00282 TDEConfigINIBackEnd *aBackEnd = dynamic_cast<TDEConfigINIBackEnd*>(backEnd); 00283 if (!aBackEnd) return 0; 00284 return aBackEnd->lockFile(bGlobal); 00285 } 00286 00287 void TDEConfig::checkUpdate(const TQString &id, const TQString &updateFile) 00288 { 00289 TQString oldGroup = group(); 00290 setGroup("$Version"); 00291 TQString cfg_id = updateFile+":"+id; 00292 TQStringList ids = readListEntry("update_info"); 00293 if (!ids.contains(cfg_id)) 00294 { 00295 TQStringList args; 00296 args << "--check" << updateFile; 00297 TDEApplication::tdeinitExecWait("tdeconf_update", args); 00298 reparseConfiguration(); 00299 } 00300 setGroup(oldGroup); 00301 } 00302 00303 TDEConfig* TDEConfig::copyTo(const TQString &file, TDEConfig *config) const 00304 { 00305 if (!config) 00306 config = new TDEConfig(TQString::null, false, false); 00307 config->backEnd->changeFileName(file, "config", false); 00308 config->setReadOnly(false); 00309 config->bFileImmutable = false; 00310 config->backEnd->mConfigState = ReadWrite; 00311 00312 TQStringList groups = groupList(); 00313 for(TQStringList::ConstIterator it = groups.begin(); 00314 it != groups.end(); ++it) 00315 { 00316 TQMap<TQString, TQString> map = entryMap(*it); 00317 config->setGroup(*it); 00318 for (TQMap<TQString,TQString>::Iterator it2 = map.begin(); 00319 it2 != map.end(); ++it2) 00320 { 00321 config->writeEntry(it2.key(), it2.data()); 00322 } 00323 00324 } 00325 return config; 00326 } 00327 00328 void TDEConfig::virtual_hook( int id, void* data ) 00329 { TDEConfigBase::virtual_hook( id, data ); } 00330 00331 static KStaticDeleter< TQValueList<TDESharedConfig*> > sd; 00332 TQValueList<TDESharedConfig*> *TDESharedConfig::s_list = 0; 00333 00334 TDESharedConfig::Ptr TDESharedConfig::openConfig(const TQString& fileName, bool readOnly, bool useKDEGlobals ) 00335 { 00336 if (s_list) 00337 { 00338 for(TQValueList<TDESharedConfig*>::ConstIterator it = s_list->begin(); 00339 it != s_list->end(); ++it) 00340 { 00341 if ((*it)->backEnd->fileName() == fileName && 00342 (*it)->bReadOnly == readOnly && 00343 (*it)->backEnd->useKDEGlobals == useKDEGlobals ) 00344 return (*it); 00345 } 00346 } 00347 return new TDESharedConfig(fileName, readOnly, useKDEGlobals); 00348 } 00349 00350 TDESharedConfig::TDESharedConfig( const TQString& fileName, bool readonly, bool usekdeglobals) 00351 : TDEConfig(fileName, readonly, usekdeglobals) 00352 { 00353 if (!s_list) 00354 { 00355 sd.setObject(s_list, new TQValueList<TDESharedConfig*>); 00356 } 00357 00358 s_list->append(this); 00359 } 00360 00361 TDESharedConfig::~TDESharedConfig() 00362 { 00363 if ( s_list ) 00364 s_list->remove(this); 00365 } 00366 00367 #include "tdeconfig.moc"