]> git.saurik.com Git - wxWidgets.git/blob - src/msw/iniconf.cpp
(blind) fix for keyboard cues display under XP (bug 1298512)
[wxWidgets.git] / src / msw / iniconf.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/iniconf.cpp
3 // Purpose: implementation of wxIniConfig class
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 27.07.98
7 // RCS-ID: $Id$
8 // Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
14
15 #ifdef __BORLANDC__
16 #pragma hdrstop
17 #endif
18
19 #ifndef WX_PRECOMP
20 #include "wx/string.h"
21 #include "wx/intl.h"
22 #include "wx/event.h"
23 #include "wx/app.h"
24 #include "wx/utils.h"
25 #endif //WX_PRECOMP
26
27 // Doesn't yet compile in Unicode mode
28
29 #if wxUSE_CONFIG && !wxUSE_UNICODE
30
31 #include "wx/dynarray.h"
32 #include "wx/log.h"
33 #include "wx/config.h"
34 #include "wx/file.h"
35
36 #include "wx/msw/iniconf.h"
37
38 // _WINDOWS_ is defined when windows.h is included,
39 // __WXMSW__ is defined for MS Windows compilation
40 #if defined(__WXMSW__) && !defined(_WINDOWS_)
41 #include "wx/msw/wrapwin.h"
42 #endif //windows.h
43
44 // ----------------------------------------------------------------------------
45 // constants
46 // ----------------------------------------------------------------------------
47
48 // we replace all path separators with this character
49 #define PATH_SEP_REPLACE '_'
50
51 // ============================================================================
52 // implementation
53 // ============================================================================
54
55 // ----------------------------------------------------------------------------
56 // ctor & dtor
57 // ----------------------------------------------------------------------------
58
59 wxIniConfig::wxIniConfig(const wxString& strAppName,
60 const wxString& strVendor,
61 const wxString& localFilename,
62 const wxString& globalFilename,
63 long style)
64 : wxConfigBase(strAppName, strVendor, localFilename, globalFilename, style)
65
66 #if 0 // This is too complex for some compilers, e.g. BC++ 5.01
67 : wxConfigBase((strAppName.IsEmpty() && wxTheApp) ? wxTheApp->GetAppName()
68 : strAppName,
69 strVendor.IsEmpty() ? (wxTheApp ? wxTheApp->GetVendorName()
70 : strAppName)
71 : strVendor,
72 localFilename, globalFilename, style)
73 #endif
74 {
75 if (strAppName.IsEmpty() && wxTheApp)
76 SetAppName(wxTheApp->GetAppName());
77 if (strVendor.IsEmpty() && wxTheApp)
78 SetVendorName(wxTheApp->GetVendorName());
79
80 m_strLocalFilename = localFilename;
81 if (m_strLocalFilename.IsEmpty())
82 {
83 m_strLocalFilename = GetAppName() + wxT(".ini");
84 }
85
86 // append the extension if none given and it's not an absolute file name
87 // (otherwise we assume that they know what they're doing)
88 if ( !wxIsPathSeparator(m_strLocalFilename[0u]) &&
89 m_strLocalFilename.Find(wxT('.')) == wxNOT_FOUND )
90 {
91 m_strLocalFilename << wxT(".ini");
92 }
93
94 // set root path
95 SetPath(wxEmptyString);
96 }
97
98 wxIniConfig::~wxIniConfig()
99 {
100 }
101
102 // ----------------------------------------------------------------------------
103 // path management
104 // ----------------------------------------------------------------------------
105
106 void wxIniConfig::SetPath(const wxString& strPath)
107 {
108 wxArrayString aParts;
109
110 if ( strPath.IsEmpty() ) {
111 // nothing
112 }
113 else if ( strPath[0u] == wxCONFIG_PATH_SEPARATOR ) {
114 // absolute path
115 wxSplitPath(aParts, strPath);
116 }
117 else {
118 // relative path, combine with current one
119 wxString strFullPath = GetPath();
120 strFullPath << wxCONFIG_PATH_SEPARATOR << strPath;
121 wxSplitPath(aParts, strFullPath);
122 }
123
124 size_t nPartsCount = aParts.Count();
125 m_strPath.Empty();
126 if ( nPartsCount == 0 ) {
127 // go to the root
128 m_strGroup = PATH_SEP_REPLACE;
129 }
130 else {
131 // translate
132 m_strGroup = aParts[0u];
133 for ( size_t nPart = 1; nPart < nPartsCount; nPart++ ) {
134 if ( nPart > 1 )
135 m_strPath << PATH_SEP_REPLACE;
136 m_strPath << aParts[nPart];
137 }
138 }
139
140 // other functions assume that all this is true, i.e. there are no trailing
141 // underscores at the end except if the group is the root one
142 wxASSERT( (m_strPath.IsEmpty() || m_strPath.Last() != PATH_SEP_REPLACE) &&
143 (m_strGroup == wxString(PATH_SEP_REPLACE) ||
144 m_strGroup.Last() != PATH_SEP_REPLACE) );
145 }
146
147 const wxString& wxIniConfig::GetPath() const
148 {
149 static wxString s_str;
150
151 // always return abs path
152 s_str = wxCONFIG_PATH_SEPARATOR;
153
154 if ( m_strGroup == wxString(PATH_SEP_REPLACE) ) {
155 // we're at the root level, nothing to do
156 }
157 else {
158 s_str << m_strGroup;
159 if ( !m_strPath.IsEmpty() )
160 s_str << wxCONFIG_PATH_SEPARATOR;
161 for ( const char *p = m_strPath; *p != '\0'; p++ ) {
162 s_str << (*p == PATH_SEP_REPLACE ? wxCONFIG_PATH_SEPARATOR : *p);
163 }
164 }
165
166 return s_str;
167 }
168
169 wxString wxIniConfig::GetPrivateKeyName(const wxString& szKey) const
170 {
171 wxString strKey;
172
173 if ( !m_strPath.IsEmpty() )
174 strKey << m_strPath << PATH_SEP_REPLACE;
175
176 strKey << szKey;
177
178 return strKey;
179 }
180
181 wxString wxIniConfig::GetKeyName(const wxString& szKey) const
182 {
183 wxString strKey;
184
185 if ( m_strGroup != wxString(PATH_SEP_REPLACE) )
186 strKey << m_strGroup << PATH_SEP_REPLACE;
187 if ( !m_strPath.IsEmpty() )
188 strKey << m_strPath << PATH_SEP_REPLACE;
189
190 strKey << szKey;
191
192 return strKey;
193 }
194
195 // ----------------------------------------------------------------------------
196 // enumeration
197 // ----------------------------------------------------------------------------
198
199 // not implemented
200 bool wxIniConfig::GetFirstGroup(wxString& WXUNUSED(str), long& WXUNUSED(lIndex)) const
201 {
202 wxFAIL_MSG("not implemented");
203
204 return false;
205 }
206
207 bool wxIniConfig::GetNextGroup (wxString& WXUNUSED(str), long& WXUNUSED(lIndex)) const
208 {
209 wxFAIL_MSG("not implemented");
210
211 return false;
212 }
213
214 bool wxIniConfig::GetFirstEntry(wxString& WXUNUSED(str), long& WXUNUSED(lIndex)) const
215 {
216 wxFAIL_MSG("not implemented");
217
218 return false;
219 }
220
221 bool wxIniConfig::GetNextEntry (wxString& WXUNUSED(str), long& WXUNUSED(lIndex)) const
222 {
223 wxFAIL_MSG("not implemented");
224
225 return false;
226 }
227
228 // ----------------------------------------------------------------------------
229 // misc info
230 // ----------------------------------------------------------------------------
231
232 // not implemented
233 size_t wxIniConfig::GetNumberOfEntries(bool WXUNUSED(bRecursive)) const
234 {
235 wxFAIL_MSG("not implemented");
236
237 return (size_t)-1;
238 }
239
240 size_t wxIniConfig::GetNumberOfGroups(bool WXUNUSED(bRecursive)) const
241 {
242 wxFAIL_MSG("not implemented");
243
244 return (size_t)-1;
245 }
246
247 bool wxIniConfig::HasGroup(const wxString& WXUNUSED(strName)) const
248 {
249 wxFAIL_MSG("not implemented");
250
251 return false;
252 }
253
254 bool wxIniConfig::HasEntry(const wxString& WXUNUSED(strName)) const
255 {
256 wxFAIL_MSG("not implemented");
257
258 return false;
259 }
260
261 // is current group empty?
262 bool wxIniConfig::IsEmpty() const
263 {
264 char szBuf[1024];
265
266 GetPrivateProfileString(m_strGroup, NULL, "",
267 szBuf, WXSIZEOF(szBuf), m_strLocalFilename);
268 if ( !::IsEmpty(szBuf) )
269 return false;
270
271 GetProfileString(m_strGroup, NULL, "", szBuf, WXSIZEOF(szBuf));
272 if ( !::IsEmpty(szBuf) )
273 return false;
274
275 return true;
276 }
277
278 // ----------------------------------------------------------------------------
279 // read/write
280 // ----------------------------------------------------------------------------
281
282 bool wxIniConfig::DoReadString(const wxString& szKey, wxString *pstr) const
283 {
284 wxConfigPathChanger path(this, szKey);
285 wxString strKey = GetPrivateKeyName(path.Name());
286
287 char szBuf[1024]; // @@ should dynamically allocate memory...
288
289 // first look in the private INI file
290
291 // NB: the lpDefault param to GetPrivateProfileString can't be NULL
292 GetPrivateProfileString(m_strGroup, strKey, "",
293 szBuf, WXSIZEOF(szBuf), m_strLocalFilename);
294 if ( ::IsEmpty(szBuf) ) {
295 // now look in win.ini
296 wxString strKey = GetKeyName(path.Name());
297 GetProfileString(m_strGroup, strKey, "", szBuf, WXSIZEOF(szBuf));
298 }
299
300 if ( ::IsEmpty(szBuf) )
301 return false;
302
303 *pstr = szBuf;
304 return true;
305 }
306
307 bool wxIniConfig::DoReadLong(const wxString& szKey, long *pl) const
308 {
309 wxConfigPathChanger path(this, szKey);
310 wxString strKey = GetPrivateKeyName(path.Name());
311
312 // hack: we have no mean to know if it really found the default value or
313 // didn't find anything, so we call it twice
314
315 static const int nMagic = 17; // 17 is some "rare" number
316 static const int nMagic2 = 28; // arbitrary number != nMagic
317 long lVal = GetPrivateProfileInt(m_strGroup, strKey, nMagic, m_strLocalFilename);
318 if ( lVal != nMagic ) {
319 // the value was read from the file
320 *pl = lVal;
321 return true;
322 }
323
324 // is it really nMagic?
325 lVal = GetPrivateProfileInt(m_strGroup, strKey, nMagic2, m_strLocalFilename);
326 if ( lVal != nMagic2 ) {
327 // the nMagic it returned was indeed read from the file
328 *pl = lVal;
329 return true;
330 }
331
332 // CS : I have no idea why they should look up in win.ini
333 // and if at all they have to do the same procedure using the two magic numbers
334 // otherwise it always returns true, even if the key was not there at all
335 #if 0
336 // no, it was just returning the default value, so now look in win.ini
337 *pl = GetProfileInt(GetVendorName(), GetKeyName(szKey), *pl);
338
339 return true;
340 #endif
341 return false ;
342 }
343
344 bool wxIniConfig::DoWriteString(const wxString& szKey, const wxString& szValue)
345 {
346 wxConfigPathChanger path(this, szKey);
347 wxString strKey = GetPrivateKeyName(path.Name());
348
349 bool bOk = WritePrivateProfileString(m_strGroup, strKey,
350 szValue, m_strLocalFilename) != 0;
351
352 if ( !bOk )
353 wxLogLastError(wxT("WritePrivateProfileString"));
354
355 return bOk;
356 }
357
358 bool wxIniConfig::DoWriteLong(const wxString& szKey, long lValue)
359 {
360 // ltoa() is not ANSI :-(
361 char szBuf[40]; // should be good for sizeof(long) <= 16 (128 bits)
362 sprintf(szBuf, "%ld", lValue);
363
364 return Write(szKey, szBuf);
365 }
366
367 bool wxIniConfig::Flush(bool /* bCurrentOnly */)
368 {
369 // this is just the way it works
370 return WritePrivateProfileString(NULL, NULL, NULL, m_strLocalFilename) != 0;
371 }
372
373 // ----------------------------------------------------------------------------
374 // delete
375 // ----------------------------------------------------------------------------
376
377 bool wxIniConfig::DeleteEntry(const wxString& szKey, bool bGroupIfEmptyAlso)
378 {
379 // passing NULL as value to WritePrivateProfileString deletes the key
380 wxConfigPathChanger path(this, szKey);
381 wxString strKey = GetPrivateKeyName(path.Name());
382
383 if (WritePrivateProfileString(m_strGroup, strKey,
384 (const char*) NULL, m_strLocalFilename) == 0)
385 return false;
386
387 if ( !bGroupIfEmptyAlso || !IsEmpty() )
388 return true;
389
390 // delete the current group too
391 bool bOk = WritePrivateProfileString(m_strGroup, NULL,
392 NULL, m_strLocalFilename) != 0;
393
394 if ( !bOk )
395 wxLogLastError(wxT("WritePrivateProfileString"));
396
397 return bOk;
398 }
399
400 bool wxIniConfig::DeleteGroup(const wxString& szKey)
401 {
402 wxConfigPathChanger path(this, szKey);
403
404 // passing NULL as section name to WritePrivateProfileString deletes the
405 // whole section according to the docs
406 bool bOk = WritePrivateProfileString(path.Name(), NULL,
407 NULL, m_strLocalFilename) != 0;
408
409 if ( !bOk )
410 wxLogLastError(wxT("WritePrivateProfileString"));
411
412 return bOk;
413 }
414
415 #ifndef MAX_PATH
416 #define MAX_PATH 256
417 #endif
418
419 bool wxIniConfig::DeleteAll()
420 {
421 // first delete our group in win.ini
422 WriteProfileString(GetVendorName(), NULL, NULL);
423
424 // then delete our own ini file
425 char szBuf[MAX_PATH];
426 size_t nRc = GetWindowsDirectory(szBuf, WXSIZEOF(szBuf));
427 if ( nRc == 0 )
428 {
429 wxLogLastError(wxT("GetWindowsDirectory"));
430 }
431 else if ( nRc > WXSIZEOF(szBuf) )
432 {
433 wxFAIL_MSG(wxT("buffer is too small for Windows directory."));
434 }
435
436 wxString strFile = szBuf;
437 strFile << '\\' << m_strLocalFilename;
438
439 if ( wxFile::Exists(strFile) && !wxRemoveFile(strFile) ) {
440 wxLogSysError(_("Can't delete the INI file '%s'"), strFile.c_str());
441 return false;
442 }
443
444 return true;
445 }
446
447 bool wxIniConfig::RenameEntry(const wxString& WXUNUSED(oldName),
448 const wxString& WXUNUSED(newName))
449 {
450 // Not implemented
451 return false;
452 }
453
454 bool wxIniConfig::RenameGroup(const wxString& WXUNUSED(oldName),
455 const wxString& WXUNUSED(newName))
456 {
457 // Not implemented
458 return false;
459 }
460
461 #endif
462 // wxUSE_CONFIG && wxUSE_UNICODE