diff options
author | Pavel Labath <pavelo@centrum.sk> | 2011-08-19 15:01:07 (GMT) |
---|---|---|
committer | Pavel Labath <pavelo@centrum.sk> | 2011-11-01 10:04:03 (GMT) |
commit | 8a3c7ff2ac1b615ed8f891814f5b3980b8327aae (patch) | |
tree | c0da38ddd391db2b2afd50c2bd569c306c677b4d /util/MenuConvertor.cc | |
parent | 18e8f7cd9906728864ecc3e25b2ab3e29070ec8a (diff) | |
download | fluxbox_paul-8a3c7ff2ac1b615ed8f891814f5b3980b8327aae.zip fluxbox_paul-8a3c7ff2ac1b615ed8f891814f5b3980b8327aae.tar.bz2 |
fluxbox-update_configs: automatically update menu file
To achieve this, I had to partially resurrect (and heavily modify) the old parsing code in
MenuCreator.cc.
Diffstat (limited to 'util/MenuConvertor.cc')
-rw-r--r-- | util/MenuConvertor.cc | 305 |
1 files changed, 305 insertions, 0 deletions
diff --git a/util/MenuConvertor.cc b/util/MenuConvertor.cc new file mode 100644 index 0000000..cc595ed --- /dev/null +++ b/util/MenuConvertor.cc | |||
@@ -0,0 +1,305 @@ | |||
1 | // MenuConvertor.cc for Fluxbox | ||
2 | // Copyright (c) 2004-2008 Henrik Kinnunen (fluxgen at fluxbox dot org) | ||
3 | // and Simon Bowden (rathnor at users.sourceforge.net) | ||
4 | // | ||
5 | // Permission is hereby granted, free of charge, to any person obtaining a | ||
6 | // copy of this software and associated documentation files (the "Software"), | ||
7 | // to deal in the Software without restriction, including without limitation | ||
8 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
9 | // and/or sell copies of the Software, and to permit persons to whom the | ||
10 | // Software is furnished to do so, subject to the following conditions: | ||
11 | // | ||
12 | // The above copyright notice and this permission notice shall be included in | ||
13 | // all copies or substantial portions of the Software. | ||
14 | // | ||
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
20 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
21 | // DEALINGS IN THE SOFTWARE. | ||
22 | |||
23 | #include "MenuConvertor.hh" | ||
24 | |||
25 | #include <algorithm> | ||
26 | #include <iostream> | ||
27 | #include <stdexcept> | ||
28 | #include <vector> | ||
29 | |||
30 | #include "FbTk/FileUtil.hh" | ||
31 | #include "FbTk/I18n.hh" | ||
32 | #include "FbTk/Luamm.hh" | ||
33 | #include "FbTk/StringUtil.hh" | ||
34 | |||
35 | #include "FbMenuParser.hh" | ||
36 | |||
37 | using std::cerr; | ||
38 | using std::endl; | ||
39 | using std::string; | ||
40 | using std::vector; | ||
41 | using std::list; | ||
42 | using std::less; | ||
43 | |||
44 | list<string> MenuConvertor::encoding_stack; | ||
45 | list<size_t> MenuConvertor::stacksize_stack; | ||
46 | |||
47 | FbTk::StringConvertor MenuConvertor::m_stringconvertor(FbTk::StringConvertor::ToFbString); | ||
48 | |||
49 | namespace { | ||
50 | |||
51 | void translateMenuItem(FbMenuParser &parse, Menu &item, Menu &parent, | ||
52 | FbTk::StringConvertor &labelconvertor); | ||
53 | |||
54 | |||
55 | void parseMenu(FbMenuParser &pars, Menu &menu, | ||
56 | FbTk::StringConvertor &label_convertor) { | ||
57 | |||
58 | while (!pars.eof()) { | ||
59 | Menu t; | ||
60 | t.load(pars, label_convertor); | ||
61 | if (t.key() == "end") | ||
62 | return; | ||
63 | translateMenuItem(pars, t, menu, label_convertor); | ||
64 | } | ||
65 | } | ||
66 | |||
67 | void translateMenuItem(FbMenuParser &parse, Menu &pitem, Menu &parent, | ||
68 | FbTk::StringConvertor &labelconvertor) { | ||
69 | |||
70 | string &str_key = pitem.key(); | ||
71 | string &str_cmd = pitem.command(); | ||
72 | string &str_label = pitem.label(); | ||
73 | |||
74 | if (str_key == "nop") { | ||
75 | } else if (str_key == "icons") { | ||
76 | } else if (str_key == "exit") { | ||
77 | } else if (str_key == "exec") { | ||
78 | } else if (str_key == "macrocmd") { | ||
79 | str_cmd = "macrocmd " + str_cmd; | ||
80 | str_key = "command"; | ||
81 | } else if (str_key == "style") { | ||
82 | } else if (str_key == "config") { | ||
83 | } else if (str_key == "include") { // include | ||
84 | |||
85 | // this will make sure we dont get stuck in a loop | ||
86 | static size_t safe_counter = 0; | ||
87 | if (safe_counter > 10) | ||
88 | return; | ||
89 | |||
90 | safe_counter++; | ||
91 | |||
92 | string newfile = FbTk::StringUtil::expandFilename(str_label); | ||
93 | if (FbTk::FileUtil::isDirectory(newfile.c_str())) { | ||
94 | // inject every file in this directory into the current menu | ||
95 | FbTk::Directory dir(newfile.c_str()); | ||
96 | |||
97 | vector<string> filelist(dir.entries()); | ||
98 | for (size_t file_index = 0; file_index < dir.entries(); ++file_index) | ||
99 | filelist[file_index] = dir.readFilename(); | ||
100 | sort(filelist.begin(), filelist.end(), less<string>()); | ||
101 | |||
102 | for (size_t file_index = 0; file_index < dir.entries(); file_index++) { | ||
103 | string thisfile(newfile + '/' + filelist[file_index]); | ||
104 | |||
105 | if (FbTk::FileUtil::isRegularFile(thisfile.c_str()) && | ||
106 | (filelist[file_index][0] != '.') && | ||
107 | (thisfile[thisfile.length() - 1] != '~')) { | ||
108 | MenuConvertor::createFromFile(thisfile, parent, false); | ||
109 | } | ||
110 | } | ||
111 | |||
112 | } else { | ||
113 | // inject this file into the current menu | ||
114 | MenuConvertor::createFromFile(newfile, parent, false); | ||
115 | } | ||
116 | |||
117 | safe_counter--; | ||
118 | str_key.clear(); | ||
119 | |||
120 | } // end of include | ||
121 | else if (str_key == "begin") | ||
122 | str_key.clear(); | ||
123 | else if (str_key == "submenu") { | ||
124 | str_key = "menu"; | ||
125 | |||
126 | parseMenu(parse, pitem, labelconvertor); | ||
127 | } else if (str_key == "stylesdir" || str_key == "stylesmenu" | ||
128 | || str_key == "themesmenu" || str_key == "themesdir") { | ||
129 | str_cmd = str_label; | ||
130 | str_label.clear(); | ||
131 | str_key = "stylesdir"; | ||
132 | } | ||
133 | else if (str_key == "wallpapers" || str_key == "wallpapermenu" || | ||
134 | str_key == "rootcommands") { | ||
135 | pitem.program = str_cmd; | ||
136 | str_cmd.clear(); | ||
137 | str_key = "wallpapers"; | ||
138 | } | ||
139 | else if (str_key == "workspaces") { | ||
140 | } else if (str_key == "separator") { | ||
141 | } else if (str_key == "encoding") { | ||
142 | MenuConvertor::startEncoding(str_cmd); | ||
143 | str_key.clear(); | ||
144 | } else if (str_key == "endencoding") { | ||
145 | MenuConvertor::endEncoding(); | ||
146 | str_key.clear(); | ||
147 | } else if (str_key == "shade") { | ||
148 | } else if (str_key == "maximize") { | ||
149 | } else if (str_key == "iconify") { | ||
150 | } else if (str_key == "close") { | ||
151 | } else if (str_key == "kill" || str_key == "killwindow") { | ||
152 | } else if (str_key == "lower") { | ||
153 | } else if (str_key == "raise") { | ||
154 | } else if (str_key == "stick") { | ||
155 | } else if (str_key == "settitledialog") { | ||
156 | } else if (str_key == "alpha") { | ||
157 | } else if (str_key == "extramenus") { | ||
158 | } else if (str_key == "sendto") { | ||
159 | } else if (str_key == "layer") { | ||
160 | } else { | ||
161 | str_cmd = str_key; | ||
162 | str_key = "command"; | ||
163 | } | ||
164 | |||
165 | parent.entries.push_back(pitem); | ||
166 | } | ||
167 | |||
168 | bool getStart(FbMenuParser &parser, string &label, FbTk::StringConvertor &labelconvertor) { | ||
169 | Menu pitem; | ||
170 | while (!parser.eof()) { | ||
171 | // get first begin line | ||
172 | pitem.load(parser, labelconvertor); | ||
173 | if (pitem.key() == "begin") { | ||
174 | break; | ||
175 | } | ||
176 | } | ||
177 | if (parser.eof()) | ||
178 | return false; | ||
179 | |||
180 | label = pitem.label(); | ||
181 | return true; | ||
182 | } | ||
183 | |||
184 | } // end of anonymous namespace | ||
185 | |||
186 | void Menu::write(std::ostream &o, unsigned level) { | ||
187 | if(key().empty()) | ||
188 | return; | ||
189 | |||
190 | const bool menu = key() == "menu"; | ||
191 | char separator = menu ? '\n': ' '; | ||
192 | std::string indent(menu ? (level+1)*4 : 0, ' '); | ||
193 | |||
194 | if(level == 0) | ||
195 | o << "return "; | ||
196 | |||
197 | o << string(level*4, ' ') << '{' << separator; | ||
198 | o << indent << "type = " << lua::quote(key()) << ';' << separator; | ||
199 | if(! label().empty()) | ||
200 | o << indent << "label = " << lua::quote(label()) << ';' << separator; | ||
201 | if(! command().empty()) { | ||
202 | o << indent << (menu ? "title = " : "param = ") | ||
203 | << lua::quote(command()) << ';' << separator; | ||
204 | } | ||
205 | if(! program.empty()) | ||
206 | o << indent << "program = " << lua::quote(program) << ';' << separator; | ||
207 | if(! icon().empty()) | ||
208 | o << indent << "icon = " << lua::quote(icon()) << ';' << separator; | ||
209 | |||
210 | for(std::list<Menu>::iterator it = entries.begin(); it != entries.end(); ++it) { | ||
211 | it->write(o, level + 1); | ||
212 | } | ||
213 | |||
214 | o << (menu ? string(level*4, ' ') : "") << "};" << endl; | ||
215 | } | ||
216 | |||
217 | bool MenuConvertor::createFromFile(const string &filename, | ||
218 | Menu &inject_into, | ||
219 | bool begin) { | ||
220 | string real_filename = FbTk::StringUtil::expandFilename(filename); | ||
221 | |||
222 | FbMenuParser parser(real_filename); | ||
223 | if (!parser.isLoaded()) | ||
224 | return false; | ||
225 | |||
226 | startFile(); | ||
227 | if (begin) { | ||
228 | if (!getStart(parser, inject_into.label(), m_stringconvertor)) { | ||
229 | endFile(); | ||
230 | return false; | ||
231 | } | ||
232 | inject_into.key() = "menu"; | ||
233 | } | ||
234 | |||
235 | parseMenu(parser, inject_into, m_stringconvertor); | ||
236 | endFile(); | ||
237 | |||
238 | return true; | ||
239 | } | ||
240 | |||
241 | /* push our encoding-stacksize onto the stack */ | ||
242 | void MenuConvertor::startFile() { | ||
243 | if (encoding_stack.empty()) | ||
244 | m_stringconvertor.setSource(""); | ||
245 | stacksize_stack.push_back(encoding_stack.size()); | ||
246 | } | ||
247 | |||
248 | /** | ||
249 | * Pop necessary encodings from the stack | ||
250 | * (and endEncoding the final one) to our matching encoding-stacksize. | ||
251 | */ | ||
252 | void MenuConvertor::endFile() { | ||
253 | size_t target_size = stacksize_stack.back(); | ||
254 | size_t curr_size = encoding_stack.size(); | ||
255 | |||
256 | if (target_size != curr_size) { | ||
257 | _FB_USES_NLS; | ||
258 | cerr<<_FB_CONSOLETEXT(Menu, ErrorEndEncoding, "Warning: unbalanced [encoding] tags", "User menu file had unbalanced [encoding] tags")<<endl; | ||
259 | } | ||
260 | |||
261 | for (; curr_size > (target_size+1); --curr_size) | ||
262 | encoding_stack.pop_back(); | ||
263 | |||
264 | if (curr_size == (target_size+1)) | ||
265 | endEncoding(); | ||
266 | |||
267 | stacksize_stack.pop_back(); | ||
268 | } | ||
269 | |||
270 | /** | ||
271 | * Push the encoding onto the stack, and make it active. | ||
272 | */ | ||
273 | void MenuConvertor::startEncoding(const string &encoding) { | ||
274 | // we push it regardless of whether it's valid, since we | ||
275 | // need to stay balanced with the endEncodings. | ||
276 | encoding_stack.push_back(encoding); | ||
277 | |||
278 | // this won't change if it doesn't succeed | ||
279 | m_stringconvertor.setSource(encoding); | ||
280 | } | ||
281 | |||
282 | /** | ||
283 | * Pop the encoding from the stack, unless we are at our stacksize limit. | ||
284 | * Restore the previous (valid) encoding. | ||
285 | */ | ||
286 | void MenuConvertor::endEncoding() { | ||
287 | size_t min_size = stacksize_stack.back(); | ||
288 | if (encoding_stack.size() <= min_size) { | ||
289 | _FB_USES_NLS; | ||
290 | cerr<<_FB_CONSOLETEXT(Menu, ErrorEndEncoding, "Warning: unbalanced [encoding] tags", "User menu file had unbalanced [encoding] tags")<<endl; | ||
291 | return; | ||
292 | } | ||
293 | |||
294 | encoding_stack.pop_back(); | ||
295 | m_stringconvertor.reset(); | ||
296 | |||
297 | list<string>::reverse_iterator it = encoding_stack.rbegin(); | ||
298 | list<string>::reverse_iterator it_end = encoding_stack.rend(); | ||
299 | while (it != it_end && !m_stringconvertor.setSource(*it)) | ||
300 | ++it; | ||
301 | |||
302 | if (it == it_end) | ||
303 | m_stringconvertor.setSource(""); | ||
304 | } | ||
305 | |||