]> git.saurik.com Git - wxWidgets.git/blob - src/msw/regconf.cpp
More fixes
[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 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #ifndef WX_PRECOMP
24 #include "wx/string.h"
25 #endif //WX_PRECOMP
26
27 #include "wx/event.h"
28 #include "wx/app.h"
29 #include "wx/log.h"
30
31 #if wxUSE_CONFIG
32
33 #include "wx/config.h"
34
35 #ifndef __WIN16__
36
37 #include "wx/msw/registry.h"
38 #include "wx/msw/regconf.h"
39
40 // ----------------------------------------------------------------------------
41 // constants
42 // ----------------------------------------------------------------------------
43
44 // we put our data in HKLM\SOFTWARE_KEY\appname
45 #define SOFTWARE_KEY wxString("Software\\")
46
47 // ----------------------------------------------------------------------------
48 // global functions
49 // ----------------------------------------------------------------------------
50
51 // get the value if the key is opened and it exists
52 bool TryGetValue(const wxRegKey& key, const wxString& str, wxString& strVal)
53 {
54 return key.IsOpened() && key.HasValue(str) && key.QueryValue(str, strVal);
55 }
56
57 bool TryGetValue(const wxRegKey& key, const wxString& str, long *plVal)
58 {
59 return key.IsOpened() && key.HasValue(str) && key.QueryValue(str, plVal);
60 }
61
62 // ============================================================================
63 // implementation
64 // ============================================================================
65
66 // ----------------------------------------------------------------------------
67 // ctor/dtor
68 // ----------------------------------------------------------------------------
69
70 // create the config object which stores its data under HKCU\vendor\app and, if
71 // style & wxCONFIG_USE_GLOBAL_FILE, under HKLM\vendor\app
72 wxRegConfig::wxRegConfig(const wxString& appName, const wxString& vendorName,
73 const wxString& strLocal, const wxString& strGlobal,
74 long style)
75 : wxConfigBase(appName, vendorName, strLocal, strGlobal, style)
76 {
77 wxString strRoot;
78
79 bool bDoUseGlobal = (style & wxCONFIG_USE_GLOBAL_FILE) != 0;
80
81 // the convention is to put the programs keys under <vendor>\<appname>
82 // (but it can be overriden by specifying the pathes explicitly in strLocal
83 // and/or strGlobal)
84 if ( strLocal.IsEmpty() || (strGlobal.IsEmpty() && bDoUseGlobal) )
85 {
86 if ( vendorName.IsEmpty() )
87 {
88 if ( wxTheApp )
89 strRoot = wxTheApp->GetVendorName();
90 }
91 else
92 {
93 strRoot = vendorName;
94 }
95
96 // no '\\' needed if no vendor name
97 if ( !strRoot.IsEmpty() )
98 {
99 strRoot += '\\';
100 }
101
102 if ( appName.IsEmpty() )
103 {
104 wxCHECK_RET( wxTheApp, wxT("No application name in wxRegConfig ctor!") );
105 strRoot << wxTheApp->GetAppName();
106 }
107 else
108 {
109 strRoot << appName;
110 }
111 }
112 //else: we don't need to do all the complicated stuff above
113
114 wxString str = strLocal.IsEmpty() ? strRoot : strLocal;
115 m_keyLocalRoot.SetName(wxRegKey::HKCU, SOFTWARE_KEY + str);
116 m_keyLocal.SetName(m_keyLocalRoot, "");
117
118 if ( bDoUseGlobal )
119 {
120 str = strGlobal.IsEmpty() ? strRoot : strGlobal;
121 m_keyGlobalRoot.SetName(wxRegKey::HKLM, SOFTWARE_KEY + str);
122 m_keyGlobal.SetName(m_keyGlobalRoot, "");
123 }
124
125 // Create() will Open() if key already exists
126 m_keyLocalRoot.Create();
127
128 // as it's the same key, Open() shouldn't fail (i.e. no need for Create())
129 m_keyLocal.Open();
130
131 // OTOH, this key may perfectly not exist, so suppress error messages the call
132 // to Open() might generate
133 if ( bDoUseGlobal )
134 {
135 wxLogNull nolog;
136 m_keyGlobalRoot.Open();
137 m_keyGlobal.Open();
138 }
139 }
140
141 wxRegConfig::~wxRegConfig()
142 {
143 // nothing to do - key will be closed in their dtors
144 }
145
146 // ----------------------------------------------------------------------------
147 // path management
148 // ----------------------------------------------------------------------------
149 void wxRegConfig::SetPath(const wxString& strPath)
150 {
151 wxArrayString aParts;
152
153 // because GetPath() returns "" when we're at root, we must understand
154 // empty string as "/"
155 if ( strPath.IsEmpty() || (strPath[0] == wxCONFIG_PATH_SEPARATOR) ) {
156 // absolute path
157 wxSplitPath(aParts, strPath);
158 }
159 else {
160 // relative path, combine with current one
161 wxString strFullPath = GetPath();
162 strFullPath << wxCONFIG_PATH_SEPARATOR << strPath;
163 wxSplitPath(aParts, strFullPath);
164 }
165
166 // recombine path parts in one variable
167 wxString strOldPath = m_strPath, strRegPath;
168 m_strPath.Empty();
169 for ( size_t n = 0; n < aParts.Count(); n++ ) {
170 strRegPath << '\\' << aParts[n];
171 m_strPath << wxCONFIG_PATH_SEPARATOR << aParts[n];
172 }
173
174 if ( m_strPath == strOldPath )
175 return;
176
177 // as we create the registry key when SetPath(key) is done, we can be left
178 // with plenty of empty keys if this was only done to try to read some value
179 // which, in fact, doesn't exist - to prevent this from happening we
180 // automatically delete the old key if it was empty
181 if ( m_keyLocal.IsEmpty() )
182 {
183 m_keyLocal.DeleteSelf();
184 }
185
186 // change current key(s)
187 m_keyLocal.SetName(m_keyLocalRoot, strRegPath);
188 m_keyGlobal.SetName(m_keyGlobalRoot, strRegPath);
189 m_keyLocal.Create();
190
191 wxLogNull nolog;
192 m_keyGlobal.Open();
193 }
194
195 // ----------------------------------------------------------------------------
196 // enumeration (works only with current group)
197 // ----------------------------------------------------------------------------
198
199 /*
200 We want to enumerate all local keys/values after the global ones, but, of
201 course, we don't want to repeat a key which appears locally as well as
202 globally twice.
203
204 We use the 15th bit of lIndex for distinction between global and local.
205 */
206
207 #define LOCAL_MASK 0x8000
208 #define IS_LOCAL_INDEX(l) (((l) & LOCAL_MASK) != 0)
209
210 bool wxRegConfig::GetFirstGroup(wxString& str, long& lIndex) const
211 {
212 lIndex = 0;
213 return GetNextGroup(str, lIndex);
214 }
215
216 bool wxRegConfig::GetNextGroup(wxString& str, long& lIndex) const
217 {
218 // are we already enumerating local entries?
219 if ( m_keyGlobal.IsOpened() && !IS_LOCAL_INDEX(lIndex) ) {
220 // try to find a global entry which doesn't appear locally
221 while ( m_keyGlobal.GetNextKey(str, lIndex) ) {
222 if ( !m_keyLocal.HasSubKey(str) ) {
223 // ok, found one - return it
224 return TRUE;
225 }
226 }
227
228 // no more global entries
229 lIndex |= LOCAL_MASK;
230 }
231
232 // much easier with local entries: get the next one we find
233 // (don't forget to clear our flag bit and set it again later)
234 lIndex &= ~LOCAL_MASK;
235 bool bOk = m_keyLocal.GetNextKey(str, lIndex);
236 lIndex |= LOCAL_MASK;
237
238 return bOk;
239 }
240
241 bool wxRegConfig::GetFirstEntry(wxString& str, long& lIndex) const
242 {
243 lIndex = 0;
244 return GetNextEntry(str, lIndex);
245 }
246
247 bool wxRegConfig::GetNextEntry(wxString& str, long& lIndex) const
248 {
249 // are we already enumerating local entries?
250 if ( m_keyGlobal.IsOpened() && !IS_LOCAL_INDEX(lIndex) ) {
251 // try to find a global entry which doesn't appear locally
252 while ( m_keyGlobal.GetNextValue(str, lIndex) ) {
253 if ( !m_keyLocal.HasValue(str) ) {
254 // ok, found one - return it
255 return TRUE;
256 }
257 }
258
259 // no more global entries
260 lIndex |= LOCAL_MASK;
261 }
262
263 // much easier with local entries: get the next one we find
264 // (don't forget to clear our flag bit and set it again later)
265 lIndex &= ~LOCAL_MASK;
266 bool bOk = m_keyLocal.GetNextValue(str, lIndex);
267 lIndex |= LOCAL_MASK;
268
269 return bOk;
270 }
271
272 size_t wxRegConfig::GetNumberOfEntries(bool bRecursive) const
273 {
274 size_t nEntries = 0;
275
276 // dummy vars
277 wxString str;
278 long l;
279 bool bCont = ((wxRegConfig*)this)->GetFirstEntry(str, l);
280 while ( bCont ) {
281 nEntries++;
282
283 bCont = ((wxRegConfig*)this)->GetNextEntry(str, l);
284 }
285
286 return nEntries;
287 }
288
289 size_t wxRegConfig::GetNumberOfGroups(bool bRecursive) const
290 {
291 size_t nGroups = 0;
292
293 // dummy vars
294 wxString str;
295 long l;
296 bool bCont = ((wxRegConfig*)this)->GetFirstGroup(str, l);
297 while ( bCont ) {
298 nGroups++;
299
300 bCont = ((wxRegConfig*)this)->GetNextGroup(str, l);
301 }
302
303 return nGroups;
304 }
305
306 // ----------------------------------------------------------------------------
307 // tests for existence
308 // ----------------------------------------------------------------------------
309
310 bool wxRegConfig::HasGroup(const wxString& key) const
311 {
312 wxConfigPathChanger path(this, key);
313
314 wxString strName(path.Name());
315
316 return m_keyLocal.HasSubKey(strName) || m_keyGlobal.HasSubKey(strName);
317 }
318
319 bool wxRegConfig::HasEntry(const wxString& key) const
320 {
321 wxConfigPathChanger path(this, key);
322
323 wxString strName(path.Name());
324
325 return m_keyLocal.HasValue(strName) || m_keyGlobal.HasValue(strName);
326 }
327
328 wxConfigBase::EntryType wxRegConfig::GetEntryType(const wxString& key) const
329 {
330 wxConfigPathChanger path(this, key);
331
332 wxString strName(path.Name());
333
334 bool isNumeric;
335 if ( m_keyLocal.HasValue(strName) )
336 isNumeric = m_keyLocal.IsNumericValue(strName);
337 else if ( m_keyGlobal.HasValue(strName) )
338 isNumeric = m_keyGlobal.IsNumericValue(strName);
339 else
340 return wxConfigBase::Type_Unknown;
341
342 return isNumeric ? wxConfigBase::Type_Integer : wxConfigBase::Type_String;
343 }
344
345 // ----------------------------------------------------------------------------
346 // reading/writing
347 // ----------------------------------------------------------------------------
348
349 bool wxRegConfig::Read(const wxString& key, wxString *pStr) 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(wxT("User value for immutable key '%s' ignored."),
361 path.Name().c_str());
362 }
363 *pStr = wxConfigBase::ExpandEnvVars(*pStr);
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 // nothing to do
376
377 *pStr = wxConfigBase::ExpandEnvVars(*pStr);
378 return TRUE;
379 }
380
381 return FALSE;
382 }
383
384 bool wxRegConfig::Read(const wxString& key, wxString *pStr,
385 const wxString& szDefault) const
386 {
387 wxConfigPathChanger path(this, key);
388
389 bool bQueryGlobal = TRUE;
390
391 // if immutable key exists in global key we must check that it's not
392 // overriden by the local key with the same name
393 if ( IsImmutable(path.Name()) ) {
394 if ( TryGetValue(m_keyGlobal, path.Name(), *pStr) ) {
395 if ( m_keyLocal.HasValue(path.Name()) ) {
396 wxLogWarning(wxT("User value for immutable key '%s' ignored."),
397 path.Name().c_str());
398 }
399
400 return TRUE;
401 }
402 else {
403 // don't waste time - it's not there anyhow
404 bQueryGlobal = FALSE;
405 }
406 }
407
408 // first try local key
409 if ( TryGetValue(m_keyLocal, path.Name(), *pStr) ||
410 (bQueryGlobal && TryGetValue(m_keyGlobal, path.Name(), *pStr)) ) {
411 *pStr = wxConfigBase::ExpandEnvVars(*pStr);
412 return TRUE;
413 }
414 else {
415 if ( IsRecordingDefaults() ) {
416 ((wxRegConfig*)this)->Write(key, szDefault);
417 }
418
419 // default value
420 *pStr = szDefault;
421 }
422
423 *pStr = wxConfigBase::ExpandEnvVars(*pStr);
424
425 return FALSE;
426 }
427
428 bool wxRegConfig::Read(const wxString& key, long *plResult) const
429 {
430 wxConfigPathChanger path(this, key);
431
432 bool bQueryGlobal = TRUE;
433
434 // if immutable key exists in global key we must check that it's not
435 // overriden by the local key with the same name
436 if ( IsImmutable(path.Name()) ) {
437 if ( TryGetValue(m_keyGlobal, path.Name(), plResult) ) {
438 if ( m_keyLocal.HasValue(path.Name()) ) {
439 wxLogWarning(wxT("User value for immutable key '%s' ignored."),
440 path.Name().c_str());
441 }
442
443 return TRUE;
444 }
445 else {
446 // don't waste time - it's not there anyhow
447 bQueryGlobal = FALSE;
448 }
449 }
450
451 // first try local key
452 if ( TryGetValue(m_keyLocal, path.Name(), plResult) ||
453 (bQueryGlobal && TryGetValue(m_keyGlobal, path.Name(), plResult)) ) {
454 return TRUE;
455 }
456 return FALSE;
457 }
458
459 bool wxRegConfig::Write(const wxString& key, const wxString& szValue)
460 {
461 wxConfigPathChanger path(this, key);
462
463 if ( IsImmutable(path.Name()) ) {
464 wxLogError(wxT("Can't change immutable entry '%s'."), path.Name().c_str());
465 return FALSE;
466 }
467
468 return m_keyLocal.SetValue(path.Name(), szValue);
469 }
470
471 bool wxRegConfig::Write(const wxString& key, long lValue)
472 {
473 wxConfigPathChanger path(this, key);
474
475 if ( IsImmutable(path.Name()) ) {
476 wxLogError(wxT("Can't change immutable entry '%s'."), path.Name().c_str());
477 return FALSE;
478 }
479
480 return m_keyLocal.SetValue(path.Name(), lValue);
481 }
482
483 // ----------------------------------------------------------------------------
484 // renaming
485 // ----------------------------------------------------------------------------
486
487 bool wxRegConfig::RenameEntry(const wxString& oldName, const wxString& newName)
488 {
489 // check that the old entry exists...
490 if ( !HasEntry(oldName) )
491 return FALSE;
492
493 // and that the new one doesn't
494 if ( HasEntry(newName) )
495 return FALSE;
496
497 // delete the old entry and create the new one - but do in the reverse
498 // order to not lose the data if Create() fails
499
500 bool ok;
501 if ( m_keyLocal.IsNumericValue(oldName) )
502 {
503 long val;
504 ok = m_keyLocal.QueryValue(oldName, &val) &&
505 m_keyLocal.SetValue(newName, val);
506 }
507 else
508 {
509 wxString val;
510 ok = m_keyLocal.QueryValue(oldName, val) &&
511 m_keyLocal.SetValue(newName, val);
512 }
513
514 if ( !ok )
515 return FALSE;
516
517 if ( !m_keyLocal.DeleteValue(oldName) )
518 {
519 m_keyLocal.DeleteValue(newName);
520
521 return FALSE;
522 }
523
524 return TRUE;
525 }
526
527 bool wxRegConfig::RenameGroup(const wxString& oldName, const wxString& newName)
528 {
529 // check that the old group exists...
530 if ( !HasGroup(oldName) )
531 return FALSE;
532
533 // and that the new one doesn't
534 if ( HasGroup(newName) )
535 return FALSE;
536
537 // TODO there is no way to rename a registry key - we must do a deep copy
538 // ourselves
539 wxFAIL_MSG(wxT("Registry key renaming not implemented"));
540
541 return FALSE;
542 }
543
544 // ----------------------------------------------------------------------------
545 // deleting
546 // ----------------------------------------------------------------------------
547 bool wxRegConfig::DeleteEntry(const wxString& value, bool bGroupIfEmptyAlso)
548 {
549 wxConfigPathChanger path(this, value);
550
551 if ( !m_keyLocal.DeleteValue(path.Name()) )
552 return FALSE;
553
554 if ( m_keyLocal.IsEmpty() ) {
555 wxString strKey = GetPath().AfterLast(wxCONFIG_PATH_SEPARATOR);
556 SetPath(".."); // changes m_keyLocal
557 return m_keyLocal.DeleteKey(strKey);
558 }
559
560 return TRUE;
561 }
562
563 bool wxRegConfig::DeleteGroup(const wxString& key)
564 {
565 wxConfigPathChanger path(this, key);
566
567 return m_keyLocal.DeleteKey(path.Name());
568 }
569
570 bool wxRegConfig::DeleteAll()
571 {
572 m_keyLocal.Close();
573 m_keyGlobal.Close();
574
575 bool bOk = m_keyLocalRoot.DeleteSelf();
576
577 // make sure that we opened m_keyGlobalRoot and so it has a reasonable name:
578 // otherwise we will delete HKEY_CLASSES_ROOT recursively
579 if ( bOk && m_keyGlobalRoot.IsOpened() )
580 bOk = m_keyGlobalRoot.DeleteSelf();
581
582 return bOk;
583 }
584
585 #endif
586 // __WIN16__
587
588 #endif
589 // wxUSE_CONFIG