QtBase  v6.3.1
tst_qmenubar.cpp
Go to the documentation of this file.
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 <QTest>
31 #include <QSignalSpy>
32 #include <qapplication.h>
33 #include <qmainwindow.h>
34 #include <qmenubar.h>
35 #include <qstyle.h>
36 #include <qproxystyle.h>
37 #include <qstylefactory.h>
38 #include <qaction.h>
39 #include <qstyleoption.h>
40 #include <QVBoxLayout>
41 #include <QLabel>
42 #include <QPlainTextEdit>
43 #include <QTranslator>
44 #include <qscreen.h>
45 
46 #include <qobject.h>
47 
49 
50 #include <qmenubar.h>
51 
52 #include <QtTest/private/qtesthelpers_p.h>
53 
54 using namespace QTestPrivate;
55 
56 // Helper to calculate the action position in window coordinates
57 static inline QPoint widgetToWindowPos(const QWidget *w, const QPoint &pos)
58 {
59  const QWindow *window = w->window()->windowHandle();
61  return window->mapFromGlobal(w->mapToGlobal(pos));
62 }
63 
64 static QPoint menuBarActionWindowPos(const QMenuBar *mb, QAction *a)
65 {
66  return widgetToWindowPos(mb, mb->actionGeometry(a).center());
67 }
68 
69 class Menu : public QMenu
70 {
71  Q_OBJECT
72  public slots:
73  void addActions()
74  {
75  //this will change the geometry of the menu
76  addAction("action1");
77  addAction("action2");
78  }
79 };
80 
81 struct TestMenu
82 {
85 };
86 
87 class tst_QMenuBar : public QObject
88 {
89  Q_OBJECT
90 public:
91  tst_QMenuBar();
92 
93 private slots:
94  void getSetCheck();
95  void cleanup();
96 
97  void clear();
98  void removeItemAt();
99  void removeItemAt_data();
100  void removeItem_data();
101  void removeItem();
102  void count();
103  void insertItem_QString_QObject();
104 
105 #if !defined(Q_OS_DARWIN)
106  void accel();
107  void activatedCount();
108  void activatedCount_data();
109 
110  void check_accelKeys();
111  void check_cursorKeys1();
112  void check_cursorKeys2();
113  void check_cursorKeys3();
114 
115  void check_escKey();
116 #endif
117  void allowActiveAndDisabled();
118  void taskQTBUG56860_focus();
119  void check_endKey();
120  void check_homeKey();
121 
122 // void check_mouse1_data();
123 // void check_mouse1();
124 // void check_mouse2_data();
125 // void check_mouse2();
126 
127  void check_altPress();
128  void check_altClosePress();
129 #if !defined(Q_OS_DARWIN)
130  void check_shortcutPress();
131  void check_menuPosition();
132  void taskQTBUG46812_doNotLeaveMenubarHighlighted();
133 #endif
134  void task223138_triggered();
135  void task256322_highlight();
136  void menubarSizeHint();
137 #ifndef Q_OS_MACOS
138  void taskQTBUG4965_escapeEaten();
139 #endif
140  void taskQTBUG11823_crashwithInvisibleActions();
141  void closeOnSecondClickAndOpenOnThirdClick();
142  void cornerWidgets_data();
143  void cornerWidgets();
144  void taskQTBUG53205_crashReparentNested();
145 #ifdef Q_OS_MACOS
146  void taskQTBUG56275_reinsertMenuInParentlessQMenuBar();
147  void QTBUG_57404_existingMenuItemException();
148  void defaultEditMenuItems();
149 
150 #endif
151  void QTBUG_25669_menubarActionDoubleTriggered();
152  void taskQTBUG55966_subMenuRemoved();
153  void QTBUG_58344_invalidIcon();
154  void platformMenu();
155  void addActionQt5connect();
156  void QTBUG_65488_hiddenActionTriggered();
157 protected slots:
158  void onSimpleActivated( QAction*);
159  void onComplexActionTriggered();
161 
162 private:
163  TestMenu initSimpleMenuBar(QMenuBar *mb, bool forceNonNative = true);
164  TestMenu initWindowWithSimpleMenuBar(QMainWindow &w, bool forceNonNative = true);
165  QAction *createCharacterAction(QMenu *menu, char lowerAscii);
166  QMenu *addNumberedMenu(QMenuBar *mb, int n);
167  TestMenu initComplexMenuBar(QMenuBar *mb);
168  TestMenu initWindowWithComplexMenuBar(QMainWindow &w);
169 
170  QAction* m_lastSimpleAcceleratorId;
171  int m_simpleActivatedCount;
172  int m_complexTriggerCount[int('k')];
173  QMenuBar* taskQTBUG53205MenuBar;
174 };
175 
176 // Testing get/set functions
177 void tst_QMenuBar::getSetCheck()
178 {
179  QMenuBar obj1;
180  // QAction * QMenuBar::activeAction()
181  // void QMenuBar::setActiveAction(QAction *)
182  QAction *var1 = new QAction(0);
183  obj1.setActiveAction(var1);
184  QCOMPARE(var1, obj1.activeAction());
185  obj1.setActiveAction((QAction *)0);
186  QCOMPARE((QAction *)0, obj1.activeAction());
187  delete var1;
188 }
189 
190 #include <qcursor.h>
191 
214 tst_QMenuBar::tst_QMenuBar() : m_lastSimpleAcceleratorId(0), m_simpleActivatedCount(0)
215 {
217 }
218 
220 {
221  m_lastSimpleAcceleratorId = action;
222  m_simpleActivatedCount++;
223 }
224 
225 void tst_QMenuBar::cleanup()
226 {
228 }
229 
230 // Create a simple menu bar and connect its actions to onSimpleActivated().
231 
232 TestMenu tst_QMenuBar::initSimpleMenuBar(QMenuBar *mb, bool forceNonNative) {
234  if (forceNonNative)
235  mb->setNativeMenuBar(false);
237  QMenu *menu = mb->addMenu(QStringLiteral("&accel"));
238  QAction *action = menu->addAction(QStringLiteral("menu1") );
239 #if QT_CONFIG(shortcut)
240  action->setShortcut(QKeySequence(Qt::ALT | Qt::Key_A));
241  action->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_A));
242 #endif
244  result.menus << menu;
245  result.actions << action;
246 
247  menu = mb->addMenu(QStringLiteral("accel1"));
248  action = menu->addAction(QStringLiteral("&Open...") );
249 #if QT_CONFIG(shortcut)
250  action->setShortcut(Qt::Key_O);
251 #endif
252  result.actions << action;
253 
254  action = menu->addAction(QStringLiteral("action"));
255 #if QT_CONFIG(shortcut)
256  action->setShortcut(QKeySequence(Qt::ALT | Qt::Key_Z));
257 #endif
258  result.actions << action;
259 
260  result.menus << menu;
262 
263  m_lastSimpleAcceleratorId = 0;
264  m_simpleActivatedCount = 0;
265 
266  return result;
267 }
268 
269 inline TestMenu tst_QMenuBar::initWindowWithSimpleMenuBar(QMainWindow &w, bool forceNonNative)
270 {
271  w.resize(200, 200);
272  centerOnScreen(&w);
273  return initSimpleMenuBar(w.menuBar(), forceNonNative);
274 }
275 
276 // add a menu with number n, set number as data.
277 QMenu *tst_QMenuBar::addNumberedMenu(QMenuBar *mb, int n)
278 {
279  const QString text = QStringLiteral("Menu &") + QString::number(n);
280  QMenu *menu = mb->addMenu(text);
283  action->setObjectName(text + QStringLiteral("Action"));
284  action->setData(QVariant(n));
286  return menu;
287 }
288 
289 // Create an action triggering on Ctrl+character, set number as data.
290 QAction *tst_QMenuBar::createCharacterAction(QMenu *menu, char lowerAscii)
291 {
292  const QString text = QStringLiteral("Item ") + QChar(QLatin1Char(lowerAscii)).toUpper();
294  action->setObjectName(text);
295  action->setData(QVariant(int(lowerAscii)));
296 #if QT_CONFIG(shortcut)
297  action->setShortcut(Qt::CTRL | Qt::Key(lowerAscii - 'a' + int(Qt::Key_A)));
298 #endif
300  return action;
301 }
302 
304 {
305  if (QAction *a = qobject_cast<QAction *>(sender()))
306  m_complexTriggerCount[a->data().toInt()]++;
307 }
308 
309 // Create a complex menu bar and connect its actions to onComplexActionTriggered()
310 // for their invocations to be counted in m_complexTriggerCount. The index is the
311 // menu number (1..n) for the menu bar actions and the ASCII-code of the shortcut
312 // character for the actions in the menus.
313 TestMenu tst_QMenuBar::initComplexMenuBar(QMenuBar *mb)
314 {
316  mb->setNativeMenuBar(false);
317  QMenu *menu = addNumberedMenu(mb, 1);
318  result.menus << menu;
319  for (char c = 'a'; c < 'c'; ++c)
320  result.actions << createCharacterAction(menu, c);
321 
322  menu = addNumberedMenu(mb, 2);
324  result.menus << menu;
325  for (char c = 'c'; c < 'g'; ++c)
326  result.actions << createCharacterAction(menu, c);
327  menu->addSeparator();
328  for (char c = 'g'; c < 'i'; ++c)
329  result.actions << createCharacterAction(menu, c);
330 
331  QAction *action = mb->addAction(QStringLiteral("M&enu 3"));
332  action->setData(QVariant(3));
333 #if QT_CONFIG(shortcut)
334  action->setShortcut(Qt::ALT | Qt::Key_J);
335 #endif
337  result.actions << action;
338 
339  std::fill(m_complexTriggerCount, m_complexTriggerCount + sizeof(m_complexTriggerCount) / sizeof(int), 0);
340 
341  return result;
342 }
343 
344 inline TestMenu tst_QMenuBar::initWindowWithComplexMenuBar(QMainWindow &w)
345 {
346  w.resize(400, 200);
347  centerOnScreen(&w);
348  return initComplexMenuBar(w.menuBar());
349 }
350 
351 // On Mac native key events are needed to test menu action activation
352 #if !defined(Q_OS_DARWIN)
353 void tst_QMenuBar::accel()
354 {
356  QSKIP("Wayland: This fails. Figure out why.");
357 
358  // create a popup menu with menu items set the accelerators later...
359  QMainWindow w;
360  const TestMenu menu = initWindowWithSimpleMenuBar(w);
361  w.show();
364  // shortcuts won't work unless the window is active
365  QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_A, Qt::ControlModifier );
366  QTest::qWait(300);
367 
368  QCOMPARE( m_lastSimpleAcceleratorId, menu.actions.front() );
369 }
370 #endif
371 
372 // On Mac native key events are needed to test menu action activation
373 #if !defined(Q_OS_DARWIN)
374 void tst_QMenuBar::activatedCount()
375 {
377  QSKIP("Wayland: This fails. Figure out why.");
378 
379  // create a popup menu with menu items set the accelerators later...
380  QMainWindow w;
381  QFETCH( bool, forceNonNative );
382  initWindowWithSimpleMenuBar(w, forceNonNative);
383  w.show();
386 
387  QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_A, Qt::ControlModifier );
388 //wait(5000);
389  QCOMPARE( m_simpleActivatedCount, 2 ); //1 from the popupmenu and 1 from the menubar
390 }
391 
392 void tst_QMenuBar::activatedCount_data()
393 {
394  QTest::addColumn<bool>("forceNonNative");
395  QTest::newRow( "forcing non-native menubar" ) << true;
396  QTest::newRow( "not forcing non-native menubar" ) << false;
397 }
398 #endif
399 
400 void tst_QMenuBar::clear()
401 {
403  initSimpleMenuBar(&menuBar);
404  menuBar.clear();
405  QCOMPARE( menuBar.actions().size(), 0 );
406 
407  menuBar.clear();
408  for (int i = 0; i < 10; i++) {
410  for (int k = 0; k < i; k++)
411  menu->addAction( QStringLiteral("Item ") + QString::number(k));
412  QCOMPARE( menuBar.actions().size(), i + 1 );
413  }
414  QCOMPARE( menuBar.actions().size(), 10 );
415  menuBar.clear();
416  QCOMPARE( menuBar.actions().size(), 0 );
417 }
418 
419 void tst_QMenuBar::count()
420 {
422  QCOMPARE( menuBar.actions().size(), 0 );
423 
424  for (int i = 0; i < 10; i++) {
426  QCOMPARE( menuBar.actions().size(), i + 1 );
427  }
428 }
429 
430 void tst_QMenuBar::removeItem_data()
431 {
432  QTest::addColumn<int>("removeIndex");
433  QTest::newRow( "first" ) << 0;
434  QTest::newRow( "middle" ) << 1;
435  QTest::newRow( "last" ) << 2;
436 }
437 
438 // Basically the same test as removeItemAt, except that we remember and remove id's.
439 void tst_QMenuBar::removeItem()
440 {
442 
443  QMenu *pm = new QMenu( "stuff", &menuBar );
444  pm->setTitle("Menu 1");
445  pm->addAction( QString("Item 10") );
446  QAction* action1 = menuBar.addMenu( pm );
447 
448  pm = new QMenu( &menuBar );
449  pm->setTitle("Menu 2");
450  pm->addAction( QString("Item 20") );
451  pm->addAction( QString("Item 21") );
452  QAction *action2 = menuBar.addMenu( pm );
453 
454  pm = new QMenu( "Menu 3", &menuBar );
455  pm->addAction( QString("Item 30") );
456  pm->addAction( QString("Item 31") );
457  pm->addAction( QString("Item 32") );
458  QAction *action3 = menuBar.addMenu( pm );
459 
460  const QList<QAction *> menuBarActions = menuBar.actions();
461 
462  QCOMPARE( action1->text(), QString("Menu 1") );
463  QCOMPARE( action2->text(), QString("Menu 2") );
464  QCOMPARE( action3->text(), QString("Menu 3") );
465 
466  QVERIFY( menuBarActions.at(0) == action1 );
467  QVERIFY( menuBarActions.at(1) == action2 );
468  QVERIFY( menuBarActions.at(2) == action3 );
469 
470  // Ok, now that we know we have created the menu we expect, lets remove an item...
471  QFETCH( int, removeIndex );
472  switch (removeIndex )
473  {
474  case 0: {
475  menuBar.removeAction(action1);
476  const QList<QAction *> menuBarActions2 = menuBar.actions();
477  QCOMPARE( menuBarActions2.at(0)->text(), QString("Menu 2") );
478  QCOMPARE( menuBarActions2.at(1)->text(), QString("Menu 3") );
479  }
480  break;
481  case 1: {
482  menuBar.removeAction(action2);
483  const QList<QAction *> menuBarActions2 = menuBar.actions();
484  QCOMPARE( menuBarActions2.at(0)->text(), QString("Menu 1") );
485  QCOMPARE( menuBarActions2.at(1)->text(), QString("Menu 3") );
486  }
487  break;
488  case 2: {
489  menuBar.removeAction(action3);
490  const QList<QAction *> menuBarActions2 = menuBar.actions();
491  QCOMPARE( menuBarActions2.at(0)->text(), QString("Menu 1") );
492  QCOMPARE( menuBarActions2.at(1)->text(), QString("Menu 2") );
493  }
494  break;
495  }
496  QList<QAction *> menuBarActions2 = menuBar.actions();
497  QVERIFY( menuBarActions2.size() == 2 );
498 }
499 
500 void tst_QMenuBar::removeItemAt_data()
501 {
502  QTest::addColumn<int>("removeIndex");
503  QTest::newRow( "first" ) << 0;
504  QTest::newRow( "middle" ) << 1;
505  QTest::newRow( "last" ) << 2;
506 }
507 
508 void tst_QMenuBar::removeItemAt()
509 {
511  QMenu *pm = new QMenu("Menu 1", &menuBar);
512  pm->addAction( QString("Item 10") );
513  menuBar.addMenu( pm );
514 
515  pm = new QMenu( "Menu 2", &menuBar);
516  pm->addAction( QString("Item 20") );
517  pm->addAction( QString("Item 21") );
518  menuBar.addMenu( pm );
519 
520  pm = new QMenu( "Menu 3", &menuBar);
521  pm->addAction( QString("Item 30") );
522  pm->addAction( QString("Item 31") );
523  pm->addAction( QString("Item 32") );
524  menuBar.addMenu( pm );
525 
526  QList<QAction *> menuBarActions = menuBar.actions();
527 
528  QCOMPARE( menuBarActions.at(0)->text(), QString("Menu 1") );
529  QCOMPARE( menuBarActions.at(1)->text(), QString("Menu 2") );
530  QCOMPARE( menuBarActions.at(2)->text(), QString("Menu 3") );
531 
532  // Ok, now that we know we have created the menu we expect, lets remove an item...
533  QFETCH( int, removeIndex );
534  menuBar.removeAction(menuBarActions.at(removeIndex));
535  const QList<QAction *> menuBarActions2 = menuBar.actions();
536  switch (removeIndex )
537  {
538  case 0:
539  QCOMPARE( menuBarActions2.at(0)->text(), QString("Menu 2") );
540  QCOMPARE( menuBarActions2.at(1)->text(), QString("Menu 3") );
541  break;
542  case 1:
543  QCOMPARE( menuBarActions2.at(0)->text(), QString("Menu 1") );
544  QCOMPARE( menuBarActions2.at(1)->text(), QString("Menu 3") );
545  break;
546  case 2:
547  QCOMPARE( menuBarActions2.at(0)->text(), QString("Menu 1") );
548  QCOMPARE( menuBarActions2.at(1)->text(), QString("Menu 2") );
549  break;
550  }
551 
552  QVERIFY( menuBarActions2.size() == 2 );
553 }
554 
555 /*
556  Check the insert functions that create menu items.
557  For the moment i only check the strings and pixmaps. The rest are special cases which are
558  used less frequently.
559 */
560 
561 void tst_QMenuBar::insertItem_QString_QObject()
562 {
564  initComplexMenuBar(&menuBar);
565 
566  const QList<QAction *> actions = menuBar.actions();
567 
568  QCOMPARE(actions.at(0)->text(), QString("Menu &1") );
569  QCOMPARE(actions.at(1)->text(), QString("Menu &2") );
570  QCOMPARE(actions.at(2)->text(), QString("M&enu 3") );
571  QVERIFY(actions.size() < 4); // there is no menu 4!
572 }
573 
574 // On Mac native key events are needed to test menu action activation
575 #if !defined(Q_OS_DARWIN)
576 void tst_QMenuBar::check_accelKeys()
577 {
579  QSKIP("Wayland: This fails. Figure out why.");
580 
581  QMainWindow w;
582  initWindowWithComplexMenuBar(w);
583  w.show();
586 
587  // start with a bogus key that shouldn't trigger anything
588  QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_I, Qt::ControlModifier);
589  QCOMPARE(m_complexTriggerCount[1], 0);
590  QCOMPARE(m_complexTriggerCount[2], 0);
591  QCOMPARE(m_complexTriggerCount[3], 0);
592  QCOMPARE(m_complexTriggerCount[4], 0);
593  QCOMPARE(m_complexTriggerCount[int('a')], 0);
594  QCOMPARE(m_complexTriggerCount[int('b')], 0);
595  QCOMPARE(m_complexTriggerCount[int('c')], 0);
596  QCOMPARE(m_complexTriggerCount[int('d')], 0);
597 
598  QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_A, Qt::ControlModifier);
599  QCOMPARE(m_complexTriggerCount[1], 0);
600  QCOMPARE(m_complexTriggerCount[2], 0);
601  QCOMPARE(m_complexTriggerCount[3], 0);
602  QCOMPARE(m_complexTriggerCount[4], 0);
603  QCOMPARE(m_complexTriggerCount[int('a')], 1);
604  QCOMPARE(m_complexTriggerCount[int('b')], 0);
605  QCOMPARE(m_complexTriggerCount[int('c')], 0);
606  QCOMPARE(m_complexTriggerCount[int('d')], 0);
607 
608  QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_C, Qt::ControlModifier);
609  QCOMPARE(m_complexTriggerCount[1], 0);
610  QCOMPARE(m_complexTriggerCount[2], 0);
611  QCOMPARE(m_complexTriggerCount[3], 0);
612  QCOMPARE(m_complexTriggerCount[4], 0);
613  QCOMPARE(m_complexTriggerCount[int('a')], 1);
614  QCOMPARE(m_complexTriggerCount[int('b')], 0);
615  QCOMPARE(m_complexTriggerCount[int('c')], 1);
616  QCOMPARE(m_complexTriggerCount[int('d')], 0);
617 
618  QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_B, Qt::ControlModifier);
619  QCOMPARE(m_complexTriggerCount[1], 0);
620  QCOMPARE(m_complexTriggerCount[2], 0);
621  QCOMPARE(m_complexTriggerCount[3], 0);
622  QCOMPARE(m_complexTriggerCount[4], 0);
623  QCOMPARE(m_complexTriggerCount[int('a')], 1);
624  QCOMPARE(m_complexTriggerCount[int('b')], 1);
625  QCOMPARE(m_complexTriggerCount[int('c')], 1);
626  QCOMPARE(m_complexTriggerCount[int('d')], 0);
627 
628  QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_D, Qt::ControlModifier);
629  QCOMPARE(m_complexTriggerCount[1], 0);
630  QCOMPARE(m_complexTriggerCount[2], 0);
631  QCOMPARE(m_complexTriggerCount[3], 0);
632  QCOMPARE(m_complexTriggerCount[4], 0);
633  QCOMPARE(m_complexTriggerCount[int('a')], 1);
634  QCOMPARE(m_complexTriggerCount[int('b')], 1);
635  QCOMPARE(m_complexTriggerCount[int('c')], 1);
636  QCOMPARE(m_complexTriggerCount[int('d')], 1);
637 
638  QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_J, Qt::AltModifier);
639  QCOMPARE(m_complexTriggerCount[1], 0);
640  QCOMPARE(m_complexTriggerCount[2], 0);
641  QCOMPARE(m_complexTriggerCount[3], 1);
642  QCOMPARE(m_complexTriggerCount[4], 0);
643  QCOMPARE(m_complexTriggerCount[int('a')], 1);
644  QCOMPARE(m_complexTriggerCount[int('b')], 1);
645  QCOMPARE(m_complexTriggerCount[int('c')], 1);
646  QCOMPARE(m_complexTriggerCount[int('d')], 1);
647 }
648 #endif
649 
650 // On Mac native key events are needed to test menu action activation
651 #if !defined(Q_OS_DARWIN)
652 void tst_QMenuBar::check_cursorKeys1()
653 {
654  if (qgetenv("XDG_CURRENT_DESKTOP") == "Unity")
655  QSKIP("This test is flaky on Ubuntu/Unity due to regression introduced by QTBUG-39362");
656 
658  QSKIP("Wayland: This fails. Figure out why.");
659 
660  QMainWindow w;
661  initWindowWithComplexMenuBar(w);
662  w.show();
665 
666  // start with a ALT + 1 that activates the first popupmenu
667  QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_1, Qt::AltModifier );
668  // the Popupmenu should be visible now
669  QCOMPARE(m_complexTriggerCount[3], 0);
670  QCOMPARE(m_complexTriggerCount[4], 0);
671  QCOMPARE(m_complexTriggerCount[int('a')], 0);
672  QCOMPARE(m_complexTriggerCount[int('b')], 0);
673  QCOMPARE(m_complexTriggerCount[int('c')], 0);
674  QCOMPARE(m_complexTriggerCount[int('d')], 0);
675 
676  // Simulate a cursor key down click
677  QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Down );
678  // and an Enter key
679  QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Enter );
680  // Let's see if the correct slot is called...
681  QCOMPARE(m_complexTriggerCount[3], 0);
682  QCOMPARE(m_complexTriggerCount[4], 0);
683  QCOMPARE(m_complexTriggerCount[int('a')], 0); // this shouldn't have been called
684  QCOMPARE(m_complexTriggerCount[int('b')], 1); // and this should have been called by a signal now
685  QCOMPARE(m_complexTriggerCount[int('c')], 0);
686  QCOMPARE(m_complexTriggerCount[int('d')], 0);
687 }
688 #endif
689 
690 // Qt/Mac does not use the native popups/menubar
691 #if !defined(Q_OS_DARWIN)
692 void tst_QMenuBar::check_cursorKeys2()
693 {
694  if (qgetenv("XDG_CURRENT_DESKTOP") == "Unity")
695  QSKIP("This test is flaky on Ubuntu/Unity due to regression introduced by QTBUG-39362");
696 
698  QSKIP("Wayland: This fails. Figure out why.");
699 
700  QMainWindow w;
701  initWindowWithComplexMenuBar(w);
702  w.show();
705 
706  // select popupmenu2
707  QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_2, Qt::AltModifier );
708 
709  // Simulate some cursor keys
710  QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Left );
711  QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Down );
712  QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Right );
713  QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Down );
714  // and an Enter key
715  QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Enter );
716  // Let's see if the correct slot is called...
717  QCOMPARE(m_complexTriggerCount[3], 0);
718  QCOMPARE(m_complexTriggerCount[4], 0);
719  QCOMPARE(m_complexTriggerCount[int('a')], 0); // this shouldn't have been caled
720  QCOMPARE(m_complexTriggerCount[int('b')], 0); // and this should have been called by a signal ow
721  QCOMPARE(m_complexTriggerCount[int('c')], 0);
722  QCOMPARE(m_complexTriggerCount[int('d')], 1);
723 }
724 #endif
725 
729 // Qt/Mac does not use the native popups/menubar
730 #if !defined(Q_OS_DARWIN)
731 void tst_QMenuBar::check_cursorKeys3()
732 {
733  if (qgetenv("XDG_CURRENT_DESKTOP") == "Unity")
734  QSKIP("This test is flaky on Ubuntu/Unity due to regression introduced by QTBUG-39362");
735 
737  QSKIP("Wayland: This fails. Figure out why.");
738 
739  QMainWindow w;
740  initWindowWithComplexMenuBar(w);
741  w.show();
744 
745  // select Popupmenu 2
746  QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_2, Qt::AltModifier );
747 
748  // Simulate some keys
749  QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Left );
750  QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Down );
751  // and press ENTER
752  QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Enter );
753  // Let's see if the correct slot is called...
754  QCOMPARE(m_complexTriggerCount[3], 0);
755  QCOMPARE(m_complexTriggerCount[4], 0);
756  QCOMPARE(m_complexTriggerCount[int('a')], 0); // this shouldn't have been called
757  QCOMPARE(m_complexTriggerCount[int('b')], 1); // and this should have been called by a signal now
758  QCOMPARE(m_complexTriggerCount[int('c')], 0);
759  QCOMPARE(m_complexTriggerCount[int('d')], 0);
760 }
761 #endif
762 
763 void tst_QMenuBar::taskQTBUG56860_focus()
764 {
765 #if defined(Q_OS_DARWIN)
766  QSKIP("Native key events are needed to test menu action activation on macOS.");
767 #endif
769  QSKIP("Wayland: This fails. Figure out why.");
770 
771  QMainWindow w;
772  QMenuBar *mb = w.menuBar();
773  mb->setNativeMenuBar(false);
774 
775  QMenu *em = mb->addMenu("&Edit");
776  em->setObjectName("EditMenu");
777  em->addAction("&Cut");
778  em->addAction("C&opy");
779  QPlainTextEdit *e = new QPlainTextEdit;
780  e->setObjectName("edit");
781 
782  w.setCentralWidget(e);
783  w.show();
786 
788 
789  // Open menu
790  QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_E, Qt::AltModifier );
792  // key down to trigger focus
793  QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Down );
794  // and press ENTER to close
795  QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Enter );
797  // focus should have returned to the editor by now
799 
800  // Now do it all over again...
801  QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_E, Qt::AltModifier );
803  QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Down );
804  QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Enter );
807 
808 }
809 
813 void tst_QMenuBar::check_homeKey()
814 {
815  // I'm temporarily shutting up this testcase.
816  // Seems like the behaviour i'm expecting isn't ok.
817  QSKIP("This test has been \"temporarily\" disabled at least since 2009 :)");
818 
819  QEXPECT_FAIL( "0", "Popupmenu should respond to a Home key", Abort );
820 
821  QMainWindow w;
822  initWindowWithComplexMenuBar(w);
823  w.show();
826 
827  // select Popupmenu 2
828  QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_2, Qt::AltModifier );
829 
830  // Simulate some keys
831  QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Down );
832  QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Down );
833  QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Down );
834  QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Home );
835  // and press ENTER
836  QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Enter );
837  // Let's see if the correct slot is called...
838 // QVERIFY2( m_complexActionTriggerCount[int('c')] == 1, "Popupmenu should respond to a Home key" );
839  QCOMPARE(m_complexTriggerCount[int('c')], 1);
840  QCOMPARE(m_complexTriggerCount[3], 0);
841  QCOMPARE(m_complexTriggerCount[4], 0);
842  QCOMPARE(m_complexTriggerCount[int('a')], 0);
843  QCOMPARE(m_complexTriggerCount[int('b')], 0);
844  QCOMPARE(m_complexTriggerCount[int('d')], 0);
845  QCOMPARE(m_complexTriggerCount[int('e')], 0);
846  QCOMPARE(m_complexTriggerCount[int('f')], 0);
847  QCOMPARE(m_complexTriggerCount[int('g')], 0);
848  QCOMPARE(m_complexTriggerCount[int('h')], 0);
849 }
850 
854 void tst_QMenuBar::check_endKey()
855 {
856  // I'm temporarily silenting this testcase.
857  // Seems like the behaviour i'm expecting isn't ok.
858  QSKIP("This test has been \"temporarily\" disabled at least since 2009 :)");
859 
860  QEXPECT_FAIL( "0", "Popupmenu should respond to an End key", Abort );
861 
862  QMainWindow w;
863  initWindowWithComplexMenuBar(w);
864  w.show();
867 
868  // select Popupmenu 2
869  QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_2, Qt::AltModifier );
870 
871  // Simulate some keys
872  QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_End );
873  // and press ENTER
874  QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Enter );
875  // Let's see if the correct slot is called...
876 // QVERIFY2( m_complexActionTriggerCount[int('h')] == 1, "Popupmenu should respond to an End key" );
877  QCOMPARE(m_complexTriggerCount[int('h')], 1);//, "Popupmenu should respond to an End key");
878  QCOMPARE(m_complexTriggerCount[3], 0);
879  QCOMPARE(m_complexTriggerCount[4], 0);
880  QCOMPARE(m_complexTriggerCount[int('a')], 0);
881  QCOMPARE(m_complexTriggerCount[int('b')], 0);
882  QCOMPARE(m_complexTriggerCount[int('c')], 0);
883  QCOMPARE(m_complexTriggerCount[int('d')], 0);
884  QCOMPARE(m_complexTriggerCount[int('e')], 0);
885  QCOMPARE(m_complexTriggerCount[int('f')], 0);
886  QCOMPARE(m_complexTriggerCount[int('g')], 0);
887 }
888 
895 // Qt/Mac does not use the native popups/menubar
896 #if !defined(Q_OS_DARWIN)
897 void tst_QMenuBar::check_escKey()
898 {
900  QSKIP("Wayland: This fails. Figure out why.");
901 
902  QMainWindow w;
903  const TestMenu menu = initWindowWithComplexMenuBar(w);
904  w.show();
905  w.setFocus();
908 
909  QVERIFY( !menu.menus.at(0)->isActiveWindow() );
910  QVERIFY( !menu.menus.at(1)->isActiveWindow() );
911 
912  // select Popupmenu 2
913  QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_2, Qt::AltModifier );
914  QVERIFY( !menu.menus.at(0)->isActiveWindow() );
915  QVERIFY( menu.menus.at(1)->isActiveWindow() );
916 
917  // If we press ESC, the popup should disappear
918  QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Escape );
919  QVERIFY( !menu.menus.at(0)->isActiveWindow() );
920  QVERIFY( !menu.menus.at(1)->isActiveWindow() );
921 
922  if (!QApplication::style()->inherits("QWindowsStyle"))
923  return;
924 
927  qWarning("Skipping menu button test on minimal/offscreen platforms");
928  return;
929  }
930 
931  // If we press Down the popupmenu should be active again
932  QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Down );
933  QVERIFY( !menu.menus.at(0)->isActiveWindow() );
934  QVERIFY( menu.menus.at(1)->isActiveWindow() );
935 
936  // and press ENTER
937  QTest::keyClick( menu.menus.at(1), Qt::Key_Enter );
938  // Let's see if the correct slot is called...
939  QVERIFY2(m_complexTriggerCount[int('c')] == 1, "Expected item 2C to be selected");
940 }
941 #endif
942 
943 
944 // void tst_QMenuBar::check_mouse1_data()
945 // {
946 // QTest::addColumn<QString>("popup_item");
947 // QTest::addColumn<int>("itemA_count");
948 // QTest::addColumn<int>("itemB_count");
949 
950 // QTest::newRow( "A" ) << QString( "Item A Ctrl+A" ) << 1 << 0;
951 // QTest::newRow( "B" ) << QString( "Item B Ctrl+B" ) << 0 << 1;
952 // }
953 
954 // /*!
955 // Check if the correct signals are emitted if we select a popupmenu.
956 // */
957 // void tst_QMenuBar::check_mouse1()
958 // {
959 // if (QSystem::curStyle() == "Motif")
960 // QSKIP("This fails in Motif due to a bug in the testing framework");
961 // QFETCH( QString, popup_item );
962 // QFETCH( int, itemA_count );
963 // QFETCH( int, itemB_count );
964 
965 // // initComplexMenubar();
966 // QVERIFY( !pm1->isActiveWindow() );
967 // QVERIFY( !pm2->isActiveWindow() );
968 
969 // QTest::qWait(1000);
970 // QtTestMouse mouse;
971 // mouse.mouseEvent( QtTestMouse::MouseClick, mb, "Menu &1", Qt::LeftButton );
972 
973 // QVERIFY( pm1->isActiveWindow() );
974 // QVERIFY( !pm2->isActiveWindow() );
975 
976 // QTest::qWait(1000);
977 // mouse.mouseEvent( QtTestMouse::MouseClick, pm1, popup_item, Qt::LeftButton );
978 
979 // QCOMPARE(m_complexActionTriggerCount[3], 0);
980 // QCOMPARE(m_complexActionTriggerCount[4], 0);
981 // QCOMPARE(m_complexActionTriggerCount['a'], (uint)itemA_count); // this option should have fired
982 // QCOMPARE(m_complexActionTriggerCount['b'], (uint)itemB_count);
983 // QCOMPARE(m_complexActionTriggerCount['c'], 0);
984 // QCOMPARE(m_complexActionTriggerCount['d'], 0);
985 // QCOMPARE(m_complexActionTriggerCount['e'], 0);
986 // QCOMPARE(m_complexActionTriggerCount['f'], 0);
987 // QCOMPARE(m_complexActionTriggerCount['g'], 0);
988 // }
989 
990 // void tst_QMenuBar::check_mouse2_data()
991 // {
992 // QTest::addColumn<QString>("label");
993 // QTest::addColumn<int>("itemA_count");
994 // QTest::addColumn<int>("itemB_count");
995 // QTest::addColumn<int>("itemC_count");
996 // QTest::addColumn<int>("itemD_count");
997 // QTest::addColumn<int>("itemE_count");
998 // QTest::addColumn<int>("itemF_count");
999 // QTest::addColumn<int>("itemG_count");
1000 // QTest::addColumn<int>("itemH_count");
1001 // QTest::addColumn<int>("menu3_count");
1002 
1003 // QTest::newRow( "A" ) << QString( "Menu &1/Item A Ctrl+A" ) << 1 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0;
1004 // QTest::newRow( "B" ) << QString( "Menu &1/Item B Ctrl+B" ) << 0 << 1 << 0 << 0 << 0 << 0 << 0 << 0 << 0;
1005 // QTest::newRow( "C" ) << QString( "Menu &2/Item C Ctrl+C" ) << 0 << 0 << 1 << 0 << 0 << 0 << 0 << 0 << 0;
1006 // QTest::newRow( "D" ) << QString( "Menu &2/Item D Ctrl+D" ) << 0 << 0 << 0 << 1 << 0 << 0 << 0 << 0 << 0;
1007 // QTest::newRow( "E" ) << QString( "Menu &2/Item E Ctrl+E" ) << 0 << 0 << 0 << 0 << 1 << 0 << 0 << 0 << 0;
1008 // QTest::newRow( "F" ) << QString( "Menu &2/Item F Ctrl+F" ) << 0 << 0 << 0 << 0 << 0 << 1 << 0 << 0 << 0;
1009 // QTest::newRow( "G" ) << QString( "Menu &2/Item G Ctrl+G" ) << 0 << 0 << 0 << 0 << 0 << 0 << 1 << 0 << 0;
1010 // QTest::newRow( "H" ) << QString( "Menu &2/Item H Ctrl+H" ) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 1 << 0;
1011 // QTest::newRow( "menu 3" ) << QString( "M&enu 3" ) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 1;
1012 // }
1013 
1014 // /*!
1015 // Check if the correct signals are emitted if we select a popupmenu.
1016 // This time, we use a little bit more magic from the testframework.
1017 // */
1018 // void tst_QMenuBar::check_mouse2()
1019 // {
1020 // if (QSystem::curStyle() == "Motif")
1021 // QSKIP("This fails in Motif due to a bug in the testing framework");
1022 // QFETCH( QString, label );
1023 // QFETCH( int, itemA_count );
1024 // QFETCH( int, itemB_count );
1025 // QFETCH( int, itemC_count );
1026 // QFETCH( int, itemD_count );
1027 // QFETCH( int, itemE_count );
1028 // QFETCH( int, itemF_count );
1029 // QFETCH( int, itemG_count );
1030 // QFETCH( int, itemH_count );
1031 // QFETCH( int, menu3_count );
1032 
1033 // // initComplexMenubar();
1034 // QtTestMouse mouse;
1035 // mouse.click( QtTestMouse::Menu, label, Qt::LeftButton );
1036 
1037 // // check if the correct signals have fired
1038 // QCOMPARE(m_complexActionTriggerCount[3], (uint)menu3_count);
1039 // QCOMPARE(m_complexActionTriggerCount[4], 0);
1040 // QCOMPARE(m_complexActionTriggerCount['a'], (uint)itemA_count);
1041 // QCOMPARE(m_complexActionTriggerCount['b'], (uint)itemB_count);
1042 // QCOMPARE(m_complexActionTriggerCount['c'], (uint)itemC_count);
1043 // QCOMPARE(m_complexActionTriggerCount['d'], (uint)itemD_count);
1044 // QCOMPARE(m_complexActionTriggerCount['e'], (uint)itemE_count);
1045 // QCOMPARE(m_complexActionTriggerCount['f'], (uint)itemF_count);
1046 // QCOMPARE(m_complexActionTriggerCount['g'], (uint)itemG_count);
1047 // QCOMPARE(m_complexActionTriggerCount['h'], (uint)itemH_count);
1048 // }
1049 
1050 void tst_QMenuBar::allowActiveAndDisabled()
1051 {
1052  QMenuBar menuBar;
1053  menuBar.setNativeMenuBar(false);
1054 
1055  // Task 241043 : check that second menu is activated if only
1056  // disabled menu items are added
1057 
1058  QMenu fileMenu("&File");
1059  // Task 241043 : check that second menu is activated
1060  // if all items are disabled
1061  QAction *act = fileMenu.addAction("Disabled");
1062  act->setEnabled(false);
1063 
1064  menuBar.addMenu(&fileMenu);
1065  QMenu disabledMenu("Disabled");
1066  disabledMenu.setEnabled(false);
1067  QMenu activeMenu("Active");
1068  menuBar.addMenu(&disabledMenu);
1069  menuBar.addMenu(&activeMenu);
1070  centerOnScreen(&menuBar);
1071  menuBar.show();
1073 
1074  // Here we verify that AllowActiveAndDisabled correctly skips
1075  // the disabled menu entry
1076  QTest::keyClick(&menuBar, Qt::Key_F, Qt::AltModifier );
1077  QTest::keyClick(&fileMenu, (Qt::Key_Right));
1078  if (qApp->style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled))
1079  QCOMPARE(menuBar.activeAction()->text(), disabledMenu.title());
1080  else
1081  QCOMPARE(menuBar.activeAction()->text(), activeMenu.title());
1082 
1083  QTest::keyClick(&menuBar, (Qt::Key_Left));
1084  if (qApp->style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled))
1085  QCOMPARE(menuBar.activeAction()->text(), fileMenu.title());
1086  else
1087  QCOMPARE(menuBar.activeAction()->text(), fileMenu.title());
1088 }
1089 
1090 void tst_QMenuBar::check_altPress()
1091 {
1093  QSKIP("Wayland: This fails. Figure out why.");
1094 
1095  if ( !qApp->style()->styleHint(QStyle::SH_MenuBar_AltKeyNavigation) ) {
1096  QSKIP(QString( "this is not supposed to work in the %1 style. Skipping." ).
1097  arg(qApp->style()->objectName()).toLatin1());
1098  }
1099 
1100  QMainWindow w;
1101  initWindowWithSimpleMenuBar(w);
1102  w.show();
1103  w.setFocus();
1106 
1107  QTest::keyClick( &w, Qt::Key_Alt );
1108  QTRY_VERIFY( ::qobject_cast<QMenuBar *>(qApp->focusWidget()) );
1109 }
1110 
1111 // QTBUG-47377: Pressing 'Alt' after opening a menu by pressing 'Alt+Accelerator'
1112 // should close it and QMenuBar::activeAction() should be 0.
1113 void tst_QMenuBar::check_altClosePress()
1114 {
1116  QSKIP("Wayland: This fails. Figure out why.");
1117 
1118  const QStyle *style = QApplication::style();
1119  if (!style->styleHint(QStyle::SH_MenuBar_AltKeyNavigation) ) {
1120  QSKIP(("This test is not supposed to work in the " + style->objectName().toLatin1()
1121  + " style. Skipping.").constData());
1122  }
1123 
1124  QMainWindow w;
1125  w.setWindowTitle(QTest::currentTestFunction());
1126  w.menuBar()->setNativeMenuBar(false);
1127  QMenu *menuFile = w.menuBar()->addMenu(tr("&File"));
1128  menuFile->addAction("Quit");
1129  QMenu *menuEdit = w.menuBar()->addMenu(tr("&Edit"));
1130  menuEdit->addAction("Copy");
1131 
1132  w.show();
1133  w.move(QGuiApplication::primaryScreen()->availableGeometry().center());
1136 
1137  QTest::keyClick(&w, Qt::Key_F, Qt::AltModifier);
1138  QTRY_VERIFY(menuFile->isVisible());
1139  QTest::keyClick(menuFile, Qt::Key_Alt, Qt::AltModifier);
1140  QTRY_VERIFY(!menuFile->isVisible());
1141  QTRY_VERIFY(!w.menuBar()->activeAction());
1142 }
1143 
1144 // Qt/Mac does not use the native popups/menubar
1145 #if !defined(Q_OS_DARWIN)
1146 void tst_QMenuBar::check_shortcutPress()
1147 {
1149  QSKIP("Wayland: This fails. Figure out why.");
1150 
1151  QMainWindow w;
1152  const TestMenu menu = initWindowWithComplexMenuBar(w);
1153  w.show();
1154  w.setFocus();
1157 
1158  QCOMPARE(m_complexTriggerCount[3], 0);
1159  QTest::keyClick(&w, Qt::Key_E, Qt::AltModifier);
1160  QTest::qWait(200);
1161  QCOMPARE(m_complexTriggerCount[3], 1);
1162  QVERIFY(!w.menuBar()->activeAction());
1163 
1164  QTest::keyClick(&w, Qt::Key_1, Qt::AltModifier );
1165  QVERIFY(menu.menus.at(0)->isActiveWindow());
1166  QTest::keyClick(&w, Qt::Key_2);
1167  QVERIFY(menu.menus.at(0)->isActiveWindow());
1168 }
1169 #endif
1170 
1171 class LayoutDirectionSaver
1172 {
1173  Q_DISABLE_COPY(LayoutDirectionSaver)
1174 public:
1175  explicit LayoutDirectionSaver(Qt::LayoutDirection direction)
1176  : m_oldDirection(qApp->layoutDirection())
1177  {
1178  qApp->setLayoutDirection(direction);
1179  }
1180 
1181  ~LayoutDirectionSaver()
1182  {
1183  qApp->setLayoutDirection(m_oldDirection);
1184  }
1185 
1186 private:
1187  const Qt::LayoutDirection m_oldDirection;
1188 };
1189 
1190 // Qt/Mac does not use the native popups/menubar
1191 #if !defined(Q_OS_DARWIN)
1192 void tst_QMenuBar::check_menuPosition()
1193 {
1195  QSKIP("Wayland: This fails. Figure out why.");
1196 
1197  QMainWindow w;
1198 
1199  Menu menu;
1200  menu.setTitle("&menu");
1201  QRect availRect = w.screen()->availableGeometry();
1202  QRect screenRect = w.screen()->geometry();
1203 
1204  while(menu.sizeHint().height() < (screenRect.height()*2/3)) {
1205  menu.addAction("item");
1206  }
1207 
1208  w.menuBar()->setNativeMenuBar(false);
1209  QAction *menu_action = w.menuBar()->addMenu(&menu);
1210  centerOnScreen(&w);
1211  w.show();
1212  qApp->setActiveWindow(&w);
1214 
1215  //the menu should be below the menubar item
1216  {
1217  w.move(availRect.topLeft());
1218  QRect mbItemRect = w.menuBar()->actionGeometry(menu_action);
1219  mbItemRect.moveTo(w.menuBar()->mapToGlobal(mbItemRect.topLeft()));
1220  QTest::keyClick(&w, Qt::Key_M, Qt::AltModifier );
1222  QCOMPARE(menu.pos(), QPoint(mbItemRect.x(), mbItemRect.bottom() + 1));
1223  menu.close();
1224  }
1225 
1226  //the menu should be above the menubar item
1227  {
1228  w.move(0,screenRect.bottom() - screenRect.height()/4); //just leave some place for the menubar
1229  QRect mbItemRect = w.menuBar()->actionGeometry(menu_action);
1230  mbItemRect.moveTo(w.menuBar()->mapToGlobal(mbItemRect.topLeft()));
1231  QTest::keyClick(&w, Qt::Key_M, Qt::AltModifier );
1233  QCOMPARE(menu.pos(), QPoint(mbItemRect.x(), mbItemRect.top() - menu.height()));
1234  menu.close();
1235  }
1236 
1237  //the menu should be on the side of the menubar item and should be "stuck" to the bottom of the screen
1238  {
1239  w.move(0,screenRect.y() + screenRect.height()/2); //put it in the middle
1240  QRect mbItemRect = w.menuBar()->actionGeometry(menu_action);
1241  mbItemRect.moveTo(w.menuBar()->mapToGlobal(mbItemRect.topLeft()));
1242  QTest::keyClick(&w, Qt::Key_M, Qt::AltModifier );
1244  QPoint firstPoint = QPoint(mbItemRect.right()+1, screenRect.bottom() - menu.height() + 1);
1245  QPoint secondPoint = QPoint(mbItemRect.right()+1, availRect.bottom() - menu.height() + 1);
1246  QVERIFY(menu.pos() == firstPoint || menu.pos() == secondPoint);
1247  menu.close();
1248  }
1249 
1250  // QTBUG-2596: in RTL, the menu should be stuck at the right of the action geometry
1251  {
1252  LayoutDirectionSaver directionSaver(Qt::RightToLeft);
1253  menu.clear();
1254  QObject::connect(&menu, SIGNAL(aboutToShow()), &menu, SLOT(addActions()));
1255  QRect mbItemRect = w.menuBar()->actionGeometry(menu_action);
1256  mbItemRect.moveTo(w.menuBar()->mapToGlobal(mbItemRect.topLeft()));
1257  QTest::keyClick(&w, Qt::Key_M, Qt::AltModifier );
1259  QCOMPARE(menu.geometry().right(), mbItemRect.right());
1260  menu.close();
1261  }
1262 
1263  // QTBUG-28031: Click at bottom-right corner.
1264  {
1265  w.move(400, 200);
1266  LayoutDirectionSaver directionSaver(Qt::RightToLeft);
1267  QMenuBar *mb = w.menuBar();
1268  const QPoint bottomRight = mb->actionGeometry(menu.menuAction()).bottomRight() - QPoint(1, 1);
1269  const QPoint localPos = widgetToWindowPos(mb, bottomRight);
1270  const QPoint globalPos = w.mapToGlobal(localPos);
1271  QTest::mouseClick(w.windowHandle(), Qt::LeftButton, {}, localPos);
1273  QCOMPARE(menu.geometry().right() - 1, globalPos.x());
1274  menu.close();
1275  }
1276 }
1277 #endif
1278 
1279 void tst_QMenuBar::task223138_triggered()
1280 {
1281  //we create a window with submenus and we check that both menubar and menus get the triggered signal
1282  QMainWindow win;
1283  centerOnScreen(&win);
1284  QMenu *menu = win.menuBar()->addMenu("test");
1285  QAction *top = menu->addAction("toplevelaction");
1286  QMenu *submenu = menu->addMenu("nested menu");
1287  QAction *action = submenu->addAction("nested action");
1288 
1289  QSignalSpy menubarSpy(win.menuBar(), SIGNAL(triggered(QAction*)));
1290  QSignalSpy menuSpy(menu, SIGNAL(triggered(QAction*)));
1291  QSignalSpy submenuSpy(submenu, SIGNAL(triggered(QAction*)));
1292 
1293  //let's trigger the first action
1294  top->trigger();
1295 
1296  QCOMPARE(menubarSpy.count(), 1);
1297  QCOMPARE(menuSpy.count(), 1);
1298  QCOMPARE(submenuSpy.count(), 0);
1299 
1300  menubarSpy.clear();
1301  menuSpy.clear();
1302  submenuSpy.clear();
1303 
1304  //let's trigger the sub action
1305  action->trigger();
1306  QCOMPARE(menubarSpy.count(), 1);
1307  QCOMPARE(menuSpy.count(), 1);
1308  QCOMPARE(submenuSpy.count(), 1);
1309 }
1310 
1311 void tst_QMenuBar::task256322_highlight()
1312 {
1314  QSKIP("Highlighting does not work correctly for minimal platform");
1315 
1317  QSKIP("Wayland: This fails. Figure out why.");
1318 
1319  QMainWindow win;
1320  win.menuBar()->setNativeMenuBar(false); //we can't check the geometry of native menubars
1321  QMenu menu;
1322  QAction *file = win.menuBar()->addMenu(&menu);
1323  file->setText("file");
1324  QMenu menu2;
1325  QAction *file2 = win.menuBar()->addMenu(&menu2);
1326  file2->setText("file2");
1327  QAction *nothing = win.menuBar()->addAction("nothing");
1328 
1329  centerOnScreen(&win);
1330  win.show();
1333 
1334  const QPoint filePos = menuBarActionWindowPos(win.menuBar(), file);
1335  QWindow *window = win.windowHandle();
1336  QTest::mousePress(window, Qt::LeftButton, {}, filePos);
1337  QTest::mouseMove(window, filePos);
1338  QTest::mouseRelease(window, Qt::LeftButton, {}, filePos);
1340  QVERIFY(!menu2.isVisible());
1341  QCOMPARE(win.menuBar()->activeAction(), file);
1342 
1343  const QPoint file2Pos = menuBarActionWindowPos(win.menuBar(), file2);
1344  QTest::mouseMove(window, file2Pos);
1346  QTRY_VERIFY(menu2.isVisible());
1347  QCOMPARE(win.menuBar()->activeAction(), file2);
1348 
1349  QPoint nothingCenter = menuBarActionWindowPos(win.menuBar(), nothing);
1350  QTest::mouseMove(window, nothingCenter);
1351  QTRY_VERIFY(!menu2.isVisible());
1352  QVERIFY(!menu.isVisible());
1353  QTRY_COMPARE(win.menuBar()->activeAction(), nothing);
1354 }
1355 
1356 void tst_QMenuBar::menubarSizeHint()
1357 {
1358  struct MyStyle : public QProxyStyle
1359  {
1360  MyStyle() : QProxyStyle(QStyleFactory::create("windows")) { }
1361 
1362  int pixelMetric(PixelMetric metric, const QStyleOption *option = 0,
1363  const QWidget *widget = 0) const override
1364  {
1365  // I chose strange values (prime numbers to be more sure that the size of the menubar is correct)
1366  switch (metric)
1367  {
1369  return 7;
1370  case PM_MenuBarHMargin:
1371  return 13;
1372  case PM_MenuBarVMargin:
1373  return 11;
1374  case PM_MenuBarPanelWidth:
1375  return 1;
1376  default:
1377  return QProxyStyle::pixelMetric(metric, option, widget);
1378  }
1379  }
1380  } style;
1381 
1382  QMenuBar mb;
1383  mb.setNativeMenuBar(false); //we can't check the geometry of native menubars
1384 
1385  mb.setStyle(&style);
1386  //this is a list of arbitrary strings so that we check the geometry
1387  QStringList list = QStringList() << "trer" << "ezrfgtgvqd" << "sdgzgzerzerzer" << "eerzertz" << "er";
1388  foreach(QString str, list)
1389  mb.addAction(str);
1390 
1391  const int panelWidth = style.pixelMetric(QStyle::PM_MenuBarPanelWidth);
1392  const int hmargin = style.pixelMetric(QStyle::PM_MenuBarHMargin);
1393  const int vmargin = style.pixelMetric(QStyle::PM_MenuBarVMargin);
1394  const int spacing = style.pixelMetric(QStyle::PM_MenuBarItemSpacing);
1395 
1396  centerOnScreen(&mb);
1397  mb.show();
1398  QRect result;
1399  foreach(QAction *action, mb.actions()) {
1400  const QRect actionRect = mb.actionGeometry(action);
1401  if (!result.isNull()) //this is the first item
1402  QCOMPARE(actionRect.left() - result.right() - 1, spacing);
1403  result |= actionRect;
1404  QCOMPARE(result.x(), panelWidth + hmargin + spacing);
1405  QCOMPARE(result.y(), panelWidth + vmargin);
1406  }
1407 
1408  //this code is copied from QMenuBar
1409  //there is no public member that allows to initialize a styleoption instance
1411  opt.rect = mb.rect();
1412  opt.menuRect = mb.rect();
1414  opt.menuItemType = QStyleOptionMenuItem::Normal;
1416  opt.palette = mb.palette();
1417 
1418  QSize resSize = QSize(result.x(), result.y()) + result.size()
1419  + QSize(panelWidth + hmargin, panelWidth + vmargin);
1420 
1421  resSize = style.sizeFromContents(QStyle::CT_MenuBar, &opt, resSize, &mb);
1422 
1423  QCOMPARE(resSize, mb.sizeHint());
1424 }
1425 
1426 // On Mac, do not test the menubar with escape key
1427 #ifndef Q_OS_MACOS
1428 void tst_QMenuBar::taskQTBUG4965_escapeEaten()
1429 {
1430  QMenuBar menubar;
1431  menubar.setNativeMenuBar(false);
1432  QMenu menu("menu1");
1433  QAction *first = menubar.addMenu(&menu);
1434 #if QT_CONFIG(shortcut)
1435  menu.addAction("quit", QKeySequence("ESC"), &menubar, SLOT(close()));
1436 #endif
1437  centerOnScreen(&menubar);
1438  menubar.show();
1441  menubar.setActiveAction(first);
1443  QCOMPARE(menubar.activeAction(), first);
1445  QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Escape);
1446  QVERIFY(!menu.isVisible());
1447  QTRY_VERIFY(menubar.hasFocus());
1448  QCOMPARE(menubar.activeAction(), first);
1449  QTest::qWait(200);
1450  QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Escape);
1451  QVERIFY(!menubar.activeAction());
1452  QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Escape); //now the action should be triggered
1453  QTRY_VERIFY(!menubar.isVisible());
1454 }
1455 #endif
1456 
1457 void tst_QMenuBar::taskQTBUG11823_crashwithInvisibleActions()
1458 {
1460  QSKIP("Wayland: This fails. Figure out why.");
1461 
1462  QMenuBar menubar;
1463  menubar.setNativeMenuBar(false); //we can't check the geometry of native menubars
1464 
1465  QAction * m = menubar.addAction( "&m" );
1466  QAction * a = menubar.addAction( "&a" );
1467 
1468  centerOnScreen(&menubar);
1469  menubar.show();
1472  menubar.setActiveAction(m);
1473  QCOMPARE(menubar.activeAction(), m);
1474  QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Right);
1475  QCOMPARE(menubar.activeAction(), a);
1476  QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Right);
1477  QCOMPARE(menubar.activeAction(), m);
1478  a->setVisible(false);
1479 
1480  menubar.setActiveAction(m);
1481  QCOMPARE(menubar.activeAction(), m); //the active action shouldn't have changed
1482 
1483  //it used to crash here because the action is invisible
1484  QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Right);
1485  QCOMPARE(menubar.activeAction(), m); //the active action shouldn't have changed
1486 }
1487 
1488 void tst_QMenuBar::closeOnSecondClickAndOpenOnThirdClick() // QTBUG-32807, menu should close on 2nd click.
1489 {
1491  QSKIP("Wayland: This fails. Figure out why.");
1492 
1494  mainWindow.resize(300, 200);
1495  centerOnScreen(&mainWindow);
1496  QMenuBar *menuBar = mainWindow.menuBar();
1497  menuBar->setNativeMenuBar(false);
1498  QMenu *fileMenu = menuBar->addMenu(QStringLiteral("OpenCloseOpen"));
1499  fileMenu->addAction(QStringLiteral("Quit"));
1500  mainWindow.show();
1503 
1504  const QPoint center = menuBarActionWindowPos(mainWindow.menuBar(), fileMenu->menuAction());
1505  const QPoint globalPos = mainWindow.mapToGlobal(center);
1506 
1510  QTRY_VERIFY(fileMenu->isVisible());
1511  QTest::mouseClick(window, Qt::LeftButton, {}, fileMenu->mapFromGlobal(globalPos));
1512  QTRY_VERIFY(!fileMenu->isVisible());
1514  QTRY_VERIFY(fileMenu->isVisible());
1515 }
1516 
1518 
1519 void tst_QMenuBar::cornerWidgets_data()
1520 {
1521  QTest::addColumn<Qt::Corner>("corner");
1522  QTest::newRow("left") << Qt::TopLeftCorner;
1523  QTest::newRow("right") << Qt::TopRightCorner;
1524 }
1525 
1526 static QByteArray msgComparison(int v1, const char *op, int v2)
1527 {
1528  QString result;
1529  QDebug(&result) << v1 << op << v2 << "failed";
1530  return result.toLocal8Bit();
1531 }
1532 
1533 void tst_QMenuBar::cornerWidgets()
1534 {
1535  enum { cornerWidgetWidth = 100 };
1536 
1537  QFETCH(Qt::Corner, corner);
1538 
1539 #if defined(Q_OS_MACOS)
1540  QSKIP("Test interferes with native menu bars on this platform");
1541 #endif
1542 
1543  QWidget widget;
1544  const QString dataTag = QLatin1String(QTest::currentDataTag());
1546  QVBoxLayout *layout = new QVBoxLayout(&widget);
1547  QMenuBar *menuBar = new QMenuBar(&widget);
1548  menuBar->setNativeMenuBar(false);
1549  layout->addWidget(menuBar);
1550  QMenu *fileMenu = menuBar->addMenu("File");
1551  fileMenu->addAction("Quit");
1552  QMenu *editMenu =menuBar->addMenu("Edit");
1553  editMenu->addAction("Copy");
1554  centerOnScreen(&widget);
1555 
1556  QLabel *cornerLabel = new QLabel(dataTag);
1557  cornerLabel->setFixedWidth(cornerWidgetWidth);
1558  menuBar->setCornerWidget(cornerLabel, corner);
1559  QCOMPARE(menuBar->cornerWidget(corner), cornerLabel);
1560  widget.show();
1562 
1563  const QRect fileMenuGeometry = menuBar->actionGeometry(fileMenu->menuAction());
1564  const QRect editMenuGeometry = menuBar->actionGeometry(editMenu->menuAction());
1565  const int menuBarWidth = menuBar->width();
1566  switch (corner) { // QTBUG-36010 , verify corner widget geometry is correct
1567  case Qt::TopLeftCorner:
1568  QVERIFY2(fileMenuGeometry.left() >= cornerWidgetWidth,
1569  msgComparison(fileMenuGeometry.left(), ">=", cornerWidgetWidth));
1570  QVERIFY2(menuBarWidth - editMenuGeometry.right() < cornerWidgetWidth,
1571  msgComparison(menuBarWidth - editMenuGeometry.right(), "<", cornerWidgetWidth));
1572  break;
1573  case Qt::TopRightCorner:
1574  QVERIFY2(fileMenuGeometry.left() < cornerWidgetWidth,
1575  msgComparison(fileMenuGeometry.left(), "<", cornerWidgetWidth));
1576  QVERIFY2(menuBarWidth - editMenuGeometry.right() >= cornerWidgetWidth,
1577  msgComparison(menuBarWidth - editMenuGeometry.right(), ">=", cornerWidgetWidth));
1578  break;
1579  default:
1580  break;
1581  }
1582 
1583  menuBar->setCornerWidget(0, corner); // Don't crash.
1584  QVERIFY(!menuBar->cornerWidget(corner));
1585  delete cornerLabel;
1586 }
1587 
1588 
1589 void tst_QMenuBar::taskQTBUG53205_crashReparentNested()
1590 {
1591  // This test was largely inspired by the test case submitted for the bug
1593  mainWindow.resize(300, 200);
1594  centerOnScreen(&mainWindow);
1595  const TestMenu testMenus = initWindowWithComplexMenuBar(mainWindow);
1597 
1598  // they can't be windows
1599  QWidget hiddenParent(&mainWindow, {});
1600  //this one is going to be moved around
1601  QWidget movingParent(&hiddenParent, {});
1602 
1603  //set up the container widget
1604  QWidget containerWidget(&movingParent, {});
1605 
1606  //set the new parent, a window
1607  QScopedPointer<QWidget> windowedParent;
1608  windowedParent.reset(new QWidget(nullptr, Qt::WindowFlags()));
1609  windowedParent->setGeometry(400, 10, 300, 300);
1610 
1611  windowedParent->show();
1612  QVERIFY(QTest::qWaitForWindowExposed(windowedParent.data()));
1613 
1614  //set the "container", can't be a window
1615  QWidget containedWidget(&containerWidget, {});
1616 
1617  taskQTBUG53205MenuBar = new QMenuBar(&containedWidget);
1618 
1620  //now, move things around
1621  //from : QMainWindow<-hiddenParent<-movingParent<-containerWidget<-containedWidget<-menuBar
1622  //to windowedParent<-movingParent<-containerWidget<-containedWidget<-menuBar
1623  movingParent.setParent(windowedParent.data(), {});
1624  // this resets the parenting and the menu bar's window
1625  taskQTBUG53205MenuBar->setParent(nullptr);
1626  taskQTBUG53205MenuBar->setParent(&containedWidget);
1627  //from windowedParent<-movingParent<-containerWidget<-containedWidget<-menuBar
1628  //to : QMainWindow<-hiddenParent<-movingParent<-containerWidget<-containedWidget<-menuBar
1629  movingParent.setParent(&hiddenParent, {});
1630  windowedParent.reset(); //make the old window invalid
1631  // trigger the aciton, reset the menu bar's window, this used to crash here.
1632  testMenus.actions[0]->trigger();
1633 }
1634 
1635 void tst_QMenuBar::QTBUG_65488_hiddenActionTriggered()
1636 {
1637  QMainWindow win;
1638  win.menuBar()->setNativeMenuBar(false);
1639  QAction *act1 = win.menuBar()->addAction("A very long named action that make menuBar item wide enough");
1640  QSignalSpy spy(win.menuBar(), &QMenuBar::triggered);
1641 
1642  QRect actRect = win.menuBar()->actionGeometry(act1);
1643  // resize to action's size to make Action1 hidden
1644  win.resize(actRect.width() - 10, win.size().height());
1645  win.show();
1648  // click center of the blank area on the menubar where Action1 resided
1649  QTest::mouseClick(win.windowHandle(), Qt::LeftButton, Qt::NoModifier, win.menuBar()->geometry().center());
1650  QCoreApplication::sendPostedEvents(); // make sure all queued events also dispatched
1651  QCOMPARE(spy.count(), 0);
1652 }
1653 
1654 // QTBUG-56526
1655 void tst_QMenuBar::platformMenu()
1656 {
1657  QMenuBar menuBar;
1658  QPlatformMenuBar *platformMenuBar = menuBar.platformMenuBar();
1659  if (!platformMenuBar)
1660  QSKIP("No platform menubar implementation available on this platform.");
1661 
1662  // QMenu must not create a platform menu instance at creation time, because
1663  // on Unity the type of the platform menu instance must be different (QGtk3Menu
1664  // vs. QDbusPlatformMenu) depending on whether the menu is in the global menubar
1665  // or a standalone context menu.
1666  QMenu *menu = new QMenu(&menuBar);
1667  QVERIFY(!menu->platformMenu());
1668 
1669  menuBar.addMenu(menu);
1671 }
1672 
1673 class TestObject : public QObject
1674 {
1675  Q_OBJECT
1676 public:
1677  bool flag = false;
1678  void setFlag()
1679  {
1680  flag = true;
1681  }
1682 };
1683 
1684 void tst_QMenuBar::addActionQt5connect()
1685 {
1686  bool flag = false;
1687  auto functor = [&flag](){ flag = true; };
1688 
1689  TestObject obj;
1690 
1691  QMenuBar menuBar;
1692 
1693  auto action1 = menuBar.addAction(QStringLiteral("1"), &obj, &TestObject::setFlag);
1694  auto action2 = menuBar.addAction(QStringLiteral("2"), functor);
1695 
1696  action1->activate(QAction::Trigger);
1697  action2->activate(QAction::Trigger);
1698 
1699  QVERIFY(obj.flag);
1700  QVERIFY(flag);
1701 
1702  flag = false;
1703 
1704  auto action3 = menuBar.addAction(QStringLiteral("3"), this, functor);
1705  action3->activate(QAction::Trigger);
1706  QVERIFY(flag);
1707 }
1708 
1709 void tst_QMenuBar::QTBUG_25669_menubarActionDoubleTriggered()
1710 {
1711  QMainWindow win;
1712  win.menuBar()->setNativeMenuBar(false);
1713  QAction *act1 = win.menuBar()->addAction("Action1");
1714  QAction *act2 = win.menuBar()->addAction("Action2");
1715  QSignalSpy spy(win.menuBar(), &QMenuBar::triggered);
1716 
1717  win.show();
1720 
1721  QPoint posAct1 = menuBarActionWindowPos(win.menuBar(), act1);
1722  QPoint posAct2 = menuBarActionWindowPos(win.menuBar(), act2);
1723 
1724  QTest::mouseClick(win.windowHandle(), Qt::LeftButton, Qt::NoModifier, posAct1);
1725  QTRY_COMPARE(spy.count(), 1);
1726 
1727  QTest::mouseClick(win.windowHandle(), Qt::LeftButton, Qt::NoModifier, posAct2);
1728  QTRY_COMPARE(spy.count(), 2);
1729 
1730  QTest::mouseClick(win.windowHandle(), Qt::LeftButton, Qt::NoModifier, posAct2);
1731  QTRY_COMPARE(spy.count(), 3);
1732 }
1733 
1735 {
1736  QWidget *parent = taskQTBUG53205MenuBar->parentWidget();
1737  taskQTBUG53205MenuBar->setParent(nullptr);
1738  taskQTBUG53205MenuBar->setParent(parent);
1739 }
1740 
1741 // Qt/Mac does not use the native popups/menubar
1742 #if !defined(Q_OS_DARWIN)
1743 void tst_QMenuBar::taskQTBUG46812_doNotLeaveMenubarHighlighted()
1744 {
1746  QSKIP("Wayland: This fails. Figure out why.");
1747 
1749  QWidget *centralWidget = new QWidget;
1750  centralWidget->setFocusPolicy(Qt::StrongFocus);
1751  mainWindow.setCentralWidget(centralWidget);
1752  initWindowWithSimpleMenuBar(mainWindow);
1753 
1754  mainWindow.show();
1757 
1758  QVERIFY(!mainWindow.menuBar()->hasFocus());
1759  QCOMPARE(m_simpleActivatedCount, 0);
1760 
1761  QTest::keyPress(&mainWindow, Qt::Key_Alt, Qt::AltModifier);
1762  QVERIFY(!mainWindow.menuBar()->hasFocus());
1763  QCOMPARE(m_simpleActivatedCount, 0);
1764 
1765  QTest::keyPress(&mainWindow, Qt::Key_Z, Qt::AltModifier);
1766  QVERIFY(!mainWindow.menuBar()->hasFocus());
1767  QCOMPARE(m_simpleActivatedCount, 2); // the action AND the menu will activate
1768 
1769  QTest::keyRelease(&mainWindow, Qt::Key_Alt, Qt::NoModifier);
1770  QVERIFY(!mainWindow.menuBar()->hasFocus());
1771  QCOMPARE(m_simpleActivatedCount, 2);
1772 
1773  QTest::keyRelease(&mainWindow, Qt::Key_Z, Qt::NoModifier);
1774  QVERIFY(!mainWindow.menuBar()->hasFocus());
1775  QCOMPARE(m_simpleActivatedCount, 2);
1776 }
1777 #endif
1778 
1779 #ifdef Q_OS_MACOS
1780 extern bool tst_qmenubar_taskQTBUG56275(QMenuBar *);
1781 
1782 void tst_QMenuBar::taskQTBUG56275_reinsertMenuInParentlessQMenuBar()
1783 {
1784  QMenuBar menubar;
1785 
1786  QMenu *menu = new QMenu("menu", &menubar);
1787  QMenu* submenu = menu->addMenu("submenu");
1788  submenu->addAction("action1");
1789  submenu->addAction("action2");
1790  menu->addAction("action3");
1791  menubar.addMenu(menu);
1792 
1793  QTest::qWait(100);
1794  menubar.clear();
1795  menubar.addMenu(menu);
1796  QTest::qWait(100);
1797 
1799 }
1800 
1801 void tst_QMenuBar::QTBUG_57404_existingMenuItemException()
1802 {
1803  QMainWindow mw1;
1804  QMainWindow mw2;
1805  mw1.show();
1806  mw2.show();
1807 
1808  QMenuBar *mb = new QMenuBar(&mw1);
1809  mw1.setMenuBar(mb);
1810  mb->show();
1811  QMenu *editMenu = new QMenu(QLatin1String("Edit"), &mw1);
1812  mb->addMenu(editMenu);
1813  QAction *copyAction = editMenu->addAction("&Copy");
1814  copyAction->setShortcut(QKeySequence("Ctrl+C"));
1815  copyAction->setMenuRole(QAction::NoRole);
1816 
1818  QTest::qWait(100);
1819  mw2.close();
1820  mw1.activateWindow();
1821  QTest::qWait(100);
1822  // No crash, all fine. Ideally, there should be only one warning.
1823 }
1824 
1825 void tst_QMenuBar::defaultEditMenuItems()
1826 {
1827  class TestTranslator : public QTranslator
1828  {
1829  public:
1830  QString translate(const char *context, const char *sourceText,
1831  const char *disambiguation = nullptr, int n = -1) const override
1832  {
1833  if (QByteArrayView(context) == "QCocoaMenu" && QByteArrayView(sourceText) == "Edit")
1834  return QString("Editieren");
1835  return QTranslator::translate(context, sourceText, disambiguation, n);
1836  }
1837  } testTranslator;
1838  qApp->installTranslator(&testTranslator);
1839 
1840  QMainWindow mw;
1841  mw.show();
1843 
1844  mw.menuBar()->addMenu("Editieren")->addAction("Undo");
1845 
1846  mw.hide();
1847  mw.show();
1848  // this should not crash with infinite recursion
1849 }
1850 #endif // Q_OS_MACOS
1851 
1852 void tst_QMenuBar::taskQTBUG55966_subMenuRemoved()
1853 {
1855  QSKIP("Wayland: This fails. Figure out why.");
1856 
1858  QMenuBar *menubar = window.menuBar();
1859  QMenu *parentMenu = menubar->addMenu("Parent menu");
1860 
1861  QAction *action = parentMenu->addAction("Action in parent menu");
1862  QMenu *subMenu = new QMenu("Submenu");
1863  action->setMenu(subMenu);
1864  delete subMenu;
1865 
1866  window.show();
1869  QTest::qWait(500);
1870 }
1871 
1872 void tst_QMenuBar::QTBUG_58344_invalidIcon()
1873 {
1874  QMenuBar menuBar;
1875  QMenu menu("menu");
1876  menu.addAction(QIcon("crash.png"), "crash");
1877  menuBar.addMenu(&menu);
1878  // No crash, all fine.
1879 }
1880 
1882 #include "tst_qmenubar.moc"
small capitals from c petite p scientific i
[1]
Definition: afcover.h:80
Arabic default style
Definition: afstyles.h:94
Menu(QGraphicsView *parent)
Definition: menu.cpp:42
void addActions()
[0]
Definition: main.cpp:86
The QAction class provides an abstraction for user commands that can be added to different user inter...
Definition: qaction.h:65
void setMenuRole(MenuRole menuRole)
Definition: qaction.cpp:1210
@ Trigger
Definition: qaction.h:207
@ NoRole
Definition: qaction.h:96
void triggered(bool checked=false)
void setText(const QString &text)
Definition: qaction.cpp:641
void activate(ActionEvent event)
Definition: qaction.cpp:1112
QString text
the action's descriptive text
Definition: qaction.h:74
void setEnabled(bool)
Definition: qaction.cpp:957
void setData(const QVariant &var)
Definition: qaction.cpp:1097
static QStyle * style()
static QWidget * focusWidget()
static QWidgetList topLevelWidgets()
static void setEffectEnabled(Qt::UIEffect, bool enable=true)
static QWidget * activePopupWidget()
static void setActiveWindow(QWidget *act)
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:85
The QChar class provides a 16-bit Unicode character.
Definition: qchar.h:84
QChar toUpper() const noexcept
Definition: qchar.h:480
static void sendPostedEvents(QObject *receiver=nullptr, int event_type=0)
The QDebug class provides an output stream for debugging information.
Definition: qdebug.h:65
QScreen * primaryScreen
the primary (or default) screen of the application.
QString platformName
The name of the underlying platform plugin.
The QLatin1String class provides a thin wrapper around an US-ASCII/Latin-1 encoded string literal.
Definition: qstring.h:84
qsizetype size() const noexcept
Definition: qlist.h:414
const_reference at(qsizetype i) const noexcept
Definition: qlist.h:457
reference front()
Definition: qlist.h:699
qsizetype count() const noexcept
Definition: qlist.h:415
The QMainWindow class provides a main application window.\inmodule QtWidgets.
Definition: qmainwindow.h:61
The QMenuBar class provides a horizontal menu bar.
Definition: qmenubar.h:56
QWidget * cornerWidget(Qt::Corner corner=Qt::TopRightCorner) const
Definition: qmenubar.cpp:1766
void setActiveAction(QAction *action)
Definition: qmenubar.cpp:851
QAction * addMenu(QMenu *menu)
Definition: qmenubar.cpp:789
void setNativeMenuBar(bool nativeMenuBar)
Definition: qmenubar.cpp:1802
QSize sizeHint() const override
Definition: qmenubar.cpp:1597
void setCornerWidget(QWidget *w, Qt::Corner corner=Qt::TopRightCorner)
Definition: qmenubar.cpp:1732
QRect actionGeometry(QAction *) const
Definition: qmenubar.cpp:1538
QPlatformMenuBar * platformMenuBar()
Definition: qmenubar.cpp:1829
void clear()
Definition: qmenubar.cpp:870
QAction * activeAction() const
Definition: qmenubar.cpp:840
void addAction(QAction *action)
Definition: qwidget.cpp:3129
void triggered(QAction *action)
The QMenu class provides a menu widget for use in menu bars, context menus, and other popup menus.
Definition: qmenu.h:62
QSize sizeHint() const override
Definition: qmenu.cpp:2263
QPlatformMenu * platformMenu()
Definition: qmenu.cpp:3698
void clear()
Definition: qmenu.cpp:2219
QAction * addSeparator()
Definition: qmenu.cpp:1915
void setTitle(const QString &title)
Definition: qmenu.cpp:1101
QAction * addMenu(QMenu *menu)
Definition: qmenu.cpp:1871
void addAction(QAction *action)
Definition: qwidget.cpp:3129
QAction * menuAction() const
Definition: qmenu.cpp:1073
Q_INVOKABLE QObject(QObject *parent=nullptr)
Definition: qobject.cpp:913
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
Definition: qobject.cpp:2772
void setObjectName(const QString &name)
Definition: qobject.cpp:1261
The QProxyStyle class is a convenience class that simplifies dynamically overriding QStyle elements.
Definition: qproxystyle.h:53
int pixelMetric(PixelMetric metric, const QStyleOption *option=nullptr, const QWidget *widget=nullptr) const override
void reset(T *other=nullptr) noexcept(noexcept(Cleanup::cleanup(std::declval< T * >())))
The QString class provides a Unicode character string.
Definition: qstring.h:388
static QString number(int, int base=10)
Definition: qstring.cpp:7538
The QStringList class provides a list of strings.
The QStyleFactory class creates QStyle objects.
Definition: qstylefactory.h:52
The QStyle class is an abstract base class that encapsulates the look and feel of a GUI.
Definition: qstyle.h:65
@ State_None
Definition: qstyle.h:102
@ CT_MenuBar
Definition: qstyle.h:590
@ SH_MenuBar_AltKeyNavigation
Definition: qstyle.h:637
@ SH_Menu_AllowActiveAndDisabled
Definition: qstyle.h:633
@ PM_MenuBarHMargin
Definition: qstyle.h:496
@ PM_MenuBarPanelWidth
Definition: qstyle.h:493
@ PM_MenuBarItemSpacing
Definition: qstyle.h:494
@ PM_MenuBarVMargin
Definition: qstyle.h:495
The QStyleOption class stores the parameters used by QStyle functions.
Definition: qstyleoption.h:75
QStyle::State state
Definition: qstyleoption.h:95
QPalette palette
Definition: qstyleoption.h:99
the minimum value for the progress bar
Definition: qstyleoption.h:369
The QTranslator class provides internationalization support for text output.
Definition: qtranslator.h:55
virtual QString translate(const char *context, const char *sourceText, const char *disambiguation=nullptr, int n=-1) const
The QVariant class acts like a union for the most common Qt data types.
Definition: qvariant.h:95
void setStyle(QStyle *)
Definition: qwidget.cpp:2642
QPointF mapToGlobal(const QPointF &) const
QRect geometry
the geometry of the widget relative to its parent and excluding the window frame
Definition: qwidget.h:140
QPalette palette
the widget's palette
Definition: qwidget.h:166
int width
the width of the widget excluding any window frame
Definition: qwidget.h:148
QPoint pos
the position of the widget within its parent widget
Definition: qwidget.h:145
bool close()
Definition: qwidget.cpp:8468
void setFocusPolicy(Qt::FocusPolicy policy)
Definition: qwidget.cpp:7773
void hide()
Definition: qwidget.cpp:8078
int height
the height of the widget excluding any window frame
Definition: qwidget.h:149
QList< QAction * > actions() const
Definition: qwidget.cpp:3219
QRect rect
the internal geometry of the widget excluding any window frame
Definition: qwidget.h:150
void show()
Definition: qwidget.cpp:7825
QWindow * windowHandle() const
Definition: qwidget.cpp:2495
void setWindowTitle(const QString &)
Definition: qwidget.cpp:6119
void resize(int w, int h)
Definition: qwidget.h:916
bool hasFocus() const
Definition: qwidget.cpp:6430
void activateWindow()
Definition: qwidget.cpp:12708
bool isActiveWindow
whether this widget's window is the active window
Definition: qwidget.h:173
void removeAction(QAction *action)
Definition: qwidget.cpp:3198
bool isVisible() const
Definition: qwidget.h:907
QPointF mapFromGlobal(const QPointF &) const
void addAction(QAction *action)
Definition: qwidget.cpp:3129
The QWindow class represents a window in the underlying windowing system.
Definition: qwindow.h:99
void slotForTaskQTBUG53205()
void onComplexActionTriggered()
void onSimpleActivated(QAction *)
QOpenGLWidget * widget
[1]
b clear()
QString str
[2]
qreal spacing
double e
QSignalSpy spy(myCustomObject, SIGNAL(mySignal(int, QString, double)))
[0]
QCOMPARE(spy.count(), 1)
direction
QStyleOptionButton opt
Q_TESTLIB_EXPORT QTestData & newRow(const char *dataTag)
Definition: qtestcase.cpp:2658
Q_TESTLIB_EXPORT const char * currentTestFunction()
Definition: qtestcase.cpp:2749
Q_GUI_EXPORT bool qWaitForWindowActive(QWindow *window, int timeout=5000)
Q_GUI_EXPORT bool qWaitForWindowExposed(QWindow *window, int timeout=5000)
void mouseMove(QWindow *window, QPoint pos=QPoint(), int delay=-1)
Definition: qtestmouse.h:175
void mouseRelease(QWindow *window, Qt::MouseButton button, Qt::KeyboardModifiers stateKey=Qt::KeyboardModifiers(), QPoint pos=QPoint(), int delay=-1)
Definition: qtestmouse.h:163
Q_TESTLIB_EXPORT const char * currentDataTag()
Definition: qtestcase.cpp:2758
void mouseClick(QWindow *window, Qt::MouseButton button, Qt::KeyboardModifiers stateKey=Qt::KeyboardModifiers(), QPoint pos=QPoint(), int delay=-1)
Definition: qtestmouse.h:167
void mousePress(QWindow *window, Qt::MouseButton button, Qt::KeyboardModifiers stateKey=Qt::KeyboardModifiers(), QPoint pos=QPoint(), int delay=-1)
Definition: qtestmouse.h:159
Q_CORE_EXPORT void qWait(int ms)
Corner
Definition: qnamespace.h:1287
@ TopRightCorner
Definition: qnamespace.h:1289
@ TopLeftCorner
Definition: qnamespace.h:1288
@ CTRL
Definition: qnamespace.h:1096
@ ALT
Definition: qnamespace.h:1097
@ LeftButton
Definition: qnamespace.h:83
LayoutDirection
Definition: qnamespace.h:1462
@ RightToLeft
Definition: qnamespace.h:1464
@ StrongFocus
Definition: qnamespace.h:135
@ UI_AnimateMenu
Definition: qnamespace.h:1168
@ Key_Escape
Definition: qnamespace.h:684
@ Key_O
Definition: qnamespace.h:586
@ Key_C
Definition: qnamespace.h:574
@ Key_B
Definition: qnamespace.h:573
@ Key_Right
Definition: qnamespace.h:700
@ Key_Enter
Definition: qnamespace.h:689
@ Key_D
Definition: qnamespace.h:575
@ Key_I
Definition: qnamespace.h:580
@ Key_2
Definition: qnamespace.h:557
@ Key_Left
Definition: qnamespace.h:698
@ Key_A
Definition: qnamespace.h:572
@ Key_Alt
Definition: qnamespace.h:707
@ Key_M
Definition: qnamespace.h:584
@ Key_1
Definition: qnamespace.h:556
@ Key_Down
Definition: qnamespace.h:701
@ Key_J
Definition: qnamespace.h:581
@ Key_Z
Definition: qnamespace.h:597
@ Key_Home
Definition: qnamespace.h:696
@ Key_F
Definition: qnamespace.h:577
@ Key_E
Definition: qnamespace.h:576
@ Key_End
Definition: qnamespace.h:697
@ ControlModifier
Definition: qnamespace.h:1076
@ NoModifier
Definition: qnamespace.h:1074
@ AltModifier
Definition: qnamespace.h:1077
@ CaseInsensitive
Definition: qnamespace.h:1283
QTextStream & center(QTextStream &stream)
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool startsWith(QByteArrayView haystack, QByteArrayView needle) noexcept
action
Definition: devices.py:78
#define QString()
Definition: parse-defines.h:51
set set set set set set set macro pixldst1 abits if abits op else op endif endm macro pixldst2 abits if abits op else op endif endm macro pixldst4 abits if abits op else op endif endm macro pixldst0 abits op endm macro pixldst3 mem_operand op endm macro pixldst30 mem_operand op endm macro pixldst abits if abits elseif abits elseif abits elseif abits elseif abits pixldst0 abits else pixldst0 abits pixldst0 abits pixldst0 abits pixldst0 abits endif elseif abits else pixldst0 abits pixldst0 abits endif elseif abits else error unsupported bpp *numpix else pixst endif endm macro vuzp8 reg2 vuzp d d &reg2 endm macro vzip8 reg2 vzip d d &reg2 endm macro pixdeinterleave basereg basereg basereg basereg basereg endif endm macro pixinterleave basereg basereg basereg basereg basereg endif endm macro PF boost_increment endif if endif PF tst PF addne PF subne PF cmp ORIG_W if endif if endif if endif PF subge ORIG_W PF subges if endif if endif if endif endif endm macro cache_preload_simple endif if dst_r_bpp pld[DST_R, #(PREFETCH_DISTANCE_SIMPLE *dst_r_bpp/8)] endif if mask_bpp pld cleanup[MASK, #(PREFETCH_DISTANCE_SIMPLE *mask_bpp/8)] endif endif endm macro ensure_destination_ptr_alignment process_pixblock_tail_head if beq irp skip1 beq endif SRC MASK if dst_r_bpp DST_R else add endif PF add sub src_basereg pixdeinterleave mask_basereg pixdeinterleave dst_r_basereg process_pixblock_head pixblock_size cache_preload_simple process_pixblock_tail pixinterleave dst_w_basereg irp beq endif process_pixblock_tail_head tst beq irp if pixblock_size chunk_size tst beq pixld SRC pixld MASK if DST_R else pixld DST_R endif if src_basereg pixdeinterleave mask_basereg pixdeinterleave dst_r_basereg process_pixblock_head if pixblock_size cache_preload_simple endif process_pixblock_tail pixinterleave dst_w_basereg irp if pixblock_size chunk_size tst beq if DST_W else pixst DST_W else mov ORIG_W endif add lsl if lsl endif if lsl endif lsl endif lsl endif lsl endif subs mov DST_W if regs_shortage str endif bge start_of_loop_label endm macro generate_composite_function
set set set set set set set macro pixldst1 op
NSMenu QCocoaMenu * platformMenu
Definition: qcocoansmenu.h:65
QList< QString > QStringList
Definition: qcontainerfwd.h:64
#define qApp
#define Q_DISABLE_COPY(Class)
Definition: qglobal.h:515
@ text
#define qWarning
Definition: qlogging.h:179
#define Q_DECLARE_METATYPE(TYPE)
Definition: qmetatype.h:1417
#define SLOT(a)
Definition: qobjectdefs.h:87
#define SIGNAL(a)
Definition: qobjectdefs.h:88
GLint GLfloat GLfloat GLfloat v2
const GLfloat * m
GLfloat GLfloat GLfloat w
[0]
GLboolean GLboolean GLboolean GLboolean a
[7]
GLdouble GLdouble GLdouble GLdouble top
GLenum GLenum GLsizei count
GLint GLfloat GLfloat v1
GLint first
GLfloat n
GLhandleARB obj
[2]
Definition: qopenglext.h:4164
const GLubyte * c
Definition: qopenglext.h:12701
GLuint64EXT * result
[6]
Definition: qopenglext.h:10932
GLuint GLenum option
Definition: qopenglext.h:5929
#define Q_ASSERT(cond)
Definition: qrandom.cpp:84
SSL_CTX int(*) void arg)
#define QStringLiteral(str)
#define tr(X)
#define QTEST_MAIN(TestObject)
Definition: qtest.h:664
#define QSKIP(statement,...)
Definition: qtestcase.h:222
#define QFETCH(Type, name)
Definition: qtestcase.h:230
#define QEXPECT_FAIL(dataIndex, comment, mode)
Definition: qtestcase.h:224
#define QTRY_COMPARE(expr, expected)
Definition: qtestcase.h:214
#define QVERIFY(statement)
Definition: qtestcase.h:64
#define QTRY_VERIFY(expr)
Definition: qtestcase.h:196
#define QVERIFY2(statement, description)
Definition: qtestcase.h:76
#define Q_OBJECT
Definition: qtmetamacros.h:158
#define slots
Definition: qtmetamacros.h:76
QWidget * win
Definition: settings.cpp:53
QFile file
[0]
connect(quitButton, &QPushButton::clicked, &app, &QCoreApplication::quit, Qt::QueuedConnection)
QVBoxLayout * layout
timer inherits("QTimer")
ba fill(true)
aWidget window() -> setWindowTitle("New Window Title")
[2]
QMenu menu
[5]
QMenuBar * menuBar
[0]
view create()
QStringList list
[0]
The QLatin1Char class provides an 8-bit ASCII/Latin-1 character.
Definition: qchar.h:53
QList< QAction * > actions
QList< QMenu * > menus
QT_FORWARD_DECLARE_CLASS(QOpenGLShaderProgram)
void compare(Input input, FnUnderTest fn_under_test, const QByteArray &output)
bool tst_qmenubar_taskQTBUG56275(QMenuBar *menubar)
QAction * triggered
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent