]> git.saurik.com Git - wxWidgets.git/blame - src/msw/regconf.cpp
checking that a wxWindow is of run-time type wxWindow is hopefully useless
[wxWidgets.git] / src / msw / regconf.cpp
CommitLineData
19454fa0 1///////////////////////////////////////////////////////////////////////////////
e4db172a 2// Name: src/msw/regconf.cpp
6d833566 3// Purpose:
19454fa0 4// Author: Vadim Zeitlin
6d833566 5// Modified by:
19454fa0
VZ
6// Created: 27.04.98
7// RCS-ID: $Id$
8// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
65571936 9// Licence: wxWindows licence
19454fa0
VZ
10///////////////////////////////////////////////////////////////////////////////
11
a3b46648
UU
12// For compilers that support precompilation, includes "wx.h".
13#include "wx/wxprec.h"
19454fa0 14
a3b46648 15#ifdef __BORLANDC__
e4db172a 16 #pragma hdrstop
82cf4761
VZ
17#endif
18
e4db172a
WS
19#if wxUSE_CONFIG
20
21#include "wx/config.h"
22
82cf4761 23#ifndef WX_PRECOMP
e4db172a
WS
24 #include "wx/string.h"
25 #include "wx/intl.h"
26 #include "wx/log.h"
d5da0ce7 27 #include "wx/event.h"
670f9935 28 #include "wx/app.h"
82cf4761
VZ
29#endif //WX_PRECOMP
30
61ba49f2
VZ
31#include "wx/msw/registry.h"
32#include "wx/msw/regconf.h"
19454fa0
VZ
33
34// ----------------------------------------------------------------------------
35// constants
36// ----------------------------------------------------------------------------
37
38// we put our data in HKLM\SOFTWARE_KEY\appname
2b5f62a0 39#define SOFTWARE_KEY wxString(wxT("Software\\"))
19454fa0
VZ
40
41// ----------------------------------------------------------------------------
42// global functions
43// ----------------------------------------------------------------------------
44
45// get the value if the key is opened and it exists
46bool TryGetValue(const wxRegKey& key, const wxString& str, wxString& strVal)
47{
48 return key.IsOpened() && key.HasValue(str) && key.QueryValue(str, strVal);
49}
50
51bool TryGetValue(const wxRegKey& key, const wxString& str, long *plVal)
52{
53 return key.IsOpened() && key.HasValue(str) && key.QueryValue(str, plVal);
54}
55
56// ============================================================================
57// implementation
58// ============================================================================
59
60// ----------------------------------------------------------------------------
61// ctor/dtor
62// ----------------------------------------------------------------------------
18244936 63
040f0110
VZ
64// create the config object which stores its data under HKCU\vendor\app and, if
65// style & wxCONFIG_USE_GLOBAL_FILE, under HKLM\vendor\app
66wxRegConfig::wxRegConfig(const wxString& appName, const wxString& vendorName,
67 const wxString& strLocal, const wxString& strGlobal,
68 long style)
69 : wxConfigBase(appName, vendorName, strLocal, strGlobal, style)
19454fa0 70{
040f0110 71 wxString strRoot;
19454fa0 72
040f0110 73 bool bDoUseGlobal = (style & wxCONFIG_USE_GLOBAL_FILE) != 0;
41286812 74
040f0110
VZ
75 // the convention is to put the programs keys under <vendor>\<appname>
76 // (but it can be overriden by specifying the pathes explicitly in strLocal
77 // and/or strGlobal)
e4db172a 78 if ( strLocal.empty() || (strGlobal.empty() && bDoUseGlobal) )
040f0110 79 {
e4db172a 80 if ( vendorName.empty() )
040f0110
VZ
81 {
82 if ( wxTheApp )
83 strRoot = wxTheApp->GetVendorName();
84 }
85 else
86 {
87 strRoot = vendorName;
88 }
18244936 89
040f0110 90 // no '\\' needed if no vendor name
e4db172a 91 if ( !strRoot.empty() )
18244936 92 {
040f0110 93 strRoot += '\\';
18244936 94 }
18244936 95
e4db172a 96 if ( appName.empty() )
040f0110 97 {
223d09f6 98 wxCHECK_RET( wxTheApp, wxT("No application name in wxRegConfig ctor!") );
040f0110
VZ
99 strRoot << wxTheApp->GetAppName();
100 }
101 else
18244936 102 {
040f0110 103 strRoot << appName;
18244936 104 }
040f0110
VZ
105 }
106 //else: we don't need to do all the complicated stuff above
18244936 107
e4db172a 108 wxString str = strLocal.empty() ? strRoot : strLocal;
807a903e
VZ
109
110 // as we're going to change the name of these keys fairly often and as
111 // there are only few of wxRegConfig objects (usually 1), we can allow
112 // ourselves to be generous and spend some memory to significantly improve
113 // performance of SetPath()
114 static const size_t MEMORY_PREALLOC = 512;
115
116 m_keyLocalRoot.ReserveMemoryForName(MEMORY_PREALLOC);
117 m_keyLocal.ReserveMemoryForName(MEMORY_PREALLOC);
118
040f0110 119 m_keyLocalRoot.SetName(wxRegKey::HKCU, SOFTWARE_KEY + str);
fda7962d 120 m_keyLocal.SetName(m_keyLocalRoot, wxEmptyString);
18244936 121
040f0110
VZ
122 if ( bDoUseGlobal )
123 {
e4db172a 124 str = strGlobal.empty() ? strRoot : strGlobal;
807a903e
VZ
125
126 m_keyGlobalRoot.ReserveMemoryForName(MEMORY_PREALLOC);
127 m_keyGlobal.ReserveMemoryForName(MEMORY_PREALLOC);
128
040f0110 129 m_keyGlobalRoot.SetName(wxRegKey::HKLM, SOFTWARE_KEY + str);
fda7962d 130 m_keyGlobal.SetName(m_keyGlobalRoot, wxEmptyString);
040f0110 131 }
18244936
JS
132
133 // Create() will Open() if key already exists
134 m_keyLocalRoot.Create();
135
136 // as it's the same key, Open() shouldn't fail (i.e. no need for Create())
137 m_keyLocal.Open();
138
040f0110
VZ
139 // OTOH, this key may perfectly not exist, so suppress error messages the call
140 // to Open() might generate
141 if ( bDoUseGlobal )
142 {
143 wxLogNull nolog;
9a85c87d
VZ
144 m_keyGlobalRoot.Open(wxRegKey::Read);
145 m_keyGlobal.Open(wxRegKey::Read);
040f0110 146 }
18244936 147}
19454fa0 148
19454fa0
VZ
149// ----------------------------------------------------------------------------
150// path management
151// ----------------------------------------------------------------------------
807a903e
VZ
152
153// this function is called a *lot* of times (as I learned after seeing from
154// profiler output that it is called ~12000 times from Mahogany start up code!)
155// so it is important to optimize it - in particular, avoid using generic
156// string functions here and do everything manually because it is faster
157//
158// I still kept the old version to be able to check that the optimized code has
159// the same output as the non optimized version.
19454fa0
VZ
160void wxRegConfig::SetPath(const wxString& strPath)
161{
807a903e
VZ
162 // remember the old path
163 wxString strOldPath = m_strPath;
19454fa0 164
807a903e
VZ
165#ifdef WX_DEBUG_SET_PATH // non optimized version kept here for testing
166 wxString m_strPathAlt;
19454fa0 167
807a903e
VZ
168 {
169 wxArrayString aParts;
170
171 // because GetPath() returns "" when we're at root, we must understand
172 // empty string as "/"
e4db172a 173 if ( strPath.empty() || (strPath[0] == wxCONFIG_PATH_SEPARATOR) ) {
807a903e
VZ
174 // absolute path
175 wxSplitPath(aParts, strPath);
176 }
177 else {
178 // relative path, combine with current one
179 wxString strFullPath = GetPath();
180 strFullPath << wxCONFIG_PATH_SEPARATOR << strPath;
181 wxSplitPath(aParts, strFullPath);
182 }
183
184 // recombine path parts in one variable
185 wxString strRegPath;
186 m_strPathAlt.Empty();
187 for ( size_t n = 0; n < aParts.Count(); n++ ) {
188 strRegPath << '\\' << aParts[n];
189 m_strPathAlt << wxCONFIG_PATH_SEPARATOR << aParts[n];
190 }
191 }
192#endif // 0
19454fa0 193
807a903e
VZ
194 // check for the most common case first
195 if ( strPath.empty() )
196 {
197 m_strPath = wxCONFIG_PATH_SEPARATOR;
198 }
199 else // not root
200 {
201 // construct the full path
202 wxString strFullPath;
203 if ( strPath[0u] == wxCONFIG_PATH_SEPARATOR )
204 {
205 // absolute path
206 strFullPath = strPath;
207 }
208 else // relative path
209 {
210 strFullPath.reserve(2*m_strPath.length());
211
e9c4c02c 212 strFullPath << m_strPath;
4d08943e 213 if ( strFullPath.Len() == 0 ||
e9c4c02c 214 strFullPath.Last() != wxCONFIG_PATH_SEPARATOR )
4d08943e 215 strFullPath << wxCONFIG_PATH_SEPARATOR;
e9c4c02c 216 strFullPath << strPath;
807a903e
VZ
217 }
218
219 // simplify it: we need to handle ".." here
220
221 // count the total number of slashes we have to know if we can go upper
222 size_t totalSlashes = 0;
223
224 // position of the last slash to be able to backtrack to it quickly if
225 // needed, but we set it to -1 if we don't have a valid position
226 //
227 // we only remember the last position which means that we handle ".."
228 // quite efficiently but not "../.." - however the latter should be
229 // much more rare, so it is probably ok
230 int posLastSlash = -1;
231
232 const wxChar *src = strFullPath.c_str();
233 size_t len = strFullPath.length();
234 const wxChar *end = src + len;
235
de564874
MB
236 wxStringBufferLength buf(m_strPath, len);
237 wxChar *dst = buf;
807a903e
VZ
238 wxChar *start = dst;
239
240 for ( ; src < end; src++, dst++ )
241 {
242 if ( *src == wxCONFIG_PATH_SEPARATOR )
243 {
244 // check for "/.."
245
246 // note that we don't have to check for src < end here as
247 // *end == 0 so can't be '.'
248 if ( src[1] == _T('.') && src[2] == _T('.') &&
249 (src + 3 == end || src[3] == wxCONFIG_PATH_SEPARATOR) )
250 {
251 if ( !totalSlashes )
252 {
253 wxLogWarning(_("'%s' has extra '..', ignored."),
254 strFullPath.c_str());
255 }
256 else // return to the previous path component
257 {
258 // do we already have its position?
259 if ( posLastSlash == -1 )
260 {
261 // no, find it: note that we are sure to have one
262 // because totalSlashes > 0 so we don't have to
263 // check the boundary condition below
264
265 // this is more efficient than strrchr()
79c3b7b2 266 dst--;
807a903e
VZ
267 while ( *dst != wxCONFIG_PATH_SEPARATOR )
268 {
269 dst--;
270 }
271 }
272 else // the position of last slash was stored
273 {
274 // go directly there
275 dst = start + posLastSlash;
276
277 // invalidate posLastSlash
278 posLastSlash = -1;
279 }
280
79c3b7b2 281 // we must have found a slash one way or another!
807a903e
VZ
282 wxASSERT_MSG( *dst == wxCONFIG_PATH_SEPARATOR,
283 _T("error in wxRegConfig::SetPath") );
284
79c3b7b2
VZ
285 // stay at the same position
286 dst--;
287
807a903e
VZ
288 // we killed one
289 totalSlashes--;
290 }
291
292 // skip both dots
293 src += 2;
294 }
295 else // not "/.."
296 {
297 if ( (dst == start) || (dst[-1] != wxCONFIG_PATH_SEPARATOR) )
298 {
299 *dst = wxCONFIG_PATH_SEPARATOR;
300
301 posLastSlash = dst - start;
302
303 totalSlashes++;
304 }
eaac8805
VZ
305 else // previous char was a slash too
306 {
307 // squeeze several subsequent slashes into one: i.e.
308 // just ignore this one
309 dst--;
310 }
807a903e
VZ
311 }
312 }
313 else // normal character
314 {
315 // just copy
316 *dst = *src;
317 }
318 }
319
320 // NUL terminate the string
321 if ( dst[-1] == wxCONFIG_PATH_SEPARATOR && (dst != start + 1) )
322 {
323 // if it has a trailing slash we remove it unless it is the only
324 // string character
325 dst--;
326 }
327
328 *dst = _T('\0');
de564874 329 buf.SetLength(dst - start);
807a903e 330 }
b568d04f 331
807a903e
VZ
332#ifdef WX_DEBUG_SET_PATH
333 wxASSERT( m_strPath == m_strPathAlt );
334#endif
335
336 if ( m_strPath == strOldPath )
337 return;
338
339 // registry APIs want backslashes instead of slashes
340 wxString strRegPath;
275dea46
VZ
341 if ( !m_strPath.empty() )
342 {
343 size_t len = m_strPath.length();
b568d04f 344
275dea46 345 const wxChar *src = m_strPath.c_str();
de564874
MB
346 wxStringBufferLength buf(strRegPath, len);
347 wxChar *dst = buf;
807a903e 348
275dea46
VZ
349 const wxChar *end = src + len;
350 for ( ; src < end; src++, dst++ )
351 {
352 if ( *src == wxCONFIG_PATH_SEPARATOR )
353 *dst = _T('\\');
354 else
355 *dst = *src;
356 }
807a903e 357
de564874 358 buf.SetLength(len);
275dea46 359 }
807a903e
VZ
360
361 // this is not needed any longer as we don't create keys unnecessarily any
362 // more (now it is done on demand, i.e. only when they're going to contain
363 // something)
364#if 0
365 // as we create the registry key when SetPath(key) is done, we can be left
366 // with plenty of empty keys if this was only done to try to read some
367 // value which, in fact, doesn't exist - to prevent this from happening we
368 // automatically delete the old key if it was empty
369 if ( m_keyLocal.Exists() && LocalKey().IsEmpty() )
370 {
371 m_keyLocal.DeleteSelf();
372 }
373#endif // 0
19454fa0 374
807a903e
VZ
375 // change current key(s)
376 m_keyLocal.SetName(m_keyLocalRoot, strRegPath);
807a903e 377
72957aa3
VZ
378 if ( GetStyle() & wxCONFIG_USE_GLOBAL_FILE )
379 {
380 m_keyGlobal.SetName(m_keyGlobalRoot, strRegPath);
807a903e 381
72957aa3 382 wxLogNull nolog;
9a85c87d 383 m_keyGlobal.Open(wxRegKey::Read);
72957aa3 384 }
19454fa0
VZ
385}
386
387// ----------------------------------------------------------------------------
388// enumeration (works only with current group)
389// ----------------------------------------------------------------------------
390
391/*
6d833566 392 We want to enumerate all local keys/values after the global ones, but, of
19454fa0
VZ
393 course, we don't want to repeat a key which appears locally as well as
394 globally twice.
395
396 We use the 15th bit of lIndex for distinction between global and local.
397 */
398
399#define LOCAL_MASK 0x8000
400#define IS_LOCAL_INDEX(l) (((l) & LOCAL_MASK) != 0)
401
02569ba8 402bool wxRegConfig::GetFirstGroup(wxString& str, long& lIndex) const
19454fa0
VZ
403{
404 lIndex = 0;
405 return GetNextGroup(str, lIndex);
406}
407
02569ba8 408bool wxRegConfig::GetNextGroup(wxString& str, long& lIndex) const
19454fa0
VZ
409{
410 // are we already enumerating local entries?
411 if ( m_keyGlobal.IsOpened() && !IS_LOCAL_INDEX(lIndex) ) {
412 // try to find a global entry which doesn't appear locally
09f50eb3 413 while ( m_keyGlobal.GetNextKey(str, lIndex) ) {
807a903e 414 if ( !m_keyLocal.Exists() || !LocalKey().HasSubKey(str) ) {
09f50eb3 415 // ok, found one - return it
4d08943e 416 return true;
19454fa0 417 }
09f50eb3
VZ
418 }
419
420 // no more global entries
421 lIndex |= LOCAL_MASK;
19454fa0
VZ
422 }
423
807a903e
VZ
424 // if we don't have the key at all, don't try to enumerate anything under it
425 if ( !m_keyLocal.Exists() )
4d08943e 426 return false;
807a903e 427
19454fa0
VZ
428 // much easier with local entries: get the next one we find
429 // (don't forget to clear our flag bit and set it again later)
430 lIndex &= ~LOCAL_MASK;
807a903e 431 bool bOk = LocalKey().GetNextKey(str, lIndex);
19454fa0
VZ
432 lIndex |= LOCAL_MASK;
433
434 return bOk;
435}
436
02569ba8 437bool wxRegConfig::GetFirstEntry(wxString& str, long& lIndex) const
19454fa0
VZ
438{
439 lIndex = 0;
82cf4761 440 return GetNextEntry(str, lIndex);
19454fa0
VZ
441}
442
02569ba8 443bool wxRegConfig::GetNextEntry(wxString& str, long& lIndex) const
19454fa0
VZ
444{
445 // are we already enumerating local entries?
446 if ( m_keyGlobal.IsOpened() && !IS_LOCAL_INDEX(lIndex) ) {
447 // try to find a global entry which doesn't appear locally
50f7d0a3 448 while ( m_keyGlobal.GetNextValue(str, lIndex) ) {
807a903e 449 if ( !m_keyLocal.Exists() || !LocalKey().HasValue(str) ) {
50f7d0a3 450 // ok, found one - return it
4d08943e 451 return true;
19454fa0 452 }
50f7d0a3
VZ
453 }
454
455 // no more global entries
456 lIndex |= LOCAL_MASK;
19454fa0
VZ
457 }
458
807a903e
VZ
459 // if we don't have the key at all, don't try to enumerate anything under it
460 if ( !m_keyLocal.Exists() )
4d08943e 461 return false;
807a903e 462
19454fa0
VZ
463 // much easier with local entries: get the next one we find
464 // (don't forget to clear our flag bit and set it again later)
465 lIndex &= ~LOCAL_MASK;
807a903e 466 bool bOk = LocalKey().GetNextValue(str, lIndex);
19454fa0
VZ
467 lIndex |= LOCAL_MASK;
468
469 return bOk;
470}
471
33ac7e6f 472size_t wxRegConfig::GetNumberOfEntries(bool WXUNUSED(bRecursive)) const
82cf4761 473{
c86f1403 474 size_t nEntries = 0;
82cf4761
VZ
475
476 // dummy vars
477 wxString str;
478 long l;
6a23cbce 479 bool bCont = ((wxRegConfig*)this)->GetFirstEntry(str, l);
82cf4761
VZ
480 while ( bCont ) {
481 nEntries++;
482
6a23cbce 483 bCont = ((wxRegConfig*)this)->GetNextEntry(str, l);
82cf4761
VZ
484 }
485
486 return nEntries;
487}
488
33ac7e6f 489size_t wxRegConfig::GetNumberOfGroups(bool WXUNUSED(bRecursive)) const
82cf4761 490{
c86f1403 491 size_t nGroups = 0;
82cf4761
VZ
492
493 // dummy vars
494 wxString str;
495 long l;
6a23cbce 496 bool bCont = ((wxRegConfig*)this)->GetFirstGroup(str, l);
82cf4761
VZ
497 while ( bCont ) {
498 nGroups++;
499
6a23cbce 500 bCont = ((wxRegConfig*)this)->GetNextGroup(str, l);
82cf4761
VZ
501 }
502
503 return nGroups;
504}
505
6d833566
VZ
506// ----------------------------------------------------------------------------
507// tests for existence
508// ----------------------------------------------------------------------------
509
61ba49f2 510bool wxRegConfig::HasGroup(const wxString& key) const
6d833566 511{
61ba49f2
VZ
512 wxConfigPathChanger path(this, key);
513
514 wxString strName(path.Name());
515
807a903e
VZ
516 return (m_keyLocal.Exists() && LocalKey().HasSubKey(strName)) ||
517 m_keyGlobal.HasSubKey(strName);
6d833566
VZ
518}
519
61ba49f2 520bool wxRegConfig::HasEntry(const wxString& key) const
6d833566 521{
61ba49f2
VZ
522 wxConfigPathChanger path(this, key);
523
524 wxString strName(path.Name());
525
807a903e
VZ
526 return (m_keyLocal.Exists() && LocalKey().HasValue(strName)) ||
527 m_keyGlobal.HasValue(strName);
61ba49f2
VZ
528}
529
530wxConfigBase::EntryType wxRegConfig::GetEntryType(const wxString& key) const
531{
532 wxConfigPathChanger path(this, key);
533
534 wxString strName(path.Name());
535
536 bool isNumeric;
807a903e 537 if ( m_keyLocal.Exists() && LocalKey().HasValue(strName) )
61ba49f2
VZ
538 isNumeric = m_keyLocal.IsNumericValue(strName);
539 else if ( m_keyGlobal.HasValue(strName) )
540 isNumeric = m_keyGlobal.IsNumericValue(strName);
541 else
542 return wxConfigBase::Type_Unknown;
543
544 return isNumeric ? wxConfigBase::Type_Integer : wxConfigBase::Type_String;
6d833566
VZ
545}
546
19454fa0
VZ
547// ----------------------------------------------------------------------------
548// reading/writing
549// ----------------------------------------------------------------------------
550
2ba41305 551bool wxRegConfig::DoReadString(const wxString& key, wxString *pStr) const
19454fa0 552{
4d08943e 553 wxCHECK_MSG( pStr, false, _T("wxRegConfig::Read(): NULL param") );
19454fa0 554
18244936
JS
555 wxConfigPathChanger path(this, key);
556
4d08943e 557 bool bQueryGlobal = true;
18244936
JS
558
559 // if immutable key exists in global key we must check that it's not
560 // overriden by the local key with the same name
561 if ( IsImmutable(path.Name()) ) {
562 if ( TryGetValue(m_keyGlobal, path.Name(), *pStr) ) {
807a903e 563 if ( m_keyLocal.Exists() && LocalKey().HasValue(path.Name()) ) {
223d09f6 564 wxLogWarning(wxT("User value for immutable key '%s' ignored."),
18244936
JS
565 path.Name().c_str());
566 }
567
4d08943e 568 return true;
18244936
JS
569 }
570 else {
571 // don't waste time - it's not there anyhow
4d08943e 572 bQueryGlobal = false;
18244936
JS
573 }
574 }
575
576 // first try local key
807a903e 577 if ( (m_keyLocal.Exists() && TryGetValue(LocalKey(), path.Name(), *pStr)) ||
18244936 578 (bQueryGlobal && TryGetValue(m_keyGlobal, path.Name(), *pStr)) ) {
4d08943e 579 return true;
41286812 580 }
baeed289 581
4d08943e 582 return false;
19454fa0
VZ
583}
584
2ba41305
VZ
585// this exactly reproduces the string version above except for ExpandEnvVars(),
586// we really should avoid this code duplication somehow...
587
588bool wxRegConfig::DoReadLong(const wxString& key, long *plResult) const
19454fa0 589{
4d08943e 590 wxCHECK_MSG( plResult, false, _T("wxRegConfig::Read(): NULL param") );
2ba41305 591
18244936 592 wxConfigPathChanger path(this, key);
19454fa0 593
4d08943e 594 bool bQueryGlobal = true;
19454fa0
VZ
595
596 // if immutable key exists in global key we must check that it's not
597 // overriden by the local key with the same name
598 if ( IsImmutable(path.Name()) ) {
02569ba8 599 if ( TryGetValue(m_keyGlobal, path.Name(), plResult) ) {
807a903e 600 if ( m_keyLocal.Exists() && LocalKey().HasValue(path.Name()) ) {
223d09f6 601 wxLogWarning(wxT("User value for immutable key '%s' ignored."),
19454fa0
VZ
602 path.Name().c_str());
603 }
604
4d08943e 605 return true;
19454fa0
VZ
606 }
607 else {
608 // don't waste time - it's not there anyhow
4d08943e 609 bQueryGlobal = false;
19454fa0
VZ
610 }
611 }
612
613 // first try local key
807a903e 614 if ( (m_keyLocal.Exists() && TryGetValue(LocalKey(), path.Name(), plResult)) ||
02569ba8 615 (bQueryGlobal && TryGetValue(m_keyGlobal, path.Name(), plResult)) ) {
4d08943e 616 return true;
19454fa0 617 }
2ba41305 618
4d08943e 619 return false;
19454fa0
VZ
620}
621
2ba41305 622bool wxRegConfig::DoWriteString(const wxString& key, const wxString& szValue)
19454fa0 623{
18244936 624 wxConfigPathChanger path(this, key);
19454fa0
VZ
625
626 if ( IsImmutable(path.Name()) ) {
223d09f6 627 wxLogError(wxT("Can't change immutable entry '%s'."), path.Name().c_str());
4d08943e 628 return false;
19454fa0
VZ
629 }
630
807a903e 631 return LocalKey().SetValue(path.Name(), szValue);
19454fa0
VZ
632}
633
2ba41305 634bool wxRegConfig::DoWriteLong(const wxString& key, long lValue)
19454fa0 635{
18244936 636 wxConfigPathChanger path(this, key);
19454fa0
VZ
637
638 if ( IsImmutable(path.Name()) ) {
223d09f6 639 wxLogError(wxT("Can't change immutable entry '%s'."), path.Name().c_str());
4d08943e 640 return false;
19454fa0
VZ
641 }
642
807a903e 643 return LocalKey().SetValue(path.Name(), lValue);
19454fa0
VZ
644}
645
646// ----------------------------------------------------------------------------
89077ebc
VZ
647// renaming
648// ----------------------------------------------------------------------------
649
650bool wxRegConfig::RenameEntry(const wxString& oldName, const wxString& newName)
651{
652 // check that the old entry exists...
653 if ( !HasEntry(oldName) )
4d08943e 654 return false;
89077ebc
VZ
655
656 // and that the new one doesn't
657 if ( HasEntry(newName) )
4d08943e 658 return false;
89077ebc 659
442d08ce 660 return m_keyLocal.RenameValue(oldName, newName);
89077ebc
VZ
661}
662
663bool wxRegConfig::RenameGroup(const wxString& oldName, const wxString& newName)
664{
665 // check that the old group exists...
666 if ( !HasGroup(oldName) )
4d08943e 667 return false;
89077ebc
VZ
668
669 // and that the new one doesn't
670 if ( HasGroup(newName) )
4d08943e 671 return false;
89077ebc 672
442d08ce 673 return wxRegKey(m_keyLocal, oldName).Rename(newName);
89077ebc
VZ
674}
675
676// ----------------------------------------------------------------------------
19454fa0
VZ
677// deleting
678// ----------------------------------------------------------------------------
1ad6d522
VZ
679
680bool wxRegConfig::DeleteEntry(const wxString& value, bool bGroupIfEmptyAlso)
19454fa0 681{
18244936 682 wxConfigPathChanger path(this, value);
19454fa0 683
807a903e
VZ
684 if ( m_keyLocal.Exists() ) {
685 if ( !m_keyLocal.DeleteValue(path.Name()) )
4d08943e 686 return false;
19454fa0 687
1ad6d522 688 if ( bGroupIfEmptyAlso && m_keyLocal.IsEmpty() ) {
807a903e 689 wxString strKey = GetPath().AfterLast(wxCONFIG_PATH_SEPARATOR);
2b5f62a0 690 SetPath(_T("..")); // changes m_keyLocal
807a903e
VZ
691 return LocalKey().DeleteKey(strKey);
692 }
19454fa0
VZ
693 }
694
4d08943e 695 return true;
19454fa0
VZ
696}
697
18244936 698bool wxRegConfig::DeleteGroup(const wxString& key)
19454fa0 699{
18244936 700 wxConfigPathChanger path(this, key);
19454fa0 701
41f30152
VZ
702 if ( !m_keyLocal.Exists() )
703 {
704 // nothing to do
705 return true;
706 }
707
708 if ( !LocalKey().DeleteKey(path.Name()) )
709 return false;
710
711 path.UpdateIfDeleted();
712
713 return true;
19454fa0
VZ
714}
715
716bool wxRegConfig::DeleteAll()
717{
19454fa0
VZ
718 m_keyLocal.Close();
719 m_keyGlobal.Close();
90186e52 720
19454fa0 721 bool bOk = m_keyLocalRoot.DeleteSelf();
90186e52
VZ
722
723 // make sure that we opened m_keyGlobalRoot and so it has a reasonable name:
724 // otherwise we will delete HKEY_CLASSES_ROOT recursively
725 if ( bOk && m_keyGlobalRoot.IsOpened() )
19454fa0
VZ
726 bOk = m_keyGlobalRoot.DeleteSelf();
727
728 return bOk;
729}
3d05544e 730
41f30152 731#endif // wxUSE_CONFIG