blob: 84120c70e9c9f5f62fe5965343aca62b6088da5a [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtTest/QtTest>
#include <qapplication.h>
#include <qtextedit.h>
#include <qlineedit.h>
#include <qcompleter.h>
#include <qpushbutton.h>
#include <qmainwindow.h>
#include <qstatusbar.h>
#include <qboxlayout.h>
#include <qdebug.h>
#include <qstring.h>
#include <qshortcut.h>
#include <qscreen.h>
QT_BEGIN_NAMESPACE
class QMainWindow;
class QTextEdit;
QT_END_NAMESPACE
class tst_QShortcut : public QObject
{
Q_OBJECT
public:
enum Action {
SetupAccel,
TestAccel,
ClearAll,
TestEnd
};
Q_ENUM(Action)
enum Widget {
NoWidget,
TriggerSlot1,
TriggerSlot2,
TriggerSlot3,
TriggerSlot4,
TriggerSlot5,
TriggerSlot6,
TriggerSlot7,
};
Q_ENUM(Widget)
enum Result {
NoResult,
Slot1Triggered,
Slot2Triggered,
Slot3Triggered,
Slot4Triggered,
Slot5Triggered,
Slot6Triggered,
Slot7Triggered,
SentKeyEvent,
Ambiguous
} currentResult = NoResult;
Q_ENUM(Result)
public slots:
void slotTrig1() { currentResult = Slot1Triggered; }
void slotTrig2() { currentResult = Slot2Triggered; }
void slotTrig3() { currentResult = Slot3Triggered; }
void slotTrig4() { currentResult = Slot4Triggered; }
void slotTrig5() { currentResult = Slot5Triggered; }
void slotTrig6() { currentResult = Slot6Triggered; }
void slotTrig7() { currentResult = Slot7Triggered; }
void ambigSlot1() { currentResult = Ambiguous; ambigResult = Slot1Triggered; }
void ambigSlot2() { currentResult = Ambiguous; ambigResult = Slot2Triggered; }
void ambigSlot3() { currentResult = Ambiguous; ambigResult = Slot3Triggered; }
void ambigSlot4() { currentResult = Ambiguous; ambigResult = Slot4Triggered; }
void ambigSlot5() { currentResult = Ambiguous; ambigResult = Slot5Triggered; }
void ambigSlot6() { currentResult = Ambiguous; ambigResult = Slot6Triggered; }
void ambigSlot7() { currentResult = Ambiguous; ambigResult = Slot7Triggered; }
private slots:
void cleanup();
void number_data();
void number();
void text_data();
void text();
void disabledItems();
void ambiguousItems();
void ambiguousRotation();
void keypressConsumption();
void unicodeCompare();
void context();
void duplicatedShortcutOverride();
void shortcutToFocusProxy();
void deleteLater();
protected:
static Qt::KeyboardModifiers toButtons( int key );
void defElements();
QShortcut *setupShortcut(QWidget *parent, const QString &name, const QKeySequence &ks,
Qt::ShortcutContext context = Qt::WindowShortcut);
QShortcut *setupShortcut(QWidget *parent, const QString &name, Widget testWidget,
const QKeySequence &ks, Qt::ShortcutContext context = Qt::WindowShortcut);
static void sendKeyEvents(QWidget *w, int k1, QChar c1 = 0, int k2 = 0, QChar c2 = 0,
int k3 = 0, QChar c3 = 0, int k4 = 0, QChar c4 = 0);
void testElement();
Result ambigResult;
};
class TestEdit : public QTextEdit
{
Q_OBJECT
public:
TestEdit(QWidget *parent, const char *name)
: QTextEdit(parent)
{
setObjectName(name);
}
protected:
bool event(QEvent *e) override
{
// Make testedit allow any Ctrl+Key as shortcut
if (e->type() == QEvent::ShortcutOverride) {
QKeyEvent *ke = static_cast<QKeyEvent*>(e);
if (ke->modifiers() == Qt::ControlModifier
&& ke->key() > Qt::Key_Any
&& ke->key() < Qt::Key_ydiaeresis) {
ke->ignore();
return true;
}
}
// If keypress not processed as normal, check for
// Ctrl+Key event, and input custom string for
// result comparison.
if (e->type() == QEvent::KeyPress) {
QKeyEvent *ke = static_cast<QKeyEvent*>(e);
if (ke->modifiers() && ke->key() > Qt::Key_Any
&& ke->key() < Qt::Key_ydiaeresis) {
const QChar c = QLatin1Char(char(ke->key()));
if (ke->modifiers() == Qt::ControlModifier)
insertPlainText(QLatin1String("<Ctrl+") + c + QLatin1Char('>'));
else if (ke->modifiers() == Qt::AltModifier)
insertPlainText(QLatin1String("<Alt+") + c + QLatin1Char('>'));
else if (ke->modifiers() == Qt::ShiftModifier)
insertPlainText(QLatin1String("<Shift+") + c + QLatin1Char('>'));
return true;
}
}
return QTextEdit::event(e);
}
};
class MainWindow : public QMainWindow
{
public:
MainWindow();
TestEdit *testEdit() const { return m_testEdit; }
private:
TestEdit *m_testEdit;
};
MainWindow::MainWindow()
{
setWindowFlags(Qt::X11BypassWindowManagerHint);
m_testEdit = new TestEdit(this, "test_edit");
setCentralWidget(m_testEdit);
setFixedSize(200, 200);
}
void tst_QShortcut::cleanup()
{
QVERIFY(QApplication::topLevelWidgets().size() <= 1); // The data driven tests keep a widget around
}
Qt::KeyboardModifiers tst_QShortcut::toButtons( int key )
{
Qt::KeyboardModifiers result = Qt::NoModifier;
if ( key & Qt::SHIFT )
result |= Qt::ShiftModifier;
if ( key & Qt::CTRL )
result |= Qt::ControlModifier;
if ( key & Qt::META )
result |= Qt::MetaModifier;
if ( key & Qt::ALT )
result |= Qt::AltModifier;
return result;
}
void tst_QShortcut::defElements()
{
QTest::addColumn<tst_QShortcut::Action>("action");
QTest::addColumn<tst_QShortcut::Widget>("testWidget");
QTest::addColumn<QString>("txt");
QTest::addColumn<int>("k1");
QTest::addColumn<int>("c1");
QTest::addColumn<int>("k2");
QTest::addColumn<int>("c2");
QTest::addColumn<int>("k3");
QTest::addColumn<int>("c3");
QTest::addColumn<int>("k4");
QTest::addColumn<int>("c4");
QTest::addColumn<tst_QShortcut::Result>("result");
}
void tst_QShortcut::number()
{
// We expect a failure on these tests, until QtTestKeyboard is
// fixed to do real platform dependent keyboard simulations
if (QTest::currentDataTag() == QString("N006a:Shift+Tab - [BackTab]")
|| QTest::currentDataTag() == QString("N006b:Shift+Tab - [Shift+BackTab]"))
QEXPECT_FAIL("", "FLAW IN QTESTKEYBOARD: Keyboard events not passed through "
"platform dependent key handling code", Continue);
testElement();
}
void tst_QShortcut::text()
{
testElement();
}
// ------------------------------------------------------------------
// Number Elements --------------------------------------------------
// ------------------------------------------------------------------
void tst_QShortcut::number_data()
{
defElements();
// Clear all
QTest::newRow("N00 - clear") << ClearAll << NoWidget <<QString()<<0<<0<<0<<0<<0<<0<<0<<0<<NoResult;
//===========================================
// [Shift + key] on non-shift shortcuts testing
//===========================================
/* Testing Single Sequences
Shift + Qt::Key_M on Qt::Key_M
Qt::Key_M on Qt::Key_M
Shift + Qt::Key_Plus on Qt::Key_Pluss
Qt::Key_Plus on Qt::Key_Pluss
*/
QTest::newRow("N001 - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
//commented out because the behaviour changed, those tests should be updated
//QTest::newRow("N001:Shift + M - [M]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_M) << int('M') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("N001:M - [M]") << TestAccel << NoWidget << QString() << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("N001 - slot2") << SetupAccel << TriggerSlot2 << QString() << int(Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
//commented out because the behaviour changed, those tests should be updated
//QTest::newRow("N001:Shift++ [+]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
QTest::newRow("N001:+ [+]") << TestAccel << NoWidget << QString() << int(Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
QTest::newRow("N001 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
/* Testing Single Sequences
Shift + Qt::Key_M on Shift + Qt::Key_M
Qt::Key_M on Shift + Qt::Key_M
Shift + Qt::Key_Plus on Shift + Qt::Key_Pluss
Qt::Key_Plus on Shift + Qt::Key_Pluss
*/
QTest::newRow("N002 - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::SHIFT + Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("N002:Shift+M - [Shift+M]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_M) << int('M') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("N002:M - [Shift+M]") << TestAccel << NoWidget << QString() << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("N002 - slot2") << SetupAccel << TriggerSlot2 << QString() << int(Qt::SHIFT + Qt::Key_Plus) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("N002:Shift++ [Shift++]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
QTest::newRow("N002:+ [Shift++]") << TestAccel << NoWidget << QString() << int(Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("N002 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
/* Testing Single Sequences
Shift + Qt::Key_F1 on Qt::Key_F1
Qt::Key_F1 on Qt::Key_F1
*/
QTest::newRow("N003 - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
//commented out because the behaviour changed, those tests should be updated
//QTest::newRow("N003:Shift+F1 - [F1]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("N003:F1 - [F1]") << TestAccel << NoWidget << QString() << int(Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("N003 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
/* Testing Single Sequences
Shift + Qt::Key_F1 on Shift + Qt::Key_F1
Qt::Key_F1 on Shift + Qt::Key_F1
*/
QTest::newRow("N004 - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::SHIFT + Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("N004:Shift+F1 - [Shift+F1]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("N004:F1 - [Shift+F1]") << TestAccel << NoWidget << QString() << int(Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("N004 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
/* Testing Single Sequences
Qt::Key_Tab on Qt::Key_Tab
Shift + Qt::Key_Tab on Qt::Key_Tab
Qt::Key_Backtab on Qt::Key_Tab
Shift + Qt::Key_Backtab on Qt::Key_Tab
*/
QTest::newRow("N005a - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("N005a:Tab - [Tab]") << TestAccel << NoWidget << QString() << int(Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
//commented out because the behaviour changed, those tests should be updated
//QTest::newRow("N005a:Shift+Tab - [Tab]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
// (Shift+)BackTab != Tab, but Shift+BackTab == Shift+Tab
QTest::newRow("N005a:Backtab - [Tab]") << TestAccel << NoWidget << QString() << int(Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("N005a:Shift+Backtab - [Tab]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("N005a - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
/* Testing Single Sequences
Qt::Key_Tab on Shift + Qt::Key_Tab
Shift + Qt::Key_Tab on Shift + Qt::Key_Tab
Qt::Key_Backtab on Shift + Qt::Key_Tab
Shift + Qt::Key_Backtab on Shift + Qt::Key_Tab
*/
QTest::newRow("N005b - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::SHIFT + Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("N005b:Tab - [Shift+Tab]") << TestAccel << NoWidget << QString() << int(Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("N005b:Shift+Tab - [Shift+Tab]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("N005b:BackTab - [Shift+Tab]") << TestAccel << NoWidget << QString() << int(Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("N005b:Shift+BackTab - [Shift+Tab]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("N005b - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
/* Testing Single Sequences
Qt::Key_Tab on Qt::Key_Backtab
Shift + Qt::Key_Tab on Qt::Key_Backtab
Qt::Key_Backtab on Qt::Key_Backtab
Shift + Qt::Key_Backtab on Qt::Key_Backtab
*/
QTest::newRow("N006a - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("N006a:Tab - [BackTab]") << TestAccel << NoWidget << QString() << int(Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
// This should work, since platform dependent code will transform the
// Shift+Tab into a Shift+BackTab, which should trigger the shortcut
QTest::newRow("N006a:Shift+Tab - [BackTab]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; //XFAIL
QTest::newRow("N006a:BackTab - [BackTab]") << TestAccel << NoWidget << QString() << int(Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
//commented out because the behaviour changed, those tests should be updated
//QTest::newRow("N006a:Shift+BackTab - [BackTab]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("N006a - clear") << ClearAll << NoWidget<< QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
/* Testing Single Sequences
Qt::Key_Tab on Shift + Qt::Key_Backtab
Shift + Qt::Key_Tab on Shift + Qt::Key_Backtab
Qt::Key_Backtab on Shift + Qt::Key_Backtab
Shift + Qt::Key_Backtab on Shift + Qt::Key_Backtab
*/
QTest::newRow("N006b - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::SHIFT + Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("N006b:Tab - [Shift+BackTab]") << TestAccel << NoWidget << QString() << int(Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("N006b:Shift+Tab - [Shift+BackTab]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("N006b:BackTab - [Shift+BackTab]") << TestAccel << NoWidget << QString() << int(Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("N006b:Shift+BackTab - [Shift+BackTab]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; //XFAIL
QTest::newRow("N006b - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
//===========================================
// [Shift + key] and [key] on shortcuts with
// and without modifiers
//===========================================
/* Testing Single Sequences
Qt::Key_F1
Shift + Qt::Key_F1
*/
QTest::newRow("N007 - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("N007 - slot2") << SetupAccel << TriggerSlot2 << QString() << int(Qt::SHIFT + Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("N007:F1") << TestAccel << NoWidget << QString() << int(Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("N007:Shift + F1") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
QTest::newRow("N007 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
/* Testing Single Sequences
Qt::Key_M
Shift + Qt::Key_M
Ctrl + Qt::Key_M
Alt + Qt::Key_M
*/
QTest::newRow("N01 - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("N02 - slot2") << SetupAccel << TriggerSlot2 << QString() << int(Qt::SHIFT + Qt::Key_M) << int('M') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("N03 - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::CTRL + Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("N04 - slot2") << SetupAccel << TriggerSlot2 << QString() << int(Qt::ALT + Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("N:Qt::Key_M") << TestAccel << NoWidget << QString() << int(Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("N:Shift+Qt::Key_M") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_M) << int('M') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
QTest::newRow("N:Ctrl+Qt::Key_M") << TestAccel << NoWidget << QString() << int(Qt::CTRL + Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("N:Alt+Qt::Key_M") << TestAccel << NoWidget << QString() << int(Qt::ALT + Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
/* Testing Single Sequence Ambiguity
Qt::Key_M on shortcut2
*/
QTest::newRow("N05 - slot2") << SetupAccel << TriggerSlot2 << QString() << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("N:Qt::Key_M on slot") << TestAccel << NoWidget << QString() << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << Ambiguous;
QTest::newRow("N05 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
/* Testing Single Specialkeys
Qt::Key_aring
Qt::Key_Aring
Qt::UNICODE_ACCEL + Qt::Key_K
*/
QTest::newRow("N06 - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::Key_Aring) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("N07 - slot2") << SetupAccel << TriggerSlot2 << QString() << int(Qt::SHIFT+Qt::Key_Aring) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("N08 - slot2") << SetupAccel << TriggerSlot1 << QString() << int(Qt::UNICODE_ACCEL + Qt::Key_K) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("N:Qt::Key_aring") << TestAccel << NoWidget << QString() << int(Qt::Key_Aring) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("N:Qt::Key_Aring") << TestAccel << NoWidget << QString() << int(Qt::SHIFT+Qt::Key_Aring) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
QTest::newRow("N:Qt::Key_aring - Text Form") << TestAccel << NoWidget << QString() << 0 << 0xC5 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("N:Qt::Key_Aring - Text Form") << TestAccel << NoWidget << QString() << int(Qt::SHIFT+0) << 0xC5 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
QTest::newRow("N:Qt::UNICODE_ACCEL + Qt::Key_K")<< TestAccel << NoWidget << QString() << int(Qt::UNICODE_ACCEL + Qt::Key_K) << int('k') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("N09 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
/* Testing Multiple Sequences
Qt::Key_M
Qt::Key_I, Qt::Key_M
Shift+Qt::Key_I, Qt::Key_M
*/
QTest::newRow("N10 - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("N11 - slot2") << SetupAccel << TriggerSlot2 << QString() << int(Qt::Key_I) << 0 << int(Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("N12 - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::SHIFT + Qt::Key_I) << 0 << int(Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("N:Qt::Key_M (2)") << TestAccel << NoWidget << QString() << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("N:Qt::Key_I, Qt::Key_M") << TestAccel << NoWidget << QString() << int(Qt::Key_I) << int('i') << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << Slot2Triggered;
QTest::newRow("N:Shift+Qt::Key_I, Qt::Key_M") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_I) << int('I') << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("N:end") << TestEnd << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
}
// ------------------------------------------------------------------
// Text Elements ----------------------------------------------------
// ------------------------------------------------------------------
void tst_QShortcut::text_data()
{
defElements();
// Clear all
QTest::newRow("T00 - clear") << ClearAll << NoWidget <<QString()<<0<<0<<0<<0<<0<<0<<0<<0<< NoResult;
//===========================================
// [Shift + key] on non-shift shortcuts testing
//===========================================
/* Testing Single Sequences
Shift + Qt::Key_M on Qt::Key_M
Qt::Key_M on Qt::Key_M
Shift + Qt::Key_Plus on Qt::Key_Pluss
Qt::Key_Plus on Qt::Key_Pluss
*/
QTest::newRow("T001 - slot1") << SetupAccel << TriggerSlot1 << QString("M") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
//commented out because the behaviour changed, those tests should be updated
//QTest::newRow("T001:Shift+M - [M]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_M) << int('M') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("T001:M - [M]") << TestAccel << NoWidget << QString() << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("T001 - slot2") << SetupAccel << TriggerSlot2 << QString("+") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
//commented out because the behaviour changed, those tests should be updated
//QTest::newRow("T001:Shift++ [+]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
QTest::newRow("T001:+ [+]") << TestAccel << NoWidget << QString() << int(Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
QTest::newRow("T001 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
/* Testing Single Sequences
Shift + Qt::Key_M on Shift + Qt::Key_M
Qt::Key_M on Shift + Qt::Key_M
Shift + Qt::Key_Plus on Shift + Qt::Key_Pluss
Qt::Key_Plus on Shift + Qt::Key_Pluss
Shift + Ctrl + Qt::Key_Plus on Ctrl + Qt::Key_Pluss
Ctrl + Qt::Key_Plus on Ctrl + Qt::Key_Pluss
*/
QTest::newRow("T002 - slot1") << SetupAccel << TriggerSlot1 << QString("Shift+M") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("T002:Shift+M - [Shift+M]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_M) << int('M') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("T002:M - [Shift+M]") << TestAccel << NoWidget << QString() << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("T002 - slot2") << SetupAccel << TriggerSlot2 << QString("Shift++") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("T002:Shift++ [Shift++]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
QTest::newRow("T002:+ [Shift++]") << TestAccel << NoWidget << QString() << int(Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("T002 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
/* Testing Single Sequences
Shift + Ctrl + Qt::Key_Plus on Ctrl + Qt::Key_Plus
Ctrl + Qt::Key_Plus on Ctrl + Qt::Key_Plus
Qt::Key_Plus on Ctrl + Qt::Key_Plus
*/
QTest::newRow("T002b - slot1") << SetupAccel << TriggerSlot1 << QString("Ctrl++") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
//commented out because the behaviour changed, those tests should be updated
//QTest::newRow("T002b:Shift+Ctrl++ [Ctrl++]")<< TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::CTRL + Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("T002b:Ctrl++ [Ctrl++]") << TestAccel << NoWidget << QString() << int(Qt::CTRL + Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("T002b:+ [Ctrl++]") << TestAccel << NoWidget << QString() << int(Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("T002b - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
/* Testing Single Sequences
Shift + Qt::Key_F1 on Qt::Key_F1
Qt::Key_F1 on Qt::Key_F1
*/
QTest::newRow("T003 - slot1") << SetupAccel << TriggerSlot1 << QString("F1") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
//commented out because the behaviour changed, those tests should be updated
//QTest::newRow("T003:Shift+F1 - [F1]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("T003:F1 - [F1]") << TestAccel << NoWidget << QString() << int(Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("T003 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
/* Testing Single Sequences
Shift + Qt::Key_F1 on Shift + Qt::Key_F1
Qt::Key_F1 on Shift + Qt::Key_F1
*/
QTest::newRow("T004 - slot1") << SetupAccel << TriggerSlot1 << QString("Shift+F1") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("T004:Shift+F1 - [Shift+F1]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("T004:F1 - [Shift+F1]") << TestAccel << NoWidget << QString() << int(Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("T004 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
//===========================================
// [Shift + key] and [key] on shortcuts with
// and without modifiers
//===========================================
/* Testing Single Sequences
Qt::Key_F1
Shift + Qt::Key_F1
*/
QTest::newRow("T007 - slot1") << SetupAccel << TriggerSlot1 << QString("F1") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("T007 - slot2") << SetupAccel << TriggerSlot2 << QString("Shift+F1") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("T007:F1") << TestAccel << NoWidget << QString() << int(Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("T007:Shift + F1") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
QTest::newRow("T007 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
/* Testing Single Sequences
Qt::Key_M
Shift + Qt::Key_M
Ctrl + Qt::Key_M
Alt + Qt::Key_M
*/
QTest::newRow("T01 - slot1") << SetupAccel << TriggerSlot1 << QString("M") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("T02 - slot2") << SetupAccel << TriggerSlot2 << QString("Shift+M") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("T03 - slot1") << SetupAccel << TriggerSlot1 << QString("Ctrl+M") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("T04 - slot2") << SetupAccel << TriggerSlot2 << QString("Alt+M") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("T:Qt::Key_M") << TestAccel << NoWidget << QString() << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("T:Shift + Qt::Key_M") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_M) << int('M') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
QTest::newRow("T:Ctrl + Qt::Key_M") << TestAccel << NoWidget << QString() << int(Qt::CTRL + Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("T:Alt + Qt::Key_M") << TestAccel << NoWidget << QString() << int(Qt::ALT + Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
/* Testing Single Sequence Ambiguity
Qt::Key_M on shortcut2
*/
QTest::newRow("T05 - slot2") << SetupAccel << TriggerSlot2 << QString("M") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("T:Qt::Key_M on TriggerSlot2") << TestAccel << NoWidget << QString() << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << Ambiguous;
QTest::newRow("T06 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
/* Testing Single Specialkeys
Qt::Key_aring
Qt::Key_Aring
Qt::UNICODE_ACCEL + Qt::Key_K
*/
/* see comments above on the #ifdef'ery */
QTest::newRow("T06 - slot1") << SetupAccel << TriggerSlot1 << QString::fromLatin1("\x0C5")<< 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("T07 - slot2") << SetupAccel << TriggerSlot2 << QString::fromLatin1("Shift+\x0C5")<< 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("T08 - slot2") << SetupAccel << TriggerSlot1 << QString("K") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("T:Qt::Key_aring") << TestAccel << NoWidget << QString() << int(Qt::Key_Aring) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("T:Qt::Key_Aring") << TestAccel << NoWidget << QString() << int(Qt::SHIFT+Qt::Key_Aring) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
QTest::newRow("T:Qt::Key_aring - Text Form") << TestAccel << NoWidget << QString() << 0 << 0xC5 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("T:Qt::Key_Aring - Text Form") << TestAccel << NoWidget << QString() << int(Qt::SHIFT+0) << 0xC5 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
QTest::newRow("T:Qt::UNICODE_ACCEL + Qt::Key_K")<< TestAccel << NoWidget << QString() << int(Qt::UNICODE_ACCEL + Qt::Key_K) << int('k') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("T09 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
/* Testing Multiple Sequences
Qt::Key_M
Qt::Key_I, Qt::Key_M
Shift+Qt::Key_I, Qt::Key_M
*/
QTest::newRow("T10 - slot1") << SetupAccel << TriggerSlot1 << QString("M") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("T11 - slot2") << SetupAccel << TriggerSlot2 << QString("I, M")<< 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("T12 - slot1") << SetupAccel << TriggerSlot1 << QString("Shift+I, M")<< 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
QTest::newRow("T:Qt::Key_M (2)") << TestAccel << NoWidget << QString() << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("T:Qt::Key_I, Qt::Key_M") << TestAccel << NoWidget << QString() << int(Qt::Key_I) << int('i') << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << Slot2Triggered;
QTest::newRow("T:Shift+Qt::Key_I, Qt::Key_M") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_I) << int('I') << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << Slot1Triggered;
QTest::newRow("T:end") << TestEnd << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
}
class ButtonWidget : public QWidget
{
public:
ButtonWidget();
QPushButton *pushButton1() const { return m_pb1; }
QPushButton *pushButton2() const { return m_pb2; }
private:
QPushButton *m_pb1;
QPushButton *m_pb2;
};
ButtonWidget::ButtonWidget()
{
// Setup two identical shortcuts on different pushbuttons
QString name = QLatin1String("pushbutton-1");
m_pb1 = new QPushButton(name, this);
m_pb1->setObjectName(name);
name = QLatin1String("pushbutton-2");
m_pb2 = new QPushButton(name, this);
m_pb2->setObjectName(name);
auto hLayout = new QHBoxLayout(this);
hLayout->addWidget(m_pb1);
hLayout->addWidget(m_pb2);
hLayout->addStretch();
}
// ------------------------------------------------------------------
// Disabled Elements ------------------------------------------------
// ------------------------------------------------------------------
void tst_QShortcut::disabledItems()
{
ButtonWidget mainW;
mainW.setWindowTitle(QTest::currentTestFunction());
mainW.show();
mainW.activateWindow();
QVERIFY(QTest::qWaitForWindowActive(&mainW));
/* Testing Disabled Shortcuts
Qt::Key_M on slot1
Shift + Qt::Key_M on slot1
Qt::Key_M on slot2 (disabled)
Shift + Qt::Key_M on slot2 (disabled)
*/
// Setup two identical shortcuts on different pushbuttons
auto pb1 = mainW.pushButton1();
auto pb2 = mainW.pushButton2();
const int shiftM = Qt::SHIFT + Qt::Key_M;
QShortcut *cut1 = setupShortcut(pb1, "shortcut1-pb1", TriggerSlot1,
QKeySequence(Qt::Key_M));
QShortcut *cut2 = setupShortcut(pb1, "shortcut2-pb1", TriggerSlot1,
QKeySequence(shiftM));
QShortcut *cut3 = setupShortcut(pb2, "shortcut3-pb2", TriggerSlot2,
QKeySequence(Qt::Key_M));
QShortcut *cut4 = setupShortcut(pb2, "shortcut4-pb2", TriggerSlot2,
QKeySequence(shiftM));
cut3->setEnabled(false);
cut4->setEnabled(false);
currentResult = NoResult;
sendKeyEvents(&mainW, Qt::Key_M, 'm');
QCOMPARE(currentResult, Slot1Triggered);
currentResult = NoResult;
sendKeyEvents(&mainW, shiftM, 'M');
QCOMPARE(currentResult, Slot1Triggered);
cut2->setEnabled(false);
cut4->setEnabled(true);
/* Testing Disabled Shortcuts
Qt::Key_M on slot1
Shift + Qt::Key_M on slot1 (disabled)
Qt::Key_M on slot2 (disabled)
Shift + Qt::Key_M on slot2
*/
currentResult = NoResult;
sendKeyEvents(&mainW, Qt::Key_M, 'm' );
QCOMPARE( currentResult, Slot1Triggered );
currentResult = NoResult;
sendKeyEvents(&mainW, shiftM, 'M' );
QCOMPARE( currentResult, Slot2Triggered );
/* Testing Disabled Accel
Qt::Key_F5 on slot1
Shift + Qt::Key_F5 on slot2 (disabled)
*/
qDeleteAll(mainW.findChildren<QShortcut *>());
const int shiftF5 = Qt::SHIFT + Qt::Key_F5;
cut1 = setupShortcut(pb1, "shortcut1-pb1", TriggerSlot1, QKeySequence(Qt::Key_F5));
cut4 = setupShortcut(pb2, "shortcut4-pb2", TriggerSlot2, QKeySequence(shiftF5));
cut1->setEnabled(true);
cut4->setEnabled(false);
currentResult = NoResult;
sendKeyEvents(&mainW, Qt::Key_F5, 0 );
QCOMPARE( currentResult, Slot1Triggered );
currentResult = NoResult;
sendKeyEvents(&mainW, shiftF5, 0 );
QCOMPARE( currentResult, NoResult );
}
// ------------------------------------------------------------------
// Ambiguous Elements -----------------------------------------------
// ------------------------------------------------------------------
void tst_QShortcut::ambiguousRotation()
{
MainWindow mainW;
const QString name = QLatin1String(QTest::currentTestFunction());
mainW.setWindowTitle(name);
mainW.show();
mainW.activateWindow();
QVERIFY(QTest::qWaitForWindowActive(&mainW));
/* Testing Shortcut rotation scheme
Ctrl + Qt::Key_A on slot1 (disabled)
Ctrl + Qt::Key_A on slot2 (disabled)
Ctrl + Qt::Key_A on slot3
Ctrl + Qt::Key_A on slot4
Ctrl + Qt::Key_A on slot5 (disabled)
Ctrl + Qt::Key_A on slot6
Ctrl + Qt::Key_A on slot7 (disabled)
*/
const int ctrlA = Qt::CTRL + Qt::Key_A;
QKeySequence ctrlA_Sequence(ctrlA);
QShortcut *cut1 = setupShortcut(&mainW, name, TriggerSlot1, ctrlA_Sequence);
QShortcut *cut2 = setupShortcut(&mainW, name, TriggerSlot2, ctrlA_Sequence);
QShortcut *cut3 = setupShortcut(&mainW, name, TriggerSlot3, ctrlA_Sequence);
QShortcut *cut4 = setupShortcut(&mainW, name, TriggerSlot4, ctrlA_Sequence);
QShortcut *cut5 = setupShortcut(&mainW, name, TriggerSlot5, ctrlA_Sequence);
QShortcut *cut6 = setupShortcut(&mainW, name, TriggerSlot6, ctrlA_Sequence);
QShortcut *cut7 = setupShortcut(&mainW, name, TriggerSlot7, ctrlA_Sequence);
cut1->setEnabled(false);
cut2->setEnabled(false);
cut5->setEnabled(false);
cut7->setEnabled(false);
// Test proper rotation
// Start on first
// Go to last
// Go back to first
// Continue...
currentResult = NoResult;
ambigResult = NoResult;
sendKeyEvents(&mainW, ctrlA);
QCOMPARE(currentResult, Ambiguous);
QCOMPARE(ambigResult, Slot3Triggered);
currentResult = NoResult;
ambigResult = NoResult;
sendKeyEvents(&mainW, ctrlA);
QCOMPARE(currentResult, Ambiguous);
QCOMPARE(ambigResult, Slot4Triggered);
currentResult = NoResult;
ambigResult = NoResult;
sendKeyEvents(&mainW, ctrlA);
QCOMPARE(currentResult, Ambiguous);
QCOMPARE(ambigResult, Slot6Triggered);
currentResult = NoResult;
ambigResult = NoResult;
sendKeyEvents(&mainW, ctrlA);
QCOMPARE(currentResult, Ambiguous);
QCOMPARE(ambigResult, Slot3Triggered);
currentResult = NoResult;
ambigResult = NoResult;
sendKeyEvents(&mainW, ctrlA);
QCOMPARE(currentResult, Ambiguous);
QCOMPARE(ambigResult, Slot4Triggered);
currentResult = NoResult;
ambigResult = NoResult;
sendKeyEvents(&mainW, ctrlA);
QCOMPARE(currentResult, Ambiguous);
QCOMPARE(ambigResult, Slot6Triggered);
/* Testing Shortcut rotation scheme
Ctrl + Qt::Key_A on slot1
Ctrl + Qt::Key_A on slot2
Ctrl + Qt::Key_A on slot3 (disabled)
Ctrl + Qt::Key_A on slot4 (disabled)
Ctrl + Qt::Key_A on slot5
Ctrl + Qt::Key_A on slot6 (disabled)
Ctrl + Qt::Key_A on slot7
*/
cut1->setEnabled(true);
cut2->setEnabled(true);
cut5->setEnabled(true);
cut7->setEnabled(true);
cut3->setEnabled(false);
cut4->setEnabled(false);
cut6->setEnabled(false);
currentResult = NoResult;
ambigResult = NoResult;
sendKeyEvents(&mainW, ctrlA);
QCOMPARE(currentResult, Ambiguous);
QCOMPARE(ambigResult, Slot1Triggered);
currentResult = NoResult;
ambigResult = NoResult;
sendKeyEvents(&mainW, ctrlA);
QCOMPARE(currentResult, Ambiguous);
QCOMPARE(ambigResult, Slot2Triggered);
currentResult = NoResult;
ambigResult = NoResult;
sendKeyEvents(&mainW, ctrlA);
QCOMPARE(currentResult, Ambiguous);
QCOMPARE(ambigResult, Slot5Triggered);
currentResult = NoResult;
ambigResult = NoResult;
sendKeyEvents(&mainW, ctrlA);
QCOMPARE(currentResult, Ambiguous);
QCOMPARE(ambigResult, Slot7Triggered);
currentResult = NoResult;
ambigResult = NoResult;
sendKeyEvents(&mainW, ctrlA);
QCOMPARE(currentResult, Ambiguous);
QCOMPARE(ambigResult, Slot1Triggered);
currentResult = NoResult;
ambigResult = NoResult;
sendKeyEvents(&mainW, ctrlA);
QCOMPARE(currentResult, Ambiguous);
QCOMPARE(ambigResult, Slot2Triggered);
currentResult = NoResult;
ambigResult = NoResult;
sendKeyEvents(&mainW, ctrlA);
QCOMPARE(currentResult, Ambiguous);
QCOMPARE(ambigResult, Slot5Triggered);
currentResult = NoResult;
ambigResult = NoResult;
sendKeyEvents(&mainW, ctrlA);
QCOMPARE(currentResult, Ambiguous);
QCOMPARE(ambigResult, Slot7Triggered);
}
void tst_QShortcut::ambiguousItems()
{
ButtonWidget mainW;
mainW.setWindowTitle(QTest::currentTestFunction());
mainW.show();
mainW.activateWindow();
QVERIFY(QTest::qWaitForWindowActive(&mainW));
/* Testing Ambiguous Shortcuts
Qt::Key_M on Pushbutton 1
Qt::Key_M on Pushbutton 2
*/
// Setup two identical shortcuts on different pushbuttons
auto pb1 = mainW.pushButton1();
auto pb2 = mainW.pushButton2();
setupShortcut(pb1, "shortcut1-pb1", TriggerSlot1, QKeySequence(Qt::Key_M));
setupShortcut(pb2, "shortcut2-pb2", TriggerSlot2, QKeySequence(Qt::Key_M));
currentResult = NoResult;
sendKeyEvents(&mainW, Qt::Key_M, 'm' );
QCOMPARE( currentResult, Ambiguous );
QCOMPARE( ambigResult, Slot1Triggered );
currentResult = NoResult;
sendKeyEvents(&mainW, Qt::Key_M, 'm' );
QCOMPARE( currentResult, Ambiguous );
QCOMPARE( ambigResult, Slot2Triggered );
currentResult = NoResult;
sendKeyEvents(&mainW, Qt::Key_M, 'm' );
QCOMPARE( currentResult, Ambiguous );
QCOMPARE( ambigResult, Slot1Triggered );
}
// ------------------------------------------------------------------
// Unicode and non-unicode Elements ---------------------------------
// ------------------------------------------------------------------
void tst_QShortcut::unicodeCompare()
{
ButtonWidget mainW;
mainW.setWindowTitle(QTest::currentTestFunction());
mainW.show();
mainW.activateWindow();
QVERIFY(QTest::qWaitForWindowActive(&mainW));
/* Testing Unicode/non-Unicode Shortcuts
Qt::Key_M on Pushbutton 1
Qt::Key_M on Pushbutton 2
*/
auto pb1 = mainW.pushButton1();
auto pb2 = mainW.pushButton2();
QKeySequence ks1("Ctrl+M"); // Unicode
QKeySequence ks2(Qt::CTRL+Qt::Key_M); // non-Unicode
setupShortcut(pb1, "shortcut1-pb1", TriggerSlot1, ks1);
setupShortcut(pb2, "shortcut2-pb2", TriggerSlot2, ks2);
currentResult = NoResult;
sendKeyEvents(&mainW, Qt::CTRL + Qt::Key_M, 0);
QCOMPARE( currentResult, Ambiguous );
// They _are_ ambiguous, so the QKeySequence operator==
// should indicate the same
QVERIFY( ks1 == ks2 );
QVERIFY( !(ks1 != ks2) );
}
// ------------------------------------------------------------------
// Keypress consumption verification --------------------------------
// ------------------------------------------------------------------
void tst_QShortcut::keypressConsumption()
{
MainWindow mainW;
mainW.setWindowTitle(QTest::currentTestFunction());
mainW.show();
mainW.activateWindow();
QVERIFY(QTest::qWaitForWindowActive(&mainW));
auto edit = mainW.testEdit();
const int ctrlI = Qt::CTRL + Qt::Key_I;
QShortcut *cut1 = setupShortcut(edit, "shortcut1-line", TriggerSlot1, QKeySequence(ctrlI, Qt::Key_A));
QShortcut *cut2 = setupShortcut(edit, "shortcut1-line", TriggerSlot2, QKeySequence(ctrlI, Qt::Key_B));
currentResult = NoResult;
ambigResult = NoResult;
sendKeyEvents(edit, ctrlI, 0); // Send key to edit
QCOMPARE( currentResult, NoResult );
QCOMPARE( ambigResult, NoResult );
QCOMPARE(edit->toPlainText(), QString());
// Make sure next keypress is eaten (failing multiple keysequence)
sendKeyEvents(edit, Qt::Key_C, 'c'); // Send key to edit
QCOMPARE( currentResult, NoResult );
QCOMPARE( ambigResult, NoResult );
QCOMPARE(edit->toPlainText(), QString());
// Next keypress should be normal
sendKeyEvents(edit, Qt::Key_C, 'c'); // Send key to edit
QCOMPARE( currentResult, NoResult );
QCOMPARE( ambigResult, NoResult );
QCOMPARE(edit->toPlainText(), QString("c"));
currentResult = NoResult;
ambigResult = NoResult;
edit->clear();
QCOMPARE(edit->toPlainText().size(), 0);
cut1->setEnabled(false);
cut2->setEnabled(false);
// Make sure keypresses is passed on, since all multiple keysequences
// with Ctrl+I are disabled
sendKeyEvents(edit, Qt::CTRL + Qt::Key_I, 0); // Send key to edit
QCOMPARE( currentResult, NoResult );
QCOMPARE( ambigResult, NoResult );
QVERIFY(edit->toPlainText().endsWith("<Ctrl+I>"));
sendKeyEvents(edit, Qt::Key_A, 'a'); // Send key to edit
QCOMPARE( currentResult, NoResult );
QCOMPARE( ambigResult, NoResult );
QVERIFY(edit->toPlainText().endsWith("<Ctrl+I>a"));
qDeleteAll(mainW.findChildren<QShortcut *>());
edit->clear();
QCOMPARE(edit->toPlainText().size(), 0);
auto cut = setupShortcut(edit, QLatin1String("first"), QKeySequence(Qt::CTRL + Qt::Key_A));
connect(cut, &QShortcut::activated, edit, [this, edit] () {
this->sendKeyEvents(edit, Qt::CTRL + Qt::Key_B, 0);
this->currentResult = tst_QShortcut::SentKeyEvent;
});
// Verify reentrancy when a non-shortcut is triggered as part
// of shortcut processing.
currentResult = NoResult;
ambigResult = NoResult;
sendKeyEvents(edit, Qt::CTRL + Qt::Key_A, 0);
QCOMPARE(currentResult, SentKeyEvent);
QCOMPARE(ambigResult, NoResult);
QCOMPARE(edit->toPlainText(), QLatin1String("<Ctrl+B>"));
}
// ------------------------------------------------------------------
// Context Validation -----------------------------------------------
// ------------------------------------------------------------------
void tst_QShortcut::context()
{
const QString name = QLatin1String(QTest::currentTestFunction());
MainWindow mainW;
mainW.setWindowTitle(name + QLatin1String("_Helper"));
mainW.show();
auto edit = mainW.testEdit();
QWidget myBox;
myBox.setWindowTitle(name);
auto other1 = new TestEdit(&myBox, "test_edit_other1");
auto other2 = new TestEdit(&myBox, "test_edit_other2");
auto layout = new QHBoxLayout(&myBox);
layout->addWidget(other1);
layout->addWidget(other2);
myBox.show();
QVERIFY(QTest::qWaitForWindowExposed(&myBox));
setupShortcut(other1, "ActiveWindow", TriggerSlot1, QKeySequence("Alt+1"), Qt::WindowShortcut);
setupShortcut(other2, "Focus", TriggerSlot2, QKeySequence("Alt+2"), Qt::WidgetShortcut);
setupShortcut(edit, "Application", TriggerSlot3, QKeySequence("Alt+3"), Qt::ApplicationShortcut);
currentResult = NoResult;
ambigResult = NoResult;
edit->clear();
other1->clear();
other2->clear();
// edit doesn't have focus, so ActiveWindow context should work
// ..but Focus context shouldn't..
// Changing focus to edit should make focus context work
// Application context should always work
// Focus on 'other1' edit, so Active Window context should trigger
other1->activateWindow(); // <---
QApplication::setActiveWindow(other1);
QCOMPARE(QApplication::activeWindow(), other1->window());
QCOMPARE(QApplication::focusWidget(), static_cast<QWidget *>(other1));
currentResult = NoResult;
ambigResult = NoResult;
edit->clear();
other1->clear();
other2->clear();
QCOMPARE(QApplication::focusWidget(), static_cast<QWidget *>(other1));
sendKeyEvents(other1, Qt::ALT+Qt::Key_1);
QCOMPARE(currentResult, Slot1Triggered);
QCOMPARE(ambigResult, NoResult);
QCOMPARE(edit->toPlainText(), QString());
QCOMPARE(other1->toPlainText(), QString());
QCOMPARE(other2->toPlainText(), QString());
// ..but not Focus context on 'other2'..
currentResult = NoResult;
ambigResult = NoResult;
edit->clear();
other1->clear();
other2->clear();
sendKeyEvents(other1, Qt::ALT+Qt::Key_2);
QCOMPARE(currentResult, NoResult);
QCOMPARE(ambigResult, NoResult);
QCOMPARE(edit->toPlainText(), QString());
QCOMPARE(other1->toPlainText(), QString("<Alt+2>"));
QCOMPARE(other2->toPlainText(), QString());
// ..however, application global context on 'edit' should..
currentResult = NoResult;
ambigResult = NoResult;
edit->clear();
other1->clear();
other2->clear();
sendKeyEvents(other1, Qt::ALT+Qt::Key_3);
QCOMPARE(currentResult, Slot3Triggered);
QCOMPARE(ambigResult, NoResult);
QCOMPARE(edit->toPlainText(), QString());
QCOMPARE(other1->toPlainText(), QString());
QCOMPARE(other2->toPlainText(), QString());
// Changing focus to 'other2' should make the Focus context there work
other2->activateWindow();
other2->setFocus(); // ###
QTRY_COMPARE(QApplication::activeWindow(), other2->window());
QCOMPARE(QApplication::focusWidget(), static_cast<QWidget *>(other2));
currentResult = NoResult;
ambigResult = NoResult;
edit->clear();
other1->clear();
other2->clear();
sendKeyEvents(other2, Qt::ALT+Qt::Key_2);
QCOMPARE(currentResult, Slot2Triggered);
QCOMPARE(ambigResult, NoResult);
QCOMPARE(edit->toPlainText(), QString());
QCOMPARE(other1->toPlainText(), QString());
QCOMPARE(other2->toPlainText(), QString());
}
// QTBUG-38986, do not generate duplicated QEvent::ShortcutOverride in event processing.
class OverrideCountingWidget : public QWidget
{
public:
using QWidget::QWidget;
int overrideCount = 0;
bool event(QEvent *e) override
{
if (e->type() == QEvent::ShortcutOverride)
overrideCount++;
return QWidget::event(e);
}
};
void tst_QShortcut::duplicatedShortcutOverride()
{
OverrideCountingWidget w;
w.setWindowTitle(Q_FUNC_INFO);
w.resize(200, 200);
w.move(QGuiApplication::primaryScreen()->availableGeometry().center() - QPoint(100, 100));
w.show();
QApplication::setActiveWindow(&w);
QVERIFY(QTest::qWaitForWindowActive(&w));
QTest::keyPress(w.windowHandle(), Qt::Key_A);
QCoreApplication::processEvents();
QCOMPARE(w.overrideCount, 1);
}
QShortcut *tst_QShortcut::setupShortcut(QWidget *parent, const QString &name, const QKeySequence &ks, Qt::ShortcutContext context)
{
// Set up shortcut for next test
auto cut = new QShortcut(ks, parent, nullptr, nullptr, context);
cut->setObjectName(name);
return cut;
}
QShortcut *tst_QShortcut::setupShortcut(QWidget *parent, const QString &name, Widget testWidget,
const QKeySequence &ks, Qt::ShortcutContext context)
{
// Set up shortcut for next test
auto cut = setupShortcut(parent, name, ks, context);
switch (testWidget) {
case TriggerSlot1:
connect(cut, &QShortcut::activated, this, &tst_QShortcut::slotTrig1);
connect(cut, &QShortcut::activatedAmbiguously, this, &tst_QShortcut::ambigSlot1);
break;
case TriggerSlot2:
connect(cut, &QShortcut::activated, this, &tst_QShortcut::slotTrig2);
connect(cut, &QShortcut::activatedAmbiguously, this, &tst_QShortcut::ambigSlot2);
break;
case TriggerSlot3:
connect(cut, &QShortcut::activated, this, &tst_QShortcut::slotTrig3);
connect(cut, &QShortcut::activatedAmbiguously, this, &tst_QShortcut::ambigSlot3);
break;
case TriggerSlot4:
connect(cut, &QShortcut::activated, this, &tst_QShortcut::slotTrig4);
connect(cut, &QShortcut::activatedAmbiguously, this, &tst_QShortcut::ambigSlot4);
break;
case TriggerSlot5:
connect(cut, &QShortcut::activated, this, &tst_QShortcut::slotTrig5);
connect(cut, &QShortcut::activatedAmbiguously, this, &tst_QShortcut::ambigSlot5);
break;
case TriggerSlot6:
connect(cut, &QShortcut::activated, this, &tst_QShortcut::slotTrig6);
connect(cut, &QShortcut::activatedAmbiguously, this, &tst_QShortcut::ambigSlot6);
break;
case TriggerSlot7:
connect(cut, &QShortcut::activated, this, &tst_QShortcut::slotTrig7);
connect(cut, &QShortcut::activatedAmbiguously, this, &tst_QShortcut::ambigSlot7);
break;
case NoWidget:
break;
}
return cut;
}
void tst_QShortcut::sendKeyEvents(QWidget *w, int k1, QChar c1, int k2, QChar c2, int k3, QChar c3, int k4, QChar c4)
{
Qt::KeyboardModifiers b1 = toButtons( k1 );
Qt::KeyboardModifiers b2 = toButtons( k2 );
Qt::KeyboardModifiers b3 = toButtons( k3 );
Qt::KeyboardModifiers b4 = toButtons( k4 );
k1 &= ~Qt::MODIFIER_MASK;
k2 &= ~Qt::MODIFIER_MASK;
k3 &= ~Qt::MODIFIER_MASK;
k4 &= ~Qt::MODIFIER_MASK;
if (k1 || c1.toLatin1()) {
QString c(c1.unicode() == QChar::Null ? QString() : QString(c1));
QTest::sendKeyEvent(QTest::Press, w, static_cast<Qt::Key>(k1), c, b1);
QTest::sendKeyEvent(QTest::Release, w, static_cast<Qt::Key>(k1), c, b1);
}
if (k2 || c2.toLatin1()) {
QString c(c2.unicode() == QChar::Null ? QString() : QString(c2));
QTest::sendKeyEvent(QTest::Press, w, static_cast<Qt::Key>(k2), c, b2);
QTest::sendKeyEvent(QTest::Release, w, static_cast<Qt::Key>(k2), c, b2);
}
if (k3 || c3.toLatin1()) {
QString c(c3.unicode() == QChar::Null ? QString() : QString(c3));
QTest::sendKeyEvent(QTest::Press, w, static_cast<Qt::Key>(k3), c, b3);
QTest::sendKeyEvent(QTest::Release, w, static_cast<Qt::Key>(k3), c, b3);
}
if (k4 || c4.toLatin1()) {
QString c(c4.unicode() == QChar::Null ? QString() : QString(c4));
QTest::sendKeyEvent(QTest::Press, w, static_cast<Qt::Key>(k4), c, b4);
QTest::sendKeyEvent(QTest::Release, w, static_cast<Qt::Key>(k4), c, b4);
}
}
void tst_QShortcut::testElement()
{
static QScopedPointer<MainWindow> mainW;
currentResult = NoResult;
QFETCH(tst_QShortcut::Action, action);
QFETCH(tst_QShortcut::Widget, testWidget);
QFETCH(QString, txt);
QFETCH(int, k1);
QFETCH(int, c1);
QFETCH(int, k2);
QFETCH(int, c2);
QFETCH(int, k3);
QFETCH(int, c3);
QFETCH(int, k4);
QFETCH(int, c4);
QFETCH(tst_QShortcut::Result, result);
if (mainW.isNull()) {
mainW.reset(new MainWindow);
mainW->setWindowTitle(QTest::currentTestFunction());
mainW->show();
mainW->activateWindow();
QVERIFY(QTest::qWaitForWindowActive(mainW.data()));
}
switch (action) {
case ClearAll:
qDeleteAll(mainW->findChildren<QShortcut *>());
break;
case SetupAccel:
setupShortcut(mainW.data(), txt, testWidget, txt.isEmpty()
? QKeySequence(k1, k2, k3, k4) : QKeySequence::fromString(txt));
break;
case TestAccel:
sendKeyEvents(mainW.data(), k1, c1, k2, c2, k3, c3, k4, c4);
QCOMPARE(currentResult, result);
break;
case TestEnd:
mainW.reset();
break;
}
}
void tst_QShortcut::shortcutToFocusProxy()
{
QLineEdit le;
QCompleter completer;
QStringListModel *slm = new QStringListModel(QStringList() << "a0" << "a1" << "a2", &completer);
completer.setModel(slm);
completer.setCompletionMode(QCompleter::PopupCompletion);
le.setCompleter(&completer);
QShortcut *shortcut = new QShortcut(QKeySequence(Qt::ALT + Qt::Key_S), &le);
QObject::connect(shortcut, &QShortcut::activated, &le, &QLineEdit::clear);
le.setFocus();
le.show();
QVERIFY(QTest::qWaitForWindowActive(&le));
QCOMPARE(QApplication::focusWidget(), &le);
QTest::keyEvent(QTest::Press, QApplication::focusWidget(), Qt::Key_A);
QCOMPARE(le.text(), QString::fromLocal8Bit("a"));
QTest::keyEvent(QTest::Press, QApplication::focusWidget(), Qt::Key_Alt);
QTest::keyEvent(QTest::Press, QApplication::focusWidget(), Qt::Key_S, Qt::AltModifier);
QCOMPARE(le.text(), QString());
}
void tst_QShortcut::deleteLater()
{
QWidget w;
QPointer<QShortcut> sc(new QShortcut(QKeySequence(Qt::Key_1), &w));
sc->deleteLater();
QTRY_VERIFY(!sc);
}
QTEST_MAIN(tst_QShortcut)
#include "tst_qshortcut.moc"