]> git.saurik.com Git - wxWidgets.git/blob - include/wx/fileconf.h
wxFileConfig bugs corrected (now the new entries belong to the right groups)
[wxWidgets.git] / include / wx / fileconf.h
1 /*****************************************************************************\
2 * Project: CppLib: C++ library for Windows/UNIX platfroms *
3 * File: fileconf.h - file based implementation of Config *
4 *---------------------------------------------------------------------------*
5 * Language: C++ *
6 * Platfrom: Any *
7 *---------------------------------------------------------------------------*
8 * Classes: *
9 *---------------------------------------------------------------------------*
10 * Author: Vadim Zeitlin zeitlin@dptmaths.ens-cachan.fr> *
11 * adapted from earlier class by VZ & Karsten Ballüder *
12 * History: *
13 * 27.04.98 created *
14 \*****************************************************************************/
15
16 #ifndef _FILECONF_H
17 #define _FILECONF_H
18
19 // ----------------------------------------------------------------------------
20 // compile options
21 // ----------------------------------------------------------------------------
22
23 // it won't compile without it anyhow
24 #ifndef USE_WXCONFIG
25 #error "Please define USE_WXCONFIG or remove fileconf.cpp from your makefile"
26 #endif // USE_WXCONFIG
27
28 // ----------------------------------------------------------------------------
29 // wxFileConfig
30 // ----------------------------------------------------------------------------
31
32 /*
33 wxFileConfig derives from base Config and implements file based config class,
34 i.e. it uses ASCII disk files to store the information. These files are
35 alternatively called INI, .conf or .rc in the documentation. They are
36 organized in groups or sections, which can nest (i.e. a group contains
37 subgroups, which contain their own subgroups &c). Each group has some
38 number of entries, which are "key = value" pairs. More precisely, the format
39 is:
40
41 # comments are allowed after either ';' or '#' (Win/UNIX standard)
42
43 # blank lines (as above) are ignored
44
45 # global entries are members of special (no name) top group
46 written_for = Windows
47 platform = Linux
48
49 # the start of the group 'Foo'
50 [Foo] # may put comments like this also
51 # following 3 lines are entries
52 key = value
53 another_key = " strings with spaces in the beginning should be quoted, \
54 otherwise the spaces are lost"
55 last_key = but you don't have to put " normally (nor quote them, like here)
56
57 # subgroup of the group 'Foo'
58 # (order is not important, only the name is: separator is '/', as in paths)
59 [Foo/Bar]
60 # entries prefixed with "!" are immutable, i.e. can't be changed if they are
61 # set in the system-wide config file
62 !special_key = value
63 bar_entry = whatever
64
65 [Foo/Bar/Fubar] # depth is (theoretically :-) unlimited
66 # may have the same name as key in another section
67 bar_entry = whatever not
68
69 You have {read/write/delete}Entry functions (guess what they do) and also
70 setCurrentPath to select current group. enum{Subgroups/Entries} allow you
71 to get all entries in the config file (in the current group). Finally,
72 flush() writes immediately all changed entries to disk (otherwise it would
73 be done automatically in dtor)
74
75 wxFileConfig manages not less than 2 config files for each program: global
76 and local (or system and user if you prefer). Entries are read from both of
77 them and the local entries override the global ones unless the latter is
78 immutable (prefixed with '!') in which case a warning message is generated
79 and local value is ignored. Of course, the changes are always written to local
80 file only.
81
82 @@@@ describe environment variable expansion
83 */
84
85 class wxFileConfig : public wxConfig
86 {
87 public:
88 // construct the "standard" full name for global (system-wide) and
89 // local (user-specific) config files from the base file name.
90 //
91 // the following are the filenames returned by this functions:
92 // global local
93 // Unix /etc/file.ext ~/.file
94 // Win %windir%\file.ext %USERPROFILE%\file.ext
95 //
96 // where file is the basename of szFile, ext is it's extension
97 // or .conf (Unix) or .ini (Win) if it has none
98 static wxString GetGlobalFileName(const char *szFile);
99 static wxString GetLocalFileName(const char *szFile);
100
101 // ctor & dtor
102 // if strGlobal is empty, only local config file is used
103 wxFileConfig(const wxString& strLocal,
104 const wxString& strGlobal = "");
105 // dtor will save unsaved data
106 virtual ~wxFileConfig();
107
108 // implement inherited pure virtual functions
109 virtual void SetPath(const wxString& strPath);
110 virtual const wxString& GetPath() const { return m_strPath; }
111
112 virtual bool GetFirstGroup(wxString& str, long& lIndex);
113 virtual bool GetNextGroup (wxString& str, long& lIndex);
114 virtual bool GetFirstEntry(wxString& str, long& lIndex);
115 virtual bool GetNextEntry (wxString& str, long& lIndex);
116
117 virtual bool Read(wxString *pstr, const char *szKey,
118 const char *szDefault = 0) const;
119 virtual const char *Read(const char *szKey,
120 const char *szDefault = 0) const;
121 virtual bool Read(long *pl, const char *szKey, long lDefault) const;
122 virtual bool Write(const char *szKey, const char *szValue);
123 virtual bool Write(const char *szKey, long lValue);
124 virtual bool Flush(bool bCurrentOnly = FALSE);
125
126 virtual bool DeleteEntry(const char *szKey, bool bGroupIfEmptyAlso);
127 virtual bool DeleteGroup(const char *szKey);
128 virtual bool DeleteAll();
129
130 public:
131 // fwd decl
132 class ConfigGroup;
133 class ConfigEntry;
134
135 // we store all lines of the local config file as a linked list in memory
136 class LineList
137 {
138 public:
139 // ctor
140 LineList(const wxString& str, LineList *pNext = NULL) : m_strLine(str)
141 { SetNext(pNext); }
142
143 //
144 LineList *Next() const { return m_pNext; }
145 void SetNext(LineList *pNext) { m_pNext = pNext; }
146
147 //
148 void SetText(const wxString& str) { m_strLine = str; }
149 const wxString& Text() const { return m_strLine; }
150
151 private:
152 wxString m_strLine; // line contents
153 LineList *m_pNext; // next node
154 };
155
156 // functions to work with this list
157 LineList *LineListAppend(const wxString& str);
158 LineList *LineListInsert(const wxString& str,
159 LineList *pLine); // NULL => Append()
160 bool LineListIsEmpty();
161
162 private:
163 // put the object in the initial state
164 void Init();
165
166 // parse the whole file
167 void Parse(wxTextFile& file, bool bLocal);
168
169 // the same as SetPath("/")
170 void SetRootPath();
171
172 // member variables
173 // ----------------
174 LineList *m_linesHead, // head of the linked list
175 *m_linesTail; // tail
176
177 wxString m_strLocalFile, // local file name passed to ctor
178 m_strGlobalFile; // global
179 wxString m_strPath; // current path (not '/' terminated)
180
181 ConfigGroup *m_pRootGroup, // the top (unnamed) group
182 *m_pCurrentGroup; // the current group
183
184 //protected: --- if wxFileConfig::ConfigEntry is not public, functions in
185 // ConfigGroup such as Find/AddEntry can't return "ConfigEntry *"
186 public:
187 WX_DEFINE_ARRAY(ConfigEntry *, ArrayEntries);
188 WX_DEFINE_ARRAY(ConfigGroup *, ArrayGroups);
189
190 class ConfigEntry
191 {
192 private:
193 ConfigGroup *m_pParent; // group that contains us
194 wxString m_strName, // entry name
195 m_strValue; // value
196 bool m_bDirty, // changed since last read?
197 m_bImmutable; // can be overriden locally?
198 int m_nLine; // used if m_pLine == NULL only
199 LineList *m_pLine; // pointer to our line in the linked list
200 // or NULL if it was found in global file
201
202 public:
203 ConfigEntry(ConfigGroup *pParent, const wxString& strName, int nLine);
204
205 // simple accessors
206 const wxString& Name() const { return m_strName; }
207 const wxString& Value() const { return m_strValue; }
208 ConfigGroup *Group() const { return m_pParent; }
209 bool IsDirty() const { return m_bDirty; }
210 bool IsImmutable() const { return m_bImmutable; }
211 bool IsLocal() const { return m_pLine != 0; }
212 int Line() const { return m_nLine; }
213 LineList *GetLine() const { return m_pLine; }
214
215 // modify entry attributes
216 void SetValue(const wxString& strValue, bool bUser = TRUE);
217 void SetDirty();
218 void SetLine(LineList *pLine);
219 };
220
221 protected:
222 class ConfigGroup
223 {
224 private:
225 wxFileConfig *m_pConfig; // config object we belong to
226 ConfigGroup *m_pParent; // parent group (NULL for root group)
227 ArrayEntries m_aEntries; // entries in this group
228 ArrayGroups m_aSubgroups; // subgroups
229 wxString m_strName; // group's name
230 bool m_bDirty; // if FALSE => all subgroups are not dirty
231 LineList *m_pLine; // pointer to our line in the linked list
232 ConfigEntry *m_pLastEntry; // last entry of this group in the local file
233 ConfigGroup *m_pLastGroup; // last subgroup
234
235 public:
236 // ctor
237 ConfigGroup(ConfigGroup *pParent, const wxString& strName, wxFileConfig *);
238
239 // dtor deletes all entries and subgroups also
240 ~ConfigGroup();
241
242 // simple accessors
243 const wxString& Name() const { return m_strName; }
244 ConfigGroup *Parent() const { return m_pParent; }
245 wxFileConfig *Config() const { return m_pConfig; }
246 bool IsDirty() const { return m_bDirty; }
247
248 bool IsEmpty() const { return Entries().IsEmpty() && Groups().IsEmpty(); }
249 const ArrayEntries& Entries() const { return m_aEntries; }
250 const ArrayGroups& Groups() const { return m_aSubgroups; }
251
252 // find entry/subgroup (NULL if not found)
253 ConfigGroup *FindSubgroup(const char *szName) const;
254 ConfigEntry *FindEntry (const char *szName) const;
255
256 // delete entry/subgroup, return FALSE if doesn't exist
257 bool DeleteSubgroup(const char *szName);
258 bool DeleteEntry(const char *szName);
259
260 // create new entry/subgroup returning pointer to newly created element
261 ConfigGroup *AddSubgroup(const wxString& strName);
262 ConfigEntry *AddEntry (const wxString& strName, int nLine = NOT_FOUND);
263
264 // will also recursively set parent's dirty flag
265 void SetDirty();
266 void SetLine(LineList *pLine);
267
268 // the new entries in this subgroup will be inserted after the last subgroup
269 // or, if there is none, after the last entry
270 void SetLastEntry(ConfigEntry *pLastEntry) { m_pLastEntry = pLastEntry; }
271 void SetLastGroup(ConfigGroup *pLastGroup) { m_pLastGroup = pLastGroup; }
272
273 wxString GetFullName() const;
274
275 // get the last line belonging to an entry/subgroup of this group
276 LineList *GetGroupLine();
277 LineList *GetLastEntryLine();
278 LineList *GetLastGroupLine();
279 };
280 };
281
282 #endif //_FILECONF_H
283