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