From ed1ee0b3624d5bd3ae279f7e9171cb615e77cbbf Mon Sep 17 00:00:00 2001
From: Martin Rotter <rotter@praktik.cz>
Date: Thu, 6 Aug 2020 08:08:46 +0200
Subject: [PATCH] Greatly simplified code for keyboard shortcuts.

---
 .../dynamicshortcutswidget.cpp                |   2 +-
 .../dynamic-shortcuts/shortcutbutton.cpp      | 122 ------------------
 .../dynamic-shortcuts/shortcutbutton.h        |  55 --------
 .../dynamic-shortcuts/shortcutcatcher.cpp     | 112 ++--------------
 .../dynamic-shortcuts/shortcutcatcher.h       |  50 +------
 src/librssguard/librssguard.pro               |   2 -
 6 files changed, 15 insertions(+), 328 deletions(-)
 delete mode 100644 src/librssguard/dynamic-shortcuts/shortcutbutton.cpp
 delete mode 100644 src/librssguard/dynamic-shortcuts/shortcutbutton.h

diff --git a/src/librssguard/dynamic-shortcuts/dynamicshortcutswidget.cpp b/src/librssguard/dynamic-shortcuts/dynamicshortcutswidget.cpp
index 5b65f5be3..789de61c1 100644
--- a/src/librssguard/dynamic-shortcuts/dynamicshortcutswidget.cpp
+++ b/src/librssguard/dynamic-shortcuts/dynamicshortcutswidget.cpp
@@ -3,7 +3,6 @@
 #include "dynamic-shortcuts/dynamicshortcutswidget.h"
 
 #include "definitions/definitions.h"
-#include "dynamic-shortcuts/shortcutbutton.h"
 #include "dynamic-shortcuts/shortcutcatcher.h"
 
 #include <QAction>
@@ -69,6 +68,7 @@ void DynamicShortcutsWidget::populate(QList<QAction*> actions) {
     // Store information for re-initialization of shortcuts
     // of actions when widget gets "confirmed".
     QPair<QAction*, ShortcutCatcher*> new_binding;
+
     new_binding.first = action;
     new_binding.second = catcher;
     m_actionBindings << new_binding;
diff --git a/src/librssguard/dynamic-shortcuts/shortcutbutton.cpp b/src/librssguard/dynamic-shortcuts/shortcutbutton.cpp
deleted file mode 100644
index 89b4dafc3..000000000
--- a/src/librssguard/dynamic-shortcuts/shortcutbutton.cpp
+++ /dev/null
@@ -1,122 +0,0 @@
-// For license of this file, see <project-root-folder>/LICENSE.md.
-
-/******************************************************************************
-   Copyright (c) 2010, Artem Galichkin <doomer3d@gmail.com>
-   All rights reserved.
-
-   Redistribution and use in source and binary forms, with or without
-   modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright
-      notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
-      notice, this list of conditions and the following disclaimer in the
-      documentation and/or other materials provided with the distribution.
- * Neither the name of the <organization> nor the
-      names of its contributors may be used to endorse or promote products
-      derived from this software without specific prior written permission.
-
-   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-   DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
-   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *******************************************************************************/
-
-#include "dynamic-shortcuts/shortcutbutton.h"
-
-#include "dynamic-shortcuts/shortcutcatcher.h"
-
-#include <QKeyEvent>
-
-ShortcutButton::ShortcutButton(ShortcutCatcher* catcher, QWidget* parent)
-  : QPushButton(parent), m_catcher(catcher) {
-  setMinimumWidth(100);
-}
-
-void ShortcutButton::keyPressEvent(QKeyEvent* event) {
-  int pressed_key = event->key();
-
-  if (pressed_key == -1) {
-    m_catcher->doneRecording();
-  }
-
-  const int new_modifiers = event->modifiers() & (Qt::SHIFT | Qt::CTRL | Qt::ALT | Qt::META);
-
-  if (!m_catcher->m_isRecording && (pressed_key == Qt::Key_Return || pressed_key == Qt::Key_Space)) {
-    return;
-  }
-
-  if (!m_catcher->m_isRecording) {
-    QPushButton::keyPressEvent(event);
-    return;
-  }
-
-  event->accept();
-  m_catcher->m_modifierKeys = new_modifiers;
-
-  switch (pressed_key) {
-    case Qt::Key_AltGr:
-      return;
-
-    case Qt::Key_Shift:
-    case Qt::Key_Control:
-    case Qt::Key_Alt:
-    case Qt::Key_Meta:
-    case Qt::Key_Menu:
-      m_catcher->controlModifierlessTimout();
-      m_catcher->updateDisplayShortcut();
-      break;
-
-    default:
-
-      // We now have a valid key press.
-      if (pressed_key != 0) {
-        if ((pressed_key == Qt::Key_Backtab) && (m_catcher->m_modifierKeys & Qt::SHIFT) > 0) {
-          pressed_key = Qt::Key_Tab | m_catcher->m_modifierKeys;
-        }
-        else {
-          pressed_key |= m_catcher->m_modifierKeys;
-        }
-
-        if (m_catcher->m_numKey == 0) {
-          m_catcher->m_currentSequence = QKeySequence(pressed_key);
-        }
-
-        m_catcher->m_numKey++;
-
-        if (m_catcher->m_numKey >= 4) {
-          m_catcher->doneRecording();
-          return;
-        }
-
-        m_catcher->controlModifierlessTimout();
-        m_catcher->updateDisplayShortcut();
-      }
-  }
-}
-
-void ShortcutButton::keyReleaseEvent(QKeyEvent* event) {
-  if (event->key() == -1) {
-    return;
-  }
-
-  if (!m_catcher->m_isRecording) {
-    QPushButton::keyReleaseEvent(event);
-    return;
-  }
-
-  event->accept();
-  const int new_modifiers = event->modifiers() & (Qt::SHIFT | Qt::CTRL | Qt::ALT | Qt::META);
-
-  if ((new_modifiers & m_catcher->m_modifierKeys) < m_catcher->m_modifierKeys) {
-    m_catcher->m_modifierKeys = new_modifiers;
-    m_catcher->controlModifierlessTimout();
-    m_catcher->updateDisplayShortcut();
-  }
-}
diff --git a/src/librssguard/dynamic-shortcuts/shortcutbutton.h b/src/librssguard/dynamic-shortcuts/shortcutbutton.h
deleted file mode 100644
index 9c65777fb..000000000
--- a/src/librssguard/dynamic-shortcuts/shortcutbutton.h
+++ /dev/null
@@ -1,55 +0,0 @@
-// For license of this file, see <project-root-folder>/LICENSE.md.
-
-/******************************************************************************
-   Copyright (c) 2010, Artem Galichkin <doomer3d@gmail.com>
-   All rights reserved.
-
-   Redistribution and use in source and binary forms, with or without
-   modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright
-      notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
-      notice, this list of conditions and the following disclaimer in the
-      documentation and/or other materials provided with the distribution.
- * Neither the name of the <organization> nor the
-      names of its contributors may be used to endorse or promote products
-      derived from this software without specific prior written permission.
-
-   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-   DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
-   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *******************************************************************************/
-
-#ifndef SHORTCUTBUTTON_H
-#define SHORTCUTBUTTON_H
-
-#include <QPushButton>
-
-class ShortcutCatcher;
-
-class ShortcutButton : public QPushButton {
-  Q_OBJECT
-
-  public:
-
-    // Constructors and destructors.
-    explicit ShortcutButton(ShortcutCatcher* catcher, QWidget* parent = nullptr);
-    virtual ~ShortcutButton() = default;
-
-  protected:
-    void keyPressEvent(QKeyEvent* event);
-    void keyReleaseEvent(QKeyEvent* event);
-
-  private:
-    ShortcutCatcher* m_catcher;
-};
-
-#endif // SHORTCUTBUTTON_H
diff --git a/src/librssguard/dynamic-shortcuts/shortcutcatcher.cpp b/src/librssguard/dynamic-shortcuts/shortcutcatcher.cpp
index e6511c959..8021afdf7 100644
--- a/src/librssguard/dynamic-shortcuts/shortcutcatcher.cpp
+++ b/src/librssguard/dynamic-shortcuts/shortcutcatcher.cpp
@@ -1,40 +1,12 @@
 // For license of this file, see <project-root-folder>/LICENSE.md.
 
-/******************************************************************************
-   Copyright (c) 2010, Artem Galichkin <doomer3d@gmail.com>
-   All rights reserved.
-
-   Redistribution and use in source and binary forms, with or without
-   modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright
-      notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
-      notice, this list of conditions and the following disclaimer in the
-      documentation and/or other materials provided with the distribution.
- * Neither the name of the <organization> nor the
-      names of its contributors may be used to endorse or promote products
-      derived from this software without specific prior written permission.
-
-   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-   DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
-   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *******************************************************************************/
-
 #include "dynamic-shortcuts/shortcutcatcher.h"
 
-#include "dynamic-shortcuts/shortcutbutton.h"
 #include "gui/plaintoolbutton.h"
 #include "miscellaneous/iconfactory.h"
 
 #include <QHBoxLayout>
+#include <QKeySequenceEdit>
 
 ShortcutCatcher::ShortcutCatcher(QWidget* parent)
   : QWidget(parent), m_isRecording(false), m_numKey(0), m_modifierKeys(0U) {
@@ -56,89 +28,24 @@ ShortcutCatcher::ShortcutCatcher(QWidget* parent)
   m_btnClear->setToolTip(tr("Clear current shortcut."));
 
   // Clear main shortcut catching button.
-  m_btnChange = new ShortcutButton(this);
-  m_btnChange->setFocusPolicy(Qt::StrongFocus);
-  m_btnChange->setToolTip(tr("Click and hit new shortcut."));
+  m_shortcutBox = new QKeySequenceEdit(this);
+  m_shortcutBox->setFocusPolicy(Qt::StrongFocus);
+  m_shortcutBox->setMinimumWidth(170);
+  m_shortcutBox->setToolTip(tr("Click and hit new shortcut."));
 
   // Add both buttons to the layout.
-  m_layout->addWidget(m_btnChange);
+  m_layout->addWidget(m_shortcutBox);
   m_layout->addWidget(m_btnReset);
   m_layout->addWidget(m_btnClear);
 
   // Establish needed connections.
   connect(m_btnReset, &QToolButton::clicked, this, &ShortcutCatcher::resetShortcut);
   connect(m_btnClear, &QToolButton::clicked, this, &ShortcutCatcher::clearShortcut);
-  connect(m_btnChange, &QToolButton::clicked, this, &ShortcutCatcher::startRecording);
-
-  // Prepare initial state of the control.
-  updateDisplayShortcut();
-}
-
-ShortcutCatcher::~ShortcutCatcher() {
-  delete m_btnReset;
-  delete m_btnChange;
-  delete m_btnClear;
-  delete m_layout;
-}
-
-void ShortcutCatcher::startRecording() {
-  m_numKey = 0;
-  m_modifierKeys = 0;
-  m_currentSequence = QKeySequence();
-  m_isRecording = true;
-  m_btnChange->setDown(true);
-  m_btnChange->grabKeyboard();
-  updateDisplayShortcut();
-}
-
-void ShortcutCatcher::doneRecording() {
-  m_isRecording = false;
-  m_btnChange->releaseKeyboard();
-  m_btnChange->setDown(false);
-  updateDisplayShortcut();
-  emit shortcutChanged(m_currentSequence);
-}
-
-void ShortcutCatcher::controlModifierlessTimout() {
-  if (m_numKey != 0 && m_modifierKeys == 0) {
-    doneRecording();
-  }
-}
-
-void ShortcutCatcher::updateDisplayShortcut() {
-  QString str = m_currentSequence.toString(QKeySequence::NativeText);
-
-  str.replace(QL1S("&"), QL1S("&&"));
-
-  if (m_isRecording) {
-    if (m_modifierKeys != 0) {
-      if (!str.isEmpty()) {
-        str.append(QSL(","));
-      }
-
-      if ((m_modifierKeys& Qt::META) > 0) {
-        str += QL1S("Meta + ");
-      }
-
-      if ((m_modifierKeys& Qt::CTRL) > 0) {
-        str += QL1S("Ctrl + ");
-      }
-
-      if ((m_modifierKeys& Qt::ALT) > 0) {
-        str += QL1S("Alt + ");
-      }
-
-      if ((m_modifierKeys& Qt::SHIFT) > 0) {
-        str += QL1S("Shift + ");
-      }
-    }
-  }
-
-  m_btnChange->setText(str);
+  connect(m_shortcutBox, &QKeySequenceEdit::keySequenceChanged, this, &ShortcutCatcher::shortcutChanged);
 }
 
 QKeySequence ShortcutCatcher::shortcut() const {
-  return m_currentSequence;
+  return m_shortcutBox->keySequence();
 }
 
 void ShortcutCatcher::setDefaultShortcut(const QKeySequence& key) {
@@ -147,8 +54,7 @@ void ShortcutCatcher::setDefaultShortcut(const QKeySequence& key) {
 }
 
 void ShortcutCatcher::setShortcut(const QKeySequence& key) {
-  m_currentSequence = key;
-  doneRecording();
+  m_shortcutBox->setKeySequence(key);
 }
 
 void ShortcutCatcher::resetShortcut() {
diff --git a/src/librssguard/dynamic-shortcuts/shortcutcatcher.h b/src/librssguard/dynamic-shortcuts/shortcutcatcher.h
index d05ea2f27..ecc0483a6 100644
--- a/src/librssguard/dynamic-shortcuts/shortcutcatcher.h
+++ b/src/librssguard/dynamic-shortcuts/shortcutcatcher.h
@@ -1,55 +1,19 @@
 // For license of this file, see <project-root-folder>/LICENSE.md.
 
-/******************************************************************************
-   Copyright (c) 2010, Artem Galichkin <doomer3d@gmail.com>
-   All rights reserved.
-
-   Redistribution and use in source and binary forms, with or without
-   modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright
-      notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
-      notice, this list of conditions and the following disclaimer in the
-      documentation and/or other materials provided with the distribution.
- * Neither the name of the <organization> nor the
-      names of its contributors may be used to endorse or promote products
-      derived from this software without specific prior written permission.
-
-   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-   DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
-   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *******************************************************************************/
-
 #ifndef SHORTCUTCATCHER_H
 #define SHORTCUTCATCHER_H
 
 #include <QWidget>
 
 class QHBoxLayout;
-class QToolButton;
-class ShortcutButton;
+class PlainToolButton;
+class QKeySequenceEdit;
 
 class ShortcutCatcher : public QWidget {
   Q_OBJECT
 
-  friend class ShortcutButton;
-
   public:
-
-    // Constructors and destructors.
     explicit ShortcutCatcher(QWidget* parent = nullptr);
-    virtual ~ShortcutCatcher();
-
-    void controlModifierlessTimout();
-    void updateDisplayShortcut();
 
     QKeySequence shortcut() const;
     void setDefaultShortcut(const QKeySequence& key);
@@ -59,17 +23,13 @@ class ShortcutCatcher : public QWidget {
     void resetShortcut();
     void clearShortcut();
 
-  private slots:
-    void startRecording();
-    void doneRecording();
-
   signals:
     void shortcutChanged(const QKeySequence& seguence);
 
   private:
-    QToolButton* m_btnReset;
-    QToolButton* m_btnClear;
-    ShortcutButton* m_btnChange;
+    PlainToolButton* m_btnReset;
+    PlainToolButton* m_btnClear;
+    QKeySequenceEdit* m_shortcutBox;
     QHBoxLayout* m_layout;
     QKeySequence m_currentSequence;
     QKeySequence m_defaultSequence;
diff --git a/src/librssguard/librssguard.pro b/src/librssguard/librssguard.pro
index 7e60d0bf9..941e52649 100644
--- a/src/librssguard/librssguard.pro
+++ b/src/librssguard/librssguard.pro
@@ -41,7 +41,6 @@ HEADERS += core/feeddownloader.h \
            definitions/definitions.h \
            dynamic-shortcuts/dynamicshortcuts.h \
            dynamic-shortcuts/dynamicshortcutswidget.h \
-           dynamic-shortcuts/shortcutbutton.h \
            dynamic-shortcuts/shortcutcatcher.h \
            exceptions/applicationexception.h \
            exceptions/filteringexception.h \
@@ -187,7 +186,6 @@ SOURCES += core/feeddownloader.cpp \
            core/messagesproxymodel.cpp \
            dynamic-shortcuts/dynamicshortcuts.cpp \
            dynamic-shortcuts/dynamicshortcutswidget.cpp \
-           dynamic-shortcuts/shortcutbutton.cpp \
            dynamic-shortcuts/shortcutcatcher.cpp \
            exceptions/applicationexception.cpp \
            exceptions/filteringexception.cpp \