1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
|
// config_signal.h -*-c++-*-
//
#ifndef CONFIG_SIGNAL_H
#define CONFIG_SIGNAL_H
#include <apt-pkg/configuration.h>
#include <sigc++/signal.h>
#include <sigc++/functors/slot.h>
#include <sigc++/trackable.h>
#include <iosfwd>
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <map>
#include <vector>
/** \brief A framework for signals that are based on the apt configuration code.
*
*
* This uses a thin wrapper around the apt Configuration class.
*
* This works in large part because apt-pkg itself does not (thankfully)
* modify configuration items after it is initialized.
*
* Important note: this configuration class supports "transparent themes".
* If PACKAGE::Theme is set, Find*(key) operations will look up key,
* followed by PACKAGE::Themes::(PACKAGE::theme)::key.
*
* This only breaks for things that use Tree -- which means that such code
* might need to explicitly understand themes in order to work. That is: if
* it is appropriate for two disparate hierarchies to be "merged", you have to
* do this on your own. The default Tree call simply uses the theme as
* a backing store.
*
* IMPORTANT NOTE: setting values in the PACKAGE::Themes hierarchy will
* not trigger signal emission on "shadowing" nodes! Because themes are
* expected to be static, I do not think this is a big deal, but you should
* be aware of it.
*
* MORE IMPORTANT NOTE: Altering the value of PACKAGE::Theme will
* not trigger ANY signal emission right now. (this *will* be a nuisance
* and I hope to change it eventually)
*
*
* In order to allow only non-default options to be saved, this does the
* following (hack :P ) -- it stores TWO configuration dictionaries, updating
* BOTH whenever an option is set, but only saving from the user's. (in
* fact, it uses three -- ouch!)
*
* \file config_signal.h
*/
class signalling_config:public sigc::trackable
{
Configuration *user_config, *system_config, *theme_config;
typedef std::map<string, sigc::signal0<void> *> connmap;
connmap conn_table;
// The current "theme" root, cached. (ie, if the theme is "bland",
// this will be "PACKAGE::UI::Themes::bland::")
std::string themeroot;
void update_theme(std::string theme);
void do_update_theme();
public:
// Assumes that all settings initially contained in user_config are
// also contained in system_config.
signalling_config(Configuration *_user_config,
Configuration *_system_config,
Configuration *_theme_config);
~signalling_config();
inline string Find(const char *Name,const char *Default = 0)
{
if(themeroot.empty() || system_config->Exists(Name))
return system_config->Find(Name, Default);
else
return theme_config->Find(themeroot+Name, Default);
}
inline string Find(string Name,const char *Default = 0)
{
if(themeroot.empty() || system_config->Exists(Name))
return system_config->Find(Name, Default);
else
return theme_config->Find(themeroot+Name, Default);
}
inline string FindFile(const char *Name,const char *Default = 0)
{
if(themeroot.empty() || system_config->Exists(Name))
return system_config->FindFile(Name, Default);
else
return theme_config->FindFile((themeroot+Name).c_str(), Default);
}
inline string FindDir(const char *Name,const char *Default = 0)
{
if(themeroot.empty() || system_config->Exists(Name))
return system_config->FindDir(Name, Default);
else
return theme_config->FindDir((themeroot+Name).c_str(), Default);
}
inline int FindI(const char *Name,int Default = 0)
{
if(themeroot.empty() || system_config->Exists(Name))
return system_config->FindI(Name, Default);
else
return theme_config->FindI(themeroot+Name, Default);
}
inline int FindI(string Name,bool Default = 0)
{
if(themeroot.empty() || system_config->Exists(Name))
return system_config->FindI(Name, Default);
else
return theme_config->FindI(themeroot+Name, Default);
}
inline bool FindB(const char *Name,bool Default = false)
{
if(themeroot.empty() || system_config->Exists(Name))
return system_config->FindB(Name, Default);
else
return theme_config->FindB(themeroot+Name, Default);
}
inline bool FindB(string Name,bool Default = false)
{
if(themeroot.empty() || system_config->Exists(Name))
return system_config->FindB(Name, Default);
else
return theme_config->FindB(themeroot+Name, Default);
}
void Set(string Name,string Value);
void Set(string Name,int Value);
/** Sets Name to Value without modifying the user's configuration. */
void SetNoUser(string Name, string Value);
/** Sets Name to Value without modifying the user's configuration. */
void SetNoUser(string name, int Value);
/** Switches to a different configuration tree (this will involve
* emitting various signals)
*
* This assumes that the "user" configuration tree has been
* appropriately modified and that new_system_cfg has the
* appropriate correspondence with it.
*/
void setcfg(Configuration *new_user_cfg,
Configuration *new_system_cfg,
Configuration *new_theme_cfg);
inline bool Exists(string Name)
{
if(system_config->Exists(Name))
return true;
else
return !themeroot.empty() && theme_config->Exists(themeroot+Name);
}
bool Exists(const char *Name)
{
if(system_config->Exists(Name))
return true;
else
return !themeroot.empty() && theme_config->Exists(themeroot+Name);
}
inline bool ExistsUser(string Name)
{
return user_config->Exists(Name);
}
inline const Configuration::Item *Tree(const char *Name)
{
if(themeroot.empty() || system_config->Exists(Name))
return system_config->Tree(Name);
else
return theme_config->Tree((themeroot+Name).c_str());
}
// FIXME: this is a hack needed to support the workaround. (for load_config)
// I think.
Configuration *get_cfg(bool theme)
{
return theme?theme_config:system_config;
}
void connect(string name, const sigc::slot0<void> &slot);
void Dump(std::ostream &out);
};
// Used to generate stack-scoped changes to a config member.
//
// TODO: should take a config_signal, but I need Clear() and
// config_signal doesn't implement that.
class config_change_pusher
{
const std::string key;
std::string old_value;
Configuration &cfg;
public:
config_change_pusher(const std::string &_key, const std::string &val,
Configuration &_cfg)
: key(_key), cfg(_cfg)
{
old_value = cfg.Find(key);
cfg.Set(key, val);
}
config_change_pusher(const std::string &_key, const char *val,
Configuration &_cfg)
: key(_key), cfg(_cfg)
{
old_value = cfg.Find(key);
cfg.Set(key, val);
}
config_change_pusher(const std::string &_key, int val,
Configuration &_cfg)
: key(_key), cfg(_cfg)
{
old_value = cfg.Find(key);
cfg.Set(key.c_str(), val);
}
config_change_pusher(const std::string &_key, bool val,
Configuration &_cfg)
: key(_key), cfg(_cfg)
{
old_value = cfg.Find(key);
cfg.Set(key, val ? "true" : "false");
}
~config_change_pusher()
{
cfg.Set(key, old_value);
}
};
#endif
|