From 7ade5c43155b376f1af8e13f57f81124013ba79c Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Sat, 29 Jun 2013 15:48:15 +0200 Subject: [PATCH] Added initial implementation of sequence widget --- CMakeLists.txt | 5 ++ src/gui/formmain.ui | 20 +++++- src/gui/formsettings.cpp | 5 ++ src/gui/shortcutbutton.cpp | 122 +++++++++++++++++++++++++++++++++ src/gui/shortcutbutton.h | 23 +++++++ src/gui/shortcutcatcher.cpp | 133 ++++++++++++++++++++++++++++++++++++ src/gui/shortcutcatcher.h | 45 ++++++++++++ 7 files changed, 352 insertions(+), 1 deletion(-) create mode 100644 src/gui/shortcutbutton.cpp create mode 100644 src/gui/shortcutbutton.h create mode 100644 src/gui/shortcutcatcher.cpp create mode 100644 src/gui/shortcutcatcher.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 198f77c0a..41870512b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -164,6 +164,7 @@ set(APP_SOURCES src/gui/formsettings.cpp src/gui/formwelcome.cpp src/gui/formabout.cpp + src/gui/shortcutcatcher.cpp # CORE sources. src/core/debugging.cpp @@ -171,6 +172,7 @@ set(APP_SOURCES src/core/systemfactory.cpp src/core/datetime.cpp src/core/localization.cpp + src/gui/shortcutbutton.cpp # Basic application sources. src/main.cpp @@ -191,6 +193,8 @@ set(APP_HEADERS src/gui/formsettings.h src/gui/formwelcome.h src/gui/formabout.h + src/gui/shortcutcatcher.h + src/gui/shortcutbutton.h # CORE headers. ) @@ -247,6 +251,7 @@ endif(Qt5LinguistTools_FOUND) # Include additional directory paths. include_directories ( ${CMAKE_CURRENT_SOURCE_DIR}/src + ${CMAKE_CURRENT_SOURCE_DIR}/src/gui ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/src ) diff --git a/src/gui/formmain.ui b/src/gui/formmain.ui index 2dc031851..7724dd9b8 100644 --- a/src/gui/formmain.ui +++ b/src/gui/formmain.ui @@ -206,6 +206,16 @@ + + + + 320 + 90 + 211 + 80 + + + @@ -213,7 +223,7 @@ 0 0 800 - 21 + 19 @@ -274,6 +284,14 @@ + + + ShortcutCatcher + QWidget +
shortcutcatcher.h
+ 1 +
+
diff --git a/src/gui/formsettings.cpp b/src/gui/formsettings.cpp index 05b44c143..cb622eff7 100644 --- a/src/gui/formsettings.cpp +++ b/src/gui/formsettings.cpp @@ -77,6 +77,11 @@ void FormSettings::loadLanguage() { } void FormSettings::saveLanguage() { + if (m_ui->m_treeLanguages->currentItem() == nullptr) { + qDebug("No localizations loaded in settings dialog, so no saving for them."); + return; + } + QString actual_lang = Settings::getInstance()->value(APP_CFG_GEN, "language", "en").toString(); diff --git a/src/gui/shortcutbutton.cpp b/src/gui/shortcutbutton.cpp new file mode 100644 index 000000000..0922add2e --- /dev/null +++ b/src/gui/shortcutbutton.cpp @@ -0,0 +1,122 @@ +/****************************************************************************** +Copyright (c) 2010, Artem Galichkin +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 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 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 + +#include "gui/shortcutbutton.h" +#include "gui/shortcutcatcher.h" + + +ShortcutButton::ShortcutButton(ShortcutCatcher *catcher, QWidget *parent) + : QPushButton(parent), m_catcher(catcher) { +} + +ShortcutButton::~ShortcutButton() { +} + +void ShortcutButton::keyPressEvent(QKeyEvent *event) { + int keyQt = event->key(); + + if (keyQt == -1) { + m_catcher->doneRecording(); + } + + Qt::KeyboardModifiers newModifiers = event->modifiers() & + (Qt::SHIFT | Qt::CTRL | Qt::ALT | Qt::META); + + if (m_catcher->m_isRecording == false && (keyQt == Qt::Key_Return || keyQt == Qt::Key_Space)) { + return; + } + + if (m_catcher->m_isRecording == false) { + return QPushButton::keyPressEvent(event); + } + + event->accept(); + m_catcher->m_modifierKeys = newModifiers; + + switch(keyQt) { + 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 (keyQt) { + if ((keyQt == Qt::Key_Backtab) && (m_catcher->m_modifierKeys & Qt::SHIFT)) { + keyQt = Qt::Key_Tab | m_catcher->m_modifierKeys; + } + else { + keyQt |= m_catcher->m_modifierKeys; + } + + if (m_catcher->m_numKey == 0) { + m_catcher->m_currentSequence = QKeySequence(keyQt); + } + + m_catcher->m_numKey++; // increment nuber of pressed keys + + 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 == false) { + return QPushButton::keyReleaseEvent(event); + } + + event->accept(); + + Qt::KeyboardModifiers newModifiers = event->modifiers() & + (Qt::SHIFT | Qt::CTRL | Qt::ALT | Qt::META); + + if ((newModifiers & m_catcher->m_modifierKeys) < m_catcher->m_modifierKeys) { + m_catcher->m_modifierKeys = newModifiers; + m_catcher->controlModifierlessTimout(); + m_catcher->updateDisplayShortcut(); + } +} diff --git a/src/gui/shortcutbutton.h b/src/gui/shortcutbutton.h new file mode 100644 index 000000000..8d674c469 --- /dev/null +++ b/src/gui/shortcutbutton.h @@ -0,0 +1,23 @@ +#ifndef SHORTCUTBUTTON_H +#define SHORTCUTBUTTON_H + +#include + + +class ShortcutCatcher; + +class ShortcutButton : public QPushButton { + Q_OBJECT + public: + explicit ShortcutButton(ShortcutCatcher *catcher, QWidget *parent = 0); + virtual ~ShortcutButton(); + + protected: + void keyPressEvent(QKeyEvent *event); + void keyReleaseEvent(QKeyEvent *event); + + private: + ShortcutCatcher *m_catcher; +}; + +#endif // SHORTCUTBUTTON_H diff --git a/src/gui/shortcutcatcher.cpp b/src/gui/shortcutcatcher.cpp new file mode 100644 index 000000000..5af15cb4e --- /dev/null +++ b/src/gui/shortcutcatcher.cpp @@ -0,0 +1,133 @@ +/****************************************************************************** +Copyright (c) 2010, Artem Galichkin +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 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 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 +#include + +#include "gui/shortcutcatcher.h" +#include "gui/shortcutbutton.h" +#include "gui/themefactory.h" + + +ShortcutCatcher::ShortcutCatcher(QWidget *parent) : QWidget(parent) { + // Setup layout of the control + m_layout = new QHBoxLayout(this); + m_layout->setSpacing(1); + + // Create clear button. + m_clearButton = new QToolButton(this); + m_clearButton->setIcon(ThemeFactory::fromTheme("dialog-cancel")); + m_clearButton->setFocusPolicy(Qt::NoFocus); + + // Clear main shortcut catching button. + m_sequenceButton = new ShortcutButton(this); + m_sequenceButton->setFocusPolicy(Qt::StrongFocus); + + // Add both buttons to the layout. + m_layout->addWidget(m_sequenceButton); + m_layout->addWidget(m_clearButton); + + // Establish needed connections. + connect(m_clearButton, &QToolButton::clicked, this, &ShortcutCatcher::clearKeySequence); + connect(m_sequenceButton, &ShortcutButton::clicked, this, &ShortcutCatcher::startRecording); + + // Prepare initial state of the control. + updateDisplayShortcut(); +} + +ShortcutCatcher::~ShortcutCatcher() { + delete m_clearButton; + delete m_sequenceButton; + delete m_layout; +} + +void ShortcutCatcher::startRecording() { + m_numKey = 0; + m_modifierKeys = 0; + m_currentSequence = QKeySequence(); + m_isRecording = true; + m_sequenceButton->setDown(true); + m_sequenceButton->grabKeyboard(); + + updateDisplayShortcut(); +} + +void ShortcutCatcher::doneRecording() { + m_isRecording = false; + m_sequenceButton->releaseKeyboard(); + m_sequenceButton->setDown(false); + + updateDisplayShortcut(); +} + +void ShortcutCatcher::controlModifierlessTimout() { + if (m_numKey && !m_modifierKeys) { + doneRecording(); + } +} + +void ShortcutCatcher::updateDisplayShortcut() +{ + QString str = m_currentSequence.toString(QKeySequence::NativeText); + str.replace('&', QLatin1String("&&")); + + if (m_isRecording) { + if (m_modifierKeys) { + if (!str.isEmpty()) { + str.append(","); + } + if (m_modifierKeys & Qt::META) { + str += "Meta + "; + } + if (m_modifierKeys & Qt::CTRL) { + str += "Ctrl + "; + } + if (m_modifierKeys & Qt::ALT) { + str += "Alt + "; + } + if (m_modifierKeys & Qt::SHIFT) { + str += "Shift + "; + } + } + } + + m_sequenceButton->setText(str); +} + +QKeySequence ShortcutCatcher::keySequence() const { + return m_currentSequence; +} + +void ShortcutCatcher::setKeySequence(const QKeySequence &key) { + m_currentSequence = m_defaultSequence = key; + doneRecording(); +} + +void ShortcutCatcher::clearKeySequence() { + setKeySequence(m_defaultSequence); +} diff --git a/src/gui/shortcutcatcher.h b/src/gui/shortcutcatcher.h new file mode 100644 index 000000000..1a0a677bd --- /dev/null +++ b/src/gui/shortcutcatcher.h @@ -0,0 +1,45 @@ +#ifndef KEYSEQUENCECATCHER_H +#define KEYSEQUENCECATCHER_H + +#include +#include + + +class QHBoxLayout; +class QToolButton; +class ShortcutButton; + +class ShortcutCatcher : public QWidget { + friend class ShortcutButton; + + Q_OBJECT + public: + explicit ShortcutCatcher(QWidget *parent = 0); + virtual ~ShortcutCatcher(); + + void controlModifierlessTimout(); + void updateDisplayShortcut(); + + protected slots: + void startRecording(); + void doneRecording(); + + public slots: + QKeySequence keySequence() const; + void setKeySequence(const QKeySequence& key); + void clearKeySequence(); + + private: + QToolButton *m_clearButton; + ShortcutButton *m_sequenceButton; + QHBoxLayout *m_layout; + + QKeySequence m_currentSequence; + QKeySequence m_defaultSequence; + + bool m_isRecording; + int m_numKey; + uint m_modifierKeys; +}; + +#endif // KEYSEQUENCECATCHER_H