]> git.saurik.com Git - wxWidgets.git/blob - src/msw/regconf.cpp
wxRegConfig now works again
[wxWidgets.git] / src / msw / regconf.cpp
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
56 bool TryGetValue(const wxRegKey& key, const wxString& str, wxString& strVal)
57 {
58 return key.IsOpened() && key.HasValue(str) && key.QueryValue(str, strVal);
59 }
60
61 bool 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
76 wxRegConfig::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
144 wxRegConfig::~wxRegConfig()
145 {
146 // nothing to do - key will be closed in their dtors
147 }
148
149 // ----------------------------------------------------------------------------
150 // path management
151 // ----------------------------------------------------------------------------
152 void 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
201 bool wxRegConfig::GetFirstGroup(wxString& str, long& lIndex) const
202 {
203 lIndex = 0;
204 return GetNextGroup(str, lIndex);
205 }
206
207 bool 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
230 bool wxRegConfig::GetFirstEntry(wxString& str, long& lIndex) const
231 {
232 lIndex = 0;
233 return GetNextEntry(str, lIndex);
234 }
235
236 bool 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
259 size_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
276 size_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
297 bool wxRegConfig::HasGroup(const wxString& strName) const
298 {
299 return m_keyLocal.HasSubKey(strName) || m_keyGlobal.HasSubKey(strName);
300 }
301
302 bool 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
311 bool 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
348 bool 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
392 bool 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
423 bool 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
435 bool 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 // ----------------------------------------------------------------------------
450 bool 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
466 bool wxRegConfig::DeleteGroup(const wxString& key)
467 {
468 wxConfigPathChanger path(this, key);
469
470 return m_keyLocal.DeleteKey(path.Name());
471 }
472
473 bool 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 }