]> git.saurik.com Git - wxWidgets.git/blob - src/msw/regconf.cpp
9b6bdf0962b40cf2884ab983c19f9eef32637585
[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 // ============================================================================
17 // declarations
18 // ============================================================================
19
20 // ----------------------------------------------------------------------------
21 // headers
22 // ----------------------------------------------------------------------------
23
24 #ifdef __GNUG__
25 #pragma implementation "regconf.h"
26 #endif
27
28 #include "wx/wxprec.h"
29
30 #ifdef __BORLANDC__
31 #pragma hdrstop
32 #endif //__BORLANDC__
33
34 #ifndef WX_PRECOMP
35 #include <wx/string.h>
36 #endif //WX_PRECOMP
37
38 #include <wx/log.h>
39 #include <wx/config.h>
40 #include <wx/msw/registry.h>
41 #include <wx/msw/regconf.h>
42
43 // ----------------------------------------------------------------------------
44 // constants
45 // ----------------------------------------------------------------------------
46
47 // we put our data in HKLM\SOFTWARE_KEY\appname
48 #define SOFTWARE_KEY wxString("Software\\")
49
50 // ----------------------------------------------------------------------------
51 // global functions
52 // ----------------------------------------------------------------------------
53
54 // get the value if the key is opened and it exists
55 bool TryGetValue(const wxRegKey& key, const wxString& str, wxString& strVal)
56 {
57 return key.IsOpened() && key.HasValue(str) && key.QueryValue(str, strVal);
58 }
59
60 bool TryGetValue(const wxRegKey& key, const wxString& str, long *plVal)
61 {
62 return key.IsOpened() && key.HasValue(str) && key.QueryValue(str, plVal);
63 }
64
65 // ============================================================================
66 // implementation
67 // ============================================================================
68
69 // ----------------------------------------------------------------------------
70 // ctor/dtor
71 // ----------------------------------------------------------------------------
72 wxRegConfig::wxRegConfig(const wxString& strRoot)
73 : m_keyLocalRoot(wxRegKey::HKCU, SOFTWARE_KEY + strRoot),
74 m_keyLocal(m_keyLocalRoot, ""),
75 m_keyGlobalRoot(wxRegKey::HKLM, SOFTWARE_KEY + strRoot),
76 m_keyGlobal(m_keyGlobalRoot, "")
77 {
78 // Create() will Open() if key already exists
79 m_keyLocalRoot.Create();
80
81 // as it's the same key, Open() shouldn't fail (i.e. no need for Create())
82 m_keyLocal.Open();
83
84 wxLogNull nolog;
85 m_keyGlobalRoot.Open();
86 }
87
88 wxRegConfig::~wxRegConfig()
89 {
90 // nothing to do - key will be closed in their dtors
91 }
92
93 // ----------------------------------------------------------------------------
94 // path management
95 // ----------------------------------------------------------------------------
96 void wxRegConfig::SetPath(const wxString& strPath)
97 {
98 wxArrayString aParts;
99
100 // because GetPath() returns "" when we're at root, we must understand
101 // empty string as "/"
102 if ( strPath.IsEmpty() || (strPath[0] == wxCONFIG_PATH_SEPARATOR) ) {
103 // absolute path
104 wxSplitPath(aParts, strPath);
105 }
106 else {
107 // relative path, combine with current one
108 wxString strFullPath = GetPath();
109 strFullPath << wxCONFIG_PATH_SEPARATOR << strPath;
110 wxSplitPath(aParts, strFullPath);
111 }
112
113 // recombine path parts in one variable
114 wxString strRegPath;
115 m_strPath.Empty();
116 for ( size_t n = 0; n < aParts.Count(); n++ ) {
117 strRegPath << '\\' << aParts[n];
118 m_strPath << wxCONFIG_PATH_SEPARATOR << aParts[n];
119 }
120
121 // change current key(s)
122 m_keyLocal.SetName(m_keyLocalRoot, strRegPath);
123 m_keyGlobal.SetName(m_keyGlobalRoot, strRegPath);
124 m_keyLocal.Create();
125
126 wxLogNull nolog;
127 m_keyGlobal.Open();
128 }
129
130 // ----------------------------------------------------------------------------
131 // enumeration (works only with current group)
132 // ----------------------------------------------------------------------------
133
134 /*
135 We want to enumerate all local keys/values after the global ones, but, of
136 course, we don't want to repeat a key which appears locally as well as
137 globally twice.
138
139 We use the 15th bit of lIndex for distinction between global and local.
140 */
141
142 #define LOCAL_MASK 0x8000
143 #define IS_LOCAL_INDEX(l) (((l) & LOCAL_MASK) != 0)
144
145 bool wxRegConfig::GetFirstGroup(wxString& str, long& lIndex) const
146 {
147 lIndex = 0;
148 return GetNextGroup(str, lIndex);
149 }
150
151 bool wxRegConfig::GetNextGroup(wxString& str, long& lIndex) const
152 {
153 // are we already enumerating local entries?
154 if ( m_keyGlobal.IsOpened() && !IS_LOCAL_INDEX(lIndex) ) {
155 // try to find a global entry which doesn't appear locally
156 do {
157 if ( !m_keyGlobal.GetNextKey(str, lIndex) ) {
158 // no more global entries
159 lIndex |= LOCAL_MASK;
160 break;
161 }
162 } while( m_keyLocal.HasSubKey(str) );
163 }
164
165 // much easier with local entries: get the next one we find
166 // (don't forget to clear our flag bit and set it again later)
167 lIndex &= ~LOCAL_MASK;
168 bool bOk = m_keyLocal.GetNextKey(str, lIndex);
169 lIndex |= LOCAL_MASK;
170
171 return bOk;
172 }
173
174 bool wxRegConfig::GetFirstEntry(wxString& str, long& lIndex) const
175 {
176 lIndex = 0;
177 return GetNextEntry(str, lIndex);
178 }
179
180 bool wxRegConfig::GetNextEntry(wxString& str, long& lIndex) const
181 {
182 // are we already enumerating local entries?
183 if ( m_keyGlobal.IsOpened() && !IS_LOCAL_INDEX(lIndex) ) {
184 // try to find a global entry which doesn't appear locally
185 do {
186 if ( !m_keyGlobal.GetNextValue(str, lIndex) ) {
187 // no more global entries
188 lIndex |= LOCAL_MASK;
189 break;
190 }
191 } while( m_keyLocal.HasValue(str) );
192 }
193
194 // much easier with local entries: get the next one we find
195 // (don't forget to clear our flag bit and set it again later)
196 lIndex &= ~LOCAL_MASK;
197 bool bOk = m_keyLocal.GetNextValue(str, lIndex);
198 lIndex |= LOCAL_MASK;
199
200 return bOk;
201 }
202
203 size_t wxRegConfig::GetNumberOfEntries(bool bRecursive) const
204 {
205 size_t nEntries = 0;
206
207 // dummy vars
208 wxString str;
209 long l;
210 bool bCont = ((wxRegConfig*)this)->GetFirstEntry(str, l);
211 while ( bCont ) {
212 nEntries++;
213
214 bCont = ((wxRegConfig*)this)->GetNextEntry(str, l);
215 }
216
217 return nEntries;
218 }
219
220 size_t wxRegConfig::GetNumberOfGroups(bool bRecursive) const
221 {
222 size_t nGroups = 0;
223
224 // dummy vars
225 wxString str;
226 long l;
227 bool bCont = ((wxRegConfig*)this)->GetFirstGroup(str, l);
228 while ( bCont ) {
229 nGroups++;
230
231 bCont = ((wxRegConfig*)this)->GetNextGroup(str, l);
232 }
233
234 return nGroups;
235 }
236
237 // ----------------------------------------------------------------------------
238 // tests for existence
239 // ----------------------------------------------------------------------------
240
241 bool wxRegConfig::HasGroup(const wxString& strName) const
242 {
243 return m_keyLocal.HasSubKey(strName) || m_keyGlobal.HasSubKey(strName);
244 }
245
246 bool wxRegConfig::HasEntry(const wxString& strName) const
247 {
248 return m_keyLocal.HasValue(strName) || m_keyGlobal.HasValue(strName);
249 }
250
251 // ----------------------------------------------------------------------------
252 // reading/writing
253 // ----------------------------------------------------------------------------
254
255 bool wxRegConfig::Read(wxString *pStr,
256 const char *szKey,
257 const char *szDefault) const
258 {
259 PathChanger path(this, szKey);
260
261 bool bQueryGlobal = TRUE;
262
263 // if immutable key exists in global key we must check that it's not
264 // overriden by the local key with the same name
265 if ( IsImmutable(path.Name()) ) {
266 if ( TryGetValue(m_keyGlobal, path.Name(), *pStr) ) {
267 if ( m_keyLocal.HasValue(path.Name()) ) {
268 wxLogWarning("User value for immutable key '%s' ignored.",
269 path.Name().c_str());
270 }
271
272 return TRUE;
273 }
274 else {
275 // don't waste time - it's not there anyhow
276 bQueryGlobal = FALSE;
277 }
278 }
279
280 // first try local key
281 if ( TryGetValue(m_keyLocal, path.Name(), *pStr) ||
282 (bQueryGlobal && TryGetValue(m_keyGlobal, path.Name(), *pStr)) ) {
283 // nothing to do
284 }
285 else {
286 if ( IsRecordingDefaults() ) {
287 ((wxRegConfig*)this)->Write(szKey, szDefault);
288 }
289
290 // default value
291 *pStr = szDefault;
292 }
293
294 *pStr = wxConfigBase::ExpandEnvVars(*pStr);
295
296 return FALSE;
297 }
298
299 bool wxRegConfig::Read(long *plResult, const char *szKey, long lDefault) const
300 {
301 PathChanger path(this, szKey);
302
303 bool bQueryGlobal = TRUE;
304
305 // if immutable key exists in global key we must check that it's not
306 // overriden by the local key with the same name
307 if ( IsImmutable(path.Name()) ) {
308 if ( TryGetValue(m_keyGlobal, path.Name(), plResult) ) {
309 if ( m_keyLocal.HasValue(path.Name()) ) {
310 wxLogWarning("User value for immutable key '%s' ignored.",
311 path.Name().c_str());
312 }
313
314 return TRUE;
315 }
316 else {
317 // don't waste time - it's not there anyhow
318 bQueryGlobal = FALSE;
319 }
320 }
321
322 // first try local key
323 if ( TryGetValue(m_keyLocal, path.Name(), plResult) ||
324 (bQueryGlobal && TryGetValue(m_keyGlobal, path.Name(), plResult)) ) {
325 return TRUE;
326 }
327
328 // default
329 *plResult = lDefault;
330 return FALSE;
331 }
332
333 bool wxRegConfig::Write(const char *szKey, const char *szValue)
334 {
335 PathChanger path(this, szKey);
336
337 if ( IsImmutable(path.Name()) ) {
338 wxLogError("Can't change immutable entry '%s'.", path.Name().c_str());
339 return FALSE;
340 }
341
342 return m_keyLocal.SetValue(path.Name(), szValue);
343 }
344
345 bool wxRegConfig::Write(const char *szKey, long lValue)
346 {
347 PathChanger path(this, szKey);
348
349 if ( IsImmutable(path.Name()) ) {
350 wxLogError("Can't change immutable entry '%s'.", path.Name().c_str());
351 return FALSE;
352 }
353
354 return m_keyLocal.SetValue(path.Name(), lValue);
355 }
356
357 // ----------------------------------------------------------------------------
358 // deleting
359 // ----------------------------------------------------------------------------
360 bool wxRegConfig::DeleteEntry(const char *szValue, bool bGroupIfEmptyAlso)
361 {
362 PathChanger path(this, szValue);
363
364 if ( !m_keyLocal.DeleteValue(path.Name()) )
365 return FALSE;
366
367 if ( !m_keyLocal.HasSubkeys() ) {
368 wxString strKey = GetPath().Right(wxCONFIG_PATH_SEPARATOR);
369 SetPath(".."); // changes m_keyLocal
370 return m_keyLocal.DeleteKey(strKey);
371 }
372
373 return TRUE;
374 }
375
376 bool wxRegConfig::DeleteGroup(const char *szKey)
377 {
378 PathChanger path(this, szKey);
379
380 return m_keyLocal.DeleteKey(path.Name());
381 }
382
383 bool wxRegConfig::DeleteAll()
384 {
385 m_keyLocal.Close();
386 m_keyGlobal.Close();
387
388 bool bOk = m_keyLocalRoot.DeleteSelf();
389 if ( bOk )
390 bOk = m_keyGlobalRoot.DeleteSelf();
391
392 return bOk;
393 }