From f63288063f980c18a55c4756d654032a22bdec25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20L=C3=B6ffler?= Date: Sun, 22 Dec 2019 22:11:21 +0100 Subject: [PATCH] Make shortcuts for autocompletion configurable (fixes #293, #654) Use the following entries in shortcuts.ini: - actionNext_Completion - actionPrevious_Completion - actionNext_Completion_Placeholder - actionPrevious_Completion_Placeholder --- src/CMakeLists.txt | 1 + src/CompletingEdit.cpp | 87 ++++++++++++++++++++++++++++------------ src/CompletingEdit.h | 6 ++- src/CompletingEdit.ui | 48 ++++++++++++++++++++++ trans/TeXworks_trans.pro | 1 + 5 files changed, 115 insertions(+), 28 deletions(-) create mode 100644 src/CompletingEdit.ui diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 35b3c352e..b14155897 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -105,6 +105,7 @@ else () endif () set(TEXWORKS_UIS CitationSelectDialog.ui + CompletingEdit.ui ConfirmDelete.ui Find.ui HardWrapDialog.ui diff --git a/src/CompletingEdit.cpp b/src/CompletingEdit.cpp index 18709b29a..5732b3375 100644 --- a/src/CompletingEdit.cpp +++ b/src/CompletingEdit.cpp @@ -81,10 +81,27 @@ CompletingEdit::CompletingEdit(QWidget *parent /* = nullptr */) connect(this, SIGNAL(textChanged()), lineNumberArea, SLOT(update())); connect(TWApp::instance(), SIGNAL(highlightLineOptionChanged()), this, SLOT(resetExtraSelections())); - + + setupUi(this); + // As these actions are not used in menus/toolbars, we need to manually add + // them to the widget for TWUtils::installCustomShortcuts to work + insertActions(nullptr, {actionNext_Completion, actionPrevious_Completion, actionNext_Completion_Placeholder, actionPrevious_Completion_Placeholder}); + +#ifdef Q_OS_DARWIN + // Backwards compatibility + // Ctrl+Tab is mapped to Command+Tab on the Mac, which is the standard key + // sequence for switching applications. Hence that combination is changed to + // Alt+Tab on the Mac + if (actionNext_Completion_Placeholder->shortcut() == QKeySequence(Qt::CTRL + Qt::Key_Tab)) + actionNext_Completion_Placeholder->setShortcut(QKeySequence(Qt::ALT + Qt::Key_Tab)); + if (actionPrevious_Completion_Placeholder->shortcut() == QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Tab)) + actionPrevious_Completion_Placeholder->setShortcut(QKeySequence(Qt::ALT + Qt::SHIFT + Qt::Key_Tab)); +#endif + cursorPositionChangedSlot(); updateLineNumberAreaWidth(0); updateColors(); + TWUtils::installCustomShortcuts(this); } void CompletingEdit::prefixLines(const QString &prefix) @@ -555,11 +572,12 @@ void CompletingEdit::resetExtraSelections() void CompletingEdit::keyPressEvent(QKeyEvent *e) { - // Shortcut key for command completion - bool isShortcut = (e->key() == Qt::Key_Tab || e->key() == Qt::Key_Backtab); - if (isShortcut && autocompleteEnabled) { - handleCompletionShortcut(e); - return; + if (autocompleteEnabled) { + QKeySequence seq(static_cast(e->modifiers()) | e->key()); + if (seq == actionNext_Completion->shortcut() || seq == actionPrevious_Completion->shortcut() || seq == actionNext_Completion_Placeholder->shortcut() || seq == actionPrevious_Completion_Placeholder->shortcut()) { + if (handleCompletionShortcut(e)) + return; + } } if (!e->text().isEmpty()) @@ -570,6 +588,11 @@ void CompletingEdit::keyPressEvent(QKeyEvent *e) handleReturn(e); break; + case Qt::Key_Tab: + case Qt::Key_Backtab: + handleTab(e); + break; + case Qt::Key_Backspace: handleBackspace(e); break; @@ -813,24 +836,16 @@ void CompletingEdit::smartenQuotes() } } -void CompletingEdit::handleCompletionShortcut(QKeyEvent *e) +// \returns true if shortcut was handled, false otherwise +bool CompletingEdit::handleCompletionShortcut(QKeyEvent *e) { -// usage: -// unmodified: next completion -// shift : previous completion -// ctl/alt : skip to next placeholder (alt on Mac, ctl elsewhere) -// ctl/alt-shift : skip to previous placeholder - -#if defined(Q_OS_DARWIN) - if ((e->modifiers() & ~Qt::ShiftModifier) == Qt::AltModifier) -#else - if ((e->modifiers() & ~Qt::ShiftModifier) == Qt::ControlModifier) -#endif + QKeySequence seq(static_cast(e->modifiers()) | e->key()); + if (seq == actionNext_Completion_Placeholder->shortcut() || seq == actionPrevious_Completion_Placeholder->shortcut()) { - if (!find(QString(0x2022), (e->modifiers() & Qt::ShiftModifier) + if (!find(QString(0x2022), (seq == actionPrevious_Completion_Placeholder->shortcut()) ? QTextDocument::FindBackward : QTextDocument::FindFlags())) QApplication::beep(); - return; + return true; } // if we are at the beginning of the line (i.e., only whitespaces before a @@ -895,10 +910,10 @@ void CompletingEdit::handleCompletionShortcut(QKeyEvent *e) setCompleter(nullptr); } else { - if (e->modifiers() == Qt::ShiftModifier) + if (seq == actionPrevious_Completion->shortcut()) c->setCurrentRow(c->completionCount() - 1); showCurrentCompletion(); - return; + return true; } } break; @@ -906,7 +921,7 @@ void CompletingEdit::handleCompletionShortcut(QKeyEvent *e) } if (c && c->completionCount() > 0) { - if (e->modifiers() == Qt::ShiftModifier) { + if (seq == actionPrevious_Completion->shortcut()) { if (c->currentRow() == 0) { showCompletion(c->completionPrefix()); setCompleter(nullptr); @@ -926,10 +941,14 @@ void CompletingEdit::handleCompletionShortcut(QKeyEvent *e) showCurrentCompletion(); } } - return; + return true; } - - if(!noSelection) { + return false; +} + +void CompletingEdit::handleTab(QKeyEvent * e) +{ + if (textCursor().hasSelection()) { if(e->modifiers() == Qt::ShiftModifier) { unPrefixLines(QString::fromLatin1("\t")); } else { @@ -1307,6 +1326,22 @@ bool CompletingEdit::event(QEvent *e) // derive the colors from the application's palette if (e->type() == QEvent::PaletteChange) updateColors(); + if (e->type() == QEvent::ShortcutOverride) { + auto ke = reinterpret_cast(e); + QKeySequence seq(static_cast(ke->modifiers()) | ke->key()); + if (seq == actionNext_Completion->shortcut() || + seq == actionPrevious_Completion->shortcut() || + seq == actionNext_Completion_Placeholder->shortcut() || + seq == actionPrevious_Completion_Placeholder->shortcut()) + { + // If the key press corresponds to a completion shortcut, accept the + // event to tell Qt not to treat it as a shortcut but to send it to + // the focused widget normally (thereby invoking the keyPressEvent + // handler) + e->accept(); + } + } + return QTextEdit::event(e); } diff --git a/src/CompletingEdit.h b/src/CompletingEdit.h index 5785b5069..78f9336d4 100644 --- a/src/CompletingEdit.h +++ b/src/CompletingEdit.h @@ -24,6 +24,7 @@ #include "document/SpellChecker.h" #include "ui/LineNumberWidget.h" +#include "ui_CompletingEdit.h" #include #include @@ -36,7 +37,7 @@ class QCompleter; class QStandardItemModel; class QTextCodec; -class CompletingEdit : public QTextEdit +class CompletingEdit : public QTextEdit, private Ui::CompletingEdit { Q_OBJECT @@ -130,9 +131,10 @@ private slots: void loadCompletionsFromFile(QStandardItemModel *model, const QString& filename); void loadCompletionFiles(QCompleter *theCompleter); - void handleCompletionShortcut(QKeyEvent *e); + bool handleCompletionShortcut(QKeyEvent *e); void handleReturn(QKeyEvent *e); void handleBackspace(QKeyEvent *e); + void handleTab(QKeyEvent * e); void handleOtherKey(QKeyEvent *e); void maybeSmartenQuote(int offset); diff --git a/src/CompletingEdit.ui b/src/CompletingEdit.ui new file mode 100644 index 000000000..606bd71df --- /dev/null +++ b/src/CompletingEdit.ui @@ -0,0 +1,48 @@ + + + CompletingEdit + + + + 0 + 0 + 100 + 30 + + + + + Next Completion + + + Tab + + + + + Previous Completion + + + Shift+Backtab + + + + + Next Completion Placeholder + + + Ctrl+Tab + + + + + Previous Completion Placeholder + + + Ctrl+Shift+Backtab + + + + + + diff --git a/trans/TeXworks_trans.pro b/trans/TeXworks_trans.pro index 5b2da3fb6..27b664a0e 100644 --- a/trans/TeXworks_trans.pro +++ b/trans/TeXworks_trans.pro @@ -90,6 +90,7 @@ HEADERS = \ FORMS = \ "../src/CitationSelectDialog.ui" \ + "../src/CompletingEdit.ui" \ "../src/ConfirmDelete.ui" \ "../src/Find.ui" \ "../src/HardWrapDialog.ui" \