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