]> git.saurik.com Git - wxWidgets.git/blame - src/msw/regconf.cpp
applied patch 403988 (fixing MDI window menu)
[wxWidgets.git] / src / msw / regconf.cpp
CommitLineData
19454fa0
VZ
1///////////////////////////////////////////////////////////////////////////////
2// Name: 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>
9// Licence: wxWindows license
10///////////////////////////////////////////////////////////////////////////////
11
cfe780fb
JS
12#ifdef __GNUG__
13#pragma implementation "regconf.h"
14#endif
15
a3b46648
UU
16// For compilers that support precompilation, includes "wx.h".
17#include "wx/wxprec.h"
19454fa0 18
a3b46648
UU
19#ifdef __BORLANDC__
20#pragma hdrstop
82cf4761
VZ
21#endif
22
82cf4761 23#ifndef WX_PRECOMP
61ba49f2 24 #include "wx/string.h"
82cf4761
VZ
25#endif //WX_PRECOMP
26
61ba49f2
VZ
27#include "wx/event.h"
28#include "wx/app.h"
29#include "wx/log.h"
f6bcfd97
BP
30
31#if wxUSE_CONFIG
32
61ba49f2 33#include "wx/config.h"
3d05544e
JS
34
35#ifndef __WIN16__
36
61ba49f2
VZ
37#include "wx/msw/registry.h"
38#include "wx/msw/regconf.h"
19454fa0
VZ
39
40// ----------------------------------------------------------------------------
41// constants
42// ----------------------------------------------------------------------------
43
44// we put our data in HKLM\SOFTWARE_KEY\appname
c19a8a9a 45#define SOFTWARE_KEY wxString("Software\\")
19454fa0
VZ
46
47// ----------------------------------------------------------------------------
48// global functions
49// ----------------------------------------------------------------------------
50
51// get the value if the key is opened and it exists
52bool TryGetValue(const wxRegKey& key, const wxString& str, wxString& strVal)
53{
54 return key.IsOpened() && key.HasValue(str) && key.QueryValue(str, strVal);
55}
56
57bool TryGetValue(const wxRegKey& key, const wxString& str, long *plVal)
58{
59 return key.IsOpened() && key.HasValue(str) && key.QueryValue(str, plVal);
60}
61
62// ============================================================================
63// implementation
64// ============================================================================
65
66// ----------------------------------------------------------------------------
67// ctor/dtor
68// ----------------------------------------------------------------------------
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
VZ
81 // the convention is to put the programs keys under <vendor>\<appname>
82 // (but it can be overriden by specifying the pathes explicitly in strLocal
83 // and/or strGlobal)
84 if ( strLocal.IsEmpty() || (strGlobal.IsEmpty() && bDoUseGlobal) )
85 {
86 if ( vendorName.IsEmpty() )
87 {
88 if ( wxTheApp )
89 strRoot = wxTheApp->GetVendorName();
90 }
91 else
92 {
93 strRoot = vendorName;
94 }
18244936 95
040f0110
VZ
96 // no '\\' needed if no vendor name
97 if ( !strRoot.IsEmpty() )
18244936 98 {
040f0110 99 strRoot += '\\';
18244936 100 }
18244936 101
040f0110
VZ
102 if ( appName.IsEmpty() )
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
040f0110
VZ
114 wxString str = strLocal.IsEmpty() ? strRoot : strLocal;
115 m_keyLocalRoot.SetName(wxRegKey::HKCU, SOFTWARE_KEY + str);
116 m_keyLocal.SetName(m_keyLocalRoot, "");
18244936 117
040f0110
VZ
118 if ( bDoUseGlobal )
119 {
120 str = strGlobal.IsEmpty() ? strRoot : strGlobal;
121 m_keyGlobalRoot.SetName(wxRegKey::HKLM, SOFTWARE_KEY + str);
122 m_keyGlobal.SetName(m_keyGlobalRoot, "");
123 }
18244936
JS
124
125 // Create() will Open() if key already exists
126 m_keyLocalRoot.Create();
127
128 // as it's the same key, Open() shouldn't fail (i.e. no need for Create())
129 m_keyLocal.Open();
130
040f0110
VZ
131 // OTOH, this key may perfectly not exist, so suppress error messages the call
132 // to Open() might generate
133 if ( bDoUseGlobal )
134 {
135 wxLogNull nolog;
136 m_keyGlobalRoot.Open();
194330c7 137 m_keyGlobal.Open();
040f0110 138 }
18244936 139}
19454fa0
VZ
140
141wxRegConfig::~wxRegConfig()
142{
143 // nothing to do - key will be closed in their dtors
144}
145
146// ----------------------------------------------------------------------------
147// path management
148// ----------------------------------------------------------------------------
149void wxRegConfig::SetPath(const wxString& strPath)
150{
82cf4761 151 wxArrayString aParts;
19454fa0 152
41286812
VZ
153 // because GetPath() returns "" when we're at root, we must understand
154 // empty string as "/"
155 if ( strPath.IsEmpty() || (strPath[0] == wxCONFIG_PATH_SEPARATOR) ) {
19454fa0 156 // absolute path
82cf4761 157 wxSplitPath(aParts, strPath);
19454fa0
VZ
158 }
159 else {
160 // relative path, combine with current one
161 wxString strFullPath = GetPath();
4d0c0756 162 strFullPath << wxCONFIG_PATH_SEPARATOR << strPath;
82cf4761 163 wxSplitPath(aParts, strFullPath);
19454fa0
VZ
164 }
165
166 // recombine path parts in one variable
b568d04f 167 wxString strOldPath = m_strPath, strRegPath;
19454fa0 168 m_strPath.Empty();
c86f1403 169 for ( size_t n = 0; n < aParts.Count(); n++ ) {
19454fa0 170 strRegPath << '\\' << aParts[n];
4d0c0756 171 m_strPath << wxCONFIG_PATH_SEPARATOR << aParts[n];
19454fa0
VZ
172 }
173
b568d04f
VZ
174 if ( m_strPath == strOldPath )
175 return;
176
177 // as we create the registry key when SetPath(key) is done, we can be left
178 // with plenty of empty keys if this was only done to try to read some value
179 // which, in fact, doesn't exist - to prevent this from happening we
180 // automatically delete the old key if it was empty
181 if ( m_keyLocal.IsEmpty() )
182 {
183 m_keyLocal.DeleteSelf();
184 }
185
19454fa0
VZ
186 // change current key(s)
187 m_keyLocal.SetName(m_keyLocalRoot, strRegPath);
188 m_keyGlobal.SetName(m_keyGlobalRoot, strRegPath);
189 m_keyLocal.Create();
190
191 wxLogNull nolog;
192 m_keyGlobal.Open();
193}
194
195// ----------------------------------------------------------------------------
196// enumeration (works only with current group)
197// ----------------------------------------------------------------------------
198
199/*
6d833566 200 We want to enumerate all local keys/values after the global ones, but, of
19454fa0
VZ
201 course, we don't want to repeat a key which appears locally as well as
202 globally twice.
203
204 We use the 15th bit of lIndex for distinction between global and local.
205 */
206
207#define LOCAL_MASK 0x8000
208#define IS_LOCAL_INDEX(l) (((l) & LOCAL_MASK) != 0)
209
02569ba8 210bool wxRegConfig::GetFirstGroup(wxString& str, long& lIndex) const
19454fa0
VZ
211{
212 lIndex = 0;
213 return GetNextGroup(str, lIndex);
214}
215
02569ba8 216bool wxRegConfig::GetNextGroup(wxString& str, long& lIndex) const
19454fa0
VZ
217{
218 // are we already enumerating local entries?
219 if ( m_keyGlobal.IsOpened() && !IS_LOCAL_INDEX(lIndex) ) {
220 // try to find a global entry which doesn't appear locally
09f50eb3
VZ
221 while ( m_keyGlobal.GetNextKey(str, lIndex) ) {
222 if ( !m_keyLocal.HasSubKey(str) ) {
223 // ok, found one - return it
224 return TRUE;
19454fa0 225 }
09f50eb3
VZ
226 }
227
228 // no more global entries
229 lIndex |= LOCAL_MASK;
19454fa0
VZ
230 }
231
232 // much easier with local entries: get the next one we find
233 // (don't forget to clear our flag bit and set it again later)
234 lIndex &= ~LOCAL_MASK;
235 bool bOk = m_keyLocal.GetNextKey(str, lIndex);
236 lIndex |= LOCAL_MASK;
237
238 return bOk;
239}
240
02569ba8 241bool wxRegConfig::GetFirstEntry(wxString& str, long& lIndex) const
19454fa0
VZ
242{
243 lIndex = 0;
82cf4761 244 return GetNextEntry(str, lIndex);
19454fa0
VZ
245}
246
02569ba8 247bool wxRegConfig::GetNextEntry(wxString& str, long& lIndex) const
19454fa0
VZ
248{
249 // are we already enumerating local entries?
250 if ( m_keyGlobal.IsOpened() && !IS_LOCAL_INDEX(lIndex) ) {
251 // try to find a global entry which doesn't appear locally
50f7d0a3
VZ
252 while ( m_keyGlobal.GetNextValue(str, lIndex) ) {
253 if ( !m_keyLocal.HasValue(str) ) {
254 // ok, found one - return it
255 return TRUE;
19454fa0 256 }
50f7d0a3
VZ
257 }
258
259 // no more global entries
260 lIndex |= LOCAL_MASK;
19454fa0
VZ
261 }
262
263 // much easier with local entries: get the next one we find
264 // (don't forget to clear our flag bit and set it again later)
265 lIndex &= ~LOCAL_MASK;
82cf4761 266 bool bOk = m_keyLocal.GetNextValue(str, lIndex);
19454fa0
VZ
267 lIndex |= LOCAL_MASK;
268
269 return bOk;
270}
271
c86f1403 272size_t wxRegConfig::GetNumberOfEntries(bool bRecursive) const
82cf4761 273{
c86f1403 274 size_t nEntries = 0;
82cf4761
VZ
275
276 // dummy vars
277 wxString str;
278 long l;
6a23cbce 279 bool bCont = ((wxRegConfig*)this)->GetFirstEntry(str, l);
82cf4761
VZ
280 while ( bCont ) {
281 nEntries++;
282
6a23cbce 283 bCont = ((wxRegConfig*)this)->GetNextEntry(str, l);
82cf4761
VZ
284 }
285
286 return nEntries;
287}
288
c86f1403 289size_t wxRegConfig::GetNumberOfGroups(bool bRecursive) const
82cf4761 290{
c86f1403 291 size_t nGroups = 0;
82cf4761
VZ
292
293 // dummy vars
294 wxString str;
295 long l;
6a23cbce 296 bool bCont = ((wxRegConfig*)this)->GetFirstGroup(str, l);
82cf4761
VZ
297 while ( bCont ) {
298 nGroups++;
299
6a23cbce 300 bCont = ((wxRegConfig*)this)->GetNextGroup(str, l);
82cf4761
VZ
301 }
302
303 return nGroups;
304}
305
6d833566
VZ
306// ----------------------------------------------------------------------------
307// tests for existence
308// ----------------------------------------------------------------------------
309
61ba49f2 310bool wxRegConfig::HasGroup(const wxString& key) const
6d833566 311{
61ba49f2
VZ
312 wxConfigPathChanger path(this, key);
313
314 wxString strName(path.Name());
315
316 return m_keyLocal.HasSubKey(strName) || m_keyGlobal.HasSubKey(strName);
6d833566
VZ
317}
318
61ba49f2 319bool wxRegConfig::HasEntry(const wxString& key) const
6d833566 320{
61ba49f2
VZ
321 wxConfigPathChanger path(this, key);
322
323 wxString strName(path.Name());
324
325 return m_keyLocal.HasValue(strName) || m_keyGlobal.HasValue(strName);
326}
327
328wxConfigBase::EntryType wxRegConfig::GetEntryType(const wxString& key) const
329{
330 wxConfigPathChanger path(this, key);
331
332 wxString strName(path.Name());
333
334 bool isNumeric;
335 if ( m_keyLocal.HasValue(strName) )
336 isNumeric = m_keyLocal.IsNumericValue(strName);
337 else if ( m_keyGlobal.HasValue(strName) )
338 isNumeric = m_keyGlobal.IsNumericValue(strName);
339 else
340 return wxConfigBase::Type_Unknown;
341
342 return isNumeric ? wxConfigBase::Type_Integer : wxConfigBase::Type_String;
6d833566
VZ
343}
344
19454fa0
VZ
345// ----------------------------------------------------------------------------
346// reading/writing
347// ----------------------------------------------------------------------------
348
18244936 349bool wxRegConfig::Read(const wxString& key, wxString *pStr) const
19454fa0 350{
18244936 351 wxConfigPathChanger path(this, key);
19454fa0 352
cf447356 353 bool bQueryGlobal = TRUE;
19454fa0
VZ
354
355 // if immutable key exists in global key we must check that it's not
356 // overriden by the local key with the same name
357 if ( IsImmutable(path.Name()) ) {
02569ba8 358 if ( TryGetValue(m_keyGlobal, path.Name(), *pStr) ) {
19454fa0 359 if ( m_keyLocal.HasValue(path.Name()) ) {
223d09f6 360 wxLogWarning(wxT("User value for immutable key '%s' ignored."),
19454fa0
VZ
361 path.Name().c_str());
362 }
18244936 363 *pStr = wxConfigBase::ExpandEnvVars(*pStr);
cf447356 364 return TRUE;
19454fa0
VZ
365 }
366 else {
367 // don't waste time - it's not there anyhow
cf447356 368 bQueryGlobal = FALSE;
19454fa0
VZ
369 }
370 }
371
372 // first try local key
02569ba8
VZ
373 if ( TryGetValue(m_keyLocal, path.Name(), *pStr) ||
374 (bQueryGlobal && TryGetValue(m_keyGlobal, path.Name(), *pStr)) ) {
41286812 375 // nothing to do
18244936 376
18244936
JS
377 *pStr = wxConfigBase::ExpandEnvVars(*pStr);
378 return TRUE;
379 }
380
381 return FALSE;
382}
383
384bool wxRegConfig::Read(const wxString& key, wxString *pStr,
385 const wxString& szDefault) const
386{
387 wxConfigPathChanger path(this, key);
388
389 bool bQueryGlobal = TRUE;
390
391 // if immutable key exists in global key we must check that it's not
392 // overriden by the local key with the same name
393 if ( IsImmutable(path.Name()) ) {
394 if ( TryGetValue(m_keyGlobal, path.Name(), *pStr) ) {
395 if ( m_keyLocal.HasValue(path.Name()) ) {
223d09f6 396 wxLogWarning(wxT("User value for immutable key '%s' ignored."),
18244936
JS
397 path.Name().c_str());
398 }
399
400 return TRUE;
401 }
402 else {
403 // don't waste time - it's not there anyhow
404 bQueryGlobal = FALSE;
405 }
406 }
407
408 // first try local key
409 if ( TryGetValue(m_keyLocal, path.Name(), *pStr) ||
410 (bQueryGlobal && TryGetValue(m_keyGlobal, path.Name(), *pStr)) ) {
411 *pStr = wxConfigBase::ExpandEnvVars(*pStr);
412 return TRUE;
41286812
VZ
413 }
414 else {
415 if ( IsRecordingDefaults() ) {
18244936 416 ((wxRegConfig*)this)->Write(key, szDefault);
41286812
VZ
417 }
418
419 // default value
420 *pStr = szDefault;
19454fa0
VZ
421 }
422
41286812 423 *pStr = wxConfigBase::ExpandEnvVars(*pStr);
baeed289 424
cf447356 425 return FALSE;
19454fa0
VZ
426}
427
18244936 428bool wxRegConfig::Read(const wxString& key, long *plResult) const
19454fa0 429{
18244936 430 wxConfigPathChanger path(this, key);
19454fa0 431
cf447356 432 bool bQueryGlobal = TRUE;
19454fa0
VZ
433
434 // if immutable key exists in global key we must check that it's not
435 // overriden by the local key with the same name
436 if ( IsImmutable(path.Name()) ) {
02569ba8 437 if ( TryGetValue(m_keyGlobal, path.Name(), plResult) ) {
19454fa0 438 if ( m_keyLocal.HasValue(path.Name()) ) {
223d09f6 439 wxLogWarning(wxT("User value for immutable key '%s' ignored."),
19454fa0
VZ
440 path.Name().c_str());
441 }
442
cf447356 443 return TRUE;
19454fa0
VZ
444 }
445 else {
446 // don't waste time - it's not there anyhow
cf447356 447 bQueryGlobal = FALSE;
19454fa0
VZ
448 }
449 }
450
451 // first try local key
02569ba8
VZ
452 if ( TryGetValue(m_keyLocal, path.Name(), plResult) ||
453 (bQueryGlobal && TryGetValue(m_keyGlobal, path.Name(), plResult)) ) {
cf447356 454 return TRUE;
19454fa0 455 }
cf447356 456 return FALSE;
19454fa0
VZ
457}
458
18244936 459bool wxRegConfig::Write(const wxString& key, const wxString& szValue)
19454fa0 460{
18244936 461 wxConfigPathChanger path(this, key);
19454fa0
VZ
462
463 if ( IsImmutable(path.Name()) ) {
223d09f6 464 wxLogError(wxT("Can't change immutable entry '%s'."), path.Name().c_str());
cf447356 465 return FALSE;
19454fa0
VZ
466 }
467
468 return m_keyLocal.SetValue(path.Name(), szValue);
469}
470
18244936 471bool wxRegConfig::Write(const wxString& key, long lValue)
19454fa0 472{
18244936 473 wxConfigPathChanger path(this, key);
19454fa0
VZ
474
475 if ( IsImmutable(path.Name()) ) {
223d09f6 476 wxLogError(wxT("Can't change immutable entry '%s'."), path.Name().c_str());
cf447356 477 return FALSE;
19454fa0
VZ
478 }
479
480 return m_keyLocal.SetValue(path.Name(), lValue);
481}
482
483// ----------------------------------------------------------------------------
89077ebc
VZ
484// renaming
485// ----------------------------------------------------------------------------
486
487bool wxRegConfig::RenameEntry(const wxString& oldName, const wxString& newName)
488{
489 // check that the old entry exists...
490 if ( !HasEntry(oldName) )
491 return FALSE;
492
493 // and that the new one doesn't
494 if ( HasEntry(newName) )
495 return FALSE;
496
497 // delete the old entry and create the new one - but do in the reverse
498 // order to not lose the data if Create() fails
499
500 bool ok;
501 if ( m_keyLocal.IsNumericValue(oldName) )
502 {
503 long val;
504 ok = m_keyLocal.QueryValue(oldName, &val) &&
505 m_keyLocal.SetValue(newName, val);
506 }
507 else
508 {
509 wxString val;
510 ok = m_keyLocal.QueryValue(oldName, val) &&
511 m_keyLocal.SetValue(newName, val);
512 }
513
514 if ( !ok )
515 return FALSE;
516
517 if ( !m_keyLocal.DeleteValue(oldName) )
518 {
519 m_keyLocal.DeleteValue(newName);
520
521 return FALSE;
522 }
523
524 return TRUE;
525}
526
527bool wxRegConfig::RenameGroup(const wxString& oldName, const wxString& newName)
528{
529 // check that the old group exists...
530 if ( !HasGroup(oldName) )
531 return FALSE;
532
533 // and that the new one doesn't
534 if ( HasGroup(newName) )
535 return FALSE;
536
537 // TODO there is no way to rename a registry key - we must do a deep copy
538 // ourselves
223d09f6 539 wxFAIL_MSG(wxT("Registry key renaming not implemented"));
89077ebc
VZ
540
541 return FALSE;
542}
543
544// ----------------------------------------------------------------------------
19454fa0
VZ
545// deleting
546// ----------------------------------------------------------------------------
18244936 547bool wxRegConfig::DeleteEntry(const wxString& value, bool bGroupIfEmptyAlso)
19454fa0 548{
18244936 549 wxConfigPathChanger path(this, value);
19454fa0
VZ
550
551 if ( !m_keyLocal.DeleteValue(path.Name()) )
cf447356 552 return FALSE;
19454fa0 553
92049cd4 554 if ( m_keyLocal.IsEmpty() ) {
08159082 555 wxString strKey = GetPath().AfterLast(wxCONFIG_PATH_SEPARATOR);
19454fa0
VZ
556 SetPath(".."); // changes m_keyLocal
557 return m_keyLocal.DeleteKey(strKey);
558 }
559
cf447356 560 return TRUE;
19454fa0
VZ
561}
562
18244936 563bool wxRegConfig::DeleteGroup(const wxString& key)
19454fa0 564{
18244936 565 wxConfigPathChanger path(this, key);
19454fa0
VZ
566
567 return m_keyLocal.DeleteKey(path.Name());
568}
569
570bool wxRegConfig::DeleteAll()
571{
19454fa0
VZ
572 m_keyLocal.Close();
573 m_keyGlobal.Close();
90186e52 574
19454fa0 575 bool bOk = m_keyLocalRoot.DeleteSelf();
90186e52
VZ
576
577 // make sure that we opened m_keyGlobalRoot and so it has a reasonable name:
578 // otherwise we will delete HKEY_CLASSES_ROOT recursively
579 if ( bOk && m_keyGlobalRoot.IsOpened() )
19454fa0
VZ
580 bOk = m_keyGlobalRoot.DeleteSelf();
581
582 return bOk;
583}
3d05544e
JS
584
585#endif
586 // __WIN16__
587
f6bcfd97
BP
588#endif
589 // wxUSE_CONFIG