1
/****************************************************************************
2
**
3
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4
** All rights reserved.
5
** Contact: Nokia Corporation (qt-info@nokia.com)
6
**
7
** This file is part of the test suite of the Qt Toolkit.
8
**
9
** $QT_BEGIN_LICENSE:LGPL$
10
** GNU Lesser General Public License Usage
11
** This file may be used under the terms of the GNU Lesser General Public
12
** License version 2.1 as published by the Free Software Foundation and
13
** appearing in the file LICENSE.LGPL included in the packaging of this
14
** file. Please review the following information to ensure the GNU Lesser
15
** General Public License version 2.1 requirements will be met:
16
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17
**
18
** In addition, as a special exception, Nokia gives you certain additional
19
** rights. These rights are described in the Nokia Qt LGPL Exception
20
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21
**
22
** GNU General Public License Usage
23
** Alternatively, this file may be used under the terms of the GNU General
24
** Public License version 3.0 as published by the Free Software Foundation
25
** and appearing in the file LICENSE.GPL included in the packaging of this
26
** file. Please review the following information to ensure the GNU General
27
** Public License version 3.0 requirements will be met:
28
** http://www.gnu.org/copyleft/gpl.html.
29
**
30
** Other Usage
31
** Alternatively, this file may be used in accordance with the terms and
32
** conditions contained in a signed written agreement between you and Nokia.
33
**
34
**
35
**
36
**
37
**
38
** $QT_END_LICENSE$
39
**
40
****************************************************************************/
41
42
43
#include <QtTest/QtTest>
44
45
46
47
#include <qapplication.h>
48
#include <qpainter.h>
49
#include <qstyleoption.h>
50
#include <qkeysequence.h>
51
#include <qevent.h>
52
#include <qgridlayout.h>
53
54
55
56
#include <qabstractbutton.h>
57
58
//TESTED_CLASS=
59
//TESTED_FILES=
60
61
class tst_QAbstractButton : public QObject
62
{
63
    Q_OBJECT
64
65
public:
66
    tst_QAbstractButton();
67
    virtual ~tst_QAbstractButton();
68
69
70
public slots:
71
    void initTestCase();
72
    void cleanupTestCase();
73
    void init();
74
    void cleanup();
75
private slots:
76
    void setAutoRepeat_data();
77
    void setAutoRepeat();
78
79
    void pressed();
80
    void released();
81
    void text();
82
    void setText();
83
    void icon();
84
    void setIcon();
85
86
    void shortcut();
87
    void setShortcut();
88
89
    void animateClick();
90
91
    void isCheckable();
92
    void isDown();
93
    void setDown();
94
    void isChecked();
95
    void autoRepeat();
96
    void toggle();
97
    void clicked();
98
    void toggled();
99
    void isEnabled();
100
    void setEnabled();
101
/*
102
    void state();
103
    void group();
104
    void stateChanged();
105
*/
106
107
    void shortcutEvents();
108
    void stopRepeatTimer();
109
110
    void keyNavigation();
111
112
protected slots:
113
    void onClicked();
114
    void onToggled( bool on );
115
    void onPressed();
116
    void onReleased();
117
    void resetValues();
118
119
private:
120
    uint click_count;
121
    uint toggle_count;
122
    uint press_count;
123
    uint release_count;
124
125
    QAbstractButton *testWidget;
126
};
127
128
// QAbstractButton is an abstract class in 4.0
129
class MyButton : public QAbstractButton
130
{
131
public:
132
    MyButton(QWidget *p = 0) : QAbstractButton(p) {}
133
    void paintEvent(QPaintEvent *)
134
    {
135
        QPainter p(this);
136
        QRect r = rect();
137
        p.fillRect(r, isDown() ? Qt::black : (isChecked() ? Qt::lightGray : Qt::white));
138
        p.setPen(isDown() ? Qt::white : Qt::black);
139
        p.drawRect(r);
140
        p.drawText(r, Qt::AlignCenter | Qt::TextShowMnemonic, text());
141
        if (hasFocus()) {
142
            r.adjust(2, 2, -2, -2);
143
            QStyleOptionFocusRect opt;
144
            opt.rect = r;
145
            opt.palette = palette();
146
            opt.state = QStyle::State_None;
147
            style()->drawPrimitive(QStyle::PE_FrameFocusRect, &opt, &p, this);
148
#ifdef Q_WS_MAC
149
            p.setPen(Qt::red);
150
            p.drawRect(r);
151
#endif
152
        }
153
    }
154
    QSize sizeHint() const
155
    {
156
        QSize sh(8, 8);
157
        if (!text().isEmpty())
158
            sh += fontMetrics().boundingRect(text()).size();
159
        return sh;
160
    }
161
162
    void resetTimerEvents() { timerEvents = 0; }
163
    int timerEventCount() const { return timerEvents; }
164
165
private:
166
167
    int timerEvents;
168
169
    void timerEvent(QTimerEvent *event)
170
    {
171
        ++timerEvents;
172
        QAbstractButton::timerEvent(event);
173
    }
174
};
175
176
tst_QAbstractButton::tst_QAbstractButton()
177
{
178
}
179
180
tst_QAbstractButton::~tst_QAbstractButton()
181
{
182
}
183
184
void tst_QAbstractButton::initTestCase()
185
{
186
    testWidget = new MyButton(0);
187
    testWidget->setObjectName("testObject");
188
    testWidget->resize( 200, 200 );
189
    testWidget->show();
190
191
    connect( testWidget, SIGNAL(clicked()), this, SLOT(onClicked()) );
192
    connect( testWidget, SIGNAL(pressed()), this, SLOT(onPressed()) );
193
    connect( testWidget, SIGNAL(released()), this, SLOT(onReleased()) );
194
    connect( testWidget, SIGNAL(toggled(bool)), this, SLOT(onToggled(bool)) );
195
}
196
197
void tst_QAbstractButton::cleanupTestCase()
198
{
199
    delete testWidget;
200
}
201
202
void tst_QAbstractButton::init()
203
{
204
    testWidget->setText("Test");
205
    testWidget->setEnabled( TRUE );
206
    testWidget->setDown( FALSE );
207
    testWidget->setAutoRepeat( FALSE );
208
    QKeySequence seq;
209
    testWidget->setShortcut( seq );
210
211
    toggle_count = 0;
212
    press_count = 0;
213
    release_count = 0;
214
    click_count = 0;
215
}
216
217
void tst_QAbstractButton::cleanup()
218
{
219
}
220
221
void tst_QAbstractButton::resetValues()
222
{
223
    toggle_count = 0;
224
    press_count = 0;
225
    release_count = 0;
226
    click_count = 0;
227
}
228
229
void tst_QAbstractButton::onClicked()
230
{
231
    click_count++;
232
}
233
234
void tst_QAbstractButton::onToggled( bool /*on*/ )
235
{
236
    toggle_count++;
237
}
238
239
void tst_QAbstractButton::onPressed()
240
{
241
    press_count++;
242
}
243
244
void tst_QAbstractButton::onReleased()
245
{
246
    release_count++;
247
}
248
249
void tst_QAbstractButton::autoRepeat()
250
{
251
    DEPENDS_ON(" setAutoRepeat" );
252
}
253
254
void tst_QAbstractButton::setAutoRepeat_data()
255
{
256
    QTest::addColumn<int>("mode");
257
    QTest::newRow( "" ) << 0;
258
    QTest::newRow( "" ) << 1;
259
    QTest::newRow( "" ) << 2;
260
    QTest::newRow( "" ) << 3;
261
    QTest::newRow( "" ) << 4;
262
    QTest::newRow( "" ) << 5;
263
    QTest::newRow( "" ) << 6;
264
}
265
266
#define REPEAT_DELAY 1000
267
268
int test_count = 0;
269
int last_mode = 0;
270
271
void tst_QAbstractButton::setAutoRepeat()
272
{
273
    QFETCH( int, mode );
274
275
    //FIXME: temp code to check that the test fails consistenly
276
    //retest( 3 );
277
278
    switch (mode)
279
    {
280
    case 0:
281
        QVERIFY( !testWidget->isCheckable() );
282
        break;
283
    case 1:
284
        // check if we can toggle the mode
285
        testWidget->setAutoRepeat( TRUE );
286
        QVERIFY( testWidget->autoRepeat() );
287
288
        testWidget->setAutoRepeat( FALSE );
289
        QVERIFY( !testWidget->autoRepeat() );
290
        break;
291
    case 2:
292
        // check that the button is down if we press space and not in autorepeat
293
        testWidget->setDown( FALSE );
294
        testWidget->setAutoRepeat( FALSE );
295
        QTest::keyPress( testWidget, Qt::Key_Space );
296
297
        QTest::qWait( REPEAT_DELAY );
298
299
        QVERIFY( release_count == 0 );
300
        QVERIFY( testWidget->isDown() );
301
        QVERIFY( toggle_count == 0 );
302
        QVERIFY( press_count == 1 );
303
        QVERIFY( click_count == 0 );
304
305
        QTest::keyRelease( testWidget, Qt::Key_Space );
306
        QVERIFY( click_count == 1 );
307
        QVERIFY( release_count == 1 );
308
        break;
309
    case 3:
310
        // check that the button is down if we press space while in autorepeat
311
        testWidget->setDown(false);
312
        testWidget->setAutoRepeat(true);
313
        QTest::keyPress(testWidget, Qt::Key_Space);
314
        QTest::qWait(REPEAT_DELAY);
315
        QVERIFY(testWidget->isDown());
316
        QTest::keyRelease(testWidget, Qt::Key_Space);
317
        QVERIFY(release_count == press_count);
318
        QVERIFY(toggle_count == 0);
319
        QVERIFY(press_count == click_count);
320
        QVERIFY(click_count > 1);
321
        break;
322
    case 4:
323
        // check that pressing ENTER has no effect when autorepeat is FALSE
324
        testWidget->setDown( FALSE );
325
        testWidget->setAutoRepeat( FALSE );
326
        QTest::keyPress( testWidget, Qt::Key_Enter );
327
328
        QTest::qWait( REPEAT_DELAY );
329
330
        QVERIFY( !testWidget->isDown() );
331
        QVERIFY( toggle_count == 0 );
332
        QVERIFY( press_count == 0 );
333
        QVERIFY( release_count == 0 );
334
        QVERIFY( click_count == 0 );
335
        QTest::keyRelease( testWidget, Qt::Key_Enter );
336
337
        QVERIFY( click_count == 0 );
338
        break;
339
    case 5:
340
        // check that pressing ENTER has no effect when autorepeat is TRUE
341
        testWidget->setDown( FALSE );
342
        testWidget->setAutoRepeat( TRUE );
343
        QTest::keyPress( testWidget, Qt::Key_Enter );
344
345
        QTest::qWait( REPEAT_DELAY );
346
347
        QVERIFY( !testWidget->isDown() );
348
        QVERIFY( toggle_count == 0 );
349
        QVERIFY( press_count == 0 );
350
        QVERIFY( release_count == 0 );
351
        QVERIFY( click_count == 0 );
352
353
        QTest::keyRelease( testWidget, Qt::Key_Enter );
354
355
        QVERIFY( click_count == 0 );
356
        break;
357
    case 6:
358
        // verify autorepeat is off by default.
359
        MyButton tmp( 0);
360
        tmp.setObjectName("tmp" );
361
        QVERIFY( !tmp.autoRepeat() );
362
        break;
363
    }
364
}
365
366
void tst_QAbstractButton::pressed()
367
{
368
    // pressed/released signals expected for a QAbstractButton
369
    QTest::keyPress( testWidget, ' ' );
370
    QCOMPARE( press_count, (uint)1 );
371
}
372
373
void tst_QAbstractButton::released()
374
{
375
    // pressed/released signals expected for a QAbstractButton
376
    QTest::keyPress( testWidget, ' ' );
377
    QTest::keyRelease( testWidget, ' ' );
378
    QCOMPARE( release_count, (uint)1 );
379
}
380
381
void tst_QAbstractButton::setText()
382
{
383
    testWidget->setText("");
384
    QCOMPARE( testWidget->text(), QString("") );
385
    testWidget->setText("simple");
386
    QCOMPARE( testWidget->text(), QString("simple") );
387
    testWidget->setText("&ampersand");
388
    QCOMPARE( testWidget->text(), QString("&ampersand") );
389
#ifndef Q_WS_MAC // no mneonics on Mac.
390
    QCOMPARE( testWidget->shortcut(), QKeySequence("ALT+A"));
391
#endif
392
    testWidget->setText("te&st");
393
    QCOMPARE( testWidget->text(), QString("te&st") );
394
#ifndef Q_WS_MAC // no mneonics on Mac.
395
    QCOMPARE( testWidget->shortcut(), QKeySequence("ALT+S"));
396
#endif
397
    testWidget->setText("foo");
398
    QCOMPARE( testWidget->text(), QString("foo") );
399
#ifndef Q_WS_MAC // no mneonics on Mac.
400
    QCOMPARE( testWidget->shortcut(), QKeySequence());
401
#endif
402
}
403
404
void tst_QAbstractButton::text()
405
{
406
    DEPENDS_ON( "setText" );
407
}
408
409
void tst_QAbstractButton::setIcon()
410
{
411
    const char *test1_xpm[] = {
412
    "12 8 2 1",
413
    ". c None",
414
    "c c #ff0000",
415
    ".........ccc",
416
    "........ccc.",
417
    ".......ccc..",
418
    "ccc...ccc...",
419
    ".ccc.ccc....",
420
    "..ccccc.....",
421
    "...ccc......",
422
    "....c.......",
423
    };
424
425
    QPixmap p(test1_xpm);
426
    testWidget->setIcon( p );
427
    QCOMPARE( testWidget->icon().pixmap(12, 8), p );
428
429
    // Test for #14793
430
431
    const char *test2_xpm[] = {
432
    "12 8 2 1",
433
    ". c None",
434
    "c c #ff0000",
435
    "ccc......ccc",
436
    ".ccc....ccc.",
437
    "..ccc..ccc..",
438
    "....cc.cc...",
439
    ".....ccc....",
440
    "....cc.cc...",
441
    "...ccc.ccc..",
442
    "..ccc...ccc.",
443
    };
444
445
    int currentHeight = testWidget->height();
446
    int currentWidth = testWidget->width();
447
448
    QPixmap p2( test2_xpm );
449
    for ( int a = 0; a<5; a++ )
450
	testWidget->setIcon( p2 );
451
452
    QCOMPARE( testWidget->icon().pixmap(12, 8), p2 );
453
454
    QCOMPARE( testWidget->height(), currentHeight );
455
    QCOMPARE( testWidget->width(), currentWidth );
456
}
457
458
void tst_QAbstractButton::icon()
459
{
460
    DEPENDS_ON( "setIcon" );
461
}
462
463
void tst_QAbstractButton::isEnabled()
464
{
465
    DEPENDS_ON( "setEnabled" );
466
}
467
468
void tst_QAbstractButton::setEnabled()
469
{
470
    testWidget->setEnabled( FALSE );
471
    QVERIFY( !testWidget->isEnabled() );
472
//    QTEST( testWidget, "disabled" );
473
474
    testWidget->setEnabled( TRUE );
475
    QVERIFY( testWidget->isEnabled() );
476
//    QTEST( testWidget, "enabled" );
477
}
478
479
void tst_QAbstractButton::isCheckable()
480
{
481
    QVERIFY( !testWidget->isCheckable() );
482
}
483
484
485
void tst_QAbstractButton::isDown()
486
{
487
    DEPENDS_ON( "setDown" );
488
}
489
490
void tst_QAbstractButton::setDown()
491
{
492
    testWidget->setDown( FALSE );
493
    QVERIFY( !testWidget->isDown() );
494
495
    testWidget->setDown( TRUE );
496
    QTest::qWait(300);
497
    QVERIFY( testWidget->isDown() );
498
499
    testWidget->setDown( TRUE );
500
501
    // add some debugging stuff
502
    QWidget *grab = QWidget::keyboardGrabber();
503
    if (grab != 0 && grab != testWidget)
504
        qDebug( "testWidget != keyboardGrabber" );
505
    grab = qApp->focusWidget();
506
    if (grab != 0 && grab != testWidget)
507
        qDebug( "testWidget != focusWidget" );
508
509
    QTest::keyClick( testWidget, Qt::Key_Escape );
510
    QVERIFY( !testWidget->isDown() );
511
}
512
513
void tst_QAbstractButton::isChecked()
514
{
515
    testWidget->setDown( FALSE );
516
    QVERIFY( !testWidget->isChecked() );
517
518
    testWidget->setDown( TRUE );
519
    QVERIFY( !testWidget->isChecked() );
520
521
    testWidget->setDown( FALSE );
522
    testWidget->toggle();
523
    QVERIFY( testWidget->isChecked() == testWidget->isCheckable() );
524
}
525
526
void tst_QAbstractButton::toggle()
527
{
528
    DEPENDS_ON( "toggled" );
529
}
530
531
void tst_QAbstractButton::toggled()
532
{
533
    testWidget->toggle();
534
    QVERIFY( toggle_count == 0 );
535
536
    QTest::mousePress( testWidget, Qt::LeftButton );
537
    QVERIFY( toggle_count == 0 );
538
    QVERIFY( click_count == 0 );
539
540
    QTest::mouseRelease( testWidget, Qt::LeftButton );
541
    QVERIFY( click_count == 1 );
542
}
543
544
void tst_QAbstractButton::shortcut()
545
{
546
    DEPENDS_ON( "setShortcut" );
547
}
548
549
void tst_QAbstractButton::setShortcut()
550
{
551
    QKeySequence seq( Qt::Key_A );
552
    testWidget->setShortcut( seq );
553
    QApplication::setActiveWindow(testWidget);
554
555
    // must be active to get shortcuts
556
    for (int i = 0; !testWidget->isActiveWindow() && i < 100; ++i) {
557
       testWidget->activateWindow();
558
       QApplication::instance()->processEvents();
559
       QTest::qWait(100);
560
    }
561
    QVERIFY(testWidget->isActiveWindow());
562
563
    QTest::keyClick( testWidget, 'A' );
564
    QTest::qWait(300);                      // Animate click takes time
565
    QCOMPARE(click_count,  (uint)1);
566
    QCOMPARE(press_count,  (uint)1); // Press is part of a click
567
    QCOMPARE(release_count,(uint)1); // Release is part of a click
568
569
    QVERIFY( toggle_count == 0 );
570
571
//     resetValues();
572
//     QTest::keyPress( testWidget, 'A' );
573
//     QTest::qWait(10000);
574
//     QTest::keyRelease( testWidget, 'A' );
575
//     QCOMPARE(click_count,  (uint)1);
576
//     QCOMPARE(press_count,  (uint)1);
577
//     QCOMPARE(release_count,(uint)1);
578
579
//     qDebug() << click_count;
580
581
}
582
583
void tst_QAbstractButton::animateClick()
584
{
585
    testWidget->animateClick();
586
    QVERIFY( testWidget->isDown() );
587
    qApp->processEvents();
588
    QVERIFY( testWidget->isDown() );
589
    QTest::qWait(200);
590
    qApp->processEvents();
591
    QVERIFY( !testWidget->isDown() );
592
}
593
594
void tst_QAbstractButton::clicked()
595
{
596
    DEPENDS_ON( "toggled" );
597
}
598
599
/*
600
void tst_QAbstractButton::group()
601
{
602
}
603
604
void tst_QAbstractButton::state()
605
{
606
}
607
608
void tst_QAbstractButton::stateChanged()
609
{
610
}
611
*/
612
613
void tst_QAbstractButton::shortcutEvents()
614
{
615
    MyButton button;
616
    QSignalSpy pressedSpy(&button, SIGNAL(pressed()));
617
    QSignalSpy releasedSpy(&button, SIGNAL(released()));
618
    QSignalSpy clickedSpy(&button, SIGNAL(clicked(bool)));
619
620
    for (int i = 0; i < 4; ++i) {
621
        QKeySequence sequence;
622
        QShortcutEvent event(sequence, false);
623
        QApplication::sendEvent(&button, &event);
624
        if (i < 2)
625
            QTest::qWait(500);
626
    }
627
628
    QTest::qWait(1000); // ensure animate timer is expired
629
630
    QCOMPARE(pressedSpy.count(), 3);
631
    QCOMPARE(releasedSpy.count(), 3);
632
    QCOMPARE(clickedSpy.count(), 3);
633
}
634
635
void tst_QAbstractButton::stopRepeatTimer()
636
{
637
    MyButton button;
638
    button.setAutoRepeat(true);
639
640
    // Mouse trigger case:
641
    button.resetTimerEvents();
642
    QTest::mousePress(&button, Qt::LeftButton);
643
    QTest::qWait(1000);
644
    QVERIFY(button.timerEventCount() > 0);
645
646
    QTest::mouseRelease(&button, Qt::LeftButton);
647
    button.resetTimerEvents();
648
    QTest::qWait(1000);
649
    QCOMPARE(button.timerEventCount(), 0);
650
651
    // Key trigger case:
652
    button.resetTimerEvents();
653
    QTest::keyPress(&button, Qt::Key_Space);
654
    QTest::qWait(1000);
655
    QVERIFY(button.timerEventCount() > 0);
656
657
    QTest::keyRelease(&button, Qt::Key_Space);
658
    button.resetTimerEvents();
659
    QTest::qWait(1000);
660
    QCOMPARE(button.timerEventCount(), 0);
661
}
662
663
void tst_QAbstractButton::keyNavigation()
664
{
665
    QSKIP("Key navigation in QAbstractButton will be fixed/improved as part of task 194373", SkipSingle);
666
667
    QWidget widget;
668
    QGridLayout *layout = new QGridLayout(&widget);
669
    QAbstractButton *buttons[3][3];
670
    for(int y = 0; y < 3; y++) {
671
        for(int x = 0; x < 3; x++) {
672
            buttons[y][x] = new MyButton(&widget);
673
            buttons[y][x]->setFocusPolicy(Qt::StrongFocus);
674
            layout->addWidget(buttons[y][x], y, x);
675
        }
676
    }
677
678
    widget.show();
679
    qApp->setActiveWindow(&widget);
680
    widget.activateWindow();
681
    QTest::qWait(30);
682
683
    buttons[1][1]->setFocus();
684
    QTest::qWait(400);
685
    QVERIFY(buttons[1][1]->hasFocus());
686
    QTest::keyPress(buttons[1][1], Qt::Key_Up);
687
    QTest::qWait(100);
688
    QVERIFY(buttons[0][1]->hasFocus());
689
    QTest::keyPress(buttons[0][1], Qt::Key_Down);
690
    QTest::qWait(100);
691
    QVERIFY(buttons[1][1]->hasFocus());
692
    QTest::keyPress(buttons[1][1], Qt::Key_Left);
693
    QTest::qWait(100);
694
    QVERIFY(buttons[1][0]->hasFocus());
695
    QTest::keyPress(buttons[1][0], Qt::Key_Down);
696
    QTest::qWait(100);
697
    QVERIFY(buttons[2][0]->hasFocus());
698
    QTest::keyPress(buttons[2][0], Qt::Key_Right);
699
    QTest::qWait(100);
700
    QVERIFY(buttons[2][1]->hasFocus());
701
    QTest::keyPress(buttons[2][1], Qt::Key_Right);
702
    QTest::qWait(100);
703
    QVERIFY(buttons[2][2]->hasFocus());
704
    QTest::keyPress(buttons[2][2], Qt::Key_Up);
705
    QTest::qWait(100);
706
    QVERIFY(buttons[1][2]->hasFocus());
707
    QTest::keyPress(buttons[1][2], Qt::Key_Up);
708
    QTest::qWait(100);
709
    QVERIFY(buttons[0][2]->hasFocus());
710
    buttons[0][1]->hide();
711
    QTest::keyPress(buttons[0][2], Qt::Key_Left);
712
    QTest::qWait(100);
713
    QVERIFY(buttons[0][0]->hasFocus());
714
715
716
}
717
718
QTEST_MAIN(tst_QAbstractButton)
719
#include "tst_qabstractbutton.moc"