From 9321ad2736704a66809e5318b015279c7f294bff Mon Sep 17 00:00:00 2001 From: Bo Peng Date: Sat, 20 Oct 2007 20:35:33 +0000 Subject: [PATCH] add a \unbind keyword and a few utility functions (unbind, write, delkey) to KeyMap.h,.cpp git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@21088 a592a061-630c-0410-9148-cb99ea01b6c8 --- src/KeyMap.cpp | 179 ++++++++++++++++++++++++++++++--- src/KeyMap.h | 40 ++++++-- src/frontends/qt4/GuiPrefs.cpp | 6 +- 3 files changed, 203 insertions(+), 22 deletions(-) diff --git a/src/KeyMap.cpp b/src/KeyMap.cpp index da95659298..9fe270a8b7 100644 --- a/src/KeyMap.cpp +++ b/src/KeyMap.cpp @@ -22,12 +22,15 @@ #include "support/filetools.h" +#include #include #include using std::endl; +using std::ios; +using std::ofstream; using std::string; -using std::make_pair; +using boost::make_tuple; namespace lyx { @@ -71,7 +74,54 @@ size_t KeyMap::bind(string const & seq, FuncRequest const & func) << endl; } - return res; + return res == string::npos ? 0 : res; +} + + +size_t KeyMap::unbind(string const & seq, FuncRequest const & func) +{ + KeySequence k(0, 0); + + string::size_type const res = k.parse(seq); + if (res == string::npos) + delkey(&k, func); + else + LYXERR(Debug::KBMAP) << "Parse error at position " << res + << " in key sequence '" << seq << "'." + << endl; + return res == string::npos ? 0 : res; +} + + +bool KeyMap::hasBinding(KeySequence const & seq, FuncRequest const & func, + unsigned int r) +{ + KeySymbol code = seq.sequence[r]; + if (!code.isOK()) + return false; + + KeyModifier const mod1 = seq.modifiers[r].first; + KeyModifier const mod2 = seq.modifiers[r].second; + + // check if key is already there + Table::iterator end = table.end(); + for (Table::iterator it = table.begin(); it != end; ++it) { + if (code == it->code + && mod1 == it->mod.first + && mod2 == it->mod.second) { + if (r + 1 == seq.length()) + return it->func == func; + else if (it->table.get()) + return it->table->hasBinding(seq, func, r + 1); + } + } + return false; +} + + +void KeyMap::clear() +{ + table.clear(); } @@ -79,18 +129,20 @@ namespace { enum BindTags { BN_BIND, - BN_BINDFILE + BN_BINDFILE, + BN_UNBIND, }; keyword_item bindTags[] = { { "\\bind", BN_BIND }, - { "\\bind_file", BN_BINDFILE } + { "\\bind_file", BN_BINDFILE }, + { "\\unbind", BN_UNBIND }, }; } -bool KeyMap::read(string const & bind_file) +bool KeyMap::read(string const & bind_file, KeyMap * unbind_map) { const int bindCount = sizeof(bindTags) / sizeof(keyword_item); @@ -148,10 +200,44 @@ bool KeyMap::read(string const & bind_file) bind(seq, func); break; } + case BN_UNBIND: + { + string seq, cmd; + + if (lexrc.next()) { + seq = lexrc.getString(); + } else { + lexrc.printError("BN_UNBIND: Missing key sequence"); + error = true; + break; + } + + if (lexrc.next(true)) { + cmd = lexrc.getString(); + } else { + lexrc.printError("BN_UNBIND: missing command"); + error = true; + break; + } + + FuncRequest func = lyxaction.lookupFunc(cmd); + if (func. action == LFUN_UNKNOWN_ACTION) { + lexrc.printError("BN_UNBIND: Unknown LyX" + " function `$$Token'"); + error = true; + break; + } + + if (unbind_map) + unbind_map->bind(seq, func); + else + unbind(seq, func); + break; + } case BN_BINDFILE: if (lexrc.next()) { string const tmp(lexrc.getString()); - error |= !read(tmp); + error != !read(tmp, unbind_map); } else { lexrc.printError("BN_BINDFILE: Missing file name"); error = true; @@ -169,6 +255,35 @@ bool KeyMap::read(string const & bind_file) } +void KeyMap::write(string const & bind_file, bool append, bool unbind) const +{ + ofstream os(bind_file.c_str(), + append ? (ios::app | ios:: out): ios::out); + + if (!append) + os << "## This file is automatically generated by lyx\n" + << "## All modifications will be lost\n\n"; + + string tag = unbind ? "\\unbind" : "\\bind"; + BindingList const list = listBindings(false); + BindingList::const_iterator it = list.begin(); + BindingList::const_iterator it_end = list.end(); + for (; it != it_end; ++it) { + kb_action action = it->get<0>().action; + string arg = to_utf8(it->get<0>().argument()); + + os << tag << " \"" + << to_utf8(it->get<1>().print(KeySequence::BindFile)) + << "\" \"" + << lyxaction.getActionName(action) + << (arg.empty() ? "" : " ") << arg + << "\"\n"; + } + os << "\n"; + os.close(); +} + + FuncRequest const & KeyMap::lookup(KeySymbol const &key, KeyModifier mod, KeySequence * seq) const { @@ -276,6 +391,44 @@ void KeyMap::defkey(KeySequence * seq, FuncRequest const & func, unsigned int r) } +void KeyMap::delkey(KeySequence * seq, FuncRequest const & func, unsigned int r) +{ + KeySymbol code = seq->sequence[r]; + if (!code.isOK()) + return; + + KeyModifier const mod1 = seq->modifiers[r].first; + KeyModifier const mod2 = seq->modifiers[r].second; + + // check if key is already there + Table::iterator end = table.end(); + Table::iterator remove = end; + for (Table::iterator it = table.begin(); it != end; ++it) { + if (code == it->code + && mod1 == it->mod.first + && mod2 == it->mod.second) { + // remove + if (r + 1 == seq->length()) { + if (it->func == func) { + remove = it; + if (it->table.get()) + it->table.reset(); + } + } else if (it->table.get()) { + it->table->delkey(seq, func, r + 1); + if (it->table->empty()) + remove = it; + return; + } + } + } + if (remove != end) { + table.erase(remove); + return; + } +} + + docstring const KeyMap::printbindings(FuncRequest const & func) const { Bindings bindings = findbindings(func); @@ -326,10 +479,10 @@ KeyMap::Bindings KeyMap::findbindings(FuncRequest const & func, } -KeyMap::BindingList const KeyMap::listBindings(bool unbound) const +KeyMap::BindingList KeyMap::listBindings(bool unbound, int tag) const { BindingList list; - listBindings(list, KeySequence(0, 0)); + listBindings(list, KeySequence(0, 0), tag); if (unbound) { LyXAction::const_func_iterator fit = lyxaction.func_begin(); LyXAction::const_func_iterator fit_end = lyxaction.func_end(); @@ -339,12 +492,12 @@ KeyMap::BindingList const KeyMap::listBindings(bool unbound) const BindingList::const_iterator it = list.begin(); BindingList::const_iterator it_end = list.end(); for (; it != it_end; ++it) - if (it->first.action == action) { + if (it->get<0>().action == action) { has_action = true; break; } if (!has_action) - list.push_back(make_pair(action, KeySequence(0, 0))); + list.push_back(make_tuple(action, KeySequence(0, 0), tag)); } } return list; @@ -352,7 +505,7 @@ KeyMap::BindingList const KeyMap::listBindings(bool unbound) const void KeyMap::listBindings(BindingList & list, - KeySequence const & prefix) const + KeySequence const & prefix, int tag) const { Table::const_iterator it = table.begin(); Table::const_iterator it_end = table.end(); @@ -361,11 +514,11 @@ void KeyMap::listBindings(BindingList & list, if (it->table.get()) { KeySequence seq = prefix; seq.addkey(it->code, it->mod.first); - it->table->listBindings(list, seq); + it->table->listBindings(list, seq, tag); } else { KeySequence seq = prefix; seq.addkey(it->code, it->mod.first); - list.push_back(make_pair(it->func, seq)); + list.push_back(make_tuple(it->func, seq, tag)); } } } diff --git a/src/KeyMap.h b/src/KeyMap.h index d8069f2d68..06caf1a37e 100644 --- a/src/KeyMap.h +++ b/src/KeyMap.h @@ -22,6 +22,7 @@ #include "support/docstream.h" #include +#include #include #include @@ -42,8 +43,32 @@ public: */ size_t bind(std::string const & seq, FuncRequest const & func); - // Parse a bind file - bool read(std::string const & bind_file); + // Unbind a key sequence + size_t unbind(std::string const & seq, FuncRequest const & func); + + // if a keybinding has been defined. + bool hasBinding(KeySequence const & seq, FuncRequest const & func, + unsigned int r = 0); + + // clear all bindings + void clear(); + + /** Parse a bind file. If a valid unbind_map is given, put \unbind + * bindings to a separate KeyMap. This is used in the Shortcut preference + * dialog where main and user bind files are loaded separately so \unbind + * in user.bind can not nullify \bind in the master bind file. + * + * @param bind_file bind file + * @param unbind_map pointer to a KeyMap that holds \unbind bindings + */ + bool read(std::string const & bind_file, KeyMap * unbind_map = NULL); + + /** write to a bind file. + * @param append append to the bind_file instead of overwrite it + * @param unbind use \unbind instead of \bind, indicating this KeyMap + * actually record unbind maps. + */ + void write(std::string const & bind_file, bool append, bool unbind=false) const; /** * print all available keysyms @@ -71,13 +96,14 @@ public: /// Given an action, print the keybindings. docstring const printbindings(FuncRequest const & func) const; - typedef std::pair Binding; + typedef boost::tuple Binding; typedef std::vector BindingList; /** * Return all lfun and their associated bindings. * @param unbound list unbound (func without any keybinding) as well + * @param tag an optional tag to indicate the source of the bindinglist */ - BindingList const listBindings(bool unbound) const; + BindingList listBindings(bool unbound, int tag = 0) const; /** * Given an action, find the first 1-key binding (if it exists). @@ -121,6 +147,8 @@ private: */ void defkey(KeySequence * seq, FuncRequest const & func, unsigned int r = 0); + void delkey(KeySequence * seq, FuncRequest const & func, + unsigned int r = 0); /** * Given an action, find all keybindings @@ -130,8 +158,8 @@ private: Bindings findbindings(FuncRequest const & func, KeySequence const & prefix) const; - void listBindings(BindingList & list, - KeySequence const & prefix) const; + void listBindings(BindingList & list, KeySequence const & prefix, + int tag) const; /// is the table empty ? bool empty() const { return table.empty(); } diff --git a/src/frontends/qt4/GuiPrefs.cpp b/src/frontends/qt4/GuiPrefs.cpp index a39e788581..265dca2afe 100644 --- a/src/frontends/qt4/GuiPrefs.cpp +++ b/src/frontends/qt4/GuiPrefs.cpp @@ -1753,11 +1753,11 @@ void PrefShortcuts::update(LyXRC const & rc) KeyMap::BindingList::const_iterator it = bindinglist.begin(); KeyMap::BindingList::const_iterator it_end = bindinglist.end(); for (; it != it_end; ++it) { - kb_action action = it->first.action; + kb_action action = it->get<0>().action; string const action_name = lyxaction.getActionName(action); QString const lfun = toqstr(from_utf8(action_name) - + " " + it->first.argument()); - QString const shortcut = toqstr(it->second.print(KeySequence::Portable)); + + " " + it->get<0>().argument()); + QString const shortcut = toqstr(it->get<1>().print(KeySequence::Portable)); QTreeWidgetItem * newItem = NULL; // if an item with the same lfun already exists, insert as a -- 2.39.2