]>
Commit | Line | Data |
---|---|---|
19454fa0 VZ |
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 | // ============================================================================ | |
13 | // declarations | |
14 | // ============================================================================ | |
15 | ||
16 | // ---------------------------------------------------------------------------- | |
17 | // headers | |
18 | // ---------------------------------------------------------------------------- | |
19 | #include <wx/wx.h> | |
20 | #include <wx/config.h> | |
21 | #include <wx/regconf.h> | |
22 | #include <wx/registry.h> | |
23 | ||
24 | // ---------------------------------------------------------------------------- | |
25 | // constants | |
26 | // ---------------------------------------------------------------------------- | |
27 | ||
28 | // we put our data in HKLM\SOFTWARE_KEY\appname | |
29 | #define SOFTWARE_KEY wxString("Software\\") | |
30 | ||
31 | // ---------------------------------------------------------------------------- | |
32 | // global functions | |
33 | // ---------------------------------------------------------------------------- | |
34 | ||
35 | // get the value if the key is opened and it exists | |
36 | bool TryGetValue(const wxRegKey& key, const wxString& str, wxString& strVal) | |
37 | { | |
38 | return key.IsOpened() && key.HasValue(str) && key.QueryValue(str, strVal); | |
39 | } | |
40 | ||
41 | bool TryGetValue(const wxRegKey& key, const wxString& str, long *plVal) | |
42 | { | |
43 | return key.IsOpened() && key.HasValue(str) && key.QueryValue(str, plVal); | |
44 | } | |
45 | ||
46 | // ============================================================================ | |
47 | // implementation | |
48 | // ============================================================================ | |
49 | ||
50 | // ---------------------------------------------------------------------------- | |
51 | // ctor/dtor | |
52 | // ---------------------------------------------------------------------------- | |
53 | wxRegConfig::wxRegConfig(const wxString& strRoot) | |
54 | : m_keyLocalRoot(wxRegKey::HKCU, SOFTWARE_KEY + strRoot), | |
55 | m_keyLocal(m_keyLocalRoot, ""), | |
56 | m_keyGlobalRoot(wxRegKey::HKLM, SOFTWARE_KEY + strRoot), | |
57 | m_keyGlobal(m_keyGlobalRoot, "") | |
58 | { | |
59 | // Create() will Open() if key already exists | |
60 | m_keyLocalRoot.Create(); | |
61 | ||
62 | wxLogNull nolog; | |
63 | m_keyGlobalRoot.Open(); | |
64 | } | |
65 | ||
66 | wxRegConfig::~wxRegConfig() | |
67 | { | |
68 | // nothing to do - key will be closed in their dtors | |
69 | } | |
70 | ||
71 | // ---------------------------------------------------------------------------- | |
72 | // path management | |
73 | // ---------------------------------------------------------------------------- | |
74 | void wxRegConfig::SetPath(const wxString& strPath) | |
75 | { | |
76 | ArrayString aParts; | |
77 | ||
78 | if ( strPath.IsEmpty() ) | |
79 | return; | |
80 | ||
81 | if ( strPath[0] == APPCONF_PATH_SEPARATOR ) { | |
82 | // absolute path | |
83 | SplitPath(aParts, strPath); | |
84 | } | |
85 | else { | |
86 | // relative path, combine with current one | |
87 | wxString strFullPath = GetPath(); | |
88 | strFullPath << APPCONF_PATH_SEPARATOR << strPath; | |
89 | SplitPath(aParts, strFullPath); | |
90 | } | |
91 | ||
92 | // recombine path parts in one variable | |
93 | wxString strRegPath; | |
94 | m_strPath.Empty(); | |
95 | for ( uint n = 0; n < aParts.Count(); n++ ) { | |
96 | strRegPath << '\\' << aParts[n]; | |
97 | m_strPath << APPCONF_PATH_SEPARATOR << aParts[n]; | |
98 | } | |
99 | ||
100 | // change current key(s) | |
101 | m_keyLocal.SetName(m_keyLocalRoot, strRegPath); | |
102 | m_keyGlobal.SetName(m_keyGlobalRoot, strRegPath); | |
103 | m_keyLocal.Create(); | |
104 | ||
105 | wxLogNull nolog; | |
106 | m_keyGlobal.Open(); | |
107 | } | |
108 | ||
109 | // ---------------------------------------------------------------------------- | |
110 | // enumeration (works only with current group) | |
111 | // ---------------------------------------------------------------------------- | |
112 | ||
113 | /* | |
114 | We want to enumerate all local keys/values after the global ones, but, of | |
115 | course, we don't want to repeat a key which appears locally as well as | |
116 | globally twice. | |
117 | ||
118 | We use the 15th bit of lIndex for distinction between global and local. | |
119 | */ | |
120 | ||
121 | #define LOCAL_MASK 0x8000 | |
122 | #define IS_LOCAL_INDEX(l) (((l) & LOCAL_MASK) != 0) | |
123 | ||
124 | bool wxRegConfig::GetFirstGroup(wxString& str, long& lIndex) | |
125 | { | |
126 | lIndex = 0; | |
127 | return GetNextGroup(str, lIndex); | |
128 | } | |
129 | ||
130 | bool wxRegConfig::GetNextGroup (wxString& str, long& lIndex) | |
131 | { | |
132 | // are we already enumerating local entries? | |
133 | if ( m_keyGlobal.IsOpened() && !IS_LOCAL_INDEX(lIndex) ) { | |
134 | // try to find a global entry which doesn't appear locally | |
135 | do { | |
136 | if ( !m_keyGlobal.GetNextKey(str, lIndex) ) { | |
137 | // no more global entries | |
138 | lIndex |= LOCAL_MASK; | |
139 | break; | |
140 | } | |
141 | } while( m_keyLocal.HasSubKey(str) ); | |
142 | } | |
143 | ||
144 | // much easier with local entries: get the next one we find | |
145 | // (don't forget to clear our flag bit and set it again later) | |
146 | lIndex &= ~LOCAL_MASK; | |
147 | bool bOk = m_keyLocal.GetNextKey(str, lIndex); | |
148 | lIndex |= LOCAL_MASK; | |
149 | ||
150 | return bOk; | |
151 | } | |
152 | ||
153 | bool wxRegConfig::GetFirstEntry(wxString& str, long& lIndex) | |
154 | { | |
155 | lIndex = 0; | |
156 | return GetNextGroup(str, lIndex); | |
157 | } | |
158 | ||
159 | bool wxRegConfig::GetNextEntry (wxString& str, long& lIndex) | |
160 | { | |
161 | // are we already enumerating local entries? | |
162 | if ( m_keyGlobal.IsOpened() && !IS_LOCAL_INDEX(lIndex) ) { | |
163 | // try to find a global entry which doesn't appear locally | |
164 | do { | |
165 | if ( !m_keyGlobal.GetNextKey(str, lIndex) ) { | |
166 | // no more global entries | |
167 | lIndex |= LOCAL_MASK; | |
168 | break; | |
169 | } | |
170 | } while( m_keyLocal.HasSubKey(str) ); | |
171 | } | |
172 | ||
173 | // much easier with local entries: get the next one we find | |
174 | // (don't forget to clear our flag bit and set it again later) | |
175 | lIndex &= ~LOCAL_MASK; | |
176 | bool bOk = m_keyLocal.GetNextKey(str, lIndex); | |
177 | lIndex |= LOCAL_MASK; | |
178 | ||
179 | return bOk; | |
180 | } | |
181 | ||
182 | // ---------------------------------------------------------------------------- | |
183 | // reading/writing | |
184 | // ---------------------------------------------------------------------------- | |
185 | ||
186 | bool wxRegConfig::Read(wxString& str, | |
187 | const char *szKey, | |
188 | const char *szDefault) const | |
189 | { | |
190 | PathChanger path(this, szKey); | |
191 | ||
cf447356 | 192 | bool bQueryGlobal = TRUE; |
19454fa0 VZ |
193 | |
194 | // if immutable key exists in global key we must check that it's not | |
195 | // overriden by the local key with the same name | |
196 | if ( IsImmutable(path.Name()) ) { | |
197 | if ( TryGetValue(m_keyGlobal, path.Name(), str) ) { | |
198 | if ( m_keyLocal.HasValue(path.Name()) ) { | |
199 | wxLogWarning("User value for immutable key '%s' ignored.", | |
200 | path.Name().c_str()); | |
201 | } | |
202 | ||
cf447356 | 203 | return TRUE; |
19454fa0 VZ |
204 | } |
205 | else { | |
206 | // don't waste time - it's not there anyhow | |
cf447356 | 207 | bQueryGlobal = FALSE; |
19454fa0 VZ |
208 | } |
209 | } | |
210 | ||
211 | // first try local key | |
212 | if ( TryGetValue(m_keyLocal, path.Name(), str) || | |
213 | (bQueryGlobal && TryGetValue(m_keyGlobal, path.Name(), str)) ) { | |
cf447356 | 214 | return TRUE; |
19454fa0 VZ |
215 | } |
216 | ||
217 | // default value | |
218 | str = szDefault; | |
cf447356 | 219 | return FALSE; |
19454fa0 VZ |
220 | } |
221 | ||
222 | bool wxRegConfig::Read(long &lValue, const char *szKey, long lDefault) const | |
223 | { | |
224 | PathChanger path(this, szKey); | |
225 | ||
cf447356 | 226 | bool bQueryGlobal = TRUE; |
19454fa0 VZ |
227 | |
228 | // if immutable key exists in global key we must check that it's not | |
229 | // overriden by the local key with the same name | |
230 | if ( IsImmutable(path.Name()) ) { | |
231 | if ( TryGetValue(m_keyGlobal, path.Name(), &lValue) ) { | |
232 | if ( m_keyLocal.HasValue(path.Name()) ) { | |
233 | wxLogWarning("User value for immutable key '%s' ignored.", | |
234 | path.Name().c_str()); | |
235 | } | |
236 | ||
cf447356 | 237 | return TRUE; |
19454fa0 VZ |
238 | } |
239 | else { | |
240 | // don't waste time - it's not there anyhow | |
cf447356 | 241 | bQueryGlobal = FALSE; |
19454fa0 VZ |
242 | } |
243 | } | |
244 | ||
245 | // first try local key | |
246 | if ( TryGetValue(m_keyLocal, path.Name(), &lValue) || | |
247 | (bQueryGlobal && TryGetValue(m_keyGlobal, path.Name(), &lValue)) ) { | |
cf447356 | 248 | return TRUE; |
19454fa0 VZ |
249 | } |
250 | ||
251 | // default | |
252 | lValue = lDefault; | |
cf447356 | 253 | return FALSE; |
19454fa0 VZ |
254 | } |
255 | ||
256 | bool wxRegConfig::Write(const char *szKey, const char *szValue) | |
257 | { | |
258 | PathChanger path(this, szKey); | |
259 | ||
260 | if ( IsImmutable(path.Name()) ) { | |
261 | wxLogError("Can't change immutable entry '%s'.", path.Name().c_str()); | |
cf447356 | 262 | return FALSE; |
19454fa0 VZ |
263 | } |
264 | ||
265 | return m_keyLocal.SetValue(path.Name(), szValue); | |
266 | } | |
267 | ||
268 | bool wxRegConfig::Write(const char *szKey, long lValue) | |
269 | { | |
270 | PathChanger path(this, szKey); | |
271 | ||
272 | if ( IsImmutable(path.Name()) ) { | |
273 | wxLogError("Can't change immutable entry '%s'.", path.Name().c_str()); | |
cf447356 | 274 | return FALSE; |
19454fa0 VZ |
275 | } |
276 | ||
277 | return m_keyLocal.SetValue(path.Name(), lValue); | |
278 | } | |
279 | ||
280 | // ---------------------------------------------------------------------------- | |
281 | // deleting | |
282 | // ---------------------------------------------------------------------------- | |
283 | bool wxRegConfig::DeleteEntry(const char *szValue, bool bGroupIfEmptyAlso) | |
284 | { | |
285 | PathChanger path(this, szValue); | |
286 | ||
287 | if ( !m_keyLocal.DeleteValue(path.Name()) ) | |
cf447356 | 288 | return FALSE; |
19454fa0 VZ |
289 | |
290 | if ( m_keyLocal.IsEmpty() ) { | |
291 | wxString strKey = GetPath().Right(APPCONF_PATH_SEPARATOR); | |
292 | SetPath(".."); // changes m_keyLocal | |
293 | return m_keyLocal.DeleteKey(strKey); | |
294 | } | |
295 | ||
cf447356 | 296 | return TRUE; |
19454fa0 VZ |
297 | } |
298 | ||
299 | bool wxRegConfig::DeleteGroup(const char *szKey) | |
300 | { | |
301 | PathChanger path(this, szKey); | |
302 | ||
303 | return m_keyLocal.DeleteKey(path.Name()); | |
304 | } | |
305 | ||
306 | bool wxRegConfig::DeleteAll() | |
307 | { | |
308 | // first of all, prevent the creation of new registry entries | |
cf447356 | 309 | Config::EnableAutosave(FALSE); |
19454fa0 VZ |
310 | |
311 | m_keyLocal.Close(); | |
312 | m_keyGlobal.Close(); | |
313 | ||
314 | bool bOk = m_keyLocalRoot.DeleteSelf(); | |
315 | if ( bOk ) | |
316 | bOk = m_keyGlobalRoot.DeleteSelf(); | |
317 | ||
318 | return bOk; | |
319 | } |