]> git.lyx.org Git - lyx.git/blob - src/kbmap.C
update build instructions (Qt 4.2.2 etc.)
[lyx.git] / src / kbmap.C
1 /**
2  * \file kbmap.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Lars Gullik Bjønnes
7  * \author Jean-Marc Lasgouttes
8  * \author John Levon
9  * \author André Pönitz
10  *
11  * Full author contact details are available in file CREDITS.
12  */
13
14 #include <config.h>
15
16 #include "kbmap.h"
17
18 #include "debug.h"
19 #include "kbsequence.h"
20 #include "LyXAction.h"
21 #include "lyxlex.h"
22
23 #include "frontends/LyXKeySym.h"
24
25 #include "support/filetools.h"
26
27 #include <sstream>
28
29
30 namespace lyx {
31
32 using support::FileName;
33 using support::i18nLibFileSearch;
34
35 using std::endl;
36 using std::string;
37
38
39 string const kb_keymap::printKeySym(LyXKeySym const & key,
40                                     key_modifier::state mod)
41 {
42         string buf;
43
44         string const s = key.getSymbolName();
45
46         if (mod & key_modifier::shift)
47                 buf += "S-";
48         if (mod & key_modifier::ctrl)
49                 buf += "C-";
50         if (mod & key_modifier::alt)
51                 buf += "M-";
52
53         buf += s;
54         return buf;
55 }
56
57
58 string::size_type kb_keymap::bind(string const & seq, FuncRequest const & func)
59 {
60         if (lyxerr.debugging(Debug::KBMAP)) {
61                 lyxerr << "BIND: Sequence `"
62                        << seq << "' Action `"
63                        << func.action << '\'' << endl;
64         }
65
66         kb_sequence k(0, 0);
67
68         string::size_type const res = k.parse(seq);
69         if (res == string::npos) {
70                 defkey(&k, func);
71         } else {
72                 lyxerr[Debug::KBMAP] << "Parse error at position " << res
73                                      << " in key sequence '" << seq << "'."
74                                      << endl;
75         }
76
77         return res;
78 }
79
80
81 namespace {
82
83 enum BindTags {
84         BN_BIND,
85         BN_BINDFILE
86 };
87
88 keyword_item bindTags[] = {
89         { "\\bind", BN_BIND },
90         { "\\bind_file", BN_BINDFILE }
91 };
92
93 }
94
95
96 bool kb_keymap::read(string const & bind_file)
97 {
98         const int bindCount = sizeof(bindTags) / sizeof(keyword_item);
99
100         LyXLex lexrc(bindTags, bindCount);
101         if (lyxerr.debugging(Debug::PARSER))
102                 lexrc.printTable(lyxerr);
103
104         FileName const tmp(i18nLibFileSearch("bind", bind_file, "bind"));
105         lexrc.setFile(tmp);
106         if (!lexrc.isOK()) {
107                 lyxerr << "kb_keymap::read: cannot open bind file:"
108                        << tmp << endl;
109                 return false;
110         }
111
112         lyxerr[Debug::KBMAP] << "Reading bind file:" << tmp << endl;
113
114         bool error = false;
115         while (lexrc.isOK()) {
116                 switch (lexrc.lex()) {
117                 case LyXLex::LEX_UNDEF:
118                         lexrc.printError("Unknown tag `$$Token'");
119                         error = true;
120                         continue;
121                 case LyXLex::LEX_FEOF:
122                         continue;
123                 case BN_BIND:
124                 {
125                         string seq, cmd;
126
127                         if (lexrc.next()) {
128                                 seq = lexrc.getString();
129                         } else {
130                                 lexrc.printError("BN_BIND: Missing key sequence");
131                                 error = true;
132                                 break;
133                         }
134
135                         if (lexrc.next(true)) {
136                                 cmd = lexrc.getString();
137                         } else {
138                                 lexrc.printError("BN_BIND: missing command");
139                                 error = true;
140                                 break;
141                         }
142
143                         FuncRequest func = lyxaction.lookupFunc(cmd);
144                         if (func. action == LFUN_UNKNOWN_ACTION) {
145                                 lexrc.printError("BN_BIND: Unknown LyX"
146                                                  " function `$$Token'");
147                                 error = true;
148                                 break;
149                         }
150
151                         bind(seq, func);
152                         break;
153                 }
154                 case BN_BINDFILE:
155                         if (lexrc.next()) {
156                                 string const tmp(lexrc.getString());
157                                 error |= !read(tmp);
158                         } else {
159                                 lexrc.printError("BN_BINDFILE: Missing file name");
160                                 error = true;
161                                 break;
162
163                         }
164                         break;
165                 }
166         }
167
168         if (error)
169                 lyxerr << "kb_keymap::read: error while reading bind file:"
170                        << tmp << endl;
171         return !error;
172 }
173
174
175 FuncRequest const &
176 kb_keymap::lookup(LyXKeySymPtr key,
177                   key_modifier::state mod, kb_sequence * seq) const
178 {
179         static FuncRequest const unknown(LFUN_UNKNOWN_ACTION);
180
181         if (table.empty()) {
182                 seq->curmap = seq->stdmap;
183                 seq->mark_deleted();
184                 return unknown;
185         }
186
187         Table::const_iterator end = table.end();
188         for (Table::const_iterator cit = table.begin(); cit != end; ++cit) {
189                 key_modifier::state mask(cit->mod.second);
190                 key_modifier::state check =
191                         static_cast<key_modifier::state>(mod & ~mask);
192
193                 if (*(cit->code) == *key && cit->mod.first == check) {
194                         // match found
195                         if (cit->table.get()) {
196                                 // this is a prefix key - set new map
197                                 seq->curmap = cit->table.get();
198                                 static FuncRequest prefix(LFUN_COMMAND_PREFIX);
199                                 return prefix;
200                         } else {
201                                 // final key - reset map
202                                 seq->curmap = seq->stdmap;
203                                 seq->mark_deleted();
204                                 return cit->func;
205                         }
206                 }
207         }
208
209         // error - key not found:
210         seq->curmap = seq->stdmap;
211         seq->mark_deleted();
212
213         return unknown;
214 }
215
216
217 docstring const kb_keymap::print(bool forgui) const
218 {
219         docstring buf;
220         Table::const_iterator end = table.end();
221         for (Table::const_iterator cit = table.begin(); cit != end; ++cit) {
222                 buf += cit->code->print(cit->mod.first, forgui);
223                 buf += ' ';
224         }
225         return buf;
226 }
227
228
229 void kb_keymap::defkey(kb_sequence * seq,
230                        FuncRequest const & func, unsigned int r)
231 {
232         LyXKeySymPtr code = seq->sequence[r];
233         if (!code->isOK())
234                 return;
235
236         key_modifier::state const mod1 = seq->modifiers[r].first;
237         key_modifier::state const mod2 = seq->modifiers[r].second;
238
239         // check if key is already there
240         Table::iterator end = table.end();
241         for (Table::iterator it = table.begin(); it != end; ++it) {
242                 if (*(code) == *(it->code)
243                     && mod1 == it->mod.first
244                     && mod2 == it->mod.second) {
245                         // overwrite binding
246                         if (r + 1 == seq->length()) {
247                                 lyxerr[Debug::KBMAP]
248                                         << "Warning: New binding for '"
249                                         << to_utf8(seq->print(false))
250                                         << "' is overriding old binding..."
251                                         << endl;
252                                 if (it->table.get()) {
253                                         it->table.reset();
254                                 }
255                                 it->func = func;
256                                 it->func.origin = FuncRequest::KEYBOARD;
257                                 return;
258                         } else if (!it->table.get()) {
259                                 lyxerr << "Error: New binding for '" 
260                                        << to_utf8(seq->print(false))
261                                        << "' is overriding old binding..."
262                                                << endl;
263                                 return;
264                         } else {
265                                 it->table->defkey(seq, func, r + 1);
266                                 return;
267                         }
268                 }
269         }
270
271         Table::iterator newone = table.insert(table.end(), kb_key());
272         newone->code = code;
273         newone->mod = seq->modifiers[r];
274         if (r + 1 == seq->length()) {
275                 newone->func = func;
276                 newone->func.origin = FuncRequest::KEYBOARD;
277                 newone->table.reset();
278         } else {
279                 newone->table.reset(new kb_keymap);
280                 newone->table->defkey(seq, func, r + 1);
281         }
282 }
283
284
285 docstring const kb_keymap::printbindings(FuncRequest const & func) const
286 {
287         odocstringstream res;
288         Bindings bindings = findbindings(func);
289         for (Bindings::const_iterator cit = bindings.begin();
290              cit != bindings.end() ; ++cit)
291                 res << '[' << cit->print(true) << ']';
292         return res.str();
293 }
294
295
296 kb_keymap::Bindings
297 kb_keymap::findbindings(FuncRequest const & func) const
298 {
299         return findbindings(func, kb_sequence(0, 0));
300 }
301
302
303 kb_keymap::Bindings
304 kb_keymap::findbindings(FuncRequest const & func,
305                         kb_sequence const & prefix) const
306 {
307         Bindings res;
308         if (table.empty()) return res;
309
310         Table::const_iterator end = table.end();
311         for (Table::const_iterator cit = table.begin();
312             cit != end; ++cit) {
313                 if (cit->table.get()) {
314                         kb_sequence seq = prefix;
315                         seq.addkey(cit->code, cit->mod.first);
316                         Bindings res2 =
317                                 cit->table->findbindings(func, seq);
318                         res.insert(res.end(), res2.begin(), res2.end());
319                 } else if (cit->func == func) {
320                         kb_sequence seq = prefix;
321                         seq.addkey(cit->code, cit->mod.first);
322                         res.push_back(seq);
323                 }
324         }
325
326         return res;
327 }
328
329
330 std::pair<LyXKeySym const *, key_modifier::state>
331 kb_keymap::find1keybinding(FuncRequest const & func) const
332 {
333         Table::const_iterator end = table.end();
334         for (Table::const_iterator cit = table.begin();
335             cit != end; ++cit) {
336                 if (!cit->table.get() && cit->func == func)
337                         return std::make_pair(cit->code.get(), cit->mod.first);
338         }
339
340         return std::make_pair<LyXKeySym const *, key_modifier::state>(0, key_modifier::none);
341 }
342
343
344 } // namespace lyx