1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the test suite of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29
30#include <QtTest/QtTest>
31#include <qapplication.h>
32#include <qtextedit.h>
33#include <qlineedit.h>
34#include <qcompleter.h>
35#include <qpushbutton.h>
36#include <qmainwindow.h>
37#include <qstatusbar.h>
38#include <qboxlayout.h>
39#include <qdebug.h>
40#include <qstring.h>
41#include <qshortcut.h>
42#include <qscreen.h>
43
44QT_BEGIN_NAMESPACE
45class QMainWindow;
46class QTextEdit;
47QT_END_NAMESPACE
48
49class tst_QShortcut : public QObject
50{
51 Q_OBJECT
52public:
53
54 enum Action {
55 SetupAccel,
56 TestAccel,
57 ClearAll,
58 TestEnd
59 };
60 Q_ENUM(Action)
61
62 enum Widget {
63 NoWidget,
64 TriggerSlot1,
65 TriggerSlot2,
66 TriggerSlot3,
67 TriggerSlot4,
68 TriggerSlot5,
69 TriggerSlot6,
70 TriggerSlot7,
71 };
72 Q_ENUM(Widget)
73
74 enum Result {
75 NoResult,
76 Slot1Triggered,
77 Slot2Triggered,
78 Slot3Triggered,
79 Slot4Triggered,
80 Slot5Triggered,
81 Slot6Triggered,
82 Slot7Triggered,
83 SentKeyEvent,
84 Ambiguous
85 } currentResult = NoResult;
86 Q_ENUM(Result)
87
88public slots:
89 void slotTrig1() { currentResult = Slot1Triggered; }
90 void slotTrig2() { currentResult = Slot2Triggered; }
91 void slotTrig3() { currentResult = Slot3Triggered; }
92 void slotTrig4() { currentResult = Slot4Triggered; }
93 void slotTrig5() { currentResult = Slot5Triggered; }
94 void slotTrig6() { currentResult = Slot6Triggered; }
95 void slotTrig7() { currentResult = Slot7Triggered; }
96 void ambigSlot1() { currentResult = Ambiguous; ambigResult = Slot1Triggered; }
97 void ambigSlot2() { currentResult = Ambiguous; ambigResult = Slot2Triggered; }
98 void ambigSlot3() { currentResult = Ambiguous; ambigResult = Slot3Triggered; }
99 void ambigSlot4() { currentResult = Ambiguous; ambigResult = Slot4Triggered; }
100 void ambigSlot5() { currentResult = Ambiguous; ambigResult = Slot5Triggered; }
101 void ambigSlot6() { currentResult = Ambiguous; ambigResult = Slot6Triggered; }
102 void ambigSlot7() { currentResult = Ambiguous; ambigResult = Slot7Triggered; }
103
104private slots:
105 void cleanup();
106 void pmf_connect();
107 void number_data();
108 void number();
109 void text_data();
110 void text();
111 void disabledItems();
112 void ambiguousItems();
113 void ambiguousRotation();
114 void keypressConsumption();
115 void unicodeCompare();
116 void context();
117 void duplicatedShortcutOverride();
118 void shortcutToFocusProxy();
119 void deleteLater();
120
121protected:
122 static Qt::KeyboardModifiers toButtons( int key );
123 void defElements();
124
125 QShortcut *setupShortcut(QWidget *parent, const QString &name, const QKeySequence &ks,
126 Qt::ShortcutContext context = Qt::WindowShortcut);
127 QShortcut *setupShortcut(QWidget *parent, const QString &name, Widget testWidget,
128 const QKeySequence &ks, Qt::ShortcutContext context = Qt::WindowShortcut);
129
130 static void sendKeyEvents(QWidget *w, int k1, QChar c1 = 0, int k2 = 0, QChar c2 = 0,
131 int k3 = 0, QChar c3 = 0, int k4 = 0, QChar c4 = 0);
132
133 void testElement();
134
135 Result ambigResult;
136};
137
138class TestEdit : public QTextEdit
139{
140 Q_OBJECT
141public:
142 TestEdit(QWidget *parent, const char *name)
143 : QTextEdit(parent)
144 {
145 setObjectName(name);
146 }
147
148protected:
149 bool event(QEvent *e) override
150 {
151 // Make testedit allow any Ctrl+Key as shortcut
152 if (e->type() == QEvent::ShortcutOverride) {
153 QKeyEvent *ke = static_cast<QKeyEvent*>(e);
154 if (ke->modifiers() == Qt::ControlModifier
155 && ke->key() > Qt::Key_Any
156 && ke->key() < Qt::Key_ydiaeresis) {
157 ke->ignore();
158 return true;
159 }
160 }
161
162 // If keypress not processed as normal, check for
163 // Ctrl+Key event, and input custom string for
164 // result comparison.
165 if (e->type() == QEvent::KeyPress) {
166 QKeyEvent *ke = static_cast<QKeyEvent*>(e);
167 if (ke->modifiers() && ke->key() > Qt::Key_Any
168 && ke->key() < Qt::Key_ydiaeresis) {
169 const QChar c = QLatin1Char(char(ke->key()));
170 if (ke->modifiers() == Qt::ControlModifier)
171 insertPlainText(text: QLatin1String("<Ctrl+") + c + QLatin1Char('>'));
172 else if (ke->modifiers() == Qt::AltModifier)
173 insertPlainText(text: QLatin1String("<Alt+") + c + QLatin1Char('>'));
174 else if (ke->modifiers() == Qt::ShiftModifier)
175 insertPlainText(text: QLatin1String("<Shift+") + c + QLatin1Char('>'));
176 return true;
177 }
178 }
179 return QTextEdit::event(e);
180 }
181};
182
183class MainWindow : public QMainWindow
184{
185public:
186 MainWindow();
187
188 TestEdit *testEdit() const { return m_testEdit; }
189
190private:
191 TestEdit *m_testEdit;
192};
193
194MainWindow::MainWindow()
195{
196 setWindowFlags(Qt::X11BypassWindowManagerHint);
197 m_testEdit = new TestEdit(this, "test_edit");
198 setCentralWidget(m_testEdit);
199 setFixedSize(w: 200, h: 200);
200}
201
202void tst_QShortcut::cleanup()
203{
204 QVERIFY(QApplication::topLevelWidgets().size() <= 1); // The data driven tests keep a widget around
205}
206
207void tst_QShortcut::pmf_connect()
208{
209 class MyObject : public QObject
210 {
211 public:
212 using QObject::QObject;
213 void onActivated() { ++activated; }
214 void onAmbiguous() { ++ambiguous; }
215 void reset() { activated = 0; ambiguous = 0; }
216 int activated = 0;
217 int ambiguous = 0;
218 } myObject;
219 QWidget parent;
220
221 auto runCheck = [&myObject](QShortcut *sc, int activated, int ambiguous)
222 {
223 myObject.reset();
224 sc->activated();
225 sc->activatedAmbiguously();
226 delete sc;
227 QCOMPARE(myObject.activated, activated);
228 QCOMPARE(myObject.ambiguous, ambiguous);
229 };
230
231 runCheck(new QShortcut(QKeySequence(), &parent,
232 [&myObject]() { ++myObject.activated; }),
233 1, 0);
234 runCheck(new QShortcut(QKeySequence(), &parent,
235 &myObject, &MyObject::onActivated),
236 1, 0);
237 runCheck(new QShortcut(QKeySequence(), &parent,
238 &myObject, &MyObject::onActivated, &MyObject::onAmbiguous),
239 1, 1);
240 runCheck(new QShortcut(QKeySequence(), &parent, &myObject,
241 &MyObject::onActivated, &myObject, &MyObject::onAmbiguous),
242 1, 1);
243}
244
245
246Qt::KeyboardModifiers tst_QShortcut::toButtons( int key )
247{
248 Qt::KeyboardModifiers result = Qt::NoModifier;
249 if ( key & Qt::SHIFT )
250 result |= Qt::ShiftModifier;
251 if ( key & Qt::CTRL )
252 result |= Qt::ControlModifier;
253 if ( key & Qt::META )
254 result |= Qt::MetaModifier;
255 if ( key & Qt::ALT )
256 result |= Qt::AltModifier;
257 return result;
258}
259
260void tst_QShortcut::defElements()
261{
262 QTest::addColumn<tst_QShortcut::Action>(name: "action");
263 QTest::addColumn<tst_QShortcut::Widget>(name: "testWidget");
264 QTest::addColumn<QString>(name: "txt");
265 QTest::addColumn<int>(name: "k1");
266 QTest::addColumn<int>(name: "c1");
267 QTest::addColumn<int>(name: "k2");
268 QTest::addColumn<int>(name: "c2");
269 QTest::addColumn<int>(name: "k3");
270 QTest::addColumn<int>(name: "c3");
271 QTest::addColumn<int>(name: "k4");
272 QTest::addColumn<int>(name: "c4");
273 QTest::addColumn<tst_QShortcut::Result>(name: "result");
274}
275
276void tst_QShortcut::number()
277{
278 // We expect a failure on these tests, until QtTestKeyboard is
279 // fixed to do real platform dependent keyboard simulations
280 if (QTest::currentDataTag() == QString("N006a:Shift+Tab - [BackTab]")
281 || QTest::currentDataTag() == QString("N006b:Shift+Tab - [Shift+BackTab]"))
282 QEXPECT_FAIL("", "FLAW IN QTESTKEYBOARD: Keyboard events not passed through "
283 "platform dependent key handling code", Continue);
284 testElement();
285}
286void tst_QShortcut::text()
287{
288 testElement();
289}
290// ------------------------------------------------------------------
291// Number Elements --------------------------------------------------
292// ------------------------------------------------------------------
293void tst_QShortcut::number_data()
294{
295 defElements();
296
297 // Clear all
298 QTest::newRow(dataTag: "N00 - clear") << ClearAll << NoWidget <<QString()<<0<<0<<0<<0<<0<<0<<0<<0<<NoResult;
299
300 //===========================================
301 // [Shift + key] on non-shift shortcuts testing
302 //===========================================
303
304 /* Testing Single Sequences
305 Shift + Qt::Key_M on Qt::Key_M
306 Qt::Key_M on Qt::Key_M
307 Shift + Qt::Key_Plus on Qt::Key_Pluss
308 Qt::Key_Plus on Qt::Key_Pluss
309 */
310 QTest::newRow(dataTag: "N001 - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
311 //commented out because the behaviour changed, those tests should be updated
312 //QTest::newRow("N001:Shift + M - [M]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_M) << int('M') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
313 QTest::newRow(dataTag: "N001:M - [M]") << TestAccel << NoWidget << QString() << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
314 QTest::newRow(dataTag: "N001 - slot2") << SetupAccel << TriggerSlot2 << QString() << int(Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
315 //commented out because the behaviour changed, those tests should be updated
316 //QTest::newRow("N001:Shift++ [+]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
317 QTest::newRow(dataTag: "N001:+ [+]") << TestAccel << NoWidget << QString() << int(Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
318 QTest::newRow(dataTag: "N001 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
319
320 /* Testing Single Sequences
321 Shift + Qt::Key_M on Shift + Qt::Key_M
322 Qt::Key_M on Shift + Qt::Key_M
323 Shift + Qt::Key_Plus on Shift + Qt::Key_Pluss
324 Qt::Key_Plus on Shift + Qt::Key_Pluss
325 */
326 QTest::newRow(dataTag: "N002 - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::SHIFT + Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
327 QTest::newRow(dataTag: "N002:Shift+M - [Shift+M]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_M) << int('M') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
328 QTest::newRow(dataTag: "N002:M - [Shift+M]") << TestAccel << NoWidget << QString() << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
329 QTest::newRow(dataTag: "N002 - slot2") << SetupAccel << TriggerSlot2 << QString() << int(Qt::SHIFT + Qt::Key_Plus) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
330 QTest::newRow(dataTag: "N002:Shift++ [Shift++]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
331 QTest::newRow(dataTag: "N002:+ [Shift++]") << TestAccel << NoWidget << QString() << int(Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
332 QTest::newRow(dataTag: "N002 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
333
334 /* Testing Single Sequences
335 Shift + Qt::Key_F1 on Qt::Key_F1
336 Qt::Key_F1 on Qt::Key_F1
337 */
338 QTest::newRow(dataTag: "N003 - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
339 //commented out because the behaviour changed, those tests should be updated
340 //QTest::newRow("N003:Shift+F1 - [F1]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
341 QTest::newRow(dataTag: "N003:F1 - [F1]") << TestAccel << NoWidget << QString() << int(Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
342 QTest::newRow(dataTag: "N003 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
343 /* Testing Single Sequences
344 Shift + Qt::Key_F1 on Shift + Qt::Key_F1
345 Qt::Key_F1 on Shift + Qt::Key_F1
346 */
347
348 QTest::newRow(dataTag: "N004 - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::SHIFT + Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
349 QTest::newRow(dataTag: "N004:Shift+F1 - [Shift+F1]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
350 QTest::newRow(dataTag: "N004:F1 - [Shift+F1]") << TestAccel << NoWidget << QString() << int(Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
351 QTest::newRow(dataTag: "N004 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
352
353 /* Testing Single Sequences
354 Qt::Key_Tab on Qt::Key_Tab
355 Shift + Qt::Key_Tab on Qt::Key_Tab
356 Qt::Key_Backtab on Qt::Key_Tab
357 Shift + Qt::Key_Backtab on Qt::Key_Tab
358 */
359 QTest::newRow(dataTag: "N005a - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
360 QTest::newRow(dataTag: "N005a:Tab - [Tab]") << TestAccel << NoWidget << QString() << int(Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
361 //commented out because the behaviour changed, those tests should be updated
362 //QTest::newRow("N005a:Shift+Tab - [Tab]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
363 // (Shift+)BackTab != Tab, but Shift+BackTab == Shift+Tab
364 QTest::newRow(dataTag: "N005a:Backtab - [Tab]") << TestAccel << NoWidget << QString() << int(Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
365 QTest::newRow(dataTag: "N005a:Shift+Backtab - [Tab]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
366 QTest::newRow(dataTag: "N005a - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
367
368 /* Testing Single Sequences
369 Qt::Key_Tab on Shift + Qt::Key_Tab
370 Shift + Qt::Key_Tab on Shift + Qt::Key_Tab
371 Qt::Key_Backtab on Shift + Qt::Key_Tab
372 Shift + Qt::Key_Backtab on Shift + Qt::Key_Tab
373 */
374 QTest::newRow(dataTag: "N005b - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::SHIFT + Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
375 QTest::newRow(dataTag: "N005b:Tab - [Shift+Tab]") << TestAccel << NoWidget << QString() << int(Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
376 QTest::newRow(dataTag: "N005b:Shift+Tab - [Shift+Tab]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
377 QTest::newRow(dataTag: "N005b:BackTab - [Shift+Tab]") << TestAccel << NoWidget << QString() << int(Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
378 QTest::newRow(dataTag: "N005b:Shift+BackTab - [Shift+Tab]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
379 QTest::newRow(dataTag: "N005b - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
380
381 /* Testing Single Sequences
382 Qt::Key_Tab on Qt::Key_Backtab
383 Shift + Qt::Key_Tab on Qt::Key_Backtab
384 Qt::Key_Backtab on Qt::Key_Backtab
385 Shift + Qt::Key_Backtab on Qt::Key_Backtab
386 */
387 QTest::newRow(dataTag: "N006a - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
388 QTest::newRow(dataTag: "N006a:Tab - [BackTab]") << TestAccel << NoWidget << QString() << int(Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
389 // This should work, since platform dependent code will transform the
390 // Shift+Tab into a Shift+BackTab, which should trigger the shortcut
391 QTest::newRow(dataTag: "N006a:Shift+Tab - [BackTab]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; //XFAIL
392 QTest::newRow(dataTag: "N006a:BackTab - [BackTab]") << TestAccel << NoWidget << QString() << int(Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
393 //commented out because the behaviour changed, those tests should be updated
394 //QTest::newRow("N006a:Shift+BackTab - [BackTab]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
395 QTest::newRow(dataTag: "N006a - clear") << ClearAll << NoWidget<< QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
396
397 /* Testing Single Sequences
398 Qt::Key_Tab on Shift + Qt::Key_Backtab
399 Shift + Qt::Key_Tab on Shift + Qt::Key_Backtab
400 Qt::Key_Backtab on Shift + Qt::Key_Backtab
401 Shift + Qt::Key_Backtab on Shift + Qt::Key_Backtab
402 */
403 QTest::newRow(dataTag: "N006b - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::SHIFT + Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
404 QTest::newRow(dataTag: "N006b:Tab - [Shift+BackTab]") << TestAccel << NoWidget << QString() << int(Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
405 QTest::newRow(dataTag: "N006b:Shift+Tab - [Shift+BackTab]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
406 QTest::newRow(dataTag: "N006b:BackTab - [Shift+BackTab]") << TestAccel << NoWidget << QString() << int(Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
407 QTest::newRow(dataTag: "N006b:Shift+BackTab - [Shift+BackTab]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; //XFAIL
408 QTest::newRow(dataTag: "N006b - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
409
410 //===========================================
411 // [Shift + key] and [key] on shortcuts with
412 // and without modifiers
413 //===========================================
414
415 /* Testing Single Sequences
416 Qt::Key_F1
417 Shift + Qt::Key_F1
418 */
419 QTest::newRow(dataTag: "N007 - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
420 QTest::newRow(dataTag: "N007 - slot2") << SetupAccel << TriggerSlot2 << QString() << int(Qt::SHIFT + Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
421 QTest::newRow(dataTag: "N007:F1") << TestAccel << NoWidget << QString() << int(Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
422 QTest::newRow(dataTag: "N007:Shift + F1") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
423 QTest::newRow(dataTag: "N007 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
424
425 /* Testing Single Sequences
426 Qt::Key_M
427 Shift + Qt::Key_M
428 Ctrl + Qt::Key_M
429 Alt + Qt::Key_M
430 */
431 QTest::newRow(dataTag: "N01 - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
432 QTest::newRow(dataTag: "N02 - slot2") << SetupAccel << TriggerSlot2 << QString() << int(Qt::SHIFT + Qt::Key_M) << int('M') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
433 QTest::newRow(dataTag: "N03 - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::CTRL + Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
434 QTest::newRow(dataTag: "N04 - slot2") << SetupAccel << TriggerSlot2 << QString() << int(Qt::ALT + Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
435 QTest::newRow(dataTag: "N:Qt::Key_M") << TestAccel << NoWidget << QString() << int(Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
436 QTest::newRow(dataTag: "N:Shift+Qt::Key_M") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_M) << int('M') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
437 QTest::newRow(dataTag: "N:Ctrl+Qt::Key_M") << TestAccel << NoWidget << QString() << int(Qt::CTRL + Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
438 QTest::newRow(dataTag: "N:Alt+Qt::Key_M") << TestAccel << NoWidget << QString() << int(Qt::ALT + Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
439
440 /* Testing Single Sequence Ambiguity
441 Qt::Key_M on shortcut2
442 */
443 QTest::newRow(dataTag: "N05 - slot2") << SetupAccel << TriggerSlot2 << QString() << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
444 QTest::newRow(dataTag: "N:Qt::Key_M on slot") << TestAccel << NoWidget << QString() << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << Ambiguous;
445 QTest::newRow(dataTag: "N05 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
446
447 /* Testing Single Specialkeys
448 Qt::Key_aring
449 Qt::Key_Aring
450 Qt::UNICODE_ACCEL + Qt::Key_K
451 */
452 QTest::newRow(dataTag: "N06 - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::Key_Aring) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
453 QTest::newRow(dataTag: "N07 - slot2") << SetupAccel << TriggerSlot2 << QString() << int(Qt::SHIFT+Qt::Key_Aring) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
454 QTest::newRow(dataTag: "N08 - slot2") << SetupAccel << TriggerSlot1 << QString() << int(Qt::UNICODE_ACCEL + Qt::Key_K) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
455
456 QTest::newRow(dataTag: "N:Qt::Key_aring") << TestAccel << NoWidget << QString() << int(Qt::Key_Aring) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
457 QTest::newRow(dataTag: "N:Qt::Key_Aring") << TestAccel << NoWidget << QString() << int(Qt::SHIFT+Qt::Key_Aring) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
458 QTest::newRow(dataTag: "N:Qt::Key_aring - Text Form") << TestAccel << NoWidget << QString() << 0 << 0xC5 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
459 QTest::newRow(dataTag: "N:Qt::Key_Aring - Text Form") << TestAccel << NoWidget << QString() << int(Qt::SHIFT+0) << 0xC5 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
460 QTest::newRow(dataTag: "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;
461 QTest::newRow(dataTag: "N09 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
462
463 /* Testing Multiple Sequences
464 Qt::Key_M
465 Qt::Key_I, Qt::Key_M
466 Shift+Qt::Key_I, Qt::Key_M
467 */
468 QTest::newRow(dataTag: "N10 - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
469 QTest::newRow(dataTag: "N11 - slot2") << SetupAccel << TriggerSlot2 << QString() << int(Qt::Key_I) << 0 << int(Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << NoResult;
470 QTest::newRow(dataTag: "N12 - slot1") << SetupAccel << TriggerSlot1 << QString() << int(Qt::SHIFT + Qt::Key_I) << 0 << int(Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << NoResult;
471
472 QTest::newRow(dataTag: "N:Qt::Key_M (2)") << TestAccel << NoWidget << QString() << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
473 QTest::newRow(dataTag: "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;
474 QTest::newRow(dataTag: "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;
475 QTest::newRow(dataTag: "N:end") << TestEnd << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
476}
477
478// ------------------------------------------------------------------
479// Text Elements ----------------------------------------------------
480// ------------------------------------------------------------------
481void tst_QShortcut::text_data()
482{
483 defElements();
484 // Clear all
485 QTest::newRow(dataTag: "T00 - clear") << ClearAll << NoWidget <<QString()<<0<<0<<0<<0<<0<<0<<0<<0<< NoResult;
486
487 //===========================================
488 // [Shift + key] on non-shift shortcuts testing
489 //===========================================
490
491 /* Testing Single Sequences
492 Shift + Qt::Key_M on Qt::Key_M
493 Qt::Key_M on Qt::Key_M
494 Shift + Qt::Key_Plus on Qt::Key_Pluss
495 Qt::Key_Plus on Qt::Key_Pluss
496 */
497 QTest::newRow(dataTag: "T001 - slot1") << SetupAccel << TriggerSlot1 << QString("M") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
498 //commented out because the behaviour changed, those tests should be updated
499 //QTest::newRow("T001:Shift+M - [M]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_M) << int('M') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
500 QTest::newRow(dataTag: "T001:M - [M]") << TestAccel << NoWidget << QString() << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
501 QTest::newRow(dataTag: "T001 - slot2") << SetupAccel << TriggerSlot2 << QString("+") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
502 //commented out because the behaviour changed, those tests should be updated
503 //QTest::newRow("T001:Shift++ [+]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
504 QTest::newRow(dataTag: "T001:+ [+]") << TestAccel << NoWidget << QString() << int(Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
505 QTest::newRow(dataTag: "T001 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
506
507 /* Testing Single Sequences
508 Shift + Qt::Key_M on Shift + Qt::Key_M
509 Qt::Key_M on Shift + Qt::Key_M
510 Shift + Qt::Key_Plus on Shift + Qt::Key_Pluss
511 Qt::Key_Plus on Shift + Qt::Key_Pluss
512 Shift + Ctrl + Qt::Key_Plus on Ctrl + Qt::Key_Pluss
513 Ctrl + Qt::Key_Plus on Ctrl + Qt::Key_Pluss
514 */
515 QTest::newRow(dataTag: "T002 - slot1") << SetupAccel << TriggerSlot1 << QString("Shift+M") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
516 QTest::newRow(dataTag: "T002:Shift+M - [Shift+M]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_M) << int('M') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
517 QTest::newRow(dataTag: "T002:M - [Shift+M]") << TestAccel << NoWidget << QString() << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
518 QTest::newRow(dataTag: "T002 - slot2") << SetupAccel << TriggerSlot2 << QString("Shift++") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
519 QTest::newRow(dataTag: "T002:Shift++ [Shift++]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
520 QTest::newRow(dataTag: "T002:+ [Shift++]") << TestAccel << NoWidget << QString() << int(Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
521 QTest::newRow(dataTag: "T002 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
522
523 /* Testing Single Sequences
524 Shift + Ctrl + Qt::Key_Plus on Ctrl + Qt::Key_Plus
525 Ctrl + Qt::Key_Plus on Ctrl + Qt::Key_Plus
526 Qt::Key_Plus on Ctrl + Qt::Key_Plus
527 */
528 QTest::newRow(dataTag: "T002b - slot1") << SetupAccel << TriggerSlot1 << QString("Ctrl++") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
529 //commented out because the behaviour changed, those tests should be updated
530 //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;
531 QTest::newRow(dataTag: "T002b:Ctrl++ [Ctrl++]") << TestAccel << NoWidget << QString() << int(Qt::CTRL + Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
532 QTest::newRow(dataTag: "T002b:+ [Ctrl++]") << TestAccel << NoWidget << QString() << int(Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
533 QTest::newRow(dataTag: "T002b - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
534
535 /* Testing Single Sequences
536 Shift + Qt::Key_F1 on Qt::Key_F1
537 Qt::Key_F1 on Qt::Key_F1
538 */
539 QTest::newRow(dataTag: "T003 - slot1") << SetupAccel << TriggerSlot1 << QString("F1") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
540 //commented out because the behaviour changed, those tests should be updated
541 //QTest::newRow("T003:Shift+F1 - [F1]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
542 QTest::newRow(dataTag: "T003:F1 - [F1]") << TestAccel << NoWidget << QString() << int(Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
543 QTest::newRow(dataTag: "T003 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
544
545 /* Testing Single Sequences
546 Shift + Qt::Key_F1 on Shift + Qt::Key_F1
547 Qt::Key_F1 on Shift + Qt::Key_F1
548 */
549 QTest::newRow(dataTag: "T004 - slot1") << SetupAccel << TriggerSlot1 << QString("Shift+F1") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
550 QTest::newRow(dataTag: "T004:Shift+F1 - [Shift+F1]") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
551 QTest::newRow(dataTag: "T004:F1 - [Shift+F1]") << TestAccel << NoWidget << QString() << int(Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
552 QTest::newRow(dataTag: "T004 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
553
554 //===========================================
555 // [Shift + key] and [key] on shortcuts with
556 // and without modifiers
557 //===========================================
558
559 /* Testing Single Sequences
560 Qt::Key_F1
561 Shift + Qt::Key_F1
562 */
563 QTest::newRow(dataTag: "T007 - slot1") << SetupAccel << TriggerSlot1 << QString("F1") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
564 QTest::newRow(dataTag: "T007 - slot2") << SetupAccel << TriggerSlot2 << QString("Shift+F1") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
565 QTest::newRow(dataTag: "T007:F1") << TestAccel << NoWidget << QString() << int(Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
566 QTest::newRow(dataTag: "T007:Shift + F1") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
567 QTest::newRow(dataTag: "T007 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
568
569 /* Testing Single Sequences
570 Qt::Key_M
571 Shift + Qt::Key_M
572 Ctrl + Qt::Key_M
573 Alt + Qt::Key_M
574 */
575 QTest::newRow(dataTag: "T01 - slot1") << SetupAccel << TriggerSlot1 << QString("M") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
576 QTest::newRow(dataTag: "T02 - slot2") << SetupAccel << TriggerSlot2 << QString("Shift+M") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
577 QTest::newRow(dataTag: "T03 - slot1") << SetupAccel << TriggerSlot1 << QString("Ctrl+M") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
578 QTest::newRow(dataTag: "T04 - slot2") << SetupAccel << TriggerSlot2 << QString("Alt+M") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
579
580 QTest::newRow(dataTag: "T:Qt::Key_M") << TestAccel << NoWidget << QString() << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
581 QTest::newRow(dataTag: "T:Shift + Qt::Key_M") << TestAccel << NoWidget << QString() << int(Qt::SHIFT + Qt::Key_M) << int('M') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
582 QTest::newRow(dataTag: "T:Ctrl + Qt::Key_M") << TestAccel << NoWidget << QString() << int(Qt::CTRL + Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
583 QTest::newRow(dataTag: "T:Alt + Qt::Key_M") << TestAccel << NoWidget << QString() << int(Qt::ALT + Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
584
585 /* Testing Single Sequence Ambiguity
586 Qt::Key_M on shortcut2
587 */
588 QTest::newRow(dataTag: "T05 - slot2") << SetupAccel << TriggerSlot2 << QString("M") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
589 QTest::newRow(dataTag: "T:Qt::Key_M on TriggerSlot2") << TestAccel << NoWidget << QString() << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << Ambiguous;
590 QTest::newRow(dataTag: "T06 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
591
592 /* Testing Single Specialkeys
593 Qt::Key_aring
594 Qt::Key_Aring
595 Qt::UNICODE_ACCEL + Qt::Key_K
596 */
597 /* see comments above on the #ifdef'ery */
598 QTest::newRow(dataTag: "T06 - slot1") << SetupAccel << TriggerSlot1 << QString::fromLatin1(str: "\x0C5")<< 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
599 QTest::newRow(dataTag: "T07 - slot2") << SetupAccel << TriggerSlot2 << QString::fromLatin1(str: "Shift+\x0C5")<< 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
600 QTest::newRow(dataTag: "T08 - slot2") << SetupAccel << TriggerSlot1 << QString("K") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
601 QTest::newRow(dataTag: "T:Qt::Key_aring") << TestAccel << NoWidget << QString() << int(Qt::Key_Aring) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
602 QTest::newRow(dataTag: "T:Qt::Key_Aring") << TestAccel << NoWidget << QString() << int(Qt::SHIFT+Qt::Key_Aring) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
603 QTest::newRow(dataTag: "T:Qt::Key_aring - Text Form") << TestAccel << NoWidget << QString() << 0 << 0xC5 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
604 QTest::newRow(dataTag: "T:Qt::Key_Aring - Text Form") << TestAccel << NoWidget << QString() << int(Qt::SHIFT+0) << 0xC5 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered;
605 QTest::newRow(dataTag: "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;
606 QTest::newRow(dataTag: "T09 - clear") << ClearAll << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; // Clear all
607
608 /* Testing Multiple Sequences
609 Qt::Key_M
610 Qt::Key_I, Qt::Key_M
611 Shift+Qt::Key_I, Qt::Key_M
612 */
613 QTest::newRow(dataTag: "T10 - slot1") << SetupAccel << TriggerSlot1 << QString("M") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
614 QTest::newRow(dataTag: "T11 - slot2") << SetupAccel << TriggerSlot2 << QString("I, M")<< 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
615 QTest::newRow(dataTag: "T12 - slot1") << SetupAccel << TriggerSlot1 << QString("Shift+I, M")<< 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
616 QTest::newRow(dataTag: "T:Qt::Key_M (2)") << TestAccel << NoWidget << QString() << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered;
617 QTest::newRow(dataTag: "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;
618 QTest::newRow(dataTag: "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;
619 QTest::newRow(dataTag: "T:end") << TestEnd << NoWidget << QString() << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult;
620}
621
622class ButtonWidget : public QWidget
623{
624public:
625 ButtonWidget();
626
627 QPushButton *pushButton1() const { return m_pb1; }
628 QPushButton *pushButton2() const { return m_pb2; }
629
630private:
631 QPushButton *m_pb1;
632 QPushButton *m_pb2;
633};
634
635ButtonWidget::ButtonWidget()
636{
637 // Setup two identical shortcuts on different pushbuttons
638 QString name = QLatin1String("pushbutton-1");
639 m_pb1 = new QPushButton(name, this);
640 m_pb1->setObjectName(name);
641 name = QLatin1String("pushbutton-2");
642 m_pb2 = new QPushButton(name, this);
643 m_pb2->setObjectName(name);
644 auto hLayout = new QHBoxLayout(this);
645 hLayout->addWidget(m_pb1);
646 hLayout->addWidget(m_pb2);
647 hLayout->addStretch();
648}
649
650// ------------------------------------------------------------------
651// Disabled Elements ------------------------------------------------
652// ------------------------------------------------------------------
653void tst_QShortcut::disabledItems()
654{
655 if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland"), cs: Qt::CaseInsensitive))
656 QSKIP("Wayland: This fails. Figure out why.");
657
658 ButtonWidget mainW;
659 mainW.setWindowTitle(QTest::currentTestFunction());
660 mainW.show();
661 mainW.activateWindow();
662 QVERIFY(QTest::qWaitForWindowActive(&mainW));
663
664 /* Testing Disabled Shortcuts
665 Qt::Key_M on slot1
666 Shift + Qt::Key_M on slot1
667 Qt::Key_M on slot2 (disabled)
668 Shift + Qt::Key_M on slot2 (disabled)
669 */
670
671 // Setup two identical shortcuts on different pushbuttons
672 auto pb1 = mainW.pushButton1();
673 auto pb2 = mainW.pushButton2();
674 const int shiftM = Qt::SHIFT + Qt::Key_M;
675 QShortcut *cut1 = setupShortcut(parent: pb1, name: "shortcut1-pb1", testWidget: TriggerSlot1,
676 ks: QKeySequence(Qt::Key_M));
677 QShortcut *cut2 = setupShortcut(parent: pb1, name: "shortcut2-pb1", testWidget: TriggerSlot1,
678 ks: QKeySequence(shiftM));
679 QShortcut *cut3 = setupShortcut(parent: pb2, name: "shortcut3-pb2", testWidget: TriggerSlot2,
680 ks: QKeySequence(Qt::Key_M));
681 QShortcut *cut4 = setupShortcut(parent: pb2, name: "shortcut4-pb2", testWidget: TriggerSlot2,
682 ks: QKeySequence(shiftM));
683
684 cut3->setEnabled(false);
685 cut4->setEnabled(false);
686
687 currentResult = NoResult;
688 sendKeyEvents(w: &mainW, k1: Qt::Key_M, c1: 'm');
689 QCOMPARE(currentResult, Slot1Triggered);
690
691 currentResult = NoResult;
692 sendKeyEvents(w: &mainW, k1: shiftM, c1: 'M');
693 QCOMPARE(currentResult, Slot1Triggered);
694
695 cut2->setEnabled(false);
696 cut4->setEnabled(true);
697
698 /* Testing Disabled Shortcuts
699 Qt::Key_M on slot1
700 Shift + Qt::Key_M on slot1 (disabled)
701 Qt::Key_M on slot2 (disabled)
702 Shift + Qt::Key_M on slot2
703 */
704 currentResult = NoResult;
705 sendKeyEvents(w: &mainW, k1: Qt::Key_M, c1: 'm' );
706 QCOMPARE( currentResult, Slot1Triggered );
707
708 currentResult = NoResult;
709 sendKeyEvents(w: &mainW, k1: shiftM, c1: 'M' );
710 QCOMPARE( currentResult, Slot2Triggered );
711
712
713 /* Testing Disabled Accel
714 Qt::Key_F5 on slot1
715 Shift + Qt::Key_F5 on slot2 (disabled)
716 */
717 qDeleteAll(c: mainW.findChildren<QShortcut *>());
718 const int shiftF5 = Qt::SHIFT + Qt::Key_F5;
719 cut1 = setupShortcut(parent: pb1, name: "shortcut1-pb1", testWidget: TriggerSlot1, ks: QKeySequence(Qt::Key_F5));
720 cut4 = setupShortcut(parent: pb2, name: "shortcut4-pb2", testWidget: TriggerSlot2, ks: QKeySequence(shiftF5));
721
722 cut1->setEnabled(true);
723 cut4->setEnabled(false);
724
725 currentResult = NoResult;
726 sendKeyEvents(w: &mainW, k1: Qt::Key_F5, c1: 0 );
727 QCOMPARE( currentResult, Slot1Triggered );
728
729 currentResult = NoResult;
730 sendKeyEvents(w: &mainW, k1: shiftF5, c1: 0 );
731 QCOMPARE( currentResult, NoResult );
732}
733// ------------------------------------------------------------------
734// Ambiguous Elements -----------------------------------------------
735// ------------------------------------------------------------------
736void tst_QShortcut::ambiguousRotation()
737{
738 if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland"), cs: Qt::CaseInsensitive))
739 QSKIP("Wayland: This fails. Figure out why.");
740
741 MainWindow mainW;
742 const QString name = QLatin1String(QTest::currentTestFunction());
743 mainW.setWindowTitle(name);
744 mainW.show();
745 mainW.activateWindow();
746 QVERIFY(QTest::qWaitForWindowActive(&mainW));
747
748 /* Testing Shortcut rotation scheme
749 Ctrl + Qt::Key_A on slot1 (disabled)
750 Ctrl + Qt::Key_A on slot2 (disabled)
751 Ctrl + Qt::Key_A on slot3
752 Ctrl + Qt::Key_A on slot4
753 Ctrl + Qt::Key_A on slot5 (disabled)
754 Ctrl + Qt::Key_A on slot6
755 Ctrl + Qt::Key_A on slot7 (disabled)
756 */
757 const int ctrlA = Qt::CTRL + Qt::Key_A;
758 QKeySequence ctrlA_Sequence(ctrlA);
759 QShortcut *cut1 = setupShortcut(parent: &mainW, name, testWidget: TriggerSlot1, ks: ctrlA_Sequence);
760 QShortcut *cut2 = setupShortcut(parent: &mainW, name, testWidget: TriggerSlot2, ks: ctrlA_Sequence);
761 QShortcut *cut3 = setupShortcut(parent: &mainW, name, testWidget: TriggerSlot3, ks: ctrlA_Sequence);
762 QShortcut *cut4 = setupShortcut(parent: &mainW, name, testWidget: TriggerSlot4, ks: ctrlA_Sequence);
763 QShortcut *cut5 = setupShortcut(parent: &mainW, name, testWidget: TriggerSlot5, ks: ctrlA_Sequence);
764 QShortcut *cut6 = setupShortcut(parent: &mainW, name, testWidget: TriggerSlot6, ks: ctrlA_Sequence);
765 QShortcut *cut7 = setupShortcut(parent: &mainW, name, testWidget: TriggerSlot7, ks: ctrlA_Sequence);
766
767 cut1->setEnabled(false);
768 cut2->setEnabled(false);
769 cut5->setEnabled(false);
770 cut7->setEnabled(false);
771
772 // Test proper rotation
773 // Start on first
774 // Go to last
775 // Go back to first
776 // Continue...
777 currentResult = NoResult;
778 ambigResult = NoResult;
779 sendKeyEvents(w: &mainW, k1: ctrlA);
780 QCOMPARE(currentResult, Ambiguous);
781 QCOMPARE(ambigResult, Slot3Triggered);
782
783 currentResult = NoResult;
784 ambigResult = NoResult;
785 sendKeyEvents(w: &mainW, k1: ctrlA);
786 QCOMPARE(currentResult, Ambiguous);
787 QCOMPARE(ambigResult, Slot4Triggered);
788
789 currentResult = NoResult;
790 ambigResult = NoResult;
791 sendKeyEvents(w: &mainW, k1: ctrlA);
792 QCOMPARE(currentResult, Ambiguous);
793 QCOMPARE(ambigResult, Slot6Triggered);
794
795 currentResult = NoResult;
796 ambigResult = NoResult;
797 sendKeyEvents(w: &mainW, k1: ctrlA);
798 QCOMPARE(currentResult, Ambiguous);
799 QCOMPARE(ambigResult, Slot3Triggered);
800
801 currentResult = NoResult;
802 ambigResult = NoResult;
803 sendKeyEvents(w: &mainW, k1: ctrlA);
804 QCOMPARE(currentResult, Ambiguous);
805 QCOMPARE(ambigResult, Slot4Triggered);
806
807 currentResult = NoResult;
808 ambigResult = NoResult;
809 sendKeyEvents(w: &mainW, k1: ctrlA);
810 QCOMPARE(currentResult, Ambiguous);
811 QCOMPARE(ambigResult, Slot6Triggered);
812
813 /* Testing Shortcut rotation scheme
814 Ctrl + Qt::Key_A on slot1
815 Ctrl + Qt::Key_A on slot2
816 Ctrl + Qt::Key_A on slot3 (disabled)
817 Ctrl + Qt::Key_A on slot4 (disabled)
818 Ctrl + Qt::Key_A on slot5
819 Ctrl + Qt::Key_A on slot6 (disabled)
820 Ctrl + Qt::Key_A on slot7
821 */
822
823 cut1->setEnabled(true);
824 cut2->setEnabled(true);
825 cut5->setEnabled(true);
826 cut7->setEnabled(true);
827
828 cut3->setEnabled(false);
829 cut4->setEnabled(false);
830 cut6->setEnabled(false);
831
832 currentResult = NoResult;
833 ambigResult = NoResult;
834 sendKeyEvents(w: &mainW, k1: ctrlA);
835 QCOMPARE(currentResult, Ambiguous);
836 QCOMPARE(ambigResult, Slot1Triggered);
837
838 currentResult = NoResult;
839 ambigResult = NoResult;
840 sendKeyEvents(w: &mainW, k1: ctrlA);
841 QCOMPARE(currentResult, Ambiguous);
842 QCOMPARE(ambigResult, Slot2Triggered);
843
844 currentResult = NoResult;
845 ambigResult = NoResult;
846 sendKeyEvents(w: &mainW, k1: ctrlA);
847 QCOMPARE(currentResult, Ambiguous);
848 QCOMPARE(ambigResult, Slot5Triggered);
849
850 currentResult = NoResult;
851 ambigResult = NoResult;
852 sendKeyEvents(w: &mainW, k1: ctrlA);
853 QCOMPARE(currentResult, Ambiguous);
854 QCOMPARE(ambigResult, Slot7Triggered);
855
856 currentResult = NoResult;
857 ambigResult = NoResult;
858 sendKeyEvents(w: &mainW, k1: ctrlA);
859 QCOMPARE(currentResult, Ambiguous);
860 QCOMPARE(ambigResult, Slot1Triggered);
861
862 currentResult = NoResult;
863 ambigResult = NoResult;
864 sendKeyEvents(w: &mainW, k1: ctrlA);
865 QCOMPARE(currentResult, Ambiguous);
866 QCOMPARE(ambigResult, Slot2Triggered);
867
868 currentResult = NoResult;
869 ambigResult = NoResult;
870 sendKeyEvents(w: &mainW, k1: ctrlA);
871 QCOMPARE(currentResult, Ambiguous);
872 QCOMPARE(ambigResult, Slot5Triggered);
873
874 currentResult = NoResult;
875 ambigResult = NoResult;
876 sendKeyEvents(w: &mainW, k1: ctrlA);
877 QCOMPARE(currentResult, Ambiguous);
878 QCOMPARE(ambigResult, Slot7Triggered);
879}
880
881void tst_QShortcut::ambiguousItems()
882{
883 if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland"), cs: Qt::CaseInsensitive))
884 QSKIP("Wayland: This fails. Figure out why.");
885
886 ButtonWidget mainW;
887 mainW.setWindowTitle(QTest::currentTestFunction());
888 mainW.show();
889 mainW.activateWindow();
890 QVERIFY(QTest::qWaitForWindowActive(&mainW));
891
892 /* Testing Ambiguous Shortcuts
893 Qt::Key_M on Pushbutton 1
894 Qt::Key_M on Pushbutton 2
895 */
896
897 // Setup two identical shortcuts on different pushbuttons
898 auto pb1 = mainW.pushButton1();
899 auto pb2 = mainW.pushButton2();
900
901 setupShortcut(parent: pb1, name: "shortcut1-pb1", testWidget: TriggerSlot1, ks: QKeySequence(Qt::Key_M));
902 setupShortcut(parent: pb2, name: "shortcut2-pb2", testWidget: TriggerSlot2, ks: QKeySequence(Qt::Key_M));
903
904 currentResult = NoResult;
905 sendKeyEvents(w: &mainW, k1: Qt::Key_M, c1: 'm' );
906 QCOMPARE( currentResult, Ambiguous );
907 QCOMPARE( ambigResult, Slot1Triggered );
908
909 currentResult = NoResult;
910 sendKeyEvents(w: &mainW, k1: Qt::Key_M, c1: 'm' );
911 QCOMPARE( currentResult, Ambiguous );
912 QCOMPARE( ambigResult, Slot2Triggered );
913
914 currentResult = NoResult;
915 sendKeyEvents(w: &mainW, k1: Qt::Key_M, c1: 'm' );
916 QCOMPARE( currentResult, Ambiguous );
917 QCOMPARE( ambigResult, Slot1Triggered );
918}
919
920
921// ------------------------------------------------------------------
922// Unicode and non-unicode Elements ---------------------------------
923// ------------------------------------------------------------------
924void tst_QShortcut::unicodeCompare()
925{
926 if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland"), cs: Qt::CaseInsensitive))
927 QSKIP("Wayland: This fails. Figure out why.");
928
929 ButtonWidget mainW;
930 mainW.setWindowTitle(QTest::currentTestFunction());
931 mainW.show();
932 mainW.activateWindow();
933 QVERIFY(QTest::qWaitForWindowActive(&mainW));
934
935 /* Testing Unicode/non-Unicode Shortcuts
936 Qt::Key_M on Pushbutton 1
937 Qt::Key_M on Pushbutton 2
938 */
939 auto pb1 = mainW.pushButton1();
940 auto pb2 = mainW.pushButton2();
941
942 QKeySequence ks1("Ctrl+M"); // Unicode
943 QKeySequence ks2(Qt::CTRL+Qt::Key_M); // non-Unicode
944 setupShortcut(parent: pb1, name: "shortcut1-pb1", testWidget: TriggerSlot1, ks: ks1);
945 setupShortcut(parent: pb2, name: "shortcut2-pb2", testWidget: TriggerSlot2, ks: ks2);
946
947 currentResult = NoResult;
948 sendKeyEvents(w: &mainW, k1: Qt::CTRL + Qt::Key_M, c1: 0);
949 QCOMPARE( currentResult, Ambiguous );
950 // They _are_ ambiguous, so the QKeySequence operator==
951 // should indicate the same
952 QVERIFY( ks1 == ks2 );
953 QVERIFY( !(ks1 != ks2) );
954}
955
956// ------------------------------------------------------------------
957// Keypress consumption verification --------------------------------
958// ------------------------------------------------------------------
959void tst_QShortcut::keypressConsumption()
960{
961 if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland"), cs: Qt::CaseInsensitive))
962 QSKIP("Wayland: This fails. Figure out why.");
963
964 MainWindow mainW;
965 mainW.setWindowTitle(QTest::currentTestFunction());
966 mainW.show();
967 mainW.activateWindow();
968 QVERIFY(QTest::qWaitForWindowActive(&mainW));
969 auto edit = mainW.testEdit();
970
971 const int ctrlI = Qt::CTRL + Qt::Key_I;
972 QShortcut *cut1 = setupShortcut(parent: edit, name: "shortcut1-line", testWidget: TriggerSlot1, ks: QKeySequence(ctrlI, Qt::Key_A));
973 QShortcut *cut2 = setupShortcut(parent: edit, name: "shortcut1-line", testWidget: TriggerSlot2, ks: QKeySequence(ctrlI, Qt::Key_B));
974
975 currentResult = NoResult;
976 ambigResult = NoResult;
977 sendKeyEvents(w: edit, k1: ctrlI, c1: 0); // Send key to edit
978 QCOMPARE( currentResult, NoResult );
979 QCOMPARE( ambigResult, NoResult );
980 QCOMPARE(edit->toPlainText(), QString());
981
982 // Make sure next keypress is eaten (failing multiple keysequence)
983 sendKeyEvents(w: edit, k1: Qt::Key_C, c1: 'c'); // Send key to edit
984 QCOMPARE( currentResult, NoResult );
985 QCOMPARE( ambigResult, NoResult );
986 QCOMPARE(edit->toPlainText(), QString());
987
988 // Next keypress should be normal
989 sendKeyEvents(w: edit, k1: Qt::Key_C, c1: 'c'); // Send key to edit
990 QCOMPARE( currentResult, NoResult );
991 QCOMPARE( ambigResult, NoResult );
992 QCOMPARE(edit->toPlainText(), QString("c"));
993
994 currentResult = NoResult;
995 ambigResult = NoResult;
996 edit->clear();
997 QCOMPARE(edit->toPlainText().size(), 0);
998
999 cut1->setEnabled(false);
1000 cut2->setEnabled(false);
1001
1002 // Make sure keypresses is passed on, since all multiple keysequences
1003 // with Ctrl+I are disabled
1004 sendKeyEvents(w: edit, k1: Qt::CTRL + Qt::Key_I, c1: 0); // Send key to edit
1005 QCOMPARE( currentResult, NoResult );
1006 QCOMPARE( ambigResult, NoResult );
1007 QVERIFY(edit->toPlainText().endsWith("<Ctrl+I>"));
1008
1009 sendKeyEvents(w: edit, k1: Qt::Key_A, c1: 'a'); // Send key to edit
1010 QCOMPARE( currentResult, NoResult );
1011 QCOMPARE( ambigResult, NoResult );
1012 QVERIFY(edit->toPlainText().endsWith("<Ctrl+I>a"));
1013
1014 qDeleteAll(c: mainW.findChildren<QShortcut *>());
1015 edit->clear();
1016 QCOMPARE(edit->toPlainText().size(), 0);
1017
1018 auto cut = setupShortcut(parent: edit, name: QLatin1String("first"), ks: QKeySequence(Qt::CTRL + Qt::Key_A));
1019 connect(sender: cut, signal: &QShortcut::activated, context: edit, slot: [this, edit] () {
1020 this->sendKeyEvents(w: edit, k1: Qt::CTRL + Qt::Key_B, c1: 0);
1021 this->currentResult = tst_QShortcut::SentKeyEvent;
1022 });
1023
1024 // Verify reentrancy when a non-shortcut is triggered as part
1025 // of shortcut processing.
1026 currentResult = NoResult;
1027 ambigResult = NoResult;
1028 sendKeyEvents(w: edit, k1: Qt::CTRL + Qt::Key_A, c1: 0);
1029 QCOMPARE(currentResult, SentKeyEvent);
1030 QCOMPARE(ambigResult, NoResult);
1031 QCOMPARE(edit->toPlainText(), QLatin1String("<Ctrl+B>"));
1032}
1033
1034// ------------------------------------------------------------------
1035// Context Validation -----------------------------------------------
1036// ------------------------------------------------------------------
1037void tst_QShortcut::context()
1038{
1039 const QString name = QLatin1String(QTest::currentTestFunction());
1040 MainWindow mainW;
1041 mainW.setWindowTitle(name + QLatin1String("_Helper"));
1042 mainW.show();
1043 auto edit = mainW.testEdit();
1044
1045 QWidget myBox;
1046 myBox.setWindowTitle(name);
1047 auto other1 = new TestEdit(&myBox, "test_edit_other1");
1048 auto other2 = new TestEdit(&myBox, "test_edit_other2");
1049 auto layout = new QHBoxLayout(&myBox);
1050 layout->addWidget(other1);
1051 layout->addWidget(other2);
1052 myBox.show();
1053 QVERIFY(QTest::qWaitForWindowExposed(&myBox));
1054
1055 setupShortcut(parent: other1, name: "ActiveWindow", testWidget: TriggerSlot1, ks: QKeySequence("Alt+1"), context: Qt::WindowShortcut);
1056 setupShortcut(parent: other2, name: "Focus", testWidget: TriggerSlot2, ks: QKeySequence("Alt+2"), context: Qt::WidgetShortcut);
1057 setupShortcut(parent: edit, name: "Application", testWidget: TriggerSlot3, ks: QKeySequence("Alt+3"), context: Qt::ApplicationShortcut);
1058
1059 currentResult = NoResult;
1060 ambigResult = NoResult;
1061 edit->clear();
1062 other1->clear();
1063 other2->clear();
1064
1065 // edit doesn't have focus, so ActiveWindow context should work
1066 // ..but Focus context shouldn't..
1067 // Changing focus to edit should make focus context work
1068 // Application context should always work
1069
1070
1071 // Focus on 'other1' edit, so Active Window context should trigger
1072 other1->activateWindow(); // <---
1073 QApplication::setActiveWindow(other1);
1074 QCOMPARE(QApplication::activeWindow(), other1->window());
1075 QCOMPARE(QApplication::focusWidget(), static_cast<QWidget *>(other1));
1076
1077 currentResult = NoResult;
1078 ambigResult = NoResult;
1079 edit->clear();
1080 other1->clear();
1081 other2->clear();
1082
1083 QCOMPARE(QApplication::focusWidget(), static_cast<QWidget *>(other1));
1084 sendKeyEvents(w: other1, k1: Qt::ALT+Qt::Key_1);
1085 QCOMPARE(currentResult, Slot1Triggered);
1086 QCOMPARE(ambigResult, NoResult);
1087 QCOMPARE(edit->toPlainText(), QString());
1088 QCOMPARE(other1->toPlainText(), QString());
1089 QCOMPARE(other2->toPlainText(), QString());
1090
1091 // ..but not Focus context on 'other2'..
1092 currentResult = NoResult;
1093 ambigResult = NoResult;
1094 edit->clear();
1095 other1->clear();
1096 other2->clear();
1097
1098 sendKeyEvents(w: other1, k1: Qt::ALT+Qt::Key_2);
1099 QCOMPARE(currentResult, NoResult);
1100 QCOMPARE(ambigResult, NoResult);
1101 QCOMPARE(edit->toPlainText(), QString());
1102 QCOMPARE(other1->toPlainText(), QString("<Alt+2>"));
1103 QCOMPARE(other2->toPlainText(), QString());
1104
1105 // ..however, application global context on 'edit' should..
1106 currentResult = NoResult;
1107 ambigResult = NoResult;
1108 edit->clear();
1109 other1->clear();
1110 other2->clear();
1111
1112 sendKeyEvents(w: other1, k1: Qt::ALT+Qt::Key_3);
1113 QCOMPARE(currentResult, Slot3Triggered);
1114 QCOMPARE(ambigResult, NoResult);
1115 QCOMPARE(edit->toPlainText(), QString());
1116 QCOMPARE(other1->toPlainText(), QString());
1117 QCOMPARE(other2->toPlainText(), QString());
1118
1119 // Changing focus to 'other2' should make the Focus context there work
1120 other2->activateWindow();
1121 other2->setFocus(); // ###
1122 QTRY_COMPARE(QApplication::activeWindow(), other2->window());
1123 QCOMPARE(QApplication::focusWidget(), static_cast<QWidget *>(other2));
1124
1125 currentResult = NoResult;
1126 ambigResult = NoResult;
1127 edit->clear();
1128 other1->clear();
1129 other2->clear();
1130
1131 sendKeyEvents(w: other2, k1: Qt::ALT+Qt::Key_2);
1132 QCOMPARE(currentResult, Slot2Triggered);
1133 QCOMPARE(ambigResult, NoResult);
1134 QCOMPARE(edit->toPlainText(), QString());
1135 QCOMPARE(other1->toPlainText(), QString());
1136 QCOMPARE(other2->toPlainText(), QString());
1137}
1138
1139// QTBUG-38986, do not generate duplicated QEvent::ShortcutOverride in event processing.
1140class OverrideCountingWidget : public QWidget
1141{
1142public:
1143 using QWidget::QWidget;
1144
1145 int overrideCount = 0;
1146
1147 bool event(QEvent *e) override
1148 {
1149 if (e->type() == QEvent::ShortcutOverride)
1150 overrideCount++;
1151 return QWidget::event(event: e);
1152 }
1153};
1154
1155void tst_QShortcut::duplicatedShortcutOverride()
1156{
1157 if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland"), cs: Qt::CaseInsensitive))
1158 QSKIP("Wayland: This fails. Figure out why.");
1159
1160 OverrideCountingWidget w;
1161 w.setWindowTitle(Q_FUNC_INFO);
1162 w.resize(w: 200, h: 200);
1163 w.move(QGuiApplication::primaryScreen()->availableGeometry().center() - QPoint(100, 100));
1164 w.show();
1165 QApplication::setActiveWindow(&w);
1166 QVERIFY(QTest::qWaitForWindowActive(&w));
1167 QTest::keyPress(window: w.windowHandle(), key: Qt::Key_A);
1168 QCoreApplication::processEvents();
1169 QCOMPARE(w.overrideCount, 1);
1170}
1171
1172QShortcut *tst_QShortcut::setupShortcut(QWidget *parent, const QString &name, const QKeySequence &ks, Qt::ShortcutContext context)
1173{
1174 // Set up shortcut for next test
1175 auto cut = new QShortcut(ks, parent, nullptr, nullptr, context);
1176 cut->setObjectName(name);
1177 return cut;
1178}
1179
1180QShortcut *tst_QShortcut::setupShortcut(QWidget *parent, const QString &name, Widget testWidget,
1181 const QKeySequence &ks, Qt::ShortcutContext context)
1182{
1183 // Set up shortcut for next test
1184 auto cut = setupShortcut(parent, name, ks, context);
1185
1186 switch (testWidget) {
1187 case TriggerSlot1:
1188 connect(sender: cut, signal: &QShortcut::activated, receiver: this, slot: &tst_QShortcut::slotTrig1);
1189 connect(sender: cut, signal: &QShortcut::activatedAmbiguously, receiver: this, slot: &tst_QShortcut::ambigSlot1);
1190 break;
1191 case TriggerSlot2:
1192 connect(sender: cut, signal: &QShortcut::activated, receiver: this, slot: &tst_QShortcut::slotTrig2);
1193 connect(sender: cut, signal: &QShortcut::activatedAmbiguously, receiver: this, slot: &tst_QShortcut::ambigSlot2);
1194 break;
1195 case TriggerSlot3:
1196 connect(sender: cut, signal: &QShortcut::activated, receiver: this, slot: &tst_QShortcut::slotTrig3);
1197 connect(sender: cut, signal: &QShortcut::activatedAmbiguously, receiver: this, slot: &tst_QShortcut::ambigSlot3);
1198 break;
1199 case TriggerSlot4:
1200 connect(sender: cut, signal: &QShortcut::activated, receiver: this, slot: &tst_QShortcut::slotTrig4);
1201 connect(sender: cut, signal: &QShortcut::activatedAmbiguously, receiver: this, slot: &tst_QShortcut::ambigSlot4);
1202 break;
1203 case TriggerSlot5:
1204 connect(sender: cut, signal: &QShortcut::activated, receiver: this, slot: &tst_QShortcut::slotTrig5);
1205 connect(sender: cut, signal: &QShortcut::activatedAmbiguously, receiver: this, slot: &tst_QShortcut::ambigSlot5);
1206 break;
1207 case TriggerSlot6:
1208 connect(sender: cut, signal: &QShortcut::activated, receiver: this, slot: &tst_QShortcut::slotTrig6);
1209 connect(sender: cut, signal: &QShortcut::activatedAmbiguously, receiver: this, slot: &tst_QShortcut::ambigSlot6);
1210 break;
1211 case TriggerSlot7:
1212 connect(sender: cut, signal: &QShortcut::activated, receiver: this, slot: &tst_QShortcut::slotTrig7);
1213 connect(sender: cut, signal: &QShortcut::activatedAmbiguously, receiver: this, slot: &tst_QShortcut::ambigSlot7);
1214 break;
1215 case NoWidget:
1216 break;
1217 }
1218 return cut;
1219}
1220
1221void tst_QShortcut::sendKeyEvents(QWidget *w, int k1, QChar c1, int k2, QChar c2, int k3, QChar c3, int k4, QChar c4)
1222{
1223 Qt::KeyboardModifiers b1 = toButtons( key: k1 );
1224 Qt::KeyboardModifiers b2 = toButtons( key: k2 );
1225 Qt::KeyboardModifiers b3 = toButtons( key: k3 );
1226 Qt::KeyboardModifiers b4 = toButtons( key: k4 );
1227 k1 &= ~Qt::MODIFIER_MASK;
1228 k2 &= ~Qt::MODIFIER_MASK;
1229 k3 &= ~Qt::MODIFIER_MASK;
1230 k4 &= ~Qt::MODIFIER_MASK;
1231
1232
1233 if (k1 || c1.toLatin1()) {
1234 QString c(c1.unicode() == QChar::Null ? QString() : QString(c1));
1235 QTest::sendKeyEvent(action: QTest::Press, widget: w, code: static_cast<Qt::Key>(k1), text: c, modifier: b1);
1236 QTest::sendKeyEvent(action: QTest::Release, widget: w, code: static_cast<Qt::Key>(k1), text: c, modifier: b1);
1237 }
1238
1239 if (k2 || c2.toLatin1()) {
1240 QString c(c2.unicode() == QChar::Null ? QString() : QString(c2));
1241 QTest::sendKeyEvent(action: QTest::Press, widget: w, code: static_cast<Qt::Key>(k2), text: c, modifier: b2);
1242 QTest::sendKeyEvent(action: QTest::Release, widget: w, code: static_cast<Qt::Key>(k2), text: c, modifier: b2);
1243 }
1244
1245 if (k3 || c3.toLatin1()) {
1246 QString c(c3.unicode() == QChar::Null ? QString() : QString(c3));
1247 QTest::sendKeyEvent(action: QTest::Press, widget: w, code: static_cast<Qt::Key>(k3), text: c, modifier: b3);
1248 QTest::sendKeyEvent(action: QTest::Release, widget: w, code: static_cast<Qt::Key>(k3), text: c, modifier: b3);
1249 }
1250
1251 if (k4 || c4.toLatin1()) {
1252 QString c(c4.unicode() == QChar::Null ? QString() : QString(c4));
1253 QTest::sendKeyEvent(action: QTest::Press, widget: w, code: static_cast<Qt::Key>(k4), text: c, modifier: b4);
1254 QTest::sendKeyEvent(action: QTest::Release, widget: w, code: static_cast<Qt::Key>(k4), text: c, modifier: b4);
1255 }
1256}
1257
1258void tst_QShortcut::testElement()
1259{
1260 if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland"), cs: Qt::CaseInsensitive))
1261 QSKIP("Wayland: This fails. Figure out why.");
1262
1263 static QScopedPointer<MainWindow> mainW;
1264
1265 currentResult = NoResult;
1266 QFETCH(tst_QShortcut::Action, action);
1267 QFETCH(tst_QShortcut::Widget, testWidget);
1268 QFETCH(QString, txt);
1269 QFETCH(int, k1);
1270 QFETCH(int, c1);
1271 QFETCH(int, k2);
1272 QFETCH(int, c2);
1273 QFETCH(int, k3);
1274 QFETCH(int, c3);
1275 QFETCH(int, k4);
1276 QFETCH(int, c4);
1277 QFETCH(tst_QShortcut::Result, result);
1278
1279 if (mainW.isNull()) {
1280 mainW.reset(other: new MainWindow);
1281 mainW->setWindowTitle(QTest::currentTestFunction());
1282 mainW->show();
1283 mainW->activateWindow();
1284 QVERIFY(QTest::qWaitForWindowActive(mainW.data()));
1285 }
1286
1287 switch (action) {
1288 case ClearAll:
1289 qDeleteAll(c: mainW->findChildren<QShortcut *>());
1290 break;
1291 case SetupAccel:
1292 setupShortcut(parent: mainW.data(), name: txt, testWidget, ks: txt.isEmpty()
1293 ? QKeySequence(k1, k2, k3, k4) : QKeySequence::fromString(str: txt));
1294 break;
1295 case TestAccel:
1296 sendKeyEvents(w: mainW.data(), k1, c1, k2, c2, k3, c3, k4, c4);
1297 QCOMPARE(currentResult, result);
1298 break;
1299 case TestEnd:
1300 mainW.reset();
1301 break;
1302 }
1303}
1304
1305void tst_QShortcut::shortcutToFocusProxy()
1306{
1307 if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland"), cs: Qt::CaseInsensitive))
1308 QSKIP("Wayland: This fails. Figure out why.");
1309
1310 QLineEdit le;
1311 QCompleter completer;
1312 QStringListModel *slm = new QStringListModel(QStringList() << "a0" << "a1" << "a2", &completer);
1313 completer.setModel(slm);
1314 completer.setCompletionMode(QCompleter::PopupCompletion);
1315 le.setCompleter(&completer);
1316 QShortcut *shortcut = new QShortcut(QKeySequence(Qt::ALT + Qt::Key_S), &le);
1317 QObject::connect(sender: shortcut, signal: &QShortcut::activated, receiver: &le, slot: &QLineEdit::clear);
1318 le.setFocus();
1319 le.show();
1320
1321 QVERIFY(QTest::qWaitForWindowActive(&le));
1322 QCOMPARE(QApplication::focusWidget(), &le);
1323 QTest::keyEvent(action: QTest::Press, widget: QApplication::focusWidget(), key: Qt::Key_A);
1324
1325 QCOMPARE(le.text(), QString::fromLocal8Bit("a"));
1326 QTest::keyEvent(action: QTest::Press, widget: QApplication::focusWidget(), key: Qt::Key_Alt);
1327 QTest::keyEvent(action: QTest::Press, widget: QApplication::focusWidget(), key: Qt::Key_S, modifier: Qt::AltModifier);
1328 QCOMPARE(le.text(), QString());
1329}
1330
1331void tst_QShortcut::deleteLater()
1332{
1333 QWidget w;
1334 QPointer<QShortcut> sc(new QShortcut(QKeySequence(Qt::Key_1), &w));
1335 sc->deleteLater();
1336 QTRY_VERIFY(!sc);
1337}
1338
1339
1340QTEST_MAIN(tst_QShortcut)
1341#include "tst_qshortcut.moc"
1342

source code of qtbase/tests/auto/widgets/kernel/qshortcut/tst_qshortcut.cpp