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
32
33#include "qcommandlinkbutton.h"
34#include <qapplication.h>
35
36#include <qcommandlinkbutton.h>
37#include <qmenu.h>
38#include <qtimer.h>
39#include <QDialog>
40#include <QGridLayout>
41#include <QPainter>
42
43class tst_QCommandLinkButton : public QObject
44{
45 Q_OBJECT
46
47private slots:
48 void initTestCase();
49 void cleanupTestCase();
50 void init();
51
52 void getSetCheck();
53 void pressed();
54 void setAccel();
55 void isCheckable();
56 void setDown();
57 void popupCrash();
58 void isChecked();
59 void animateClick();
60 void toggle();
61 void clicked();
62 void toggled();
63 void defaultAndAutoDefault();
64 void setAutoRepeat();
65 void heightForWithWithIcon();
66
67protected slots:
68 void resetCounters();
69 void onClicked();
70 void onToggled( bool on );
71 void onPressed();
72 void onReleased();
73 void helperSlotDelete();
74
75private:
76 uint click_count;
77 uint toggle_count;
78 uint press_count;
79 uint release_count;
80
81 QCommandLinkButton *testWidget;
82};
83
84// Testing get/set functions
85void tst_QCommandLinkButton::getSetCheck()
86{
87 QCommandLinkButton obj1;
88
89 QString text("mytext");
90 QVERIFY(obj1.description().isEmpty());
91 obj1.setDescription(text);
92 QCOMPARE(obj1.description(), text);
93
94 QVERIFY(obj1.text().isEmpty());
95 obj1.setText(text);
96 QCOMPARE(obj1.text(), text);
97
98 QMenu *var1 = new QMenu;
99 obj1.setMenu(var1);
100 QCOMPARE(var1, obj1.menu());
101 obj1.setMenu((QMenu *)0);
102 QCOMPARE((QMenu *)0, obj1.menu());
103 delete var1;
104}
105
106void tst_QCommandLinkButton::initTestCase()
107{
108 // Create the test class
109 testWidget = new QCommandLinkButton( "&Start", 0 );
110 testWidget->setObjectName("testWidget");
111 testWidget->resize( w: 200, h: 200 );
112 testWidget->show();
113 if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland"), cs: Qt::CaseInsensitive))
114 QSKIP("Wayland: This fails. Figure out why.");
115 QVERIFY(QTest::qWaitForWindowActive(testWidget));
116
117 connect( sender: testWidget, SIGNAL(clicked()), receiver: this, SLOT(onClicked()) );
118 connect( sender: testWidget, SIGNAL(pressed()), receiver: this, SLOT(onPressed()) );
119 connect( sender: testWidget, SIGNAL(released()), receiver: this, SLOT(onReleased()) );
120 connect( sender: testWidget, SIGNAL(toggled(bool)), receiver: this, SLOT(onToggled(bool)) );
121}
122
123void tst_QCommandLinkButton::cleanupTestCase()
124{
125 delete testWidget;
126 testWidget = 0;
127}
128
129void tst_QCommandLinkButton::init()
130{
131 testWidget->setAutoRepeat( false );
132 testWidget->setDown( false );
133 testWidget->setText("Test");
134 testWidget->setDescription("Description text.");
135 testWidget->setEnabled( true );
136 QKeySequence seq;
137 testWidget->setShortcut( seq );
138
139 resetCounters();
140}
141
142void tst_QCommandLinkButton::resetCounters()
143{
144 toggle_count = 0;
145 press_count = 0;
146 release_count = 0;
147 click_count = 0;
148}
149
150void tst_QCommandLinkButton::onClicked()
151{
152 click_count++;
153}
154
155void tst_QCommandLinkButton::onToggled( bool /*on*/ )
156{
157 toggle_count++;
158}
159
160void tst_QCommandLinkButton::onPressed()
161{
162 press_count++;
163}
164
165void tst_QCommandLinkButton::onReleased()
166{
167 release_count++;
168}
169
170void tst_QCommandLinkButton::setAutoRepeat()
171{
172 // Give the last tests time to finish - i.e., wait for the window close and
173 // deactivate to avoid a race condition here. We can't add this to the end
174 // of the defaultAndAutoDefault test, since any failure in that test will
175 // return out of that function.
176 QTest::qWait(ms: 1000);
177
178 // If this changes, this test must be completely revised.
179 QVERIFY( !testWidget->isCheckable() );
180
181 // verify autorepeat is off by default.
182 QCommandLinkButton tmp( 0 );
183 tmp.setObjectName("tmp");
184 QVERIFY( !tmp.autoRepeat() );
185
186 // check if we can toggle the mode
187 testWidget->setAutoRepeat( true );
188 QVERIFY( testWidget->autoRepeat() );
189
190 testWidget->setAutoRepeat( false );
191 QVERIFY( !testWidget->autoRepeat() );
192
193 resetCounters();
194
195 // check that the button is down if we press space and not in autorepeat
196 testWidget->setDown( false );
197 testWidget->setAutoRepeat( false );
198 QTest::keyPress( widget: testWidget, key: Qt::Key_Space );
199
200 QVERIFY( testWidget->isDown() );
201 QVERIFY( toggle_count == 0 );
202 QVERIFY( press_count == 1 );
203 QVERIFY( release_count == 0 );
204 QVERIFY( click_count == 0 );
205
206 QTest::keyRelease( widget: testWidget, key: Qt::Key_Space );
207 resetCounters();
208
209 // check that the button is down if we press space while in autorepeat
210
211 testWidget->setDown( false );
212 testWidget->setAutoRepeat( true );
213 QTest::keyPress( widget: testWidget, key: Qt::Key_Space );
214 QTRY_VERIFY(press_count > 10);
215 QVERIFY( testWidget->isDown() );
216 QVERIFY( toggle_count == 0 );
217 QTest::keyRelease( widget: testWidget, key: Qt::Key_Space );
218 QCOMPARE(press_count, release_count);
219 QCOMPARE(release_count, click_count);
220
221 // #### shouldn't I check here to see if multiple signals have been fired???
222
223 // check that pressing ENTER has no effect
224 resetCounters();
225 testWidget->setDown( false );
226 testWidget->setAutoRepeat( false );
227 QTest::keyPress( widget: testWidget, key: Qt::Key_Enter );
228
229 QVERIFY( !testWidget->isDown() );
230 QVERIFY( toggle_count == 0 );
231 QVERIFY( press_count == 0 );
232 QVERIFY( release_count == 0 );
233 QVERIFY( click_count == 0 );
234 QTest::keyRelease( widget: testWidget, key: Qt::Key_Enter );
235
236 // check that pressing ENTER has no effect
237 resetCounters();
238 testWidget->setDown( false );
239 testWidget->setAutoRepeat( true );
240 QTest::keyClick( widget: testWidget, key: Qt::Key_Enter );
241 QVERIFY( !testWidget->isDown() );
242 QVERIFY( toggle_count == 0 );
243 QVERIFY( press_count == 0 );
244 QVERIFY( release_count == 0 );
245 QVERIFY( click_count == 0 );
246}
247
248void tst_QCommandLinkButton::pressed()
249{
250 QTest::keyPress( widget: testWidget, key: ' ' );
251 QCOMPARE( press_count, (uint)1 );
252 QCOMPARE( release_count, (uint)0 );
253
254 QTest::keyRelease( widget: testWidget, key: ' ' );
255 QCOMPARE( press_count, (uint)1 );
256 QCOMPARE( release_count, (uint)1 );
257
258 QTest::keyPress( widget: testWidget,key: Qt::Key_Enter );
259 QCOMPARE( press_count, (uint)1 );
260 QCOMPARE( release_count, (uint)1 );
261
262 testWidget->setAutoDefault(true);
263 QTest::keyPress( widget: testWidget,key: Qt::Key_Enter );
264 QCOMPARE( press_count, (uint)2 );
265 QCOMPARE( release_count, (uint)2 );
266 testWidget->setAutoDefault(false);
267}
268
269void tst_QCommandLinkButton::isCheckable()
270{
271 QVERIFY( !testWidget->isCheckable() );
272}
273
274void tst_QCommandLinkButton::setDown()
275{
276 testWidget->setDown( false );
277 QVERIFY( !testWidget->isDown() );
278
279 testWidget->setDown( true );
280 QVERIFY( testWidget->isDown() );
281
282 testWidget->setDown( true );
283 QTest::keyClick( widget: testWidget, key: Qt::Key_Escape );
284 QVERIFY( !testWidget->isDown() );
285}
286
287void tst_QCommandLinkButton::isChecked()
288{
289 testWidget->setDown( false );
290 QVERIFY( !testWidget->isChecked() );
291
292 testWidget->setDown( true );
293 QVERIFY( !testWidget->isChecked() );
294
295 testWidget->setDown( false );
296 testWidget->toggle();
297 QVERIFY( testWidget->isChecked() == testWidget->isCheckable() );
298}
299
300void tst_QCommandLinkButton::toggle()
301{
302 // the pushbutton shouldn't toggle the button.
303 testWidget->toggle();
304 QVERIFY(!testWidget->isChecked());
305}
306
307void tst_QCommandLinkButton::toggled()
308{
309 // the pushbutton shouldn't send a toggled signal when we call the toggle slot.
310 QVERIFY( !testWidget->isCheckable() );
311
312 testWidget->toggle();
313 QVERIFY( toggle_count == 0 );
314
315 // do it again, just to be sure
316 resetCounters();
317 testWidget->toggle();
318 QVERIFY( toggle_count == 0 );
319
320 // finally check that we can toggle using the mouse
321 resetCounters();
322 QTest::mousePress( widget: testWidget, button: Qt::LeftButton );
323 QVERIFY( toggle_count == 0 );
324 QVERIFY( click_count == 0 );
325
326 QTest::mouseRelease( widget: testWidget, button: Qt::LeftButton );
327 QVERIFY( click_count == 1 );
328}
329
330/*
331 If we press an accelerator key we ONLY get a pressed signal and
332 NOT a released or clicked signal.
333*/
334
335void tst_QCommandLinkButton::setAccel()
336{
337 testWidget->setText("&AccelTest");
338 QKeySequence seq( Qt::ALT + Qt::Key_A );
339 testWidget->setShortcut( seq );
340
341 // The shortcut will not be activated unless the button is in a active
342 // window and has focus
343 testWidget->setFocus();
344 QVERIFY(QTest::qWaitForWindowActive(testWidget));
345
346 QTest::keyClick( widget: testWidget, key: 'A', modifier: Qt::AltModifier );
347 QTest::qWait( ms: 500 );
348 QVERIFY( click_count == 1 );
349 QVERIFY( press_count == 1 );
350 QVERIFY( release_count == 1 );
351 QVERIFY( toggle_count == 0 );
352
353 // wait 200 ms because setAccel uses animateClick.
354 // if we don't wait this may screw up a next test.
355 QTest::qWait(ms: 200);
356}
357
358void tst_QCommandLinkButton::animateClick()
359{
360 QVERIFY( !testWidget->isDown() );
361 testWidget->animateClick();
362 QVERIFY( testWidget->isDown() );
363 QTest::qWait( ms: 200 );
364 QVERIFY( !testWidget->isDown() );
365
366 QVERIFY( click_count == 1 );
367 QVERIFY( press_count == 1 );
368 QVERIFY( release_count == 1 );
369 QVERIFY( toggle_count == 0 );
370}
371
372void tst_QCommandLinkButton::clicked()
373{
374 QTest::mousePress( widget: testWidget, button: Qt::LeftButton );
375 QVERIFY( press_count == 1 );
376 QVERIFY( release_count == 0 );
377
378 QTest::mouseRelease( widget: testWidget, button: Qt::LeftButton );
379 QCOMPARE( press_count, (uint)1 );
380 QCOMPARE( release_count, (uint)1 );
381
382 press_count = 0;
383 release_count = 0;
384 testWidget->setDown(false);
385 for (uint i=0; i<10; i++)
386 QTest::mouseClick( widget: testWidget, button: Qt::LeftButton );
387 QCOMPARE( press_count, (uint)10 );
388 QCOMPARE( release_count, (uint)10 );
389}
390
391QCommandLinkButton *pb = 0;
392void tst_QCommandLinkButton::helperSlotDelete()
393{
394 delete pb;
395 pb = 0;
396}
397
398void tst_QCommandLinkButton::popupCrash()
399{
400 pb = new QCommandLinkButton("foo", "description");
401 QMenu *menu = new QMenu("bar", pb);
402 pb->setMenu(menu);
403 QTimer::singleShot(msec: 1000, receiver: this, SLOT(helperSlotDelete()));
404 pb->show();
405 pb->click();
406}
407
408void tst_QCommandLinkButton::defaultAndAutoDefault()
409{
410 {
411 // Adding buttons directly to QDialog
412 QDialog dialog;
413
414 QCommandLinkButton button1(&dialog);
415 QVERIFY(button1.autoDefault());
416 QVERIFY(!button1.isDefault());
417
418 QCommandLinkButton button2(&dialog);
419 QVERIFY(button2.autoDefault());
420 QVERIFY(!button2.isDefault());
421
422 button1.setDefault(true);
423 QVERIFY(button1.autoDefault());
424 QVERIFY(button1.isDefault());
425 QVERIFY(button2.autoDefault());
426 QVERIFY(!button2.isDefault());
427
428 dialog.show();
429 QVERIFY(dialog.isVisible());
430
431 QObject::connect(sender: &button1, SIGNAL(clicked()), receiver: &dialog, SLOT(hide()));
432 QTest::keyClick(widget: &dialog, key: Qt::Key_Return);
433 QVERIFY(!dialog.isVisible());
434 }
435
436 {
437 // Adding buttons to QDialog through a layout
438 QDialog dialog;
439
440 QCommandLinkButton button3;
441 button3.setAutoDefault(false);
442
443 QCommandLinkButton button1;
444 QVERIFY(!button1.autoDefault());
445 QVERIFY(!button1.isDefault());
446
447 QCommandLinkButton button2;
448 QVERIFY(!button2.autoDefault());
449 QVERIFY(!button2.isDefault());
450
451 button1.setDefault(true);
452 QVERIFY(!button1.autoDefault());
453 QVERIFY(button1.isDefault());
454 QVERIFY(!button2.autoDefault());
455 QVERIFY(!button2.isDefault());
456
457 QGridLayout layout;
458 layout.addWidget(&button3, row: 0, column: 3);
459 layout.addWidget(&button2, row: 0, column: 2);
460 layout.addWidget(&button1, row: 0, column: 1);
461 dialog.setLayout(&layout);
462 button3.setFocus();
463 QVERIFY(button1.autoDefault());
464 QVERIFY(button1.isDefault());
465 QVERIFY(button2.autoDefault());
466 QVERIFY(!button2.isDefault());
467
468 dialog.show();
469 QVERIFY(dialog.isVisible());
470
471 QObject::connect(sender: &button1, SIGNAL(clicked()), receiver: &dialog, SLOT(hide()));
472 QTest::keyClick(widget: &dialog, key: Qt::Key_Return);
473 QVERIFY(!dialog.isVisible());
474 }
475
476 {
477 // autoDefault behavior.
478 QDialog dialog;
479 QCommandLinkButton button2(&dialog);
480 QCommandLinkButton button1(&dialog);
481 dialog.show();
482 QVERIFY(dialog.isVisible());
483
484 // No default button is set, and button2 is the first autoDefault button
485 // that is next in the tab order
486 QObject::connect(sender: &button2, SIGNAL(clicked()), receiver: &dialog, SLOT(hide()));
487 QTest::keyClick(widget: &dialog, key: Qt::Key_Return);
488 QVERIFY(!dialog.isVisible());
489
490 // Reparenting
491 QVERIFY(button2.autoDefault());
492 button2.setParent(0);
493 QVERIFY(!button2.autoDefault());
494 button2.setAutoDefault(false);
495 button2.setParent(&dialog);
496 QVERIFY(!button2.autoDefault());
497
498 button1.setAutoDefault(true);
499 button1.setParent(0);
500 QVERIFY(button1.autoDefault());
501 }
502}
503
504void tst_QCommandLinkButton::heightForWithWithIcon()
505{
506 QWidget mainWin;
507
508 QPixmap pixmap(64, 64);
509 {
510 pixmap.fill(fillColor: Qt::white);
511 QPainter painter(&pixmap);
512 painter.setBrush(Qt::black);
513 painter.drawEllipse(x: 0, y: 0, w: 63, h: 63);
514 }
515
516 QCommandLinkButton *largeIconButton = new QCommandLinkButton(QString("Large Icon"),
517 QString("Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Mauris nibh lectus, adipiscing eu."),
518 &mainWin);
519 largeIconButton->setIconSize(QSize(64, 64));
520 largeIconButton->setIcon(pixmap);
521
522 QVBoxLayout *layout = new QVBoxLayout();
523 layout->addWidget(largeIconButton);
524 layout->addStretch();
525 mainWin.setLayout(layout);
526 mainWin.showMaximized();
527 QVERIFY(QTest::qWaitForWindowExposed(&mainWin));
528 QVERIFY(largeIconButton->height() > 68); //enough room for the icon
529
530}
531
532QTEST_MAIN(tst_QCommandLinkButton)
533#include "tst_qcommandlinkbutton.moc"
534

source code of qtbase/tests/auto/widgets/widgets/qcommandlinkbutton/tst_qcommandlinkbutton.cpp