]> git.lyx.org Git - features.git/commitdiff
add a \unbind keyword and a few utility functions (unbind, write, delkey) to KeyMap...
authorBo Peng <bpeng@lyx.org>
Sat, 20 Oct 2007 20:35:33 +0000 (20:35 +0000)
committerBo Peng <bpeng@lyx.org>
Sat, 20 Oct 2007 20:35:33 +0000 (20:35 +0000)
git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@21088 a592a061-630c-0410-9148-cb99ea01b6c8

src/KeyMap.cpp
src/KeyMap.h
src/frontends/qt4/GuiPrefs.cpp

index da9565929890a05e4f29ac3e9fb5d74871679967..9fe270a8b7fe13aa9324bf986d3a3dbcb28ac9d3 100644 (file)
 
 #include "support/filetools.h"
 
+#include <fstream>
 #include <sstream>
 #include <utility>
 
 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));
                }
        }
 }
index d8069f2d6876bdbc3c8c8f367a33915cdeff0866..06caf1a37ee8e68560cb3903af5deee6f278434e 100644 (file)
@@ -22,6 +22,7 @@
 #include "support/docstream.h"
 
 #include <boost/shared_ptr.hpp>
+#include <boost/tuple/tuple.hpp>
 
 #include <vector>
 #include <deque>
@@ -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<FuncRequest, KeySequence> Binding; 
+       typedef boost::tuple<FuncRequest, KeySequence, int> Binding; 
        typedef std::vector<Binding> 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(); }
index a39e788581ddcd4b4db96f43a613d09ee2067728..265dca2afe8998ab4390fb1cbbcc7a2d9bec6b4b 100644 (file)
@@ -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