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