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