From e6dd86863527686b044794137d1a19f9a198d623 Mon Sep 17 00:00:00 2001 From: Bo Peng Date: Fri, 26 Oct 2007 20:43:22 +0000 Subject: [PATCH] PrefShortcuts: improve the Shortcut input dialog * src/KeyMap.h|cpp: change interface and allow bind(KeySequence, FuncRequest) * src/frontends/qt4/CustomizedWidgets.h|cpp: use KeySequence, add event filter from Edwin * src/frontends/qt4/GuiPrefs.cpp: add another column, get KeySequence from the shortcut edit dialog directly git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@21220 a592a061-630c-0410-9148-cb99ea01b6c8 --- src/KeyMap.cpp | 14 +-- src/KeyMap.h | 23 +++-- src/frontends/qt4/CustomizedWidgets.cpp | 116 +++++++++++++++++------- src/frontends/qt4/CustomizedWidgets.h | 17 +++- src/frontends/qt4/GuiPrefs.cpp | 41 +++++---- 5 files changed, 139 insertions(+), 72 deletions(-) diff --git a/src/KeyMap.cpp b/src/KeyMap.cpp index b32bda3e4b..3fbd46ede4 100644 --- a/src/KeyMap.cpp +++ b/src/KeyMap.cpp @@ -67,7 +67,7 @@ size_t KeyMap::bind(string const & seq, FuncRequest const & func) string::size_type const res = k.parse(seq); if (res == string::npos) { - defkey(&k, func); + bind(&k, func); } else { LYXERR(Debug::KBMAP) << "Parse error at position " << res << " in key sequence '" << seq << "'." @@ -84,7 +84,7 @@ size_t KeyMap::unbind(string const & seq, FuncRequest const & func) string::size_type const res = k.parse(seq); if (res == string::npos) - delkey(&k, func); + unbind(&k, func); else LYXERR(Debug::KBMAP) << "Parse error at position " << res << " in key sequence '" << seq << "'." @@ -336,7 +336,7 @@ docstring const KeyMap::print(bool forgui) const } -void KeyMap::defkey(KeySequence * seq, FuncRequest const & func, unsigned int r) +void KeyMap::bind(KeySequence * seq, FuncRequest const & func, unsigned int r) { KeySymbol code = seq->sequence[r]; if (!code.isOK()) @@ -371,7 +371,7 @@ void KeyMap::defkey(KeySequence * seq, FuncRequest const & func, unsigned int r) << endl; return; } else { - it->table->defkey(seq, func, r + 1); + it->table->bind(seq, func, r + 1); return; } } @@ -386,12 +386,12 @@ void KeyMap::defkey(KeySequence * seq, FuncRequest const & func, unsigned int r) newone->table.reset(); } else { newone->table.reset(new KeyMap); - newone->table->defkey(seq, func, r + 1); + newone->table->bind(seq, func, r + 1); } } -void KeyMap::delkey(KeySequence * seq, FuncRequest const & func, unsigned int r) +void KeyMap::unbind(KeySequence * seq, FuncRequest const & func, unsigned int r) { KeySymbol code = seq->sequence[r]; if (!code.isOK()) @@ -415,7 +415,7 @@ void KeyMap::delkey(KeySequence * seq, FuncRequest const & func, unsigned int r) it->table.reset(); } } else if (it->table.get()) { - it->table->delkey(seq, func, r + 1); + it->table->unbind(seq, func, r + 1); if (it->table->empty()) remove = it; return; diff --git a/src/KeyMap.h b/src/KeyMap.h index 06caf1a37e..05709e6905 100644 --- a/src/KeyMap.h +++ b/src/KeyMap.h @@ -36,16 +36,24 @@ class KeySequence; class KeyMap { public: /** - * Bind a key sequence to an action. + * Bind/Unbind a key sequence to an action. * @return 0 on success, or position in string seq where error * occurs. * See KeySequence::parse for the syntax of the seq string */ size_t bind(std::string const & seq, FuncRequest const & func); - - // Unbind a key sequence size_t unbind(std::string const & seq, FuncRequest const & func); + /** + * Define/Undefine an action for a key sequence. + * @param r internal recursion level + */ + void bind(KeySequence * seq, FuncRequest const & func, + unsigned int r = 0); + void unbind(KeySequence * seq, FuncRequest const & func, + unsigned int r = 0); + + // if a keybinding has been defined. bool hasBinding(KeySequence const & seq, FuncRequest const & func, unsigned int r = 0); @@ -141,15 +149,6 @@ private: FuncRequest func; }; - /** - * Define an action for a key sequence. - * @param r internal recursion level - */ - 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 * @param func the action diff --git a/src/frontends/qt4/CustomizedWidgets.cpp b/src/frontends/qt4/CustomizedWidgets.cpp index 0154472fb2..ed9dfee8fd 100644 --- a/src/frontends/qt4/CustomizedWidgets.cpp +++ b/src/frontends/qt4/CustomizedWidgets.cpp @@ -24,16 +24,63 @@ #include "CustomizedWidgets.h" #include "GuiKeySymbol.h" +#include +#include + #include "support/qstring_helpers.h" using lyx::KeySymbol; +using lyx::KeySequence; +using lyx::KeyModifier; using lyx::toqstr; +ShortcutLineEdit::ShortcutLineEdit(QWidget * parent) + : QLineEdit(parent), keysequence_() +{ + QApplication::instance()->installEventFilter(this); + has_cursor_ = false; +} + + +void ShortcutLineEdit::reset() +{ + clear(); + keysequence_ = KeySequence(); +} + + +bool ShortcutLineEdit::eventFilter(QObject * obj, QEvent * e) +{ + if (!has_cursor_) + return false; + + switch (e->type()) { + // swallow these if we have focus and they come from elsewhere + case QEvent::Shortcut: + case QEvent::ShortcutOverride: + if (obj != this) + return true; + default: + break; + } + return false; +} + + +KeySequence const ShortcutLineEdit::getKeySequence() const +{ + return keysequence_; +} + + void ShortcutLineEdit::keyPressEvent(QKeyEvent * e) { - int keyQt = e->key(); - switch (e->key()) { + int const keyQt = e->key(); + if (!keyQt) + return; + + switch(keyQt) { case Qt::Key_AltGr: //or else we get unicode salad case Qt::Key_Shift: case Qt::Key_Control: @@ -41,45 +88,52 @@ void ShortcutLineEdit::keyPressEvent(QKeyEvent * e) case Qt::Key_Meta: break; default: - if (keyQt) { - uint modifierKeys = e->modifiers(); - - QString txt; - if (modifierKeys & Qt::SHIFT) - txt += "S-"; - if (modifierKeys & Qt::CTRL) - txt += "C-"; - if (modifierKeys & Qt::ALT) - txt += "M-"; - - KeySymbol sym; - setKeySymbol(&sym, e); - txt += toqstr(sym.getSymbolName()); - - if (text().isEmpty()) - setText(txt); - else - setText(text() + " " + txt); - } + appendToSequence(e); + setText(toqstr(keysequence_.print(KeySequence::BindFile))); } } -//prevent Qt from special casing Tab and Backtab -bool ShortcutLineEdit::event(QEvent* e) +bool ShortcutLineEdit::event(QEvent * e) { - if (e->type() == QEvent::ShortcutOverride) - return false; - - if (e->type() == QEvent::KeyPress) { - keyPressEvent(static_cast(e)); - return true; + switch (e->type()) { + case QEvent::FocusOut: + has_cursor_ = false; + break; + case QEvent::FocusIn: + has_cursor_ = true; + break; + case QEvent::ShortcutOverride: + keyPressEvent(static_cast(e)); + return true; + case QEvent::KeyRelease: + case QEvent::Shortcut: + case QEvent::KeyPress: + return true; + default: + break; } - return QLineEdit::event(e); } +void ShortcutLineEdit::appendToSequence(QKeyEvent * e) +{ + KeySymbol sym; + setKeySymbol(&sym, e); + + KeyModifier mod = lyx::NoModifier; + if (e->modifiers() & Qt::SHIFT) + mod |= lyx::ShiftModifier; + if (e->modifiers() & Qt::CTRL) + mod |= lyx::ControlModifier; + if (e->modifiers() & Qt::ALT | e->modifiers() & Qt::META) + mod |= lyx::AltModifier; + + keysequence_.addkey(sym, mod, lyx::NoModifier); +} + + QString const SearchLineEdit::hintMessage() const { return toqstr("Search ..."); diff --git a/src/frontends/qt4/CustomizedWidgets.h b/src/frontends/qt4/CustomizedWidgets.h index cb01094446..495f56a3d1 100644 --- a/src/frontends/qt4/CustomizedWidgets.h +++ b/src/frontends/qt4/CustomizedWidgets.h @@ -13,9 +13,11 @@ #ifndef CUSTOMIZEDWIDGETS_H #define CUSTOMIZEDWIDGETS_H -#include -#include #include +#include "KeySequence.h" + +class QEvent; +class QKeyEvent; /** * A lineedit for inputting shortcuts @@ -23,10 +25,17 @@ class ShortcutLineEdit : public QLineEdit { Q_OBJECT public: - ShortcutLineEdit(QWidget * parent) : QLineEdit(parent) {} + ShortcutLineEdit(QWidget * parent); + void reset(); + bool eventFilter(QObject*, QEvent* e ); + lyx::KeySequence const getKeySequence() const; protected Q_SLOTS: + bool event(QEvent* e); void keyPressEvent(QKeyEvent * e); - bool event(QEvent * e); +private: + void appendToSequence(QKeyEvent * e); + lyx::KeySequence keysequence_; + bool has_cursor_; }; diff --git a/src/frontends/qt4/GuiPrefs.cpp b/src/frontends/qt4/GuiPrefs.cpp index 99a4d4fa13..6255e849d1 100644 --- a/src/frontends/qt4/GuiPrefs.cpp +++ b/src/frontends/qt4/GuiPrefs.cpp @@ -1711,9 +1711,10 @@ PrefShortcuts::PrefShortcuts(GuiPreferences * form, QWidget * parent) { setupUi(this); - shortcutsTW->setColumnCount(2); + shortcutsTW->setColumnCount(3); shortcutsTW->headerItem()->setText(0, qt_("Function")); shortcutsTW->headerItem()->setText(1, qt_("Shortcut")); + shortcutsTW->headerItem()->setText(2, qt_("Type")); shortcutsTW->setSortingEnabled(true); // Multi-selection can be annoying. // shortcutsTW->setSelectionMode(QAbstractItemView::MultiSelection); @@ -1841,24 +1842,27 @@ void PrefShortcuts::setItemType(QTreeWidgetItem * item, item_type tag) switch (tag) { case System: color = "black"; + item->setText(2, "System shortcut"); break; case UserBind: color = "green"; + item->setText(2, "User defined shortcut"); break; case UserUnbind: color = "red"; + item->setText(2, "Removed system shortcut"); break; case UserExtraUnbind: color = "purple"; + item->setText(2, "Unmatched removed system shortcut"); break; } + for (int col = 0; col < shortcutsTW->columnCount(); ++col) #if QT_VERSION >= 0x040200 - item->setForeground(0, QBrush(QColor(color))); - item->setForeground(1, QBrush(QColor(color))); + item->setForeground(col, QBrush(QColor(color))); #else - item->setTextColor(0, QColor(color)); - item->setTextColor(1, QColor(color)); + item->setTextColor(col, QColor(color)); #endif } @@ -1870,9 +1874,9 @@ QTreeWidgetItem * PrefShortcuts::insertShortcutItem(FuncRequest const & lfun, string const action_name = lyxaction.getActionName(action); QString const lfun_name = toqstr(from_utf8(action_name) + " " + lfun.argument()); - // use BindFile format instead of a more verbose form Portable - // if the Shortcut dialog can hide all the bind file stuff, - // Portable format can be used. + // use BindFile format instead of a more verbose form Portable. If the + // Shortcut dialog can hide all the bind file stuff, and on_removePB_pressed + // can parse Portable format, Portable format can be used. QString const shortcut = toqstr(seq.print(KeySequence::BindFile)); item_type item_tag = tag; @@ -1942,7 +1946,10 @@ void PrefShortcuts::on_shortcutsTW_itemDoubleClicked() QTreeWidgetItem * item = shortcutsTW->currentItem(); if (item->flags() & Qt::ItemIsSelectable) { shortcut_->lfunLE->setText(item->text(0)); - shortcut_->shortcutLE->setText(item->text(1)); + // clear the shortcut because I assume that a user will enter + // a new shortcut. + shortcut_->shortcutLE->reset(); + shortcut_->shortcutLE->setFocus(); shortcut_->exec(); } } @@ -1965,7 +1972,7 @@ void PrefShortcuts::select_bind() void PrefShortcuts::on_newPB_pressed() { shortcut_->lfunLE->clear(); - shortcut_->shortcutLE->clear(); + shortcut_->shortcutLE->reset(); shortcut_->exec(); } @@ -2046,21 +2053,19 @@ void PrefShortcuts::on_searchLE_textChanged() void PrefShortcuts::shortcut_okPB_pressed() { - string shortcut = fromqstr(shortcut_->shortcutLE->text()); string lfun = fromqstr(shortcut_->lfunLE->text()); FuncRequest func = lyxaction.lookupFunc(lfun); - if (shortcut.empty() || func.action == LFUN_UNKNOWN_ACTION) { + if (func.action == LFUN_UNKNOWN_ACTION) { Alert::error(_("Failed to create shortcut"), _("Unknown or invalid LyX function")); return; } - KeySequence k(0, 0); - string::size_type const res = k.parse(shortcut); - if (res != string::npos) { + KeySequence k = shortcut_->shortcutLE->getKeySequence(); + if (k.length() == 0) { Alert::error(_("Failed to create shortcut"), - _("Invalid key sequence")); + _("Invalid or empty key sequence")); return; } @@ -2073,7 +2078,7 @@ void PrefShortcuts::shortcut_okPB_pressed() QTreeWidgetItem * item = insertShortcutItem(func, k, UserBind); if (item) { - user_bind_.bind(shortcut, func); + user_bind_.bind(&k, func); shortcutsTW->sortItems(0, Qt::AscendingOrder); shortcutsTW->setItemExpanded(item->parent(), true); shortcutsTW->scrollToItem(item); @@ -2087,7 +2092,7 @@ void PrefShortcuts::shortcut_okPB_pressed() void PrefShortcuts::shortcut_clearPB_pressed() { - shortcut_->shortcutLE->clear(); + shortcut_->shortcutLE->reset(); shortcut_->shortcutLE->setFocus(); } -- 2.39.2