]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/msw/regconf.cpp
More Motif stuff, minor stubs correction
[wxWidgets.git] / src / msw / regconf.cpp
... / ...
CommitLineData
1///////////////////////////////////////////////////////////////////////////////
2// Name: msw/regconf.cpp
3// Purpose:
4// Author: Vadim Zeitlin
5// Modified by:
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
12#ifdef __GNUG__
13#pragma implementation "regconf.h"
14#endif
15
16// ============================================================================
17// declarations
18// ============================================================================
19
20// ----------------------------------------------------------------------------
21// headers
22// ----------------------------------------------------------------------------
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
38#include <wx/app.h>
39#include <wx/log.h>
40#include <wx/config.h>
41#include <wx/msw/registry.h>
42#include <wx/msw/regconf.h>
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// ----------------------------------------------------------------------------
73
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)
80{
81 wxString strRoot;
82
83 bool bDoUseGlobal = (style & wxCONFIG_USE_GLOBAL_FILE) != 0;
84
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 }
99
100 // no '\\' needed if no vendor name
101 if ( !strRoot.IsEmpty() )
102 {
103 strRoot += '\\';
104 }
105
106 if ( appName.IsEmpty() )
107 {
108 wxCHECK_RET( wxTheApp, "No application name in wxRegConfig ctor!" );
109 strRoot << wxTheApp->GetAppName();
110 }
111 else
112 {
113 strRoot << appName;
114 }
115 }
116 //else: we don't need to do all the complicated stuff above
117
118 wxString str = strLocal.IsEmpty() ? strRoot : strLocal;
119 m_keyLocalRoot.SetName(wxRegKey::HKCU, SOFTWARE_KEY + str);
120 m_keyLocal.SetName(m_keyLocalRoot, "");
121
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 }
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
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 }
142}
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{
154 wxArrayString aParts;
155
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) ) {
159 // absolute path
160 wxSplitPath(aParts, strPath);
161 }
162 else {
163 // relative path, combine with current one
164 wxString strFullPath = GetPath();
165 strFullPath << wxCONFIG_PATH_SEPARATOR << strPath;
166 wxSplitPath(aParts, strFullPath);
167 }
168
169 // recombine path parts in one variable
170 wxString strRegPath;
171 m_strPath.Empty();
172 for ( size_t n = 0; n < aParts.Count(); n++ ) {
173 strRegPath << '\\' << aParts[n];
174 m_strPath << wxCONFIG_PATH_SEPARATOR << aParts[n];
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/*
191 We want to enumerate all local keys/values after the global ones, but, of
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
201bool wxRegConfig::GetFirstGroup(wxString& str, long& lIndex) const
202{
203 lIndex = 0;
204 return GetNextGroup(str, lIndex);
205}
206
207bool wxRegConfig::GetNextGroup(wxString& str, long& lIndex) const
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
230bool wxRegConfig::GetFirstEntry(wxString& str, long& lIndex) const
231{
232 lIndex = 0;
233 return GetNextEntry(str, lIndex);
234}
235
236bool wxRegConfig::GetNextEntry(wxString& str, long& lIndex) const
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 {
242 if ( !m_keyGlobal.GetNextValue(str, lIndex) ) {
243 // no more global entries
244 lIndex |= LOCAL_MASK;
245 break;
246 }
247 } while( m_keyLocal.HasValue(str) );
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;
253 bool bOk = m_keyLocal.GetNextValue(str, lIndex);
254 lIndex |= LOCAL_MASK;
255
256 return bOk;
257}
258
259size_t wxRegConfig::GetNumberOfEntries(bool bRecursive) const
260{
261 size_t nEntries = 0;
262
263 // dummy vars
264 wxString str;
265 long l;
266 bool bCont = ((wxRegConfig*)this)->GetFirstEntry(str, l);
267 while ( bCont ) {
268 nEntries++;
269
270 bCont = ((wxRegConfig*)this)->GetNextEntry(str, l);
271 }
272
273 return nEntries;
274}
275
276size_t wxRegConfig::GetNumberOfGroups(bool bRecursive) const
277{
278 size_t nGroups = 0;
279
280 // dummy vars
281 wxString str;
282 long l;
283 bool bCont = ((wxRegConfig*)this)->GetFirstGroup(str, l);
284 while ( bCont ) {
285 nGroups++;
286
287 bCont = ((wxRegConfig*)this)->GetNextGroup(str, l);
288 }
289
290 return nGroups;
291}
292
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
307// ----------------------------------------------------------------------------
308// reading/writing
309// ----------------------------------------------------------------------------
310
311bool wxRegConfig::Read(const wxString& key, wxString *pStr) const
312{
313 wxConfigPathChanger path(this, key);
314
315 bool bQueryGlobal = TRUE;
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()) ) {
320 if ( TryGetValue(m_keyGlobal, path.Name(), *pStr) ) {
321 if ( m_keyLocal.HasValue(path.Name()) ) {
322 wxLogWarning("User value for immutable key '%s' ignored.",
323 path.Name().c_str());
324 }
325 *pStr = wxConfigBase::ExpandEnvVars(*pStr);
326 return TRUE;
327 }
328 else {
329 // don't waste time - it's not there anyhow
330 bQueryGlobal = FALSE;
331 }
332 }
333
334 // first try local key
335 if ( TryGetValue(m_keyLocal, path.Name(), *pStr) ||
336 (bQueryGlobal && TryGetValue(m_keyGlobal, path.Name(), *pStr)) ) {
337 // nothing to do
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;
377 }
378 else {
379 if ( IsRecordingDefaults() ) {
380 ((wxRegConfig*)this)->Write(key, szDefault);
381 }
382
383 // default value
384 *pStr = szDefault;
385 }
386
387 *pStr = wxConfigBase::ExpandEnvVars(*pStr);
388
389 return FALSE;
390}
391
392bool wxRegConfig::Read(const wxString& key, long *plResult) const
393{
394 wxConfigPathChanger path(this, key);
395
396 bool bQueryGlobal = TRUE;
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()) ) {
401 if ( TryGetValue(m_keyGlobal, path.Name(), plResult) ) {
402 if ( m_keyLocal.HasValue(path.Name()) ) {
403 wxLogWarning("User value for immutable key '%s' ignored.",
404 path.Name().c_str());
405 }
406
407 return TRUE;
408 }
409 else {
410 // don't waste time - it's not there anyhow
411 bQueryGlobal = FALSE;
412 }
413 }
414
415 // first try local key
416 if ( TryGetValue(m_keyLocal, path.Name(), plResult) ||
417 (bQueryGlobal && TryGetValue(m_keyGlobal, path.Name(), plResult)) ) {
418 return TRUE;
419 }
420 return FALSE;
421}
422
423bool wxRegConfig::Write(const wxString& key, const wxString& szValue)
424{
425 wxConfigPathChanger path(this, key);
426
427 if ( IsImmutable(path.Name()) ) {
428 wxLogError("Can't change immutable entry '%s'.", path.Name().c_str());
429 return FALSE;
430 }
431
432 return m_keyLocal.SetValue(path.Name(), szValue);
433}
434
435bool wxRegConfig::Write(const wxString& key, long lValue)
436{
437 wxConfigPathChanger path(this, key);
438
439 if ( IsImmutable(path.Name()) ) {
440 wxLogError("Can't change immutable entry '%s'.", path.Name().c_str());
441 return FALSE;
442 }
443
444 return m_keyLocal.SetValue(path.Name(), lValue);
445}
446
447// ----------------------------------------------------------------------------
448// deleting
449// ----------------------------------------------------------------------------
450bool wxRegConfig::DeleteEntry(const wxString& value, bool bGroupIfEmptyAlso)
451{
452 wxConfigPathChanger path(this, value);
453
454 if ( !m_keyLocal.DeleteValue(path.Name()) )
455 return FALSE;
456
457 if ( !m_keyLocal.HasSubkeys() ) {
458 wxString strKey = GetPath().Right(wxCONFIG_PATH_SEPARATOR);
459 SetPath(".."); // changes m_keyLocal
460 return m_keyLocal.DeleteKey(strKey);
461 }
462
463 return TRUE;
464}
465
466bool wxRegConfig::DeleteGroup(const wxString& key)
467{
468 wxConfigPathChanger path(this, key);
469
470 return m_keyLocal.DeleteKey(path.Name());
471}
472
473bool wxRegConfig::DeleteAll()
474{
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}