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