]> git.saurik.com Git - wxWidgets.git/blame - src/msw/regconf.cpp
More Motif stuff, minor stubs correction
[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
19454fa0
VZ
16// ============================================================================
17// declarations
18// ============================================================================
19
20// ----------------------------------------------------------------------------
21// headers
22// ----------------------------------------------------------------------------
82cf4761
VZ
23
24#ifdef __GNUG__
25 #pragma implementation "regconf.h"
26#endif
27
28#include "wx/wxprec.h"
29
30#ifdef __BORLANDC__
31 #pragma hdrstop
32#endif //__BORLANDC__
33
34#ifndef WX_PRECOMP
35 #include <wx/string.h>
36#endif //WX_PRECOMP
37
18244936 38#include <wx/app.h>
82cf4761 39#include <wx/log.h>
19454fa0 40#include <wx/config.h>
6d833566 41#include <wx/msw/registry.h>
82cf4761 42#include <wx/msw/regconf.h>
19454fa0
VZ
43
44// ----------------------------------------------------------------------------
45// constants
46// ----------------------------------------------------------------------------
47
48// we put our data in HKLM\SOFTWARE_KEY\appname
49#define SOFTWARE_KEY wxString("Software\\")
50
51// ----------------------------------------------------------------------------
52// global functions
53// ----------------------------------------------------------------------------
54
55// get the value if the key is opened and it exists
56bool TryGetValue(const wxRegKey& key, const wxString& str, wxString& strVal)
57{
58 return key.IsOpened() && key.HasValue(str) && key.QueryValue(str, strVal);
59}
60
61bool TryGetValue(const wxRegKey& key, const wxString& str, long *plVal)
62{
63 return key.IsOpened() && key.HasValue(str) && key.QueryValue(str, plVal);
64}
65
66// ============================================================================
67// implementation
68// ============================================================================
69
70// ----------------------------------------------------------------------------
71// ctor/dtor
72// ----------------------------------------------------------------------------
18244936 73
040f0110
VZ
74// create the config object which stores its data under HKCU\vendor\app and, if
75// style & wxCONFIG_USE_GLOBAL_FILE, under HKLM\vendor\app
76wxRegConfig::wxRegConfig(const wxString& appName, const wxString& vendorName,
77 const wxString& strLocal, const wxString& strGlobal,
78 long style)
79 : wxConfigBase(appName, vendorName, strLocal, strGlobal, style)
19454fa0 80{
040f0110 81 wxString strRoot;
19454fa0 82
040f0110 83 bool bDoUseGlobal = (style & wxCONFIG_USE_GLOBAL_FILE) != 0;
41286812 84
040f0110
VZ
85 // the convention is to put the programs keys under <vendor>\<appname>
86 // (but it can be overriden by specifying the pathes explicitly in strLocal
87 // and/or strGlobal)
88 if ( strLocal.IsEmpty() || (strGlobal.IsEmpty() && bDoUseGlobal) )
89 {
90 if ( vendorName.IsEmpty() )
91 {
92 if ( wxTheApp )
93 strRoot = wxTheApp->GetVendorName();
94 }
95 else
96 {
97 strRoot = vendorName;
98 }
18244936 99
040f0110
VZ
100 // no '\\' needed if no vendor name
101 if ( !strRoot.IsEmpty() )
18244936 102 {
040f0110 103 strRoot += '\\';
18244936 104 }
18244936 105
040f0110
VZ
106 if ( appName.IsEmpty() )
107 {
108 wxCHECK_RET( wxTheApp, "No application name in wxRegConfig ctor!" );
109 strRoot << wxTheApp->GetAppName();
110 }
111 else
18244936 112 {
040f0110 113 strRoot << appName;
18244936 114 }
040f0110
VZ
115 }
116 //else: we don't need to do all the complicated stuff above
18244936 117
040f0110
VZ
118 wxString str = strLocal.IsEmpty() ? strRoot : strLocal;
119 m_keyLocalRoot.SetName(wxRegKey::HKCU, SOFTWARE_KEY + str);
120 m_keyLocal.SetName(m_keyLocalRoot, "");
18244936 121
040f0110
VZ
122 if ( bDoUseGlobal )
123 {
124 str = strGlobal.IsEmpty() ? strRoot : strGlobal;
125 m_keyGlobalRoot.SetName(wxRegKey::HKLM, SOFTWARE_KEY + str);
126 m_keyGlobal.SetName(m_keyGlobalRoot, "");
127 }
18244936
JS
128
129 // Create() will Open() if key already exists
130 m_keyLocalRoot.Create();
131
132 // as it's the same key, Open() shouldn't fail (i.e. no need for Create())
133 m_keyLocal.Open();
134
040f0110
VZ
135 // OTOH, this key may perfectly not exist, so suppress error messages the call
136 // to Open() might generate
137 if ( bDoUseGlobal )
138 {
139 wxLogNull nolog;
140 m_keyGlobalRoot.Open();
141 }
18244936 142}
19454fa0
VZ
143
144wxRegConfig::~wxRegConfig()
145{
146 // nothing to do - key will be closed in their dtors
147}
148
149// ----------------------------------------------------------------------------
150// path management
151// ----------------------------------------------------------------------------
152void wxRegConfig::SetPath(const wxString& strPath)
153{
82cf4761 154 wxArrayString aParts;
19454fa0 155
41286812
VZ
156 // because GetPath() returns "" when we're at root, we must understand
157 // empty string as "/"
158 if ( strPath.IsEmpty() || (strPath[0] == wxCONFIG_PATH_SEPARATOR) ) {
19454fa0 159 // absolute path
82cf4761 160 wxSplitPath(aParts, strPath);
19454fa0
VZ
161 }
162 else {
163 // relative path, combine with current one
164 wxString strFullPath = GetPath();
4d0c0756 165 strFullPath << wxCONFIG_PATH_SEPARATOR << strPath;
82cf4761 166 wxSplitPath(aParts, strFullPath);
19454fa0
VZ
167 }
168
169 // recombine path parts in one variable
170 wxString strRegPath;
171 m_strPath.Empty();
c86f1403 172 for ( size_t n = 0; n < aParts.Count(); n++ ) {
19454fa0 173 strRegPath << '\\' << aParts[n];
4d0c0756 174 m_strPath << wxCONFIG_PATH_SEPARATOR << aParts[n];
19454fa0
VZ
175 }
176
177 // change current key(s)
178 m_keyLocal.SetName(m_keyLocalRoot, strRegPath);
179 m_keyGlobal.SetName(m_keyGlobalRoot, strRegPath);
180 m_keyLocal.Create();
181
182 wxLogNull nolog;
183 m_keyGlobal.Open();
184}
185
186// ----------------------------------------------------------------------------
187// enumeration (works only with current group)
188// ----------------------------------------------------------------------------
189
190/*
6d833566 191 We want to enumerate all local keys/values after the global ones, but, of
19454fa0
VZ
192 course, we don't want to repeat a key which appears locally as well as
193 globally twice.
194
195 We use the 15th bit of lIndex for distinction between global and local.
196 */
197
198#define LOCAL_MASK 0x8000
199#define IS_LOCAL_INDEX(l) (((l) & LOCAL_MASK) != 0)
200
02569ba8 201bool wxRegConfig::GetFirstGroup(wxString& str, long& lIndex) const
19454fa0
VZ
202{
203 lIndex = 0;
204 return GetNextGroup(str, lIndex);
205}
206
02569ba8 207bool wxRegConfig::GetNextGroup(wxString& str, long& lIndex) const
19454fa0
VZ
208{
209 // are we already enumerating local entries?
210 if ( m_keyGlobal.IsOpened() && !IS_LOCAL_INDEX(lIndex) ) {
211 // try to find a global entry which doesn't appear locally
212 do {
213 if ( !m_keyGlobal.GetNextKey(str, lIndex) ) {
214 // no more global entries
215 lIndex |= LOCAL_MASK;
216 break;
217 }
218 } while( m_keyLocal.HasSubKey(str) );
219 }
220
221 // much easier with local entries: get the next one we find
222 // (don't forget to clear our flag bit and set it again later)
223 lIndex &= ~LOCAL_MASK;
224 bool bOk = m_keyLocal.GetNextKey(str, lIndex);
225 lIndex |= LOCAL_MASK;
226
227 return bOk;
228}
229
02569ba8 230bool wxRegConfig::GetFirstEntry(wxString& str, long& lIndex) const
19454fa0
VZ
231{
232 lIndex = 0;
82cf4761 233 return GetNextEntry(str, lIndex);
19454fa0
VZ
234}
235
02569ba8 236bool wxRegConfig::GetNextEntry(wxString& str, long& lIndex) const
19454fa0
VZ
237{
238 // are we already enumerating local entries?
239 if ( m_keyGlobal.IsOpened() && !IS_LOCAL_INDEX(lIndex) ) {
240 // try to find a global entry which doesn't appear locally
241 do {
82cf4761 242 if ( !m_keyGlobal.GetNextValue(str, lIndex) ) {
19454fa0
VZ
243 // no more global entries
244 lIndex |= LOCAL_MASK;
245 break;
246 }
82cf4761 247 } while( m_keyLocal.HasValue(str) );
19454fa0
VZ
248 }
249
250 // much easier with local entries: get the next one we find
251 // (don't forget to clear our flag bit and set it again later)
252 lIndex &= ~LOCAL_MASK;
82cf4761 253 bool bOk = m_keyLocal.GetNextValue(str, lIndex);
19454fa0
VZ
254 lIndex |= LOCAL_MASK;
255
256 return bOk;
257}
258
c86f1403 259size_t wxRegConfig::GetNumberOfEntries(bool bRecursive) const
82cf4761 260{
c86f1403 261 size_t nEntries = 0;
82cf4761
VZ
262
263 // dummy vars
264 wxString str;
265 long l;
6a23cbce 266 bool bCont = ((wxRegConfig*)this)->GetFirstEntry(str, l);
82cf4761
VZ
267 while ( bCont ) {
268 nEntries++;
269
6a23cbce 270 bCont = ((wxRegConfig*)this)->GetNextEntry(str, l);
82cf4761
VZ
271 }
272
273 return nEntries;
274}
275
c86f1403 276size_t wxRegConfig::GetNumberOfGroups(bool bRecursive) const
82cf4761 277{
c86f1403 278 size_t nGroups = 0;
82cf4761
VZ
279
280 // dummy vars
281 wxString str;
282 long l;
6a23cbce 283 bool bCont = ((wxRegConfig*)this)->GetFirstGroup(str, l);
82cf4761
VZ
284 while ( bCont ) {
285 nGroups++;
286
6a23cbce 287 bCont = ((wxRegConfig*)this)->GetNextGroup(str, l);
82cf4761
VZ
288 }
289
290 return nGroups;
291}
292
6d833566
VZ
293// ----------------------------------------------------------------------------
294// tests for existence
295// ----------------------------------------------------------------------------
296
297bool wxRegConfig::HasGroup(const wxString& strName) const
298{
299 return m_keyLocal.HasSubKey(strName) || m_keyGlobal.HasSubKey(strName);
300}
301
302bool wxRegConfig::HasEntry(const wxString& strName) const
303{
304 return m_keyLocal.HasValue(strName) || m_keyGlobal.HasValue(strName);
305}
306
19454fa0
VZ
307// ----------------------------------------------------------------------------
308// reading/writing
309// ----------------------------------------------------------------------------
310
18244936 311bool wxRegConfig::Read(const wxString& key, wxString *pStr) const
19454fa0 312{
18244936 313 wxConfigPathChanger path(this, key);
19454fa0 314
cf447356 315 bool bQueryGlobal = TRUE;
19454fa0
VZ
316
317 // if immutable key exists in global key we must check that it's not
318 // overriden by the local key with the same name
319 if ( IsImmutable(path.Name()) ) {
02569ba8 320 if ( TryGetValue(m_keyGlobal, path.Name(), *pStr) ) {
19454fa0 321 if ( m_keyLocal.HasValue(path.Name()) ) {
6d833566 322 wxLogWarning("User value for immutable key '%s' ignored.",
19454fa0
VZ
323 path.Name().c_str());
324 }
18244936 325 *pStr = wxConfigBase::ExpandEnvVars(*pStr);
cf447356 326 return TRUE;
19454fa0
VZ
327 }
328 else {
329 // don't waste time - it's not there anyhow
cf447356 330 bQueryGlobal = FALSE;
19454fa0
VZ
331 }
332 }
333
334 // first try local key
02569ba8
VZ
335 if ( TryGetValue(m_keyLocal, path.Name(), *pStr) ||
336 (bQueryGlobal && TryGetValue(m_keyGlobal, path.Name(), *pStr)) ) {
41286812 337 // nothing to do
18244936
JS
338
339 // TODO: do we return TRUE? Not in original implementation,
340 // but I don't see why not. -- JACS
341 *pStr = wxConfigBase::ExpandEnvVars(*pStr);
342 return TRUE;
343 }
344
345 return FALSE;
346}
347
348bool wxRegConfig::Read(const wxString& key, wxString *pStr,
349 const wxString& szDefault) const
350{
351 wxConfigPathChanger path(this, key);
352
353 bool bQueryGlobal = TRUE;
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()) ) {
358 if ( TryGetValue(m_keyGlobal, path.Name(), *pStr) ) {
359 if ( m_keyLocal.HasValue(path.Name()) ) {
360 wxLogWarning("User value for immutable key '%s' ignored.",
361 path.Name().c_str());
362 }
363
364 return TRUE;
365 }
366 else {
367 // don't waste time - it's not there anyhow
368 bQueryGlobal = FALSE;
369 }
370 }
371
372 // first try local key
373 if ( TryGetValue(m_keyLocal, path.Name(), *pStr) ||
374 (bQueryGlobal && TryGetValue(m_keyGlobal, path.Name(), *pStr)) ) {
375 *pStr = wxConfigBase::ExpandEnvVars(*pStr);
376 return TRUE;
41286812
VZ
377 }
378 else {
379 if ( IsRecordingDefaults() ) {
18244936 380 ((wxRegConfig*)this)->Write(key, szDefault);
41286812
VZ
381 }
382
383 // default value
384 *pStr = szDefault;
19454fa0
VZ
385 }
386
41286812 387 *pStr = wxConfigBase::ExpandEnvVars(*pStr);
baeed289 388
cf447356 389 return FALSE;
19454fa0
VZ
390}
391
18244936 392bool wxRegConfig::Read(const wxString& key, long *plResult) const
19454fa0 393{
18244936 394 wxConfigPathChanger path(this, key);
19454fa0 395
cf447356 396 bool bQueryGlobal = TRUE;
19454fa0
VZ
397
398 // if immutable key exists in global key we must check that it's not
399 // overriden by the local key with the same name
400 if ( IsImmutable(path.Name()) ) {
02569ba8 401 if ( TryGetValue(m_keyGlobal, path.Name(), plResult) ) {
19454fa0 402 if ( m_keyLocal.HasValue(path.Name()) ) {
6d833566 403 wxLogWarning("User value for immutable key '%s' ignored.",
19454fa0
VZ
404 path.Name().c_str());
405 }
406
cf447356 407 return TRUE;
19454fa0
VZ
408 }
409 else {
410 // don't waste time - it's not there anyhow
cf447356 411 bQueryGlobal = FALSE;
19454fa0
VZ
412 }
413 }
414
415 // first try local key
02569ba8
VZ
416 if ( TryGetValue(m_keyLocal, path.Name(), plResult) ||
417 (bQueryGlobal && TryGetValue(m_keyGlobal, path.Name(), plResult)) ) {
cf447356 418 return TRUE;
19454fa0 419 }
cf447356 420 return FALSE;
19454fa0
VZ
421}
422
18244936 423bool wxRegConfig::Write(const wxString& key, const wxString& szValue)
19454fa0 424{
18244936 425 wxConfigPathChanger path(this, key);
19454fa0
VZ
426
427 if ( IsImmutable(path.Name()) ) {
428 wxLogError("Can't change immutable entry '%s'.", path.Name().c_str());
cf447356 429 return FALSE;
19454fa0
VZ
430 }
431
432 return m_keyLocal.SetValue(path.Name(), szValue);
433}
434
18244936 435bool wxRegConfig::Write(const wxString& key, long lValue)
19454fa0 436{
18244936 437 wxConfigPathChanger path(this, key);
19454fa0
VZ
438
439 if ( IsImmutable(path.Name()) ) {
440 wxLogError("Can't change immutable entry '%s'.", path.Name().c_str());
cf447356 441 return FALSE;
19454fa0
VZ
442 }
443
444 return m_keyLocal.SetValue(path.Name(), lValue);
445}
446
447// ----------------------------------------------------------------------------
448// deleting
449// ----------------------------------------------------------------------------
18244936 450bool wxRegConfig::DeleteEntry(const wxString& value, bool bGroupIfEmptyAlso)
19454fa0 451{
18244936 452 wxConfigPathChanger path(this, value);
19454fa0
VZ
453
454 if ( !m_keyLocal.DeleteValue(path.Name()) )
cf447356 455 return FALSE;
19454fa0 456
82cf4761 457 if ( !m_keyLocal.HasSubkeys() ) {
4d0c0756 458 wxString strKey = GetPath().Right(wxCONFIG_PATH_SEPARATOR);
19454fa0
VZ
459 SetPath(".."); // changes m_keyLocal
460 return m_keyLocal.DeleteKey(strKey);
461 }
462
cf447356 463 return TRUE;
19454fa0
VZ
464}
465
18244936 466bool wxRegConfig::DeleteGroup(const wxString& key)
19454fa0 467{
18244936 468 wxConfigPathChanger path(this, key);
19454fa0
VZ
469
470 return m_keyLocal.DeleteKey(path.Name());
471}
472
473bool wxRegConfig::DeleteAll()
474{
19454fa0
VZ
475 m_keyLocal.Close();
476 m_keyGlobal.Close();
477
478 bool bOk = m_keyLocalRoot.DeleteSelf();
479 if ( bOk )
480 bOk = m_keyGlobalRoot.DeleteSelf();
481
482 return bOk;
483}