aboutsummaryrefslogtreecommitdiff
path: root/util/MenuConvertor.cc
diff options
context:
space:
mode:
authorPavel Labath <pavelo@centrum.sk>2011-08-19 15:01:07 (GMT)
committerPaul Tagliamonte <paultag@fluxbox.org>2012-04-07 02:13:14 (GMT)
commit23736ab3339e9e5d6d1d7a09218f8df9a39a5ff5 (patch)
treec4313b638fbb361f932af02d651c1ed9c9de3ab1 /util/MenuConvertor.cc
parentb7ab35e5f5624589f57c9de8afefab952dfffd32 (diff)
downloadfluxbox_paul-23736ab3339e9e5d6d1d7a09218f8df9a39a5ff5.zip
fluxbox_paul-23736ab3339e9e5d6d1d7a09218f8df9a39a5ff5.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.cc305
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
37using std::cerr;
38using std::endl;
39using std::string;
40using std::vector;
41using std::list;
42using std::less;
43
44list<string> MenuConvertor::encoding_stack;
45list<size_t> MenuConvertor::stacksize_stack;
46
47FbTk::StringConvertor MenuConvertor::m_stringconvertor(FbTk::StringConvertor::ToFbString);
48
49namespace {
50
51void translateMenuItem(FbMenuParser &parse, Menu &item, Menu &parent,
52 FbTk::StringConvertor &labelconvertor);
53
54
55void 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
67void 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
168bool 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
186void 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
217bool 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 */
242void 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 */
252void 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 */
273void 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 */
286void 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