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