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