/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the Technology Preview License Agreement accompanying ** this package. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** ** ** ** ** ** ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../../shared/util.h" //TESTED_CLASS= //TESTED_FILES= class tst_QMenu : public QObject { Q_OBJECT public: tst_QMenu(); virtual ~tst_QMenu(); public slots: void initTestCase(); void cleanupTestCase(); void init(); void cleanup(); private slots: void getSetCheck(); void addActionsAndClear(); void keyboardNavigation_data(); void keyboardNavigation(); void focus(); void overrideMenuAction(); void statusTip(); void widgetActionFocus(); void mouseActivation(); void tearOff(); void layoutDirection(); #if defined(QT3_SUPPORT) void indexBasedInsertion_data(); void indexBasedInsertion(); #endif void task208001_stylesheet(); void activeSubMenuPosition(); void task242454_sizeHint(); void task176201_clear(); void task250673_activeMultiColumnSubMenuPosition(); void task256918_setFont(); void menuSizeHint(); void task258920_mouseBorder(); void setFixedWidth(); void deleteActionInTriggered(); void pushButtonPopulateOnAboutToShow(); void QTBUG7907_submenus_autoselect(); void QTBUG7411_submenus_activate(); void QTBUG_10735_crashWithDialog(); protected slots: void onActivated(QAction*); void onHighlighted(QAction*); void onStatusMessageChanged(const QString &); void onStatusTipTimer(); void deleteAction(QAction *a) { delete a; } void populateMenu(); private: void createActions(); QMenu *menus[2], *lastMenu; enum { num_builtins = 10 }; QAction *activated, *highlighted, *builtins[num_builtins]; QString statustip; }; // Testing get/set functions void tst_QMenu::getSetCheck() { QMenu obj1; // QAction * QMenu::defaultAction() // void QMenu::setDefaultAction(QAction *) QAction *var1 = new QAction(0); obj1.setDefaultAction(var1); QCOMPARE(var1, obj1.defaultAction()); obj1.setDefaultAction((QAction *)0); QCOMPARE((QAction *)0, obj1.defaultAction()); delete var1; // QAction * QMenu::activeAction() // void QMenu::setActiveAction(QAction *) QAction *var2 = new QAction(0); obj1.setActiveAction(var2); QCOMPARE(var2, obj1.activeAction()); obj1.setActiveAction((QAction *)0); QCOMPARE((QAction *)0, obj1.activeAction()); delete var2; } tst_QMenu::tst_QMenu() { QApplication::setEffectEnabled(Qt::UI_AnimateMenu, false); } tst_QMenu::~tst_QMenu() { } void tst_QMenu::initTestCase() { for(int i = 0; i < num_builtins; i++) builtins[i] = 0; for(int i = 0; i < 2; i++) { menus[i] = new QMenu; QObject::connect(menus[i], SIGNAL(triggered(QAction*)), this, SLOT(onActivated(QAction*))); QObject::connect(menus[i], SIGNAL(hovered(QAction*)), this, SLOT(onHighlighted(QAction*))); } } void tst_QMenu::cleanupTestCase() { for(int i = 0; i < 2; i++) menus[i]->clear(); for(int i = 0; i < num_builtins; i++) { bool menuAction = false; for (int j = 0; j < 2; ++j) if (menus[j]->menuAction() == builtins[i]) menuAction = true; if (!menuAction) delete builtins[i]; } delete menus[0]; delete menus[1]; } void tst_QMenu::init() { activated = highlighted = 0; lastMenu = 0; } void tst_QMenu::cleanup() { } void tst_QMenu::createActions() { if(!builtins[0]) builtins[0] = new QAction("New", 0); menus[0]->addAction(builtins[0]); if(!builtins[1]) { builtins[1] = new QAction(0); builtins[1]->setSeparator(true); } menus[0]->addAction(builtins[1]); if(!builtins[2]) { builtins[2] = menus[1]->menuAction(); builtins[2]->setText("&Open.."); builtins[8] = new QAction("Close", 0); menus[1]->addAction(builtins[8]); builtins[9] = new QAction("Quit", 0); menus[1]->addAction(builtins[9]); } menus[0]->addAction(builtins[2]); if(!builtins[3]) builtins[3] = new QAction("Open &as..", 0); menus[0]->addAction(builtins[3]); if(!builtins[4]) { builtins[4] = new QAction("Save", 0); builtins[4]->setEnabled(false); } menus[0]->addAction(builtins[4]); if(!builtins[5]) builtins[5] = new QAction("Sa&ve as..", 0); menus[0]->addAction(builtins[5]); if(!builtins[6]) { builtins[6] = new QAction(0); builtins[6]->setSeparator(true); } menus[0]->addAction(builtins[6]); if(!builtins[7]) builtins[7] = new QAction("Prin&t", 0); menus[0]->addAction(builtins[7]); } void tst_QMenu::onHighlighted(QAction *action) { highlighted = action; lastMenu = qobject_cast(sender()); } void tst_QMenu::onActivated(QAction *action) { activated = action; lastMenu = qobject_cast(sender()); } void tst_QMenu::onStatusMessageChanged(const QString &s) { statustip=s; } void tst_QMenu::populateMenu(){ //just adds 3 dummy actions and a separator. lastMenu->addAction("Foo"); lastMenu->addAction("Bar"); lastMenu->addAction("FooBar"); lastMenu->addSeparator(); } //actual tests void tst_QMenu::addActionsAndClear() { #ifdef QT_SOFTKEYS_ENABLED // Softkeys add extra "Select" and "Back" actions to menu by default. // Two first actions will be Select and Back when softkeys are enabled int numSoftkeyActions = 2; #else int numSoftkeyActions = 0; #endif QCOMPARE(menus[0]->actions().count(), 0 + numSoftkeyActions); createActions(); QCOMPARE(menus[0]->actions().count(), 8 + numSoftkeyActions); menus[0]->clear(); QCOMPARE(menus[0]->actions().count(), 0); } void tst_QMenu::mouseActivation() { #ifdef Q_OS_WINCE_WM QSKIP("We have a separate mouseActivation test for Windows mobile.", SkipAll); #endif QWidget topLevel; QMenu menu(&topLevel); topLevel.show(); menu.addAction("Menu Action"); menu.show(); QTest::mouseClick(&menu, Qt::LeftButton, 0, menu.rect().center(), 300); QVERIFY(!menu.isVisible()); //context menus can allways be accessed with right click except on windows menu.show(); QTest::mouseClick(&menu, Qt::RightButton, 0, menu.rect().center(), 300); QVERIFY(!menu.isVisible()); #ifdef Q_OS_WIN //on windows normal mainwindow menus Can only be accessed with left mouse button QMenuBar menubar; QMenu submenu("Menu"); submenu.addAction("action"); QAction *action = menubar.addMenu(&submenu); menubar.show(); QTest::mouseClick(&menubar, Qt::LeftButton, 0, menubar.actionGeometry(action).center(), 300); QVERIFY(submenu.isVisible()); QTest::mouseClick(&submenu, Qt::LeftButton, 0, QPoint(5, 5), 300); QVERIFY(!submenu.isVisible()); QTest::mouseClick(&menubar, Qt::LeftButton, 0, menubar.actionGeometry(action).center(), 300); QVERIFY(submenu.isVisible()); QTest::mouseClick(&submenu, Qt::RightButton, 0, QPoint(5, 5), 300); QVERIFY(submenu.isVisible()); #endif } void tst_QMenu::keyboardNavigation_data() { QTest::addColumn("key"); QTest::addColumn("expected_action"); QTest::addColumn("expected_menu"); QTest::addColumn("init"); QTest::addColumn("expected_activated"); QTest::addColumn("expected_highlighted"); //test up and down (order is important here) QTest::newRow("data0") << int(Qt::Key_Down) << 0 << 0 << true << false << true; QTest::newRow("data1") << int(Qt::Key_Down) << 2 << 0 << false << false << true; //skips the separator QTest::newRow("data2") << int(Qt::Key_Down) << 3 << 0 << false << false << true; if (QApplication::style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled)) QTest::newRow("data3_noMac") << int(Qt::Key_Down) << 4 << 0 << false << false << true; else QTest::newRow("data3_Mac") << int(Qt::Key_Down) << 5 << 0 << false << false << true; QTest::newRow("data4") << int(Qt::Key_Up) << 3 << 0 << false << false << true; QTest::newRow("data5") << int(Qt::Key_Up) << 2 << 0 << false << false << true; QTest::newRow("data6") << int(Qt::Key_Right) << 8 << 1 << false << false << true; QTest::newRow("data7") << int(Qt::Key_Down) << 9 << 1 << false << false << true; QTest::newRow("data8") << int(Qt::Key_Escape) << 2 << 0 << false << false << false; QTest::newRow("data9") << int(Qt::Key_Down) << 3 << 0 << false << false<< true; QTest::newRow("data10") << int(Qt::Key_Return) << 3 << 0 << false << true << false; //test shortcuts #if 0 QTest::newRow("shortcut0") << (Qt::ALT | Qt::Key_A) << 2 << 0 << true << true << false; #endif } void tst_QMenu::keyboardNavigation() { DEPENDS_ON( "addActionsAndClear" ); //if add/clear fails... QFETCH(int, key); QFETCH(int, expected_action); QFETCH(int, expected_menu); QFETCH(bool, init); QFETCH(bool, expected_activated); QFETCH(bool, expected_highlighted); if(init) { lastMenu = menus[0]; lastMenu->clear(); createActions(); lastMenu->popup(QPoint(0, 0)); } QTest::keyClick(lastMenu, (Qt::Key)key); if(expected_activated) { QCOMPARE(activated, builtins[expected_action]); QCOMPARE(menus[expected_menu]->activeAction(), (QAction *)0); } else { QCOMPARE(menus[expected_menu]->activeAction(), builtins[expected_action]); if(expected_highlighted) QCOMPARE(menus[expected_menu]->activeAction(), highlighted); } } #ifdef Q_WS_MAC QT_BEGIN_NAMESPACE extern bool qt_tab_all_widgets; // qapplication_mac.cpp QT_END_NAMESPACE #endif void tst_QMenu::focus() { QMenu menu; menu.addAction("One"); menu.addAction("Two"); menu.addAction("Three"); bool fullKeyboardControl = true; #ifdef Q_WS_MAC fullKeyboardControl = qt_tab_all_widgets; #endif if (!fullKeyboardControl) QSKIP("Computer is currently set up to NOT tab to all widgets," " this test assumes you can tab to all widgets", SkipAll); QWidget window; QPushButton button("Push me", &window); window.show(); qApp->setActiveWindow(&window); QVERIFY(button.hasFocus()); QCOMPARE(QApplication::focusWidget(), (QWidget *)&button); QCOMPARE(QApplication::activeWindow(), &window); menu.show(); #if 0 QVERIFY(!button.hasFocus()); QCOMPARE(QApplication::focusWidget(), &menu); QCOMPARE(QApplication::activeWindow(), &window); #else QVERIFY(button.hasFocus()); QCOMPARE(QApplication::focusWidget(), (QWidget *)&button); QCOMPARE(QApplication::activeWindow(), &window); #endif menu.hide(); QVERIFY(button.hasFocus()); QCOMPARE(QApplication::focusWidget(), (QWidget *)&button); QCOMPARE(QApplication::activeWindow(), &window); } void tst_QMenu::overrideMenuAction() { //test the override menu action by first creating an action to which we set its menu QMainWindow w; QAction *aFileMenu = new QAction("&File", &w); w.menuBar()->addAction(aFileMenu); QMenu *m = new QMenu(&w); QAction *menuaction = m->menuAction(); connect(m, SIGNAL(triggered(QAction*)), SLOT(onActivated(QAction*))); aFileMenu->setMenu(m); //this sets the override menu action for the QMenu QCOMPARE(m->menuAction(), aFileMenu); #ifdef Q_WS_MAC QSKIP("On Mac, we need to create native key events to test menu action activation", SkipAll); #elif defined(Q_OS_WINCE) QSKIP("On Windows CE, we need to create native key events to test menu action activation", SkipAll); #elif defined(Q_OS_SYMBIAN) QSKIP("On Symbian OS, we need to create native key events to test menu action activation", SkipAll); #endif QAction *aQuit = new QAction("Quit", &w); aQuit->setShortcut(QKeySequence("Ctrl+X")); m->addAction(aQuit); w.show(); QTest::qWaitForWindowShown(&w); QApplication::setActiveWindow(&w); w.setFocus(); QTRY_VERIFY(w.hasFocus()); //test of the action inside the menu QTest::keyClick(&w, Qt::Key_X, Qt::ControlModifier); QTRY_COMPARE(activated, aQuit); //test if the menu still pops out QTest::keyClick(&w, Qt::Key_F, Qt::AltModifier); QTRY_VERIFY(m->isVisible()); delete aFileMenu; //after the deletion of the override menu action, //the menu should have its default menu action back QCOMPARE(m->menuAction(), menuaction); } void tst_QMenu::statusTip() { //check that the statustip of actions inserted into the menu are displayed QMainWindow w; connect(w.statusBar(), SIGNAL(messageChanged(const QString &)), SLOT(onStatusMessageChanged(const QString &)));; //creates the status bar QToolBar tb; QAction a("main action", &tb); a.setStatusTip("main action"); QMenu m(&tb); QAction subact("sub action", &m); subact.setStatusTip("sub action"); m.addAction(&subact); a.setMenu(&m); tb.addAction(&a); w.addToolBar(&tb); w.show(); QTest::qWaitForWindowShown(&w); QRect rect1 = tb.actionGeometry(&a); QToolButton *btn = qobject_cast(tb.childAt(rect1.center())); QVERIFY(btn != NULL); //because showMenu calls QMenu::exec, we need to use a singleshot //to continue the test QTimer::singleShot(200,this, SLOT(onStatusTipTimer())); btn->showMenu(); QVERIFY(statustip.isEmpty()); } //2nd part of the test void tst_QMenu::onStatusTipTimer() { QMenu *menu = qobject_cast(QApplication::activePopupWidget()); QVERIFY(menu != 0); QVERIFY(menu->isVisible()); QTest::keyClick(menu, Qt::Key_Down); //we store the statustip to press escape in any case //otherwise, if the test fails it blocks (never gets out of QMenu::exec const QString st=statustip; menu->close(); //goes out of the menu QCOMPARE(st, QString("sub action")); QVERIFY(menu->isVisible() == false); } void tst_QMenu::widgetActionFocus() { //test if the focus is correctly handled with a QWidgetAction QMenu m; QListWidget *l = new QListWidget(&m); for(int i = 1; i<3 ; i++) l->addItem(QString("item%1").arg(i)); QWidgetAction *wa = new QWidgetAction(&m); wa->setDefaultWidget(l); m.addAction(wa); m.setActiveAction(wa); l->setFocus(); //to ensure it has primarily the focus QAction *menuitem1=m.addAction("menuitem1"); QAction *menuitem2=m.addAction("menuitem2"); m.popup(QPoint()); QVERIFY(m.isVisible()); QVERIFY(l->hasFocus()); QVERIFY(l->currentItem()); QCOMPARE(l->currentItem()->text(), QString("item1")); QTest::keyClick(QApplication::focusWidget(), Qt::Key_Down); QVERIFY(l->currentItem()); QCOMPARE(l->currentItem()->text(), QString("item2")); QTest::keyClick(QApplication::focusWidget(), Qt::Key_Down); QVERIFY(m.hasFocus()); QCOMPARE(m.activeAction(), menuitem1); QTest::keyClick(QApplication::focusWidget(), Qt::Key_Down); QVERIFY(m.hasFocus()); QCOMPARE(m.activeAction(), menuitem2); QTest::keyClick(QApplication::focusWidget(), Qt::Key_Up); QVERIFY(m.hasFocus()); QCOMPARE(m.activeAction(), menuitem1); QTest::keyClick(QApplication::focusWidget(), Qt::Key_Up); QVERIFY(l->hasFocus()); QCOMPARE(m.activeAction(), (QAction *)wa); } void tst_QMenu::tearOff() { QWidget widget; QMenu *menu = new QMenu(&widget); QVERIFY(!menu->isTearOffEnabled()); //default value menu->setTearOffEnabled(true); menu->addAction("aaa"); menu->addAction("bbb"); QVERIFY(menu->isTearOffEnabled()); widget.show(); QTest::qWaitForWindowShown(&widget); widget.activateWindow(); menu->popup(QPoint(0,0)); QTest::qWait(50); QVERIFY(!menu->isTearOffMenuVisible()); QTest::mouseClick(menu, Qt::LeftButton, 0, QPoint(3, 3), 10); QTest::qWait(100); QVERIFY(menu->isTearOffMenuVisible()); QPointer torn = 0; foreach (QWidget *w, QApplication::allWidgets()) { if (w->inherits("QTornOffMenu")) { torn = static_cast(w); break; } } QVERIFY(torn); QVERIFY(torn->isVisible()); menu->hideTearOffMenu(); QVERIFY(!menu->isTearOffMenuVisible()); QVERIFY(!torn->isVisible()); } void tst_QMenu::layoutDirection() { QMainWindow win; win.setLayoutDirection(Qt::RightToLeft); QMenu menu(&win); menu.show(); QTest::qWaitForWindowShown(&menu); QCOMPARE(menu.layoutDirection(), Qt::RightToLeft); menu.close(); menu.setParent(0); menu.show(); QTest::qWaitForWindowShown(&menu); QCOMPARE(menu.layoutDirection(), QApplication::layoutDirection()); menu.close(); //now the menubar QAction *action = win.menuBar()->addMenu(&menu); win.menuBar()->setActiveAction(action); QTest::qWaitForWindowShown(&menu); QCOMPARE(menu.layoutDirection(), Qt::RightToLeft); } #if defined(QT3_SUPPORT) void tst_QMenu::indexBasedInsertion_data() { QTest::addColumn("indexForInsertion"); QTest::addColumn("expectedIndex"); QTest::newRow("negative-index-appends") << -1 << 1; QTest::newRow("prepend") << 0 << 0; QTest::newRow("append") << 1 << 1; } void tst_QMenu::indexBasedInsertion() { // test the compat'ed index based insertion QFETCH(int, indexForInsertion); QFETCH(int, expectedIndex); { QMenu menu; menu.addAction("Regular Item"); menu.insertItem("New Item", -1 /*id*/, indexForInsertion); QAction *act = menu.actions().value(expectedIndex); QVERIFY(act); QCOMPARE(act->text(), QString("New Item")); } { QMenu menu; menu.addAction("Regular Item"); menu.insertSeparator(indexForInsertion); QAction *act = menu.actions().value(expectedIndex); QVERIFY(act); QVERIFY(act->isSeparator()); } } #endif void tst_QMenu::task208001_stylesheet() { //test if it crash QMainWindow main; main.setStyleSheet("QMenu [title =\"File\"] { color: red;}"); main.menuBar()->addMenu("File"); } void tst_QMenu::activeSubMenuPosition() { QPushButton lab("subMenuPosition test"); QMenu *sub = new QMenu("Submenu", &lab); sub->addAction("Sub-Item1"); QAction *subAction = sub->addAction("Sub-Item2"); QMenu *main = new QMenu("Menu-Title", &lab); (void)main->addAction("Item 1"); QAction *menuAction = main->addMenu(sub); (void)main->addAction("Item 3"); (void)main->addAction("Item 4"); main->setActiveAction(menuAction); sub->setActiveAction(subAction); #ifdef Q_OS_SYMBIAN main->popup(QPoint(50,200)); #else main->popup(QPoint(200,200)); #endif QVERIFY(main->isVisible()); QCOMPARE(main->activeAction(), menuAction); QVERIFY(sub->isVisible()); QVERIFY(sub->pos() != QPoint(0,0)); // well, it's enough to check the pos is not (0,0) but it's more safe // to check that submenu is to the right of the main menu too. #ifdef Q_OS_WINCE_WM QSKIP("Not true for Windows Mobile Soft Keys", SkipSingle); #endif #ifdef Q_OS_SYMBIAN // On Symbian, QS60Style::pixelMetric(QStyle::PM_SubMenuOverlap) is different with other styles. QVERIFY(sub->pos().x() < main->pos().x()); #else QVERIFY(sub->pos().x() > main->pos().x()); #endif QCOMPARE(sub->activeAction(), subAction); } void tst_QMenu::task242454_sizeHint() { QMenu menu; QString s = QLatin1String("foo\nfoo\nfoo\nfoo"); menu.addAction(s); QVERIFY(menu.sizeHint().width() > menu.fontMetrics().boundingRect(QRect(), Qt::TextSingleLine, s).width()); } class Menu : public QMenu { Q_OBJECT public slots: void clear() { QMenu::clear(); } }; void tst_QMenu::task176201_clear() { //this test used to crash Menu menu; QAction *action = menu.addAction("test"); menu.connect(action, SIGNAL(triggered()), SLOT(clear())); menu.popup(QPoint()); QTest::mouseClick(&menu, Qt::LeftButton, 0, menu.rect().center()); } void tst_QMenu::task250673_activeMultiColumnSubMenuPosition() { class MyMenu : public QMenu { public: int columnCount() const { return QMenu::columnCount(); } }; QMenu sub; if (sub.style()->styleHint(QStyle::SH_Menu_Scrollable, 0, &sub)) { //the style prevents the menus from getting columns QSKIP("the style doesn't support multiple columns, it makes the menu scrollable", SkipSingle); } sub.addAction("Sub-Item1"); QAction *subAction = sub.addAction("Sub-Item2"); MyMenu main; main.addAction("Item 1"); QAction *menuAction = main.addMenu(&sub); main.popup(QPoint(200,200)); uint i = 2; while (main.columnCount() < 2) { main.addAction(QString("Item %1").arg(i)); ++i; Q_ASSERT(i<1000); } main.setActiveAction(menuAction); sub.setActiveAction(subAction); QVERIFY(main.isVisible()); QCOMPARE(main.activeAction(), menuAction); QVERIFY(sub.isVisible()); QVERIFY(sub.pos().x() > main.pos().x()); const int subMenuOffset = main.style()->pixelMetric(QStyle::PM_SubMenuOverlap, 0, &main); QVERIFY((sub.geometry().left() - subMenuOffset + 5) < main.geometry().right()); } void tst_QMenu::task256918_setFont() { QMenu menu; QAction *action = menu.addAction("foo"); QFont f; f.setPointSize(30); action->setFont(f); menu.show(); //ensures that the actiongeometry are calculated QVERIFY(menu.actionGeometry(action).height() > f.pointSize()); } void tst_QMenu::menuSizeHint() { QMenu menu; //this is a list of arbitrary strings so that we check the geometry QStringList list = QStringList() << "trer" << "ezrfgtgvqd" << "sdgzgzerzerzer" << "eerzertz" << "er"; foreach(QString str, list) menu.addAction(str); int left, top, right, bottom; menu.getContentsMargins(&left, &top, &right, &bottom); const int panelWidth = menu.style()->pixelMetric(QStyle::PM_MenuPanelWidth, 0, &menu); const int hmargin = menu.style()->pixelMetric(QStyle::PM_MenuHMargin, 0, &menu), vmargin = menu.style()->pixelMetric(QStyle::PM_MenuVMargin, 0, &menu); int maxWidth =0; QRect result; foreach(QAction *action, menu.actions()) { #ifdef QT_SOFTKEYS_ENABLED // Softkey actions are not widgets and have no geometry. if (menu.actionGeometry(action).topLeft() == QPoint(0,0)) continue; #endif maxWidth = qMax(maxWidth, menu.actionGeometry(action).width()); result |= menu.actionGeometry(action); QCOMPARE(result.x(), left + hmargin + panelWidth); QCOMPARE(result.y(), top + vmargin + panelWidth); } QStyleOption opt(0); opt.rect = menu.rect(); opt.state = QStyle::State_None; QSize resSize = QSize(result.x(), result.y()) + result.size() + QSize(hmargin + right + panelWidth, vmargin + top + panelWidth); resSize = menu.style()->sizeFromContents(QStyle::CT_Menu, &opt, resSize.expandedTo(QApplication::globalStrut()), &menu); QCOMPARE(resSize, menu.sizeHint()); } class Menu258920 : public QMenu { Q_OBJECT public slots: void paintEvent(QPaintEvent *e) { QMenu::paintEvent(e); painted = true; } public: bool painted; }; void tst_QMenu::task258920_mouseBorder() { #ifdef Q_OS_WINCE_WM QSKIP("Mouse move related signals for Windows Mobile unavailable", SkipAll); #endif Menu258920 menu; // On Symbian, styleHint(QStyle::SH_Menu_MouseTracking) in QS60Style is false. // For other styles which inherit from QWindowsStyle, the value is true. menu.setMouseTracking(true); QAction *action = menu.addAction("test"); menu.popup(QApplication::desktop()->availableGeometry().center()); QTest::qWaitForWindowShown(&menu); QTest::qWait(100); QRect actionRect = menu.actionGeometry(action); QTest::mouseMove(&menu, actionRect.center()); QTest::qWait(30); QTest::mouseMove(&menu, actionRect.center() + QPoint(10, 0)); QTest::qWait(30); QCOMPARE(action, menu.activeAction()); menu.painted = false; QTest::mouseMove(&menu, QPoint(actionRect.center().x(), actionRect.bottom() + 1)); QTest::qWait(30); QCOMPARE(static_cast(0), menu.activeAction()); QVERIFY(menu.painted); } void tst_QMenu::setFixedWidth() { QMenu menu; menu.addAction("action"); menu.setFixedWidth(300); //the sizehint should reflect the minimumwidth because the action will try to //get as much space as possible QCOMPARE(menu.sizeHint().width(), menu.minimumWidth()); } void tst_QMenu::deleteActionInTriggered() { // should not crash QMenu m; QObject::connect(&m, SIGNAL(triggered(QAction*)), this, SLOT(deleteAction(QAction*))); QWeakPointer a = m.addAction("action"); a.data()->trigger(); QVERIFY(!a); } void tst_QMenu::pushButtonPopulateOnAboutToShow() { QPushButton b("Test PushButton"); b.setWindowFlags(Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint); lastMenu = new QMenu; b.setMenu(lastMenu); const int scrNumber = QApplication::desktop()->screenNumber(&b); connect(lastMenu, SIGNAL(aboutToShow()), this, SLOT(populateMenu())); b.show(); const QRect screen = QApplication::desktop()->screenGeometry(scrNumber); b.move(10, screen.bottom()-b.height()-5); QTest::qWaitForWindowShown(&b); QTimer::singleShot(300,lastMenu, SLOT(hide())); QTest::mouseClick(&b, Qt::LeftButton, Qt::NoModifier, b.rect().center()); QVERIFY(!lastMenu->geometry().intersects(b.geometry())); b.move(10, screen.bottom()-lastMenu->height()-5); QTimer::singleShot(300,lastMenu, SLOT(hide())); QTest::mouseClick(&b, Qt::LeftButton, Qt::NoModifier, b.rect().center()); QVERIFY(!lastMenu->geometry().intersects(b.geometry())); } void tst_QMenu::QTBUG7907_submenus_autoselect() { QMenu menu("Test Menu"); QMenu set1("Setting1"); QMenu set2("Setting2"); QMenu subset("Subsetting"); subset.addAction("Values"); set1.addMenu(&subset); menu.addMenu(&set1); menu.addMenu(&set2); menu.show(); QTest::qWaitForWindowShown(&menu); QTest::mouseClick(&menu, Qt::LeftButton, Qt::NoModifier, QPoint(5,5) ); QTest::qWait(500); QVERIFY(!subset.isVisible()); } void tst_QMenu::QTBUG7411_submenus_activate() { QMenu menu("Test Menu"); QAction *act = menu.addAction("foo"); QMenu sub1("&sub1"); sub1.addAction("foo"); sub1.setTitle("&sub1"); QAction *act1 = menu.addMenu(&sub1); menu.show(); QTest::qWaitForWindowShown(&menu); menu.setActiveAction(act); QTest::keyPress(&menu, Qt::Key_Down); QCOMPARE(menu.activeAction(), act1); QVERIFY(!sub1.isVisible()); QTest::keyPress(&menu, Qt::Key_S); QTRY_VERIFY(sub1.isVisible()); } class MyMenu : public QMenu { Q_OBJECT public: MyMenu() : m_currentIndex(0) { for (int i = 0; i < 2; ++i) dialogActions[i] = addAction( QString("dialog %1").arg(i), dialogs + i, SLOT(exec())); } void activateAction(int index) { m_currentIndex = index; popup(QPoint()); QTest::qWaitForWindowShown(this); setActiveAction(dialogActions[index]); QTimer::singleShot(500, this, SLOT(checkVisibility())); QTest::keyClick(this, Qt::Key_Enter); //activation } public slots: void activateLastAction() { activateAction(1); } void checkVisibility() { QTRY_VERIFY(dialogs[m_currentIndex].isVisible()); if (m_currentIndex == 1) { QApplication::closeAllWindows(); //this is the end of the test } } private: QAction *dialogActions[2]; QDialog dialogs[2]; int m_currentIndex; }; void tst_QMenu::QTBUG_10735_crashWithDialog() { MyMenu menu; QTimer::singleShot(1000, &menu, SLOT(activateLastAction())); menu.activateAction(0); } QTEST_MAIN(tst_QMenu) #include "tst_qmenu.moc"