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 "qbuttongroup.h" |
34 | #include <qaction.h> |
35 | #include <qapplication.h> |
36 | #include <qdialog.h> |
37 | #include <qlayout.h> |
38 | #include <qgroupbox.h> |
39 | #include <qradiobutton.h> |
40 | #include <qpushbutton.h> |
41 | #include <qlineedit.h> |
42 | #include <qtoolbutton.h> |
43 | #ifdef Q_OS_MAC |
44 | #include <qsettings.h> |
45 | #endif |
46 | |
47 | class SpecialRadioButton: public QRadioButton |
48 | { |
49 | public: |
50 | SpecialRadioButton(QWidget *parent) : QRadioButton(parent) |
51 | { } |
52 | |
53 | protected: |
54 | void focusInEvent(QFocusEvent *) |
55 | { |
56 | QCoreApplication::postEvent(receiver: this, event: new QKeyEvent(QEvent::KeyPress, |
57 | Qt::Key_Down, Qt::NoModifier)); |
58 | } |
59 | }; |
60 | |
61 | class TestPushButton : public QPushButton |
62 | { |
63 | public: |
64 | TestPushButton(QWidget *parent = nullptr) |
65 | : QPushButton(parent) |
66 | {} |
67 | TestPushButton(const QString &title, QWidget *parent = nullptr) |
68 | : QPushButton(title, parent) |
69 | {} |
70 | |
71 | protected: |
72 | bool hitButton(const QPoint &pos) const override |
73 | { |
74 | return rect().contains(p: pos); |
75 | } |
76 | }; |
77 | |
78 | #include <qbuttongroup.h> |
79 | |
80 | class tst_QButtonGroup : public QObject |
81 | { |
82 | Q_OBJECT |
83 | |
84 | private slots: |
85 | void arrowKeyNavigation(); |
86 | void keyNavigationPushButtons(); |
87 | void exclusive(); |
88 | void exclusiveWithActions(); |
89 | void testSignals(); |
90 | void checkedButton(); |
91 | |
92 | void task106609(); |
93 | |
94 | void autoIncrementId(); |
95 | |
96 | void task209485_removeFromGroupInEventHandler_data(); |
97 | void task209485_removeFromGroupInEventHandler(); |
98 | }; |
99 | |
100 | QT_BEGIN_NAMESPACE |
101 | extern bool Q_GUI_EXPORT qt_tab_all_widgets(); |
102 | QT_END_NAMESPACE |
103 | |
104 | |
105 | void tst_QButtonGroup::arrowKeyNavigation() |
106 | { |
107 | if (!qt_tab_all_widgets()) |
108 | QSKIP("This test requires full keyboard control to be enabled." ); |
109 | |
110 | if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) |
111 | QSKIP("Wayland: This fails. Figure out why." ); |
112 | |
113 | QDialog dlg(0); |
114 | QHBoxLayout layout(&dlg); |
115 | QGroupBox g1("1" , &dlg); |
116 | QHBoxLayout g1layout(&g1); |
117 | QRadioButton bt1("Radio1" , &g1); |
118 | TestPushButton pb("PB" , &g1); |
119 | QLineEdit le(&g1); |
120 | QRadioButton bt2("Radio2" , &g1); |
121 | g1layout.addWidget(&bt1); |
122 | g1layout.addWidget(&pb); |
123 | g1layout.addWidget(&le); |
124 | g1layout.addWidget(&bt2); |
125 | |
126 | // create a mixed button group with radion buttons and push |
127 | // buttons. Not very useful, but it tests borderline cases wrt |
128 | // focus handling. |
129 | QButtonGroup bgrp1(&g1); |
130 | bgrp1.addButton(&bt1); |
131 | bgrp1.addButton(&pb); |
132 | bgrp1.addButton(&bt2); |
133 | |
134 | QGroupBox g2("2" , &dlg); |
135 | QVBoxLayout g2layout(&g2); |
136 | // we don't need a button group here, because radio buttons are |
137 | // auto exclusive, i.e. they group themselves in he same parent |
138 | // widget. |
139 | QRadioButton bt3("Radio3" , &g2); |
140 | QRadioButton bt4("Radio4" , &g2); |
141 | g2layout.addWidget(&bt3); |
142 | g2layout.addWidget(&bt4); |
143 | |
144 | layout.addWidget(&g1); |
145 | layout.addWidget(&g2); |
146 | |
147 | dlg.show(); |
148 | qApp->setActiveWindow(&dlg); |
149 | QVERIFY(QTest::qWaitForWindowActive(&dlg)); |
150 | |
151 | bt1.setFocus(); |
152 | |
153 | QTRY_VERIFY(bt1.hasFocus()); |
154 | |
155 | QTest::keyClick(widget: &bt1, key: Qt::Key_Right); |
156 | QVERIFY(pb.hasFocus()); |
157 | QTest::keyClick(widget: &pb, key: Qt::Key_Right); |
158 | QVERIFY(bt2.hasFocus()); |
159 | QTest::keyClick(widget: &bt2, key: Qt::Key_Right); |
160 | QVERIFY(bt2.hasFocus()); |
161 | QTest::keyClick(widget: &bt2, key: Qt::Key_Left); |
162 | QVERIFY(pb.hasFocus()); |
163 | QTest::keyClick(widget: &pb, key: Qt::Key_Left); |
164 | QVERIFY(bt1.hasFocus()); |
165 | |
166 | QTest::keyClick(widget: &bt1, key: Qt::Key_Tab); |
167 | QVERIFY(pb.hasFocus()); |
168 | QTest::keyClick(widget: &pb, key: Qt::Key_Tab); |
169 | |
170 | QVERIFY(le.hasFocus()); |
171 | QCOMPARE(le.selectedText(), le.text()); |
172 | QTest::keyClick(widget: &le, key: Qt::Key_Tab); |
173 | |
174 | QVERIFY(bt2.hasFocus()); |
175 | QTest::keyClick(widget: &bt2, key: Qt::Key_Tab); |
176 | QVERIFY(bt3.hasFocus()); |
177 | |
178 | QTest::keyClick(widget: &bt3, key: Qt::Key_Down); |
179 | QVERIFY(bt4.hasFocus()); |
180 | QTest::keyClick(widget: &bt4, key: Qt::Key_Down); |
181 | QVERIFY(bt4.hasFocus()); |
182 | |
183 | QTest::keyClick(widget: &bt4, key: Qt::Key_Up); |
184 | QVERIFY(bt3.hasFocus()); |
185 | QTest::keyClick(widget: &bt3, key: Qt::Key_Up); |
186 | QVERIFY(bt3.hasFocus()); |
187 | } |
188 | |
189 | /* |
190 | Test that tab and arrow key navigation through buttons |
191 | in an invisible button group works as expected. Tabbing |
192 | into the group should give focus to the checked button, |
193 | and arrow navigation should change the checked button and |
194 | move focus. |
195 | */ |
196 | void tst_QButtonGroup::keyNavigationPushButtons() |
197 | { |
198 | if (!qt_tab_all_widgets()) |
199 | QSKIP("This test requires full keyboard control to be enabled." ); |
200 | |
201 | QDialog dlg(nullptr); |
202 | QLineEdit *le1 = new QLineEdit; |
203 | le1->setObjectName("le1" ); |
204 | QPushButton *pb1 = new QPushButton("Exclusive 1" ); |
205 | pb1->setObjectName("pb1" ); |
206 | pb1->setCheckable(true); |
207 | pb1->setChecked(true); |
208 | QPushButton *pb2 = new QPushButton("Exclusive 2" ); |
209 | pb2->setObjectName("pb2" ); |
210 | pb2->setCheckable(true); |
211 | QPushButton *pb3 = new QPushButton("Exclusive 3" ); |
212 | pb3->setObjectName("pb3" ); |
213 | pb3->setCheckable(true); |
214 | QLineEdit *le2 = new QLineEdit; |
215 | le2->setObjectName("le2" ); |
216 | |
217 | QVBoxLayout* layout = new QVBoxLayout(&dlg); |
218 | layout->addWidget(le1); |
219 | layout->addWidget(pb1); |
220 | layout->addWidget(pb2); |
221 | layout->addWidget(pb3); |
222 | layout->addWidget(le2); |
223 | |
224 | QButtonGroup *buttonGroup = new QButtonGroup; |
225 | buttonGroup->addButton(pb1); |
226 | buttonGroup->addButton(pb2); |
227 | buttonGroup->addButton(pb3); |
228 | |
229 | dlg.show(); |
230 | qApp->setActiveWindow(&dlg); |
231 | if (!QTest::qWaitForWindowActive(widget: &dlg)) |
232 | QSKIP("Window activation failed, skipping test" ); |
233 | |
234 | QVERIFY2(le1->hasFocus(), qPrintable(qApp->focusWidget()->objectName())); |
235 | QTest::keyClick(qApp->focusWidget(), key: Qt::Key_Tab); |
236 | QVERIFY2(pb1->hasFocus(), qPrintable(qApp->focusWidget()->objectName())); |
237 | QVERIFY2(pb1->isChecked(), qPrintable(buttonGroup->checkedButton()->objectName())); |
238 | QTest::keyClick(qApp->focusWidget(), key: Qt::Key_Down); |
239 | QVERIFY2(pb2->hasFocus(), qPrintable(qApp->focusWidget()->objectName())); |
240 | QVERIFY2(pb2->isChecked(), qPrintable(buttonGroup->checkedButton()->objectName())); |
241 | QTest::keyClick(qApp->focusWidget(), key: Qt::Key_Down); |
242 | QVERIFY2(pb3->hasFocus(), qPrintable(qApp->focusWidget()->objectName())); |
243 | QVERIFY2(pb3->isChecked(), qPrintable(buttonGroup->checkedButton()->objectName())); |
244 | QTest::keyClick(qApp->focusWidget(), key: Qt::Key_Up); |
245 | QVERIFY2(pb2->hasFocus(), qPrintable(qApp->focusWidget()->objectName())); |
246 | QVERIFY2(pb2->isChecked(), qPrintable(buttonGroup->checkedButton()->objectName())); |
247 | QTest::keyClick(qApp->focusWidget(), key: Qt::Key_Tab); |
248 | QVERIFY2(le2->hasFocus(), qPrintable(qApp->focusWidget()->objectName())); |
249 | QTest::keyClick(qApp->focusWidget(), key: Qt::Key_Backtab); |
250 | QVERIFY2(pb2->hasFocus(), qPrintable(qApp->focusWidget()->objectName())); |
251 | QVERIFY2(pb2->isChecked(), qPrintable(buttonGroup->checkedButton()->objectName())); |
252 | QTest::keyClick(qApp->focusWidget(), key: Qt::Key_Backtab); |
253 | QVERIFY2(le1->hasFocus(), qPrintable(qApp->focusWidget()->objectName())); |
254 | } |
255 | |
256 | void tst_QButtonGroup::exclusiveWithActions() |
257 | { |
258 | QDialog dlg(0); |
259 | QHBoxLayout layout(&dlg); |
260 | QAction *action1 = new QAction("Action 1" , &dlg); |
261 | action1->setCheckable(true); |
262 | QAction *action2 = new QAction("Action 2" , &dlg); |
263 | action2->setCheckable(true); |
264 | QAction *action3 = new QAction("Action 3" , &dlg); |
265 | action3->setCheckable(true); |
266 | QToolButton *toolButton1 = new QToolButton(&dlg); |
267 | QToolButton *toolButton2 = new QToolButton(&dlg); |
268 | QToolButton *toolButton3 = new QToolButton(&dlg); |
269 | toolButton1->setDefaultAction(action1); |
270 | toolButton2->setDefaultAction(action2); |
271 | toolButton3->setDefaultAction(action3); |
272 | layout.addWidget(toolButton1); |
273 | layout.addWidget(toolButton2); |
274 | layout.addWidget(toolButton3); |
275 | QButtonGroup *buttonGroup = new QButtonGroup( &dlg ); |
276 | buttonGroup->setExclusive(true); |
277 | buttonGroup->addButton(toolButton1, id: 1); |
278 | buttonGroup->addButton(toolButton2, id: 2); |
279 | buttonGroup->addButton(toolButton3, id: 3); |
280 | dlg.show(); |
281 | |
282 | QTest::mouseClick(widget: toolButton1, button: Qt::LeftButton); |
283 | QVERIFY(toolButton1->isChecked()); |
284 | QVERIFY(action1->isChecked()); |
285 | QVERIFY(!toolButton2->isChecked()); |
286 | QVERIFY(!toolButton3->isChecked()); |
287 | QVERIFY(!action2->isChecked()); |
288 | QVERIFY(!action3->isChecked()); |
289 | |
290 | QTest::mouseClick(widget: toolButton2, button: Qt::LeftButton); |
291 | QVERIFY(toolButton2->isChecked()); |
292 | QVERIFY(action2->isChecked()); |
293 | QVERIFY(!toolButton1->isChecked()); |
294 | QVERIFY(!toolButton3->isChecked()); |
295 | QVERIFY(!action1->isChecked()); |
296 | QVERIFY(!action3->isChecked()); |
297 | |
298 | QTest::mouseClick(widget: toolButton3, button: Qt::LeftButton); |
299 | QVERIFY(toolButton3->isChecked()); |
300 | QVERIFY(action3->isChecked()); |
301 | QVERIFY(!toolButton1->isChecked()); |
302 | QVERIFY(!toolButton2->isChecked()); |
303 | QVERIFY(!action1->isChecked()); |
304 | QVERIFY(!action2->isChecked()); |
305 | |
306 | QTest::mouseClick(widget: toolButton2, button: Qt::LeftButton); |
307 | QVERIFY(toolButton2->isChecked()); |
308 | QVERIFY(action2->isChecked()); |
309 | QVERIFY(!toolButton1->isChecked()); |
310 | QVERIFY(!toolButton3->isChecked()); |
311 | QVERIFY(!action1->isChecked()); |
312 | QVERIFY(!action3->isChecked()); |
313 | } |
314 | |
315 | void tst_QButtonGroup::exclusive() |
316 | { |
317 | QDialog dlg(0); |
318 | QHBoxLayout layout(&dlg); |
319 | TestPushButton *pushButton1 = new TestPushButton(&dlg); |
320 | TestPushButton *pushButton2 = new TestPushButton(&dlg); |
321 | TestPushButton *pushButton3 = new TestPushButton(&dlg); |
322 | pushButton1->setCheckable(true); |
323 | pushButton2->setCheckable(true); |
324 | pushButton3->setCheckable(true); |
325 | layout.addWidget(pushButton1); |
326 | layout.addWidget(pushButton2); |
327 | layout.addWidget(pushButton3); |
328 | QButtonGroup *buttonGroup = new QButtonGroup( &dlg ); |
329 | buttonGroup->setExclusive(true); |
330 | buttonGroup->addButton(pushButton1, id: 1); |
331 | buttonGroup->addButton(pushButton2, id: 2); |
332 | buttonGroup->addButton(pushButton3, id: 3); |
333 | dlg.show(); |
334 | |
335 | QTest::mouseClick(widget: pushButton1, button: Qt::LeftButton); |
336 | QVERIFY(pushButton1->isChecked()); |
337 | QVERIFY(!pushButton2->isChecked()); |
338 | QVERIFY(!pushButton3->isChecked()); |
339 | |
340 | QTest::mouseClick(widget: pushButton2, button: Qt::LeftButton); |
341 | QVERIFY(pushButton2->isChecked()); |
342 | QVERIFY(!pushButton1->isChecked()); |
343 | QVERIFY(!pushButton3->isChecked()); |
344 | |
345 | QTest::mouseClick(widget: pushButton3, button: Qt::LeftButton); |
346 | QVERIFY(pushButton3->isChecked()); |
347 | QVERIFY(!pushButton1->isChecked()); |
348 | QVERIFY(!pushButton2->isChecked()); |
349 | |
350 | QTest::mouseClick(widget: pushButton2, button: Qt::LeftButton); |
351 | QVERIFY(pushButton2->isChecked()); |
352 | QVERIFY(!pushButton1->isChecked()); |
353 | QVERIFY(!pushButton3->isChecked()); |
354 | } |
355 | |
356 | void tst_QButtonGroup::testSignals() |
357 | { |
358 | QButtonGroup buttons; |
359 | TestPushButton pb1; |
360 | TestPushButton pb2; |
361 | TestPushButton pb3; |
362 | buttons.addButton(&pb1); |
363 | buttons.addButton(&pb2, id: 23); |
364 | buttons.addButton(&pb3); |
365 | |
366 | qRegisterMetaType<QAbstractButton *>(typeName: "QAbstractButton *" ); |
367 | QSignalSpy clickedSpy(&buttons, SIGNAL(buttonClicked(QAbstractButton*))); |
368 | QSignalSpy clickedIdSpy(&buttons, SIGNAL(idClicked(int))); |
369 | QSignalSpy pressedSpy(&buttons, SIGNAL(buttonPressed(QAbstractButton*))); |
370 | QSignalSpy pressedIdSpy(&buttons, SIGNAL(idPressed(int))); |
371 | QSignalSpy releasedSpy(&buttons, SIGNAL(buttonReleased(QAbstractButton*))); |
372 | QSignalSpy releasedIdSpy(&buttons, SIGNAL(idReleased(int))); |
373 | |
374 | pb1.animateClick(); |
375 | QTestEventLoop::instance().enterLoop(secs: 1); |
376 | |
377 | QCOMPARE(clickedSpy.count(), 1); |
378 | QCOMPARE(clickedIdSpy.count(), 1); |
379 | |
380 | int expectedId = -2; |
381 | |
382 | QCOMPARE(clickedIdSpy.takeFirst().at(0).toInt(), expectedId); |
383 | QCOMPARE(pressedSpy.count(), 1); |
384 | QCOMPARE(pressedIdSpy.count(), 1); |
385 | QCOMPARE(pressedIdSpy.takeFirst().at(0).toInt(), expectedId); |
386 | QCOMPARE(releasedSpy.count(), 1); |
387 | QCOMPARE(releasedIdSpy.count(), 1); |
388 | QCOMPARE(releasedIdSpy.takeFirst().at(0).toInt(), expectedId); |
389 | |
390 | clickedSpy.clear(); |
391 | clickedIdSpy.clear(); |
392 | pressedSpy.clear(); |
393 | pressedIdSpy.clear(); |
394 | releasedSpy.clear(); |
395 | releasedIdSpy.clear(); |
396 | |
397 | pb2.animateClick(); |
398 | QTestEventLoop::instance().enterLoop(secs: 1); |
399 | |
400 | QCOMPARE(clickedSpy.count(), 1); |
401 | QCOMPARE(clickedIdSpy.count(), 1); |
402 | QCOMPARE(clickedIdSpy.takeFirst().at(0).toInt(), 23); |
403 | QCOMPARE(pressedSpy.count(), 1); |
404 | QCOMPARE(pressedIdSpy.count(), 1); |
405 | QCOMPARE(pressedIdSpy.takeFirst().at(0).toInt(), 23); |
406 | QCOMPARE(releasedSpy.count(), 1); |
407 | QCOMPARE(releasedIdSpy.count(), 1); |
408 | QCOMPARE(releasedIdSpy.takeFirst().at(0).toInt(), 23); |
409 | |
410 | |
411 | QSignalSpy toggledSpy(&buttons, SIGNAL(buttonToggled(QAbstractButton*, bool))); |
412 | QSignalSpy toggledIdSpy(&buttons, SIGNAL(idToggled(int, bool))); |
413 | |
414 | pb1.setCheckable(true); |
415 | pb2.setCheckable(true); |
416 | pb1.toggle(); |
417 | QCOMPARE(toggledSpy.count(), 1); |
418 | QCOMPARE(toggledIdSpy.count(), 1); |
419 | |
420 | pb2.toggle(); |
421 | QCOMPARE(toggledSpy.count(), 3); // equals 3 since pb1 and pb2 are both toggled |
422 | QCOMPARE(toggledIdSpy.count(), 3); |
423 | |
424 | pb1.setCheckable(false); |
425 | pb2.setCheckable(false); |
426 | pb1.toggle(); |
427 | QCOMPARE(toggledSpy.count(), 3); |
428 | QCOMPARE(toggledIdSpy.count(), 3); |
429 | } |
430 | |
431 | void tst_QButtonGroup::task106609() |
432 | { |
433 | // task is: |
434 | // sometimes, only one of the two signals in QButtonGroup get emitted |
435 | // they get emitted when using the mouse, but when using the keyboard, only one is |
436 | // |
437 | |
438 | QDialog dlg(0); |
439 | QButtonGroup *buttons = new QButtonGroup(&dlg); |
440 | QVBoxLayout *vbox = new QVBoxLayout(&dlg); |
441 | |
442 | SpecialRadioButton *radio1 = new SpecialRadioButton(&dlg); |
443 | radio1->setText("radio1" ); |
444 | SpecialRadioButton *radio2 = new SpecialRadioButton(&dlg); |
445 | radio2->setText("radio2" ); |
446 | QRadioButton *radio3 = new QRadioButton(&dlg); |
447 | radio3->setText("radio3" ); |
448 | |
449 | buttons->addButton(radio1, id: 1); |
450 | vbox->addWidget(radio1); |
451 | buttons->addButton(radio2, id: 2); |
452 | vbox->addWidget(radio2); |
453 | buttons->addButton(radio3, id: 3); |
454 | vbox->addWidget(radio3); |
455 | dlg.show(); |
456 | QVERIFY(QTest::qWaitForWindowExposed(&dlg)); |
457 | |
458 | qRegisterMetaType<QAbstractButton*>(typeName: "QAbstractButton*" ); |
459 | QSignalSpy spy1(buttons, SIGNAL(buttonClicked(QAbstractButton*))); |
460 | QSignalSpy spy2(buttons, SIGNAL(buttonClicked(int))); |
461 | |
462 | QApplication::setActiveWindow(&dlg); |
463 | QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget*>(&dlg)); |
464 | |
465 | radio1->setFocus(); |
466 | radio1->setChecked(true); |
467 | QTestEventLoop::instance().enterLoop(secs: 1); |
468 | |
469 | //qDebug() << "int:" << spy2.count() << "QAbstractButton*:" << spy1.count(); |
470 | QCOMPARE(spy2.count(), 2); |
471 | QCOMPARE(spy1.count(), 2); |
472 | } |
473 | |
474 | void tst_QButtonGroup::checkedButton() |
475 | { |
476 | QButtonGroup buttons; |
477 | buttons.setExclusive(false); |
478 | TestPushButton pb1; |
479 | pb1.setCheckable(true); |
480 | TestPushButton pb2; |
481 | pb2.setCheckable(true); |
482 | buttons.addButton(&pb1); |
483 | buttons.addButton(&pb2, id: 23); |
484 | |
485 | QVERIFY(!buttons.checkedButton()); |
486 | pb1.setChecked(true); |
487 | QCOMPARE(buttons.checkedButton(), &pb1); |
488 | pb2.setChecked(true); |
489 | QCOMPARE(buttons.checkedButton(), &pb2); |
490 | pb2.setChecked(false); |
491 | QCOMPARE(buttons.checkedButton(), &pb1); |
492 | pb1.setChecked(false); |
493 | QVERIFY(!buttons.checkedButton()); |
494 | |
495 | buttons.setExclusive(true); |
496 | QVERIFY(!buttons.checkedButton()); |
497 | pb1.setChecked(true); |
498 | QCOMPARE(buttons.checkedButton(), &pb1); |
499 | pb2.setChecked(true); |
500 | QCOMPARE(buttons.checkedButton(), &pb2); |
501 | // checked button cannot be unchecked |
502 | pb2.setChecked(false); |
503 | QCOMPARE(buttons.checkedButton(), &pb2); |
504 | } |
505 | |
506 | class task209485_ButtonDeleter : public QObject |
507 | { |
508 | Q_OBJECT |
509 | |
510 | public: |
511 | task209485_ButtonDeleter(QButtonGroup *group, bool deleteButton) |
512 | : group(group) |
513 | , deleteButton(deleteButton) |
514 | { |
515 | connect(asender: group, SIGNAL(buttonClicked(int)), SLOT(buttonClicked(int))); |
516 | } |
517 | |
518 | private slots: |
519 | void buttonClicked(int) |
520 | { |
521 | if (deleteButton) |
522 | group->removeButton(group->buttons().first()); |
523 | } |
524 | |
525 | private: |
526 | QButtonGroup *group; |
527 | bool deleteButton; |
528 | }; |
529 | |
530 | void tst_QButtonGroup::task209485_removeFromGroupInEventHandler_data() |
531 | { |
532 | QTest::addColumn<bool>(name: "deleteButton" ); |
533 | QTest::addColumn<int>(name: "signalCount" ); |
534 | QTest::newRow(dataTag: "buttonPress 1" ) << true << 1; |
535 | QTest::newRow(dataTag: "buttonPress 2" ) << false << 2; |
536 | } |
537 | |
538 | void tst_QButtonGroup::task209485_removeFromGroupInEventHandler() |
539 | { |
540 | QFETCH(bool, deleteButton); |
541 | QFETCH(int, signalCount); |
542 | qRegisterMetaType<QAbstractButton *>(typeName: "QAbstractButton *" ); |
543 | |
544 | TestPushButton *button = new TestPushButton; |
545 | QButtonGroup group; |
546 | group.addButton(button); |
547 | |
548 | task209485_ButtonDeleter buttonDeleter(&group, deleteButton); |
549 | |
550 | QSignalSpy spy1(&group, SIGNAL(buttonClicked(QAbstractButton*))); |
551 | QSignalSpy spy2(&group, SIGNAL(buttonClicked(int))); |
552 | |
553 | // NOTE: Reintroducing the bug of this task will cause the following line to crash: |
554 | QTest::mouseClick(widget: button, button: Qt::LeftButton); |
555 | |
556 | QCOMPARE(spy1.count() + spy2.count(), signalCount); |
557 | } |
558 | |
559 | void tst_QButtonGroup::autoIncrementId() |
560 | { |
561 | QDialog dlg(0); |
562 | QButtonGroup *buttons = new QButtonGroup(&dlg); |
563 | QVBoxLayout *vbox = new QVBoxLayout(&dlg); |
564 | |
565 | QRadioButton *radio1 = new QRadioButton(&dlg); |
566 | radio1->setText("radio1" ); |
567 | QRadioButton *radio2 = new QRadioButton(&dlg); |
568 | radio2->setText("radio2" ); |
569 | QRadioButton *radio3 = new QRadioButton(&dlg); |
570 | radio3->setText("radio3" ); |
571 | |
572 | buttons->addButton(radio1); |
573 | vbox->addWidget(radio1); |
574 | buttons->addButton(radio2); |
575 | vbox->addWidget(radio2); |
576 | buttons->addButton(radio3); |
577 | vbox->addWidget(radio3); |
578 | |
579 | radio1->setChecked(true); |
580 | |
581 | QCOMPARE(buttons->id(radio1), -2); |
582 | QCOMPARE(buttons->id(radio2), -3); |
583 | QCOMPARE(buttons->id(radio3), -4); |
584 | |
585 | dlg.show(); |
586 | } |
587 | |
588 | QTEST_MAIN(tst_QButtonGroup) |
589 | #include "tst_qbuttongroup.moc" |
590 | |