]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/msw/regconf.cpp
missing functions implemented in wxMSW tree ctrl (custom sorting,
[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/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
45bool TryGetValue(const wxRegKey& key, const wxString& str, wxString& strVal)
46{
47 return key.IsOpened() && key.HasValue(str) && key.QueryValue(str, strVal);
48}
49
50bool 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
65wxRegConfig::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
133wxRegConfig::~wxRegConfig()
134{
135 // nothing to do - key will be closed in their dtors
136}
137
138// ----------------------------------------------------------------------------
139// path management
140// ----------------------------------------------------------------------------
141void 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
190bool wxRegConfig::GetFirstGroup(wxString& str, long& lIndex) const
191{
192 lIndex = 0;
193 return GetNextGroup(str, lIndex);
194}
195
196bool 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
219bool wxRegConfig::GetFirstEntry(wxString& str, long& lIndex) const
220{
221 lIndex = 0;
222 return GetNextEntry(str, lIndex);
223}
224
225bool 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
248size_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
265size_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
286bool wxRegConfig::HasGroup(const wxString& strName) const
287{
288 return m_keyLocal.HasSubKey(strName) || m_keyGlobal.HasSubKey(strName);
289}
290
291bool 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
300bool 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
337bool 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
381bool 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
412bool 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
424bool 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// ----------------------------------------------------------------------------
439bool 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
455bool wxRegConfig::DeleteGroup(const wxString& key)
456{
457 wxConfigPathChanger path(this, key);
458
459 return m_keyLocal.DeleteKey(path.Name());
460}
461
462bool 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}