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 | #include <QtTest/QtTest> |
29 | #include <QMessageBox> |
30 | #include <QDebug> |
31 | #include <QPair> |
32 | #include <QList> |
33 | #include <QPointer> |
34 | #include <QTimer> |
35 | #include <QApplication> |
36 | #include <QPushButton> |
37 | #include <QDialogButtonBox> |
38 | #include <qpa/qplatformtheme.h> |
39 | #include <private/qguiapplication_p.h> |
40 | |
41 | class tst_QMessageBox : public QObject |
42 | { |
43 | Q_OBJECT |
44 | |
45 | private slots: |
46 | void sanityTest(); |
47 | void defaultButton(); |
48 | void escapeButton(); |
49 | void button(); |
50 | void statics(); |
51 | void about(); |
52 | void detailsText(); |
53 | void detailsButtonText(); |
54 | void expandDetailsWithoutMoving(); |
55 | |
56 | #ifndef Q_OS_MAC |
57 | void shortcut(); |
58 | #endif |
59 | |
60 | void staticSourceCompat(); |
61 | void instanceSourceCompat(); |
62 | |
63 | void incorrectDefaultButton(); |
64 | void updateSize(); |
65 | |
66 | void setInformativeText(); |
67 | void iconPixmap(); |
68 | |
69 | // QTBUG-44131 |
70 | void acceptedRejectedSignals(); |
71 | void acceptedRejectedSignals_data(); |
72 | |
73 | void cleanup(); |
74 | }; |
75 | |
76 | class tst_ResizingMessageBox : public QMessageBox |
77 | { |
78 | public: |
79 | tst_ResizingMessageBox() : QMessageBox(), resized(false) { } |
80 | bool resized; |
81 | |
82 | protected: |
83 | void resizeEvent ( QResizeEvent * event ) { |
84 | resized = true; |
85 | QMessageBox::resizeEvent(event); |
86 | } |
87 | }; |
88 | |
89 | // ExecCloseHelper: Closes a modal QDialog during its exec() function by either |
90 | // sending a key event or closing it (CloseWindow) once it becomes the active |
91 | // modal window. Pass nullptr to "autodetect" the instance for static methods. |
92 | class ExecCloseHelper : public QObject |
93 | { |
94 | public: |
95 | enum { CloseWindow = -1 }; |
96 | |
97 | explicit ExecCloseHelper(QObject *parent = nullptr) |
98 | : QObject(parent), m_key(0), m_timerId(0), m_testCandidate(nullptr) { } |
99 | |
100 | void start(int key, QWidget *testCandidate = nullptr) |
101 | { |
102 | m_key = key; |
103 | m_testCandidate = testCandidate; |
104 | m_timerId = startTimer(interval: 50); |
105 | } |
106 | |
107 | bool done() const { return !m_timerId; } |
108 | |
109 | protected: |
110 | void timerEvent(QTimerEvent *te) override; |
111 | |
112 | private: |
113 | int m_key; |
114 | int m_timerId; |
115 | QWidget *m_testCandidate; |
116 | }; |
117 | |
118 | void ExecCloseHelper::timerEvent(QTimerEvent *te) |
119 | { |
120 | if (te->timerId() != m_timerId) |
121 | return; |
122 | |
123 | QWidget *modalWidget = QApplication::activeModalWidget(); |
124 | |
125 | if (!m_testCandidate && modalWidget) |
126 | m_testCandidate = modalWidget; |
127 | |
128 | if (m_testCandidate && m_testCandidate == modalWidget) { |
129 | if (m_key == CloseWindow) { |
130 | m_testCandidate->close(); |
131 | } else { |
132 | QKeyEvent *ke = new QKeyEvent(QEvent::KeyPress, m_key, Qt::NoModifier); |
133 | QCoreApplication::postEvent(receiver: m_testCandidate, event: ke); |
134 | } |
135 | m_testCandidate = nullptr; |
136 | killTimer(id: m_timerId); |
137 | m_timerId = m_key = 0; |
138 | } |
139 | } |
140 | |
141 | void tst_QMessageBox::cleanup() |
142 | { |
143 | QTRY_VERIFY(QApplication::topLevelWidgets().isEmpty()); // OS X requires TRY |
144 | } |
145 | |
146 | void tst_QMessageBox::sanityTest() |
147 | { |
148 | #if defined(Q_OS_MACOS) |
149 | if (QSysInfo::productVersion() == QLatin1String("10.12" )) { |
150 | QSKIP("Test hangs on macOS 10.12 -- QTQAINFRA-1362" ); |
151 | return; |
152 | } |
153 | #elif defined(Q_OS_WINRT) |
154 | QSKIP("Test hangs on winrt -- QTBUG-68297" ); |
155 | #endif |
156 | QMessageBox msgBox; |
157 | msgBox.setText("This is insane" ); |
158 | for (int i = 0; i < 10; i++) |
159 | msgBox.setIcon(QMessageBox::Icon(i)); |
160 | msgBox.setIconPixmap(QPixmap()); |
161 | msgBox.setIconPixmap(QPixmap("whatever.png" )); |
162 | msgBox.setTextFormat(Qt::RichText); |
163 | msgBox.setTextFormat(Qt::PlainText); |
164 | ExecCloseHelper closeHelper; |
165 | closeHelper.start(key: ExecCloseHelper::CloseWindow, testCandidate: &msgBox); |
166 | msgBox.exec(); |
167 | } |
168 | |
169 | void tst_QMessageBox::button() |
170 | { |
171 | QMessageBox msgBox; |
172 | msgBox.addButton(text: "retry" , role: QMessageBox::DestructiveRole); |
173 | QVERIFY(msgBox.button(QMessageBox::Ok) == nullptr); // not added yet |
174 | QPushButton *b1 = msgBox.addButton(button: QMessageBox::Ok); |
175 | QCOMPARE(msgBox.button(QMessageBox::Ok), static_cast<QAbstractButton *>(b1)); // just added |
176 | QCOMPARE(msgBox.standardButton(b1), QMessageBox::Ok); |
177 | msgBox.addButton(button: QMessageBox::Cancel); |
178 | QCOMPARE(msgBox.standardButtons(), QMessageBox::Ok | QMessageBox::Cancel); |
179 | |
180 | // remove the cancel, should not exist anymore |
181 | msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); |
182 | QVERIFY(!msgBox.button(QMessageBox::Cancel)); |
183 | QVERIFY(msgBox.button(QMessageBox::Yes) != nullptr); |
184 | |
185 | // should not crash |
186 | QPushButton *b4 = new QPushButton; |
187 | msgBox.addButton(button: b4, role: QMessageBox::DestructiveRole); |
188 | msgBox.addButton(button: nullptr, role: QMessageBox::ActionRole); |
189 | } |
190 | |
191 | void tst_QMessageBox::defaultButton() |
192 | { |
193 | QMessageBox msgBox; |
194 | QVERIFY(!msgBox.defaultButton()); |
195 | msgBox.addButton(button: QMessageBox::Ok); |
196 | msgBox.addButton(button: QMessageBox::Cancel); |
197 | QVERIFY(!msgBox.defaultButton()); |
198 | QPushButton pushButton; |
199 | msgBox.setDefaultButton(&pushButton); |
200 | QVERIFY(msgBox.defaultButton() == nullptr); // we have not added it yet |
201 | QPushButton *retryButton = msgBox.addButton(button: QMessageBox::Retry); |
202 | msgBox.setDefaultButton(retryButton); |
203 | QCOMPARE(msgBox.defaultButton(), retryButton); |
204 | ExecCloseHelper closeHelper; |
205 | closeHelper.start(key: ExecCloseHelper::CloseWindow, testCandidate: &msgBox); |
206 | msgBox.exec(); |
207 | QCOMPARE(msgBox.clickedButton(), msgBox.button(QMessageBox::Cancel)); |
208 | |
209 | closeHelper.start(key: Qt::Key_Enter, testCandidate: &msgBox); |
210 | msgBox.exec(); |
211 | QCOMPARE(msgBox.clickedButton(), static_cast<QAbstractButton *>(retryButton)); |
212 | |
213 | QAbstractButton *okButton = msgBox.button(which: QMessageBox::Ok); |
214 | msgBox.setDefaultButton(QMessageBox::Ok); |
215 | QCOMPARE(msgBox.defaultButton(), static_cast<QPushButton *>(okButton)); |
216 | closeHelper.start(key: Qt::Key_Enter, testCandidate: &msgBox); |
217 | msgBox.exec(); |
218 | QCOMPARE(msgBox.clickedButton(), okButton); |
219 | msgBox.setDefaultButton(QMessageBox::Yes); // its not in there! |
220 | QCOMPARE(msgBox.defaultButton(), okButton); |
221 | msgBox.removeButton(button: okButton); |
222 | delete okButton; |
223 | okButton = nullptr; |
224 | QVERIFY(!msgBox.defaultButton()); |
225 | msgBox.setDefaultButton(QMessageBox::Ok); |
226 | QVERIFY(!msgBox.defaultButton()); |
227 | } |
228 | |
229 | void tst_QMessageBox::escapeButton() |
230 | { |
231 | QMessageBox msgBox; |
232 | QVERIFY(!msgBox.escapeButton()); |
233 | msgBox.addButton(button: QMessageBox::Ok); |
234 | ExecCloseHelper closeHelper; |
235 | closeHelper.start(key: ExecCloseHelper::CloseWindow, testCandidate: &msgBox); |
236 | msgBox.exec(); |
237 | QVERIFY(msgBox.clickedButton() == msgBox.button(QMessageBox::Ok)); // auto detected (one button only) |
238 | msgBox.addButton(button: QMessageBox::Cancel); |
239 | QVERIFY(!msgBox.escapeButton()); |
240 | QPushButton invalidButton; |
241 | msgBox.setEscapeButton(&invalidButton); |
242 | QVERIFY(!msgBox.escapeButton()); |
243 | QAbstractButton *retryButton = msgBox.addButton(button: QMessageBox::Retry); |
244 | |
245 | closeHelper.start(key: ExecCloseHelper::CloseWindow, testCandidate: &msgBox); |
246 | msgBox.exec(); |
247 | QVERIFY(msgBox.clickedButton() == msgBox.button(QMessageBox::Cancel)); // auto detected (cancel) |
248 | |
249 | msgBox.setEscapeButton(retryButton); |
250 | QCOMPARE(msgBox.escapeButton(), static_cast<QAbstractButton *>(retryButton)); |
251 | |
252 | // with escape |
253 | closeHelper.start(key: Qt::Key_Escape, testCandidate: &msgBox); |
254 | msgBox.exec(); |
255 | QCOMPARE(msgBox.clickedButton(), retryButton); |
256 | |
257 | // with close |
258 | closeHelper.start(key: ExecCloseHelper::CloseWindow, testCandidate: &msgBox); |
259 | msgBox.exec(); |
260 | QCOMPARE(msgBox.clickedButton(), static_cast<QAbstractButton *>(retryButton)); |
261 | |
262 | QAbstractButton *okButton = msgBox.button(which: QMessageBox::Ok); |
263 | msgBox.setEscapeButton(QMessageBox::Ok); |
264 | QCOMPARE(msgBox.escapeButton(), okButton); |
265 | closeHelper.start(key: Qt::Key_Escape, testCandidate: &msgBox); |
266 | msgBox.exec(); |
267 | QCOMPARE(msgBox.clickedButton(), okButton); |
268 | msgBox.setEscapeButton(QMessageBox::Yes); // its not in there! |
269 | QCOMPARE(msgBox.escapeButton(), okButton); |
270 | msgBox.removeButton(button: okButton); |
271 | delete okButton; |
272 | okButton = nullptr; |
273 | QVERIFY(!msgBox.escapeButton()); |
274 | msgBox.setEscapeButton(QMessageBox::Ok); |
275 | QVERIFY(!msgBox.escapeButton()); |
276 | |
277 | QMessageBox msgBox2; |
278 | msgBox2.addButton(button: QMessageBox::Yes); |
279 | msgBox2.addButton(button: QMessageBox::No); |
280 | closeHelper.start(key: ExecCloseHelper::CloseWindow, testCandidate: &msgBox2); |
281 | msgBox2.exec(); |
282 | QVERIFY(msgBox2.clickedButton() == msgBox2.button(QMessageBox::No)); // auto detected (one No button only) |
283 | |
284 | QPushButton *rejectButton = new QPushButton; |
285 | msgBox2.addButton(button: rejectButton, role: QMessageBox::RejectRole); |
286 | closeHelper.start(key: ExecCloseHelper::CloseWindow, testCandidate: &msgBox2); |
287 | msgBox2.exec(); |
288 | QVERIFY(msgBox2.clickedButton() == rejectButton); // auto detected (one reject button only) |
289 | |
290 | msgBox2.addButton(button: new QPushButton, role: QMessageBox::RejectRole); |
291 | closeHelper.start(key: ExecCloseHelper::CloseWindow, testCandidate: &msgBox2); |
292 | msgBox2.exec(); |
293 | QVERIFY(msgBox2.clickedButton() == msgBox2.button(QMessageBox::No)); // auto detected (one No button only) |
294 | |
295 | QMessageBox msgBox3; |
296 | msgBox3.setDetailedText("Details" ); |
297 | closeHelper.start(key: ExecCloseHelper::CloseWindow, testCandidate: &msgBox3); |
298 | msgBox3.exec(); |
299 | QVERIFY(msgBox3.clickedButton() == msgBox3.button(QMessageBox::Ok)); // auto detected |
300 | } |
301 | |
302 | void tst_QMessageBox::statics() |
303 | { |
304 | QMessageBox::StandardButton (*statics[4])(QWidget *, const QString &, |
305 | const QString&, QMessageBox::StandardButtons buttons, |
306 | QMessageBox::StandardButton); |
307 | |
308 | statics[0] = QMessageBox::information; |
309 | statics[1] = QMessageBox::critical; |
310 | statics[2] = QMessageBox::question; |
311 | statics[3] = QMessageBox::warning; |
312 | |
313 | ExecCloseHelper closeHelper; |
314 | for (int i = 0; i < 4; i++) { |
315 | closeHelper.start(key: Qt::Key_Escape); |
316 | QMessageBox::StandardButton sb = (*statics[i])(nullptr, "caption" , |
317 | "text" , QMessageBox::Yes | QMessageBox::No | QMessageBox::Help | QMessageBox::Cancel, |
318 | QMessageBox::NoButton); |
319 | QCOMPARE(sb, QMessageBox::Cancel); |
320 | QVERIFY(closeHelper.done()); |
321 | |
322 | closeHelper.start(key: ExecCloseHelper::CloseWindow); |
323 | sb = (*statics[i])(nullptr, "caption" , |
324 | "text" , QMessageBox::Yes | QMessageBox::No | QMessageBox::Help | QMessageBox::Cancel, |
325 | QMessageBox::NoButton); |
326 | QCOMPARE(sb, QMessageBox::Cancel); |
327 | QVERIFY(closeHelper.done()); |
328 | |
329 | closeHelper.start(key: Qt::Key_Enter); |
330 | sb = (*statics[i])(nullptr, "caption" , |
331 | "text" , QMessageBox::Yes | QMessageBox::No | QMessageBox::Help, |
332 | QMessageBox::Yes); |
333 | QCOMPARE(sb, QMessageBox::Yes); |
334 | QVERIFY(closeHelper.done()); |
335 | |
336 | closeHelper.start(key: Qt::Key_Enter); |
337 | sb = (*statics[i])(nullptr, "caption" , |
338 | "text" , QMessageBox::Yes | QMessageBox::No | QMessageBox::Help, |
339 | QMessageBox::No); |
340 | QCOMPARE(sb, QMessageBox::No); |
341 | QVERIFY(closeHelper.done()); |
342 | } |
343 | } |
344 | |
345 | // shortcuts are not used on OS X |
346 | #ifndef Q_OS_MAC |
347 | void tst_QMessageBox::shortcut() |
348 | { |
349 | QMessageBox msgBox; |
350 | msgBox.addButton(text: "O&k" , role: QMessageBox::YesRole); |
351 | msgBox.addButton(text: "&No" , role: QMessageBox::YesRole); |
352 | msgBox.addButton(text: "&Maybe" , role: QMessageBox::YesRole); |
353 | ExecCloseHelper closeHelper; |
354 | closeHelper.start(key: Qt::Key_M, testCandidate: &msgBox); |
355 | QCOMPARE(msgBox.exec(), 2); |
356 | } |
357 | #endif |
358 | |
359 | void tst_QMessageBox::about() |
360 | { |
361 | ExecCloseHelper closeHelper; |
362 | closeHelper.start(key: Qt::Key_Escape); |
363 | QMessageBox::about(parent: nullptr, title: "Caption" , text: "This is an auto test" ); |
364 | // On Mac, about and aboutQt are not modal, so we need to |
365 | // explicitly run the event loop |
366 | #ifdef Q_OS_MAC |
367 | QTRY_VERIFY(closeHelper.done()); |
368 | #else |
369 | QVERIFY(closeHelper.done()); |
370 | #endif |
371 | |
372 | const int keyToSend = Qt::Key_Enter; |
373 | |
374 | closeHelper.start(key: keyToSend); |
375 | QMessageBox::aboutQt(parent: nullptr, title: "Caption" ); |
376 | #ifdef Q_OS_MAC |
377 | QTRY_VERIFY(closeHelper.done()); |
378 | #else |
379 | QVERIFY(closeHelper.done()); |
380 | #endif |
381 | } |
382 | |
383 | void tst_QMessageBox::staticSourceCompat() |
384 | { |
385 | int ret; |
386 | |
387 | // source compat tests for < 4.2 |
388 | ExecCloseHelper closeHelper; |
389 | closeHelper.start(key: Qt::Key_Enter); |
390 | ret = QMessageBox::information(parent: nullptr, title: "title" , text: "text" , button0: QMessageBox::Yes, button1: QMessageBox::No); |
391 | int expectedButton = int(QMessageBox::Yes); |
392 | if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) { |
393 | const int dialogButtonBoxLayout = theme->themeHint(hint: QPlatformTheme::DialogButtonBoxLayout).toInt(); |
394 | if (dialogButtonBoxLayout == QDialogButtonBox::MacLayout |
395 | || dialogButtonBoxLayout == QDialogButtonBox::GnomeLayout) |
396 | expectedButton = int(QMessageBox::No); |
397 | } |
398 | QCOMPARE(ret, expectedButton); |
399 | QVERIFY(closeHelper.done()); |
400 | |
401 | closeHelper.start(key: Qt::Key_Enter); |
402 | ret = QMessageBox::information(parent: nullptr, title: "title" , text: "text" , buttons: QMessageBox::Yes | QMessageBox::Default, defaultButton: QMessageBox::No); |
403 | QCOMPARE(ret, int(QMessageBox::Yes)); |
404 | QVERIFY(closeHelper.done()); |
405 | |
406 | closeHelper.start(key: Qt::Key_Enter); |
407 | ret = QMessageBox::information(parent: nullptr, title: "title" , text: "text" , button0: QMessageBox::Yes, button1: QMessageBox::No | QMessageBox::Default); |
408 | QCOMPARE(ret, int(QMessageBox::No)); |
409 | QVERIFY(closeHelper.done()); |
410 | |
411 | closeHelper.start(key: Qt::Key_Enter); |
412 | ret = QMessageBox::information(parent: nullptr, title: "title" , text: "text" , button0: QMessageBox::Yes | QMessageBox::Default, button1: QMessageBox::No | QMessageBox::Escape); |
413 | QCOMPARE(ret, int(QMessageBox::Yes)); |
414 | QVERIFY(closeHelper.done()); |
415 | |
416 | closeHelper.start(key: Qt::Key_Enter); |
417 | ret = QMessageBox::information(parent: nullptr, title: "title" , text: "text" , button0: QMessageBox::Yes | QMessageBox::Escape, button1: QMessageBox::No | QMessageBox::Default); |
418 | QCOMPARE(ret, int(QMessageBox::No)); |
419 | QVERIFY(closeHelper.done()); |
420 | |
421 | // the button text versions |
422 | closeHelper.start(key: Qt::Key_Enter); |
423 | ret = QMessageBox::information(parent: nullptr, title: "title" , text: "text" , button0Text: "Yes" , button1Text: "No" , button2Text: QString(), defaultButtonNumber: 1); |
424 | QCOMPARE(ret, 1); |
425 | QVERIFY(closeHelper.done()); |
426 | |
427 | if (0) { // don't run these tests since the dialog won't close! |
428 | closeHelper.start(key: Qt::Key_Escape); |
429 | ret = QMessageBox::information(parent: nullptr, title: "title" , text: "text" , button0Text: "Yes" , button1Text: "No" , button2Text: QString(), defaultButtonNumber: 1); |
430 | QCOMPARE(ret, -1); |
431 | QVERIFY(closeHelper.done()); |
432 | |
433 | closeHelper.start(key: Qt::Key_Escape); |
434 | ret = QMessageBox::information(parent: nullptr, title: "title" , text: "text" , button0Text: "Yes" , button1Text: "No" , button2Text: QString(), defaultButtonNumber: 0, escapeButtonNumber: 1); |
435 | QCOMPARE(ret, 1); |
436 | QVERIFY(closeHelper.done()); |
437 | } |
438 | } |
439 | |
440 | void tst_QMessageBox::instanceSourceCompat() |
441 | { |
442 | QMessageBox mb("Application name here" , |
443 | "Saving the file will overwrite the original file on the disk.\n" |
444 | "Do you really want to save?" , |
445 | QMessageBox::Information, |
446 | QMessageBox::Yes | QMessageBox::Default, |
447 | QMessageBox::No, |
448 | QMessageBox::Cancel | QMessageBox::Escape); |
449 | mb.setButtonText(button: QMessageBox::Yes, text: "Save" ); |
450 | mb.setButtonText(button: QMessageBox::No, text: "Discard" ); |
451 | mb.addButton(text: "&Revert" , role: QMessageBox::RejectRole); |
452 | mb.addButton(text: "&Zoo" , role: QMessageBox::ActionRole); |
453 | |
454 | ExecCloseHelper closeHelper; |
455 | closeHelper.start(key: Qt::Key_Enter, testCandidate: &mb); |
456 | QCOMPARE(mb.exec(), int(QMessageBox::Yes)); |
457 | closeHelper.start(key: Qt::Key_Escape, testCandidate: &mb); |
458 | QCOMPARE(mb.exec(), int(QMessageBox::Cancel)); |
459 | #ifndef Q_OS_MAC |
460 | // mnemonics are not used on OS X |
461 | closeHelper.start(key: Qt::ALT + Qt::Key_R, testCandidate: &mb); |
462 | QCOMPARE(mb.exec(), 0); |
463 | closeHelper.start(key: Qt::ALT + Qt::Key_Z, testCandidate: &mb); |
464 | QCOMPARE(mb.exec(), 1); |
465 | #endif |
466 | } |
467 | |
468 | void tst_QMessageBox::detailsText() |
469 | { |
470 | QMessageBox box; |
471 | QString text("This is the details text." ); |
472 | box.setDetailedText(text); |
473 | QCOMPARE(box.detailedText(), text); |
474 | box.show(); |
475 | QVERIFY(QTest::qWaitForWindowExposed(&box)); |
476 | // QTBUG-39334, the box should now have the default "Ok" button as well as |
477 | // the "Show Details.." button. |
478 | QCOMPARE(box.findChildren<QAbstractButton *>().size(), 2); |
479 | } |
480 | |
481 | void tst_QMessageBox::detailsButtonText() |
482 | { |
483 | QMessageBox box; |
484 | box.setDetailedText("bla" ); |
485 | box.open(); |
486 | QApplication::postEvent(receiver: &box, event: new QEvent(QEvent::LanguageChange)); |
487 | QApplication::processEvents(); |
488 | QDialogButtonBox* bb = box.findChild<QDialogButtonBox*>(aName: "qt_msgbox_buttonbox" ); |
489 | QVERIFY(bb); //get the detail button |
490 | |
491 | auto list = bb->buttons(); |
492 | for (auto btn : list) { |
493 | if (btn && (btn->inherits(classname: "QPushButton" ))) { |
494 | if (btn->text().remove(c: QLatin1Char('&')) != QMessageBox::tr(s: "OK" ) |
495 | && btn->text() != QMessageBox::tr(s: "Show Details..." )) { |
496 | QFAIL(qPrintable(QString("Unexpected messagebox button text: %1" ).arg(btn->text()))); |
497 | } |
498 | } |
499 | } |
500 | } |
501 | |
502 | void tst_QMessageBox::expandDetailsWithoutMoving() // QTBUG-32473 |
503 | { |
504 | tst_ResizingMessageBox box; |
505 | box.setDetailedText("bla" ); |
506 | box.show(); |
507 | QApplication::postEvent(receiver: &box, event: new QEvent(QEvent::LanguageChange)); |
508 | QApplication::processEvents(); |
509 | QDialogButtonBox* bb = box.findChild<QDialogButtonBox*>(aName: "qt_msgbox_buttonbox" ); |
510 | QVERIFY(bb); |
511 | |
512 | auto list = bb->buttons(); |
513 | auto it = std::find_if(first: list.rbegin(), last: list.rend(), pred: [&](QAbstractButton *btn) { |
514 | return btn && bb->buttonRole(button: btn) == QDialogButtonBox::ActionRole; }); |
515 | QVERIFY(it != list.rend()); |
516 | auto moreButton = *it; |
517 | |
518 | QVERIFY(QTest::qWaitForWindowExposed(&box)); |
519 | QTRY_VERIFY2(!box.geometry().topLeft().isNull(), "window manager is expected to decorate and position the dialog" ); |
520 | QRect geom = box.geometry(); |
521 | box.resized = false; |
522 | // now click the "more" button, and verify that the dialog resizes but does not move |
523 | moreButton->click(); |
524 | QTRY_VERIFY(box.resized); |
525 | QVERIFY(box.geometry().height() > geom.height()); |
526 | QCOMPARE(box.geometry().topLeft(), geom.topLeft()); |
527 | } |
528 | |
529 | void tst_QMessageBox::incorrectDefaultButton() |
530 | { |
531 | ExecCloseHelper closeHelper; |
532 | closeHelper.start(key: Qt::Key_Escape); |
533 | //Do not crash here |
534 | QTest::ignoreMessage(type: QtWarningMsg, message: "QDialogButtonBox::createButton: Invalid ButtonRole, button not added" ); |
535 | QMessageBox::question(parent: nullptr, title: "" , text: "I've been hit!" ,buttons: QMessageBox::Ok | QMessageBox::Cancel,defaultButton: QMessageBox::Save); |
536 | QVERIFY(closeHelper.done()); |
537 | |
538 | closeHelper.start(key: Qt::Key_Escape); |
539 | QTest::ignoreMessage(type: QtWarningMsg, message: "QDialogButtonBox::createButton: Invalid ButtonRole, button not added" ); |
540 | QMessageBox::question(parent: nullptr, title: "" , text: "I've been hit!" ,buttons: QFlag(QMessageBox::Ok | QMessageBox::Cancel),defaultButton: QMessageBox::Save); |
541 | QVERIFY(closeHelper.done()); |
542 | |
543 | closeHelper.start(key: Qt::Key_Escape); |
544 | QTest::ignoreMessage(type: QtWarningMsg, message: "QDialogButtonBox::createButton: Invalid ButtonRole, button not added" ); |
545 | QTest::ignoreMessage(type: QtWarningMsg, message: "QDialogButtonBox::createButton: Invalid ButtonRole, button not added" ); |
546 | //do not crash here -> call old function of QMessageBox in this case |
547 | QMessageBox::question(parent: nullptr, title: "" , text: "I've been hit!" ,button0: QMessageBox::Ok | QMessageBox::Cancel,button1: QMessageBox::Save | QMessageBox::Cancel,button2: QMessageBox::Ok); |
548 | QVERIFY(closeHelper.done()); |
549 | } |
550 | |
551 | void tst_QMessageBox::updateSize() |
552 | { |
553 | QMessageBox box; |
554 | box.setText("This is awesome" ); |
555 | box.show(); |
556 | QSize oldSize = box.size(); |
557 | QString longText; |
558 | for (int i = 0; i < 20; i++) |
559 | longText += box.text(); |
560 | box.setText(longText); |
561 | QVERIFY(box.size() != oldSize); // should have grown |
562 | QVERIFY(box.width() > oldSize.width() || box.height() > oldSize.height()); |
563 | oldSize = box.size(); |
564 | box.setStandardButtons(QMessageBox::StandardButtons(0xFFFF)); |
565 | QVERIFY(box.size() != oldSize); // should have grown |
566 | QVERIFY(box.width() > oldSize.width() || box.height() > oldSize.height()); |
567 | } |
568 | |
569 | void tst_QMessageBox::setInformativeText() |
570 | { |
571 | QMessageBox msgbox(QMessageBox::Warning, "" , "" , QMessageBox::Ok); |
572 | QString itext = "This is a very long message and it should make the dialog have enough width to fit this message in" ; |
573 | msgbox.setInformativeText(itext); |
574 | msgbox.show(); |
575 | QCOMPARE(msgbox.informativeText(), itext); |
576 | QVERIFY2(msgbox.width() > 190, //verify it's big enough (task181688) |
577 | qPrintable(QString("%1 > 190" ).arg(msgbox.width()))); |
578 | } |
579 | |
580 | void tst_QMessageBox::iconPixmap() |
581 | { |
582 | QMessageBox messageBox; |
583 | QCOMPARE(messageBox.iconPixmap(), QPixmap()); |
584 | } |
585 | |
586 | using SignalSignature = void(QDialog::*)(); |
587 | Q_DECLARE_METATYPE(SignalSignature); |
588 | Q_DECLARE_METATYPE(QMessageBox::ButtonRole) |
589 | |
590 | using ButtonsCreator = std::function<QVector<QPushButton*>(QMessageBox &)>; |
591 | Q_DECLARE_METATYPE(ButtonsCreator); |
592 | |
593 | using RoleSet = QSet<QMessageBox::ButtonRole>; |
594 | Q_DECLARE_METATYPE(RoleSet); |
595 | |
596 | void tst_QMessageBox::acceptedRejectedSignals() |
597 | { |
598 | QMessageBox messageBox(QMessageBox::Information, "Test window" , "Test text" ); |
599 | |
600 | QFETCH(ButtonsCreator, buttonsCreator); |
601 | QVERIFY(buttonsCreator); |
602 | |
603 | const auto buttons = buttonsCreator(messageBox); |
604 | QVERIFY(!buttons.isEmpty()); |
605 | |
606 | QFETCH(RoleSet, roles); |
607 | QFETCH(SignalSignature, signalSignature); |
608 | for (auto button: buttons) { |
609 | QVERIFY(button); |
610 | |
611 | messageBox.show(); |
612 | QVERIFY(QTest::qWaitForWindowExposed(&messageBox)); |
613 | |
614 | QSignalSpy spy(&messageBox, signalSignature); |
615 | QVERIFY(spy.isValid()); |
616 | button->click(); |
617 | |
618 | if (roles.contains(value: messageBox.buttonRole(button))) |
619 | QCOMPARE(spy.count(), 1); |
620 | else |
621 | QVERIFY(spy.isEmpty()); |
622 | } |
623 | } |
624 | |
625 | static void addAcceptedRow(const char *title, ButtonsCreator bc) |
626 | { |
627 | QTest::newRow(dataTag: title) << (RoleSet() << QMessageBox::AcceptRole << QMessageBox::YesRole) |
628 | << &QDialog::accepted << bc; |
629 | } |
630 | |
631 | static void addRejectedRow(const char *title, ButtonsCreator bc) |
632 | { |
633 | QTest::newRow(dataTag: title) << (RoleSet() << QMessageBox::RejectRole << QMessageBox::NoRole) |
634 | << &QDialog::rejected << bc; |
635 | } |
636 | |
637 | static void addCustomButtonsData() |
638 | { |
639 | ButtonsCreator buttonsCreator = [](QMessageBox &messageBox) { |
640 | QVector<QPushButton*> buttons(QMessageBox::NRoles); |
641 | for (int i = QMessageBox::AcceptRole; i < QMessageBox::NRoles; ++i) { |
642 | buttons[i] = messageBox.addButton( |
643 | text: QString("Button role: %1" ).arg(a: i), role: QMessageBox::ButtonRole(i)); |
644 | } |
645 | |
646 | return buttons; |
647 | }; |
648 | |
649 | addAcceptedRow(title: "Accepted_CustomButtons" , bc: buttonsCreator); |
650 | addRejectedRow(title: "Rejected_CustomButtons" , bc: buttonsCreator); |
651 | } |
652 | |
653 | static void addStandardButtonsData() |
654 | { |
655 | ButtonsCreator buttonsCreator = [](QMessageBox &messageBox) { |
656 | QVector<QPushButton*> buttons; |
657 | for (int i = QMessageBox::FirstButton; i <= QMessageBox::LastButton; i <<= 1) |
658 | buttons << messageBox.addButton(button: QMessageBox::StandardButton(i)); |
659 | |
660 | return buttons; |
661 | }; |
662 | |
663 | addAcceptedRow(title: "Accepted_StandardButtons" , bc: buttonsCreator); |
664 | addRejectedRow(title: "Rejected_StandardButtons" , bc: buttonsCreator); |
665 | } |
666 | |
667 | void tst_QMessageBox::acceptedRejectedSignals_data() |
668 | { |
669 | QTest::addColumn<RoleSet>(name: "roles" ); |
670 | QTest::addColumn<SignalSignature>(name: "signalSignature" ); |
671 | QTest::addColumn<ButtonsCreator>(name: "buttonsCreator" ); |
672 | |
673 | addStandardButtonsData(); |
674 | addCustomButtonsData(); |
675 | } |
676 | |
677 | QTEST_MAIN(tst_QMessageBox) |
678 | #include "tst_qmessagebox.moc" |
679 | |