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 <qabstractbutton.h>
34#include <qaction.h>
35#include <qlayout.h>
36#include <qmainwindow.h>
37#include <qpixmap.h>
38#include <qstyle.h>
39#include <qtoolbar.h>
40#include <qwidgetaction.h>
41#include <qtoolbutton.h>
42#include <qlineedit.h>
43#include <qkeysequence.h>
44#include <qmenu.h>
45#include <qlabel.h>
46#include <private/qtoolbarextension_p.h>
47
48QT_FORWARD_DECLARE_CLASS(QAction)
49
50class tst_QToolBar : public QObject
51{
52 Q_OBJECT
53
54public:
55 tst_QToolBar();
56
57public slots:
58 void slot();
59 void slot(QAction *action);
60
61private slots:
62 void isMovable();
63 void allowedAreas();
64 void orientation();
65 void addAction();
66 void addActionConnect();
67 void insertAction();
68 void addSeparator();
69 void insertSeparator();
70 void addWidget();
71 void insertWidget();
72 void actionGeometry();
73 void toggleViewAction();
74 void iconSize();
75 void toolButtonStyle();
76 void actionTriggered();
77 void visibilityChanged();
78 void actionOwnership();
79 void widgetAction();
80 void accel();
81
82 void task191727_layout();
83 void task197996_visibility();
84
85 void extraCpuConsumption(); // QTBUG-54676
86};
87
88
89QAction *triggered = 0;
90
91tst_QToolBar::tst_QToolBar()
92{
93 qRegisterMetaType<Qt::Orientation>(typeName: "Qt::Orientation");
94 qRegisterMetaType<Qt::ToolBarAreas>(typeName: "Qt::ToolBarAreas");
95 qRegisterMetaType<Qt::ToolButtonStyle>(typeName: "Qt::ToolButtonStyle");
96}
97
98void tst_QToolBar::slot()
99{ }
100
101void tst_QToolBar::slot(QAction *action)
102{ ::triggered = action; }
103
104void tst_QToolBar::isMovable()
105{
106#define DO_TEST \
107 do { \
108 QVERIFY(tb.isMovable()); \
109 tb.setMovable(false); \
110 QVERIFY(!tb.isMovable()); \
111 QCOMPARE(spy.count(), 1); \
112 QCOMPARE(spy.at(0).value(0).toBool(), tb.isMovable()); \
113 spy.clear(); \
114 tb.setMovable(tb.isMovable()); \
115 QCOMPARE(spy.count(), 0); \
116 spy.clear(); \
117 tb.setMovable(true); \
118 QVERIFY(tb.isMovable()); \
119 QCOMPARE(spy.count(), 1); \
120 QCOMPARE(spy.at(0).value(0).toBool(), tb.isMovable()); \
121 spy.clear(); \
122 tb.setMovable(tb.isMovable()); \
123 QCOMPARE(spy.count(), 0); \
124 spy.clear(); \
125 } while (false)
126
127 QMainWindow mw;
128 QToolBar tb;
129
130 QCOMPARE(tb.isMovable(), (bool)qApp->style()->styleHint(QStyle::SH_ToolBar_Movable));
131 if (!tb.isMovable())
132 tb.setMovable(true);
133
134 QSignalSpy spy(&tb, SIGNAL(movableChanged(bool)));
135
136 DO_TEST;
137 mw.addToolBar(toolbar: &tb);
138 DO_TEST;
139 mw.removeToolBar(toolbar: &tb);
140 DO_TEST;
141}
142
143void tst_QToolBar::allowedAreas()
144{
145 QToolBar tb;
146
147 QSignalSpy spy(&tb, SIGNAL(allowedAreasChanged(Qt::ToolBarAreas)));
148
149 // default
150 QCOMPARE((int)tb.allowedAreas(), (int)Qt::AllToolBarAreas);
151 QVERIFY(tb.isAreaAllowed(Qt::LeftToolBarArea));
152 QVERIFY(tb.isAreaAllowed(Qt::RightToolBarArea));
153 QVERIFY(tb.isAreaAllowed(Qt::TopToolBarArea));
154 QVERIFY(tb.isAreaAllowed(Qt::BottomToolBarArea));
155
156 // a single dock window area
157 tb.setAllowedAreas(Qt::LeftToolBarArea);
158 QCOMPARE((int)tb.allowedAreas(), (int)Qt::LeftToolBarArea);
159 QVERIFY(tb.isAreaAllowed(Qt::LeftToolBarArea));
160 QVERIFY(!tb.isAreaAllowed(Qt::RightToolBarArea));
161 QVERIFY(!tb.isAreaAllowed(Qt::TopToolBarArea));
162 QVERIFY(!tb.isAreaAllowed(Qt::BottomToolBarArea));
163 QCOMPARE(spy.count(), 1);
164 QCOMPARE(*static_cast<const Qt::ToolBarAreas *>(spy.at(0).value(0).constData()),
165 tb.allowedAreas());
166 spy.clear();
167 tb.setAllowedAreas(tb.allowedAreas());
168 QCOMPARE(spy.count(), 0);
169
170 tb.setAllowedAreas(Qt::RightToolBarArea);
171 QCOMPARE((int)tb.allowedAreas(), (int)Qt::RightToolBarArea);
172 QVERIFY(!tb.isAreaAllowed(Qt::LeftToolBarArea));
173 QVERIFY(tb.isAreaAllowed(Qt::RightToolBarArea));
174 QVERIFY(!tb.isAreaAllowed(Qt::TopToolBarArea));
175 QVERIFY(!tb.isAreaAllowed(Qt::BottomToolBarArea));
176 QCOMPARE(spy.count(), 1);
177 QCOMPARE(*static_cast<const Qt::ToolBarAreas *>(spy.at(0).value(0).constData()),
178 tb.allowedAreas());
179 spy.clear();
180 tb.setAllowedAreas(tb.allowedAreas());
181 QCOMPARE(spy.count(), 0);
182
183 tb.setAllowedAreas(Qt::TopToolBarArea);
184 QCOMPARE((int)tb.allowedAreas(), (int)Qt::TopToolBarArea);
185 QVERIFY(!tb.isAreaAllowed(Qt::LeftToolBarArea));
186 QVERIFY(!tb.isAreaAllowed(Qt::RightToolBarArea));
187 QVERIFY(tb.isAreaAllowed(Qt::TopToolBarArea));
188 QVERIFY(!tb.isAreaAllowed(Qt::BottomToolBarArea));
189 QCOMPARE(spy.count(), 1);
190 QCOMPARE(*static_cast<const Qt::ToolBarAreas *>(spy.at(0).value(0).constData()),
191 tb.allowedAreas());
192 spy.clear();
193 tb.setAllowedAreas(tb.allowedAreas());
194 QCOMPARE(spy.count(), 0);
195
196 tb.setAllowedAreas(Qt::BottomToolBarArea);
197 QCOMPARE((int)tb.allowedAreas(), (int)Qt::BottomToolBarArea);
198 QVERIFY(!tb.isAreaAllowed(Qt::LeftToolBarArea));
199 QVERIFY(!tb.isAreaAllowed(Qt::RightToolBarArea));
200 QVERIFY(!tb.isAreaAllowed(Qt::TopToolBarArea));
201 QVERIFY(tb.isAreaAllowed(Qt::BottomToolBarArea));
202 QCOMPARE(spy.count(), 1);
203 QCOMPARE(*static_cast<const Qt::ToolBarAreas *>(spy.at(0).value(0).constData()),
204 tb.allowedAreas());
205 spy.clear();
206 tb.setAllowedAreas(tb.allowedAreas());
207 QCOMPARE(spy.count(), 0);
208
209 // multiple dock window areas
210 tb.setAllowedAreas(Qt::TopToolBarArea | Qt::BottomToolBarArea);
211 QCOMPARE(tb.allowedAreas(), Qt::TopToolBarArea | Qt::BottomToolBarArea);
212 QVERIFY(!tb.isAreaAllowed(Qt::LeftToolBarArea));
213 QVERIFY(!tb.isAreaAllowed(Qt::RightToolBarArea));
214 QVERIFY(tb.isAreaAllowed(Qt::TopToolBarArea));
215 QVERIFY(tb.isAreaAllowed(Qt::BottomToolBarArea));
216 QCOMPARE(spy.count(), 1);
217 QCOMPARE(*static_cast<const Qt::ToolBarAreas *>(spy.at(0).value(0).constData()),
218 tb.allowedAreas());
219 spy.clear();
220 tb.setAllowedAreas(tb.allowedAreas());
221 QCOMPARE(spy.count(), 0);
222
223 tb.setAllowedAreas(Qt::LeftToolBarArea | Qt::RightToolBarArea);
224 QCOMPARE(tb.allowedAreas(), Qt::LeftToolBarArea | Qt::RightToolBarArea);
225 QVERIFY(tb.isAreaAllowed(Qt::LeftToolBarArea));
226 QVERIFY(tb.isAreaAllowed(Qt::RightToolBarArea));
227 QVERIFY(!tb.isAreaAllowed(Qt::TopToolBarArea));
228 QVERIFY(!tb.isAreaAllowed(Qt::BottomToolBarArea));
229 QCOMPARE(spy.count(), 1);
230 QCOMPARE(*static_cast<const Qt::ToolBarAreas *>(spy.at(0).value(0).constData()),
231 tb.allowedAreas());
232 spy.clear();
233 tb.setAllowedAreas(tb.allowedAreas());
234 QCOMPARE(spy.count(), 0);
235
236 tb.setAllowedAreas(Qt::TopToolBarArea | Qt::LeftToolBarArea);
237 QCOMPARE(tb.allowedAreas(), Qt::TopToolBarArea | Qt::LeftToolBarArea);
238 QVERIFY(tb.isAreaAllowed(Qt::LeftToolBarArea));
239 QVERIFY(!tb.isAreaAllowed(Qt::RightToolBarArea));
240 QVERIFY(tb.isAreaAllowed(Qt::TopToolBarArea));
241 QVERIFY(!tb.isAreaAllowed(Qt::BottomToolBarArea));
242 QCOMPARE(spy.count(), 1);
243 QCOMPARE(*static_cast<const Qt::ToolBarAreas *>(spy.at(0).value(0).constData()),
244 tb.allowedAreas());
245 spy.clear();
246 tb.setAllowedAreas(tb.allowedAreas());
247 QCOMPARE(spy.count(), 0);
248
249 tb.setAllowedAreas(Qt::BottomToolBarArea | Qt::RightToolBarArea);
250 QCOMPARE(tb.allowedAreas(), Qt::BottomToolBarArea | Qt::RightToolBarArea);
251 QVERIFY(!tb.isAreaAllowed(Qt::LeftToolBarArea));
252 QVERIFY(tb.isAreaAllowed(Qt::RightToolBarArea));
253 QVERIFY(!tb.isAreaAllowed(Qt::TopToolBarArea));
254 QVERIFY(tb.isAreaAllowed(Qt::BottomToolBarArea));
255 QCOMPARE(spy.count(), 1);
256 QCOMPARE(*static_cast<const Qt::ToolBarAreas *>(spy.at(0).value(0).constData()),
257 tb.allowedAreas());
258 spy.clear();
259 tb.setAllowedAreas(tb.allowedAreas());
260 QCOMPARE(spy.count(), 0);
261}
262
263void tst_QToolBar::orientation()
264{
265 QToolBar tb;
266 QCOMPARE(tb.orientation(), Qt::Horizontal);
267
268 QSignalSpy spy(&tb, SIGNAL(orientationChanged(Qt::Orientation)));
269
270 tb.setOrientation(Qt::Vertical);
271 QCOMPARE(tb.orientation(), Qt::Vertical);
272 QCOMPARE(spy.count(), 1);
273 QCOMPARE(*static_cast<const Qt::Orientation *>(spy.at(0).value(0).constData()),
274 tb.orientation());
275 spy.clear();
276 tb.setOrientation(tb.orientation());
277 QCOMPARE(spy.count(), 0);
278
279 tb.setOrientation(Qt::Horizontal);
280 QCOMPARE(tb.orientation(), Qt::Horizontal);
281 QCOMPARE(spy.count(), 1);
282 QCOMPARE(*static_cast<const Qt::Orientation *>(spy.at(0).value(0).constData()),
283 tb.orientation());
284 spy.clear();
285 tb.setOrientation(tb.orientation());
286 QCOMPARE(spy.count(), 0);
287
288 tb.setOrientation(Qt::Vertical);
289 QCOMPARE(tb.orientation(), Qt::Vertical);
290 QCOMPARE(spy.count(), 1);
291 QCOMPARE(*static_cast<const Qt::Orientation *>(spy.at(0).value(0).constData()),
292 tb.orientation());
293 spy.clear();
294 tb.setOrientation(tb.orientation());
295 QCOMPARE(spy.count(), 0);
296
297 tb.setOrientation(Qt::Horizontal);
298 QCOMPARE(tb.orientation(), Qt::Horizontal);
299 QCOMPARE(spy.count(), 1);
300 QCOMPARE(*static_cast<const Qt::Orientation *>(spy.at(0).value(0).constData()),
301 tb.orientation());
302 spy.clear();
303 tb.setOrientation(tb.orientation());
304 QCOMPARE(spy.count(), 0);
305
306 tb.setOrientation(Qt::Vertical);
307 QCOMPARE(tb.orientation(), Qt::Vertical);
308 QCOMPARE(spy.count(), 1);
309 QCOMPARE(*static_cast<const Qt::Orientation *>(spy.at(0).value(0).constData()),
310 tb.orientation());
311 spy.clear();
312 tb.setOrientation(tb.orientation());
313 QCOMPARE(spy.count(), 0);
314}
315
316void tst_QToolBar::addAction()
317{
318 QToolBar tb;
319
320 {
321 QAction action(0);
322
323 QCOMPARE(tb.actions().count(), 0);
324 tb.addAction(action: &action);
325 QCOMPARE(tb.actions().count(), 1);
326 QCOMPARE(tb.actions()[0], &action);
327
328 tb.clear();
329 QCOMPARE(tb.actions().count(), 0);
330 }
331
332 {
333 QString text = "text";
334 QPixmap pm(32, 32);
335 pm.fill(fillColor: Qt::blue);
336 QIcon icon = pm;
337
338 QAction *action1 = tb.addAction(text);
339 QCOMPARE(text, action1->text());
340
341 QAction *action2 = tb.addAction(icon, text);
342 QCOMPARE(icon, action2->icon());
343 QCOMPARE(text, action2->text());
344
345 QAction *action3 = tb.addAction(text, receiver: this, SLOT(slot()));
346 QCOMPARE(text, action3->text());
347
348 QAction *action4 = tb.addAction(icon, text, receiver: this, SLOT(slot()));
349 QCOMPARE(icon, action4->icon());
350 QCOMPARE(text, action4->text());
351
352 QCOMPARE(tb.actions().count(), 4);
353 QCOMPARE(tb.actions()[0], action1);
354 QCOMPARE(tb.actions()[1], action2);
355 QCOMPARE(tb.actions()[2], action3);
356 QCOMPARE(tb.actions()[3], action4);
357
358 tb.clear();
359 QCOMPARE(tb.actions().count(), 0);
360 }
361}
362
363static void testFunction() { }
364
365void tst_QToolBar::addActionConnect()
366{
367 QToolBar tb;
368 const QString text = QLatin1String("bla");
369 const QIcon icon;
370 tb.addAction(text, receiver: &tb, SLOT(deleteLater()));
371 tb.addAction(text, object: &tb, slot: &QMenu::deleteLater);
372 tb.addAction(text, slot: testFunction);
373 tb.addAction(text, object: &tb, slot: testFunction);
374 tb.addAction(icon, text, receiver: &tb, SLOT(deleteLater()));
375 tb.addAction(actionIcon: icon, text, object: &tb, slot: &QMenu::deleteLater);
376 tb.addAction(actionIcon: icon, text, slot: testFunction);
377 tb.addAction(actionIcon: icon, text, object: &tb, slot: testFunction);
378}
379
380void tst_QToolBar::insertAction()
381{
382 QToolBar tb;
383 QAction action1(0);
384 QAction action2(0);
385 QAction action3(0);
386 QAction action4(0);
387
388 QCOMPARE(tb.actions().count(), 0);
389 tb.insertAction(before: 0, action: &action1);
390 tb.insertAction(before: &action1, action: &action2);
391 tb.insertAction(before: &action2, action: &action3);
392 tb.insertAction(before: &action3, action: &action4);
393 QCOMPARE(tb.actions().count(), 4);
394 QCOMPARE(tb.actions()[0], &action4);
395 QCOMPARE(tb.actions()[1], &action3);
396 QCOMPARE(tb.actions()[2], &action2);
397 QCOMPARE(tb.actions()[3], &action1);
398
399 tb.clear();
400 QCOMPARE(tb.actions().count(), 0);
401}
402
403void tst_QToolBar::addSeparator()
404{
405 QToolBar tb;
406
407 QAction action1(0);
408 QAction action2(0);
409
410 tb.addAction(action: &action1);
411 QAction *sep = tb.addSeparator();
412 tb.addAction(action: &action2);
413
414 QCOMPARE(tb.actions().count(), 3);
415 QCOMPARE(tb.actions()[0], &action1);
416 QCOMPARE(tb.actions()[1], sep);
417 QCOMPARE(tb.actions()[2], &action2);
418
419 tb.clear();
420 QCOMPARE(tb.actions().count(), 0);
421}
422
423void tst_QToolBar::insertSeparator()
424{
425 QToolBar tb;
426
427 QAction action1(0);
428 QAction action2(0);
429
430 tb.addAction(action: &action1);
431 tb.addAction(action: &action2);
432 QAction *sep = tb.insertSeparator(before: &action2);
433
434 QCOMPARE(tb.actions().count(), 3);
435 QCOMPARE(tb.actions()[0], &action1);
436 QCOMPARE(tb.actions()[1], sep);
437 QCOMPARE(tb.actions()[2], &action2);
438
439 tb.clear();
440 QCOMPARE(tb.actions().count(), 0);
441}
442
443void tst_QToolBar::addWidget()
444{
445 QToolBar tb;
446 QWidget w(&tb);
447
448 QAction action1(0);
449 QAction action2(0);
450
451 tb.addAction(action: &action1);
452 QAction *widget = tb.addWidget(widget: &w);
453 tb.addAction(action: &action2);
454
455 QCOMPARE(tb.actions().count(), 3);
456 QCOMPARE(tb.actions()[0], &action1);
457 QCOMPARE(tb.actions()[1], widget);
458 QCOMPARE(tb.actions()[2], &action2);
459
460 // it should be possible to reuse the action returned by
461 // addWidget() to place the widget somewhere else in the toolbar
462 tb.removeAction(action: widget);
463 QCOMPARE(tb.actions().count(), 2);
464 QCOMPARE(tb.actions()[0], &action1);
465 QCOMPARE(tb.actions()[1], &action2);
466
467 tb.addAction(action: widget);
468 QCOMPARE(tb.actions().count(), 3);
469 QCOMPARE(tb.actions()[0], &action1);
470 QCOMPARE(tb.actions()[1], &action2);
471 QCOMPARE(tb.actions()[2], widget);
472
473 tb.clear();
474 QCOMPARE(tb.actions().count(), 0);
475}
476
477void tst_QToolBar::insertWidget()
478{
479 QToolBar tb;
480 QWidget w(&tb);
481
482 QAction action1(0);
483 QAction action2(0);
484
485 tb.addAction(action: &action1);
486 tb.addAction(action: &action2);
487 QAction *widget = tb.insertWidget(before: &action2, widget: &w);
488
489 QCOMPARE(tb.actions().count(), 3);
490 QCOMPARE(tb.actions()[0], &action1);
491 QCOMPARE(tb.actions()[1], widget);
492 QCOMPARE(tb.actions()[2], &action2);
493
494 // it should be possible to reuse the action returned by
495 // addWidget() to place the widget somewhere else in the toolbar
496 tb.removeAction(action: widget);
497 QCOMPARE(tb.actions().count(), 2);
498 QCOMPARE(tb.actions()[0], &action1);
499 QCOMPARE(tb.actions()[1], &action2);
500
501 tb.insertAction(before: &action1, action: widget);
502 QCOMPARE(tb.actions().count(), 3);
503 QCOMPARE(tb.actions()[0], widget);
504 QCOMPARE(tb.actions()[1], &action1);
505 QCOMPARE(tb.actions()[2], &action2);
506
507 tb.clear();
508 QCOMPARE(tb.actions().count(), 0);
509
510 {
511 QToolBar tb;
512 QPointer<QWidget> widget = new QWidget;
513 QAction *action = tb.addWidget(widget);
514 QCOMPARE(action->parent(), &tb);
515
516 QToolBar tb2;
517 tb.removeAction(action);
518 tb2.addAction(action);
519 QVERIFY(widget && widget->parent() == &tb2);
520 QCOMPARE(action->parent(), &tb2);
521 }
522}
523
524void tst_QToolBar::actionGeometry()
525{
526 QToolBar tb;
527
528 QAction action1(0);
529 QAction action2(0);
530 QAction action3(0);
531 QAction action4(0);
532
533 tb.addAction(action: &action1);
534 tb.addAction(action: &action2);
535 tb.addAction(action: &action3);
536 tb.addAction(action: &action4);
537
538 tb.show();
539 QVERIFY(QTest::qWaitForWindowExposed(&tb));
540
541 QList<QToolBarExtension *> extensions = tb.findChildren<QToolBarExtension *>();
542
543 QRect rect01;
544 QRect rect02;
545 QRect rect03;
546 QRect rect04;
547 QMenu *popupMenu = 0;
548
549 if (extensions.size() != 0)
550 {
551 QToolBarExtension *extension = extensions.at(i: 0);
552 if (extension->isVisible()) {
553 QRect rect0 = extension->geometry();
554 QTest::mouseClick( widget: extension, button: Qt::LeftButton, stateKey: {}, pos: rect0.center(), delay: -1 );
555 QApplication::processEvents();
556 popupMenu = qobject_cast<QMenu *>(object: extension->menu());
557 rect01 = popupMenu->actionGeometry(&action1);
558 rect02 = popupMenu->actionGeometry(&action2);
559 rect03 = popupMenu->actionGeometry(&action3);
560 rect04 = popupMenu->actionGeometry(&action4);
561 }
562 }
563
564 QRect rect1 = tb.actionGeometry(action: &action1);
565 QRect rect2 = tb.actionGeometry(action: &action2);
566 QRect rect3 = tb.actionGeometry(action: &action3);
567 QRect rect4 = tb.actionGeometry(action: &action4);
568
569 QVERIFY(rect1.isValid());
570 QVERIFY(!rect1.isNull());
571 QVERIFY(!rect1.isEmpty());
572
573 QVERIFY(rect2.isValid());
574 QVERIFY(!rect2.isNull());
575 QVERIFY(!rect2.isEmpty());
576
577 QVERIFY(rect3.isValid());
578 QVERIFY(!rect3.isNull());
579 QVERIFY(!rect3.isEmpty());
580
581 QVERIFY(rect4.isValid());
582 QVERIFY(!rect4.isNull());
583 QVERIFY(!rect4.isEmpty());
584
585 if (rect01.isValid())
586 QCOMPARE(popupMenu->actionAt(rect01.center()), &action1);
587 else
588 QCOMPARE(tb.actionAt(rect1.center()), &action1);
589
590 if (rect02.isValid())
591 QCOMPARE(popupMenu->actionAt(rect02.center()), &action2);
592 else
593 QCOMPARE(tb.actionAt(rect2.center()), &action2);
594
595 if (rect03.isValid())
596 QCOMPARE(popupMenu->actionAt(rect03.center()), &action3);
597 else
598 QCOMPARE(tb.actionAt(rect3.center()), &action3);
599
600 if (rect04.isValid())
601 QCOMPARE(popupMenu->actionAt(rect04.center()), &action4);
602 else
603 QCOMPARE(tb.actionAt(rect4.center()), &action4);
604}
605
606void tst_QToolBar::toggleViewAction()
607{
608 {
609 QToolBar tb;
610 QAction *toggleViewAction = tb.toggleViewAction();
611 QVERIFY(tb.isHidden());
612 toggleViewAction->trigger();
613 QVERIFY(!tb.isHidden());
614 toggleViewAction->trigger();
615 QVERIFY(tb.isHidden());
616 }
617
618 {
619 QMainWindow mw;
620 QToolBar tb(&mw);
621 mw.addToolBar(toolbar: &tb);
622 mw.show();
623 QAction *toggleViewAction = tb.toggleViewAction();
624 QVERIFY(!tb.isHidden());
625 toggleViewAction->trigger();
626 QVERIFY(tb.isHidden());
627 toggleViewAction->trigger();
628 QVERIFY(!tb.isHidden());
629 toggleViewAction->trigger();
630 QVERIFY(tb.isHidden());
631 }
632}
633
634void tst_QToolBar::iconSize()
635{
636 {
637 QToolBar tb;
638
639 QSignalSpy spy(&tb, SIGNAL(iconSizeChanged(QSize)));
640
641 // the default is determined by the style
642 const int metric = tb.style()->pixelMetric(metric: QStyle::PM_ToolBarIconSize);
643 const QSize defaultIconSize = QSize(metric, metric);
644 const QSize smallIconSize = QSize(metric / 2, metric / 2);
645 const QSize largeIconSize = QSize(metric * 2, metric * 2);
646
647 QCOMPARE(tb.iconSize(), defaultIconSize);
648 tb.setIconSize(defaultIconSize);
649 QCOMPARE(tb.iconSize(), defaultIconSize);
650 QCOMPARE(spy.count(), 0);
651
652 spy.clear();
653 tb.setIconSize(largeIconSize);
654 QCOMPARE(tb.iconSize(), largeIconSize);
655 QCOMPARE(spy.count(), 1);
656 QCOMPARE(spy.first().first().toSize(), largeIconSize);
657
658 // no-op
659 spy.clear();
660 tb.setIconSize(largeIconSize);
661 QCOMPARE(tb.iconSize(), largeIconSize);
662 QCOMPARE(spy.count(), 0);
663
664 spy.clear();
665 tb.setIconSize(defaultIconSize);
666 QCOMPARE(tb.iconSize(), defaultIconSize);
667 QCOMPARE(spy.count(), 1);
668 QCOMPARE(spy.first().first().toSize(), defaultIconSize);
669
670 // no-op
671 spy.clear();
672 tb.setIconSize(defaultIconSize);
673 QCOMPARE(tb.iconSize(), defaultIconSize);
674 QCOMPARE(spy.count(), 0);
675
676 spy.clear();
677 tb.setIconSize(smallIconSize);
678 QCOMPARE(tb.iconSize(), smallIconSize);
679 QCOMPARE(spy.count(), 1);
680 QCOMPARE(spy.first().first().toSize(), smallIconSize);
681
682 // no-op
683 spy.clear();
684 tb.setIconSize(smallIconSize);
685 QCOMPARE(tb.iconSize(), smallIconSize);
686 QCOMPARE(spy.count(), 0);
687
688 // setting the icon size to an invalid QSize will reset the
689 // iconSize property to the default
690 tb.setIconSize(QSize());
691 QCOMPARE(tb.iconSize(), defaultIconSize);
692 QCOMPARE(spy.size(), 1);
693 QCOMPARE(spy.first().first().toSize(), defaultIconSize);
694 spy.clear();
695 }
696
697 {
698 QMainWindow mw;
699 QToolBar tb;
700 QSignalSpy mwSpy(&mw, SIGNAL(iconSizeChanged(QSize)));
701 QSignalSpy tbSpy(&tb, SIGNAL(iconSizeChanged(QSize)));
702
703 // the default is determined by the style
704 const int metric = tb.style()->pixelMetric(metric: QStyle::PM_ToolBarIconSize);
705 const QSize defaultIconSize = QSize(metric, metric);
706 const QSize smallIconSize = QSize(metric / 2, metric / 2);
707 const QSize largeIconSize = QSize(metric * 2, metric * 2);
708
709 mw.setIconSize(smallIconSize);
710
711 // explicitly set it to the default
712 tb.setIconSize(defaultIconSize);
713 QCOMPARE(tb.iconSize(), defaultIconSize);
714 QCOMPARE(tbSpy.count(), 0);
715
716 mw.addToolBar(toolbar: &tb);
717
718 // tb icon size should not change since it has been explicitly set
719 QCOMPARE(tb.iconSize(), defaultIconSize);
720 QCOMPARE(tbSpy.count(), 0);
721
722 mw.setIconSize(largeIconSize);
723
724 QCOMPARE(tb.iconSize(), defaultIconSize);
725 QCOMPARE(tbSpy.count(), 0);
726
727 mw.setIconSize(defaultIconSize);
728
729 QCOMPARE(tb.iconSize(), defaultIconSize);
730 QCOMPARE(tbSpy.count(), 0);
731
732 mw.setIconSize(smallIconSize);
733
734 QCOMPARE(tb.iconSize(), defaultIconSize);
735 QCOMPARE(tbSpy.count(), 0);
736
737 // resetting to the default should cause the toolbar to take
738 // on the mainwindow's icon size
739 tb.setIconSize(QSize());
740 QCOMPARE(tb.iconSize(), smallIconSize);
741 QCOMPARE(tbSpy.size(), 1);
742 QCOMPARE(tbSpy.first().first().toSize(), smallIconSize);
743 tbSpy.clear();
744 }
745}
746
747void tst_QToolBar::toolButtonStyle()
748{
749 {
750 QToolBar tb;
751
752 QSignalSpy spy(&tb, SIGNAL(toolButtonStyleChanged(Qt::ToolButtonStyle)));
753
754 // no-op
755 QCOMPARE(tb.toolButtonStyle(), Qt::ToolButtonIconOnly);
756 tb.setToolButtonStyle(Qt::ToolButtonIconOnly);
757 QCOMPARE(tb.toolButtonStyle(), Qt::ToolButtonIconOnly);
758 QCOMPARE(spy.count(), 0);
759
760 tb.setToolButtonStyle(Qt::ToolButtonTextOnly);
761 QCOMPARE(tb.toolButtonStyle(), Qt::ToolButtonTextOnly);
762 QCOMPARE(spy.count(), 1);
763 spy.clear();
764
765 // no-op
766 tb.setToolButtonStyle(Qt::ToolButtonTextOnly);
767 QCOMPARE(tb.toolButtonStyle(), Qt::ToolButtonTextOnly);
768 QCOMPARE(spy.count(), 0);
769
770 tb.setToolButtonStyle(Qt::ToolButtonIconOnly);
771 QCOMPARE(tb.toolButtonStyle(), Qt::ToolButtonIconOnly);
772 QCOMPARE(spy.count(), 1);
773 spy.clear();
774
775 // no-op
776 tb.setToolButtonStyle(Qt::ToolButtonIconOnly);
777 QCOMPARE(tb.toolButtonStyle(), Qt::ToolButtonIconOnly);
778 QCOMPARE(spy.count(), 0);
779
780 tb.setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
781 QCOMPARE(tb.toolButtonStyle(), Qt::ToolButtonTextBesideIcon);
782 QCOMPARE(spy.count(), 1);
783 spy.clear();
784
785 // no-op
786 tb.setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
787 QCOMPARE(tb.toolButtonStyle(), Qt::ToolButtonTextBesideIcon);
788 QCOMPARE(spy.count(), 0);
789
790 tb.setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
791 QCOMPARE(tb.toolButtonStyle(), Qt::ToolButtonTextUnderIcon);
792 QCOMPARE(spy.count(), 1);
793 spy.clear();
794
795 // no-op
796 tb.setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
797 QCOMPARE(tb.toolButtonStyle(), Qt::ToolButtonTextUnderIcon);
798 QCOMPARE(spy.count(), 0);
799
800 tb.setToolButtonStyle(Qt::ToolButtonFollowStyle);
801 QCOMPARE(tb.toolButtonStyle(), Qt::ToolButtonFollowStyle);
802 QCOMPARE(spy.count(), 1);
803 }
804
805 {
806 QMainWindow mw;
807 QToolBar tb;
808 QSignalSpy mwSpy(&mw, SIGNAL(toolButtonStyleChanged(Qt::ToolButtonStyle)));
809 QSignalSpy tbSpy(&tb, SIGNAL(toolButtonStyleChanged(Qt::ToolButtonStyle)));
810
811 mw.setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
812
813 // explicitly set the tb to the default
814 tb.setToolButtonStyle(Qt::ToolButtonIconOnly);
815 QCOMPARE(tb.toolButtonStyle(), Qt::ToolButtonIconOnly);
816 QCOMPARE(tbSpy.count(), 0);
817
818 mw.addToolBar(toolbar: &tb);
819
820 // tb icon size should not change since it has been explicitly set
821 QCOMPARE(tb.toolButtonStyle(), Qt::ToolButtonIconOnly);
822 QCOMPARE(tbSpy.count(), 0);
823
824 mw.setToolButtonStyle(Qt::ToolButtonIconOnly);
825
826 QCOMPARE(tb.toolButtonStyle(), Qt::ToolButtonIconOnly);
827 QCOMPARE(tbSpy.count(), 0);
828
829 mw.setToolButtonStyle(Qt::ToolButtonTextOnly);
830
831 QCOMPARE(tb.toolButtonStyle(), Qt::ToolButtonIconOnly);
832 QCOMPARE(tbSpy.count(), 0);
833
834 mw.setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
835
836 QCOMPARE(tb.toolButtonStyle(), Qt::ToolButtonIconOnly);
837 QCOMPARE(tbSpy.count(), 0);
838
839 // note: there is no way to clear the explicitly set tool
840 // button style... once you explicitly set it, the toolbar
841 // will never follow the mainwindow again
842 }
843}
844
845void tst_QToolBar::actionTriggered()
846{
847 QToolBar tb;
848 connect(asender: &tb, SIGNAL(actionTriggered(QAction*)), SLOT(slot(QAction*)));
849
850 QAction action1(0);
851 QAction action2(0);
852 QAction action3(0);
853 QAction action4(0);
854
855 tb.addAction(action: &action1);
856 tb.addAction(action: &action2);
857 tb.addAction(action: &action3);
858 tb.addAction(action: &action4);
859
860 tb.show();
861 QVERIFY(QTest::qWaitForWindowExposed(&tb));
862
863 QList<QToolBarExtension *> extensions = tb.findChildren<QToolBarExtension *>();
864
865 QRect rect01;
866 QRect rect02;
867 QRect rect03;
868 QRect rect04;
869 QMenu *popupMenu = 0;
870
871 if (extensions.size() != 0)
872 {
873 QToolBarExtension *extension = extensions.at(i: 0);
874 if (extension->isVisible()) {
875 QRect rect0 = extension->geometry();
876 QTest::mouseClick( widget: extension, button: Qt::LeftButton, stateKey: {}, pos: rect0.center(), delay: -1 );
877 QApplication::processEvents();
878 popupMenu = qobject_cast<QMenu *>(object: extension->menu());
879 rect01 = popupMenu->actionGeometry(&action1);
880 rect02 = popupMenu->actionGeometry(&action2);
881 rect03 = popupMenu->actionGeometry(&action3);
882 rect04 = popupMenu->actionGeometry(&action4);
883 }
884 }
885
886 QRect rect1 = tb.actionGeometry(action: &action1);
887 QRect rect2 = tb.actionGeometry(action: &action2);
888 QRect rect3 = tb.actionGeometry(action: &action3);
889 QRect rect4 = tb.actionGeometry(action: &action4);
890
891 QAbstractButton *button1 = 0;
892 QAbstractButton *button2 = 0;
893 QAbstractButton *button3 = 0;
894 QAbstractButton *button4 = 0;
895
896 if (!rect01.isValid()) {
897 button1 = qobject_cast<QAbstractButton *>(object: tb.childAt(p: rect1.center()));
898 QVERIFY(button1 != 0);
899 }
900 if (!rect02.isValid()) {
901 button2 = qobject_cast<QAbstractButton *>(object: tb.childAt(p: rect2.center()));
902 QVERIFY(button2 != 0);
903 }
904 if (!rect03.isValid()) {
905 button3 = qobject_cast<QAbstractButton *>(object: tb.childAt(p: rect3.center()));
906 QVERIFY(button3 != 0);
907 }
908 if (!rect04.isValid()) {
909 button4 = qobject_cast<QAbstractButton *>(object: tb.childAt(p: rect4.center()));
910 QVERIFY(button4 != 0);
911 }
912
913 ::triggered = 0;
914 if (!rect01.isValid())
915 QTest::mouseClick(widget: button1, button: Qt::LeftButton);
916 else
917 QTest::mouseClick(widget: popupMenu, button: Qt::LeftButton, stateKey: {}, pos: rect01.center(), delay: -1 );
918 QCOMPARE(::triggered, &action1);
919
920 ::triggered = 0;
921 if (!rect02.isValid())
922 QTest::mouseClick(widget: button2, button: Qt::LeftButton);
923 else
924 QTest::mouseClick(widget: popupMenu, button: Qt::LeftButton, stateKey: {}, pos: rect02.center(), delay: -1 );
925 QCOMPARE(::triggered, &action2);
926
927 ::triggered = 0;
928 if (!rect03.isValid())
929 QTest::mouseClick(widget: button3, button: Qt::LeftButton);
930 else
931 QTest::mouseClick(widget: popupMenu, button: Qt::LeftButton, stateKey: {}, pos: rect03.center(), delay: -1 );
932 QCOMPARE(::triggered, &action3);
933
934 ::triggered = 0;
935 if (!rect04.isValid())
936 QTest::mouseClick(widget: button4, button: Qt::LeftButton);
937 else
938 QTest::mouseClick(widget: popupMenu, button: Qt::LeftButton, stateKey: {}, pos: rect04.center(), delay: -1 );
939 QCOMPARE(::triggered, &action4);
940}
941
942void tst_QToolBar::visibilityChanged()
943{
944 QMainWindow mw;
945 QToolBar tb;
946 QSignalSpy spy(&tb, SIGNAL(visibilityChanged(bool)));
947
948 mw.addToolBar(toolbar: &tb);
949 mw.show();
950
951 QCOMPARE(spy.count(), 1);
952 QCOMPARE(spy.at(0).at(0).toBool(), true);
953 spy.clear();
954
955 tb.hide();
956 QCOMPARE(spy.count(), 1);
957 QCOMPARE(spy.at(0).at(0).toBool(), false);
958 spy.clear();
959
960 tb.hide();
961 QCOMPARE(spy.count(), 0);
962
963 tb.show();
964 QCOMPARE(spy.count(), 1);
965 QCOMPARE(spy.at(0).at(0).toBool(), true);
966 spy.clear();
967
968 tb.show();
969 QCOMPARE(spy.count(), 0);
970}
971
972void tst_QToolBar::actionOwnership()
973{
974 {
975 QToolBar *tb1 = new QToolBar;
976 QToolBar *tb2 = new QToolBar;
977
978 QPointer<QAction> action = tb1->addAction(text: "test");
979 QCOMPARE(action->parent(), tb1);
980
981 tb2->addAction(action);
982 QCOMPARE(action->parent(), tb1);
983
984 delete tb1;
985 QVERIFY(!action);
986 delete tb2;
987 }
988 {
989 QToolBar *tb1 = new QToolBar;
990 QToolBar *tb2 = new QToolBar;
991
992 QPointer<QAction> action = tb1->addAction(text: "test");
993 QCOMPARE(action->parent(), tb1);
994
995 tb1->removeAction(action);
996 QCOMPARE(action->parent(), tb1);
997
998 tb2->addAction(action);
999 QCOMPARE(action->parent(), tb1);
1000
1001 delete tb1;
1002 QVERIFY(!action);
1003 delete tb2;
1004 }
1005}
1006
1007void tst_QToolBar::widgetAction()
1008{
1009 // ensure that a QWidgetAction without widget behaves like a normal action
1010 QToolBar tb;
1011 QWidgetAction *a = new QWidgetAction(0);
1012 a->setIconText("Blah");
1013
1014 tb.addAction(action: a);
1015 QWidget *w = tb.widgetForAction(action: a);
1016 QVERIFY(w);
1017 QToolButton *button = qobject_cast<QToolButton *>(object: w);
1018 QVERIFY(button);
1019 QCOMPARE(a->iconText(), button->text());
1020
1021 delete a;
1022}
1023
1024#ifdef Q_OS_MAC
1025QT_BEGIN_NAMESPACE
1026extern void qt_set_sequence_auto_mnemonic(bool b);
1027QT_END_NAMESPACE
1028#endif
1029
1030void tst_QToolBar::accel()
1031{
1032 if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland"), cs: Qt::CaseInsensitive))
1033 QSKIP("Wayland: This fails. Figure out why.");
1034
1035#ifdef Q_OS_MAC
1036 qt_set_sequence_auto_mnemonic(true);
1037#endif
1038 QMainWindow mw;
1039 QToolBar *toolBar = mw.addToolBar(title: "test");
1040 QAction *action = toolBar->addAction(text: "&test");
1041 action->setIconText(action->text()); // we really want that mnemonic in the button!
1042
1043 QSignalSpy spy(action, SIGNAL(triggered(bool)));
1044
1045 mw.show();
1046 QApplication::setActiveWindow(&mw);
1047 QVERIFY(QTest::qWaitForWindowActive(&mw));
1048
1049 QTest::keyClick(widget: &mw, key: Qt::Key_T, modifier: Qt::AltModifier);
1050
1051 QTRY_COMPARE(spy.count(), 1);
1052#ifdef Q_OS_MAC
1053 qt_set_sequence_auto_mnemonic(false);
1054#endif
1055}
1056
1057void tst_QToolBar::task191727_layout()
1058{
1059 QMainWindow mw;
1060 QToolBar *toolBar = mw.addToolBar(title: "test");
1061 toolBar->addAction(text: "one");
1062 QAction *action = toolBar->addAction(text: "two");
1063
1064 QLineEdit *lineedit = new QLineEdit;
1065 lineedit->setMaximumWidth(50);
1066 toolBar->addWidget(widget: lineedit);
1067
1068 mw.resize(w: 400, h: 400);
1069 mw.show();
1070
1071 QWidget *actionwidget = toolBar->widgetForAction(action);
1072 QVERIFY(qAbs(lineedit->pos().x() - (actionwidget->geometry().right() + 1 + toolBar->layout()->spacing())) < 2);
1073}
1074
1075void tst_QToolBar::task197996_visibility()
1076{
1077 if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland"), cs: Qt::CaseInsensitive))
1078 QSKIP("Wayland: This fails. Figure out why.");
1079
1080 QMainWindow mw;
1081 QToolBar *toolBar = new QToolBar(&mw);
1082
1083 mw.addToolBar(toolbar: toolBar);
1084 toolBar->addAction(action: new QAction("Foo", &mw));
1085 QAction *pAction = new QAction("Test", &mw);
1086 toolBar->addAction(action: pAction);
1087
1088 pAction->setVisible(false);
1089 toolBar->setVisible(false);
1090
1091 toolBar->setVisible(true);
1092 pAction->setVisible(true);
1093
1094 mw.show();
1095 QVERIFY(QTest::qWaitForWindowActive(&mw));
1096
1097 QVERIFY(toolBar->widgetForAction(pAction)->isVisible());
1098
1099 toolBar->setVisible(false);
1100 pAction->setVisible(false);
1101
1102 QVERIFY(!toolBar->widgetForAction(pAction)->isVisible());
1103
1104 toolBar->setVisible(true);
1105 pAction->setVisible(true);
1106
1107 QTRY_VERIFY(toolBar->widgetForAction(pAction)->isVisible());
1108}
1109
1110class ShowHideEventCounter : public QObject
1111{
1112public:
1113 using QObject::QObject;
1114
1115 bool eventFilter(QObject *watched, QEvent *event) override
1116 {
1117 if (qobject_cast<QLineEdit*>(object: watched) && !event->spontaneous()) {
1118 if (event->type() == QEvent::Show)
1119 ++m_showEventsCount;
1120
1121 if (event->type() == QEvent::Hide)
1122 ++m_hideEventsCount;
1123 }
1124
1125 return QObject::eventFilter(watched, event);
1126 }
1127
1128 uint showEventsCount() const { return m_showEventsCount; }
1129 uint hideEventsCount() const { return m_hideEventsCount; }
1130
1131private:
1132 uint m_showEventsCount = 0;
1133 uint m_hideEventsCount = 0;
1134};
1135
1136void tst_QToolBar::extraCpuConsumption()
1137{
1138 if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland"), cs: Qt::CaseInsensitive))
1139 QSKIP("Wayland: This fails. Figure out why.");
1140
1141 QMainWindow mainWindow;
1142
1143 auto tb = new QToolBar(&mainWindow);
1144 tb->setMovable(false);
1145
1146 auto extensions = tb->findChildren<QToolBarExtension *>();
1147 QVERIFY(!extensions.isEmpty());
1148
1149 auto extensionButton = extensions.at(i: 0);
1150 QVERIFY(extensionButton);
1151
1152 tb->addWidget(widget: new QLabel("Lorem ipsum dolor sit amet"));
1153
1154 auto le = new QLineEdit;
1155 le->setClearButtonEnabled(true);
1156 le->setText("Lorem ipsum");
1157 tb->addWidget(widget: le);
1158
1159 mainWindow.addToolBar(toolbar: tb);
1160 mainWindow.show();
1161 QVERIFY(QTest::qWaitForWindowActive(&mainWindow));
1162
1163 auto eventCounter = new ShowHideEventCounter(&mainWindow);
1164 le->installEventFilter(filterObj: eventCounter);
1165
1166 auto defaultSize = mainWindow.size();
1167
1168 // Line edit should be hidden now and extension button should be displayed
1169 for (double p = 0.7; extensionButton->isHidden() || qFuzzyCompare(p1: p, p2: 0.); p -= 0.01) {
1170 mainWindow.resize(w: int(defaultSize.width() * p), h: defaultSize.height());
1171 }
1172 QVERIFY(!extensionButton->isHidden());
1173
1174 // Line edit should be visible, but smaller
1175 for (double p = 0.75; !extensionButton->isHidden() || qFuzzyCompare(p1: p, p2: 1.); p += 0.01) {
1176 mainWindow.resize(w: int(defaultSize.width() * p), h: defaultSize.height());
1177 }
1178 QVERIFY(extensionButton->isHidden());
1179
1180 // Dispatch all pending events
1181 qApp->sendPostedEvents();
1182 qApp->processEvents();
1183
1184 QCOMPARE(eventCounter->showEventsCount(), eventCounter->hideEventsCount());
1185 QCOMPARE(eventCounter->showEventsCount(), uint(1));
1186 QCOMPARE(eventCounter->hideEventsCount(), uint(1));
1187}
1188
1189QTEST_MAIN(tst_QToolBar)
1190#include "tst_qtoolbar.moc"
1191

source code of qtbase/tests/auto/widgets/widgets/qtoolbar/tst_qtoolbar.cpp