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