|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the test suite of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 |
|
43 #include <QtTest/QtTest> |
|
44 #include <qapplication.h> |
|
45 #include <QPushButton> |
|
46 #include <QMainWindow> |
|
47 #include <QMenuBar> |
|
48 #include <QToolBar> |
|
49 #include <QToolButton> |
|
50 #include <QStatusBar> |
|
51 #include <QListWidget> |
|
52 #include <QWidgetAction> |
|
53 #include <QDesktopWidget> |
|
54 |
|
55 #include <qmenu.h> |
|
56 #include <qstyle.h> |
|
57 #include <qdebug.h> |
|
58 |
|
59 #include "../../shared/util.h" |
|
60 |
|
61 //TESTED_CLASS= |
|
62 //TESTED_FILES= |
|
63 |
|
64 class tst_QMenu : public QObject |
|
65 { |
|
66 Q_OBJECT |
|
67 |
|
68 public: |
|
69 tst_QMenu(); |
|
70 virtual ~tst_QMenu(); |
|
71 |
|
72 |
|
73 public slots: |
|
74 void initTestCase(); |
|
75 void cleanupTestCase(); |
|
76 void init(); |
|
77 void cleanup(); |
|
78 private slots: |
|
79 void getSetCheck(); |
|
80 void addActionsAndClear(); |
|
81 |
|
82 void keyboardNavigation_data(); |
|
83 void keyboardNavigation(); |
|
84 void focus(); |
|
85 void overrideMenuAction(); |
|
86 void statusTip(); |
|
87 void widgetActionFocus(); |
|
88 void mouseActivation(); |
|
89 void tearOff(); |
|
90 |
|
91 #if defined(QT3_SUPPORT) |
|
92 void indexBasedInsertion_data(); |
|
93 void indexBasedInsertion(); |
|
94 #endif |
|
95 void task208001_stylesheet(); |
|
96 void activeSubMenuPosition(); |
|
97 void task242454_sizeHint(); |
|
98 void task176201_clear(); |
|
99 void task250673_activeMultiColumnSubMenuPosition(); |
|
100 void task256918_setFont(); |
|
101 void menuSizeHint(); |
|
102 void task258920_mouseBorder(); |
|
103 void setFixedWidth(); |
|
104 protected slots: |
|
105 void onActivated(QAction*); |
|
106 void onHighlighted(QAction*); |
|
107 void onStatusMessageChanged(const QString &); |
|
108 void onStatusTipTimer(); |
|
109 private: |
|
110 void createActions(); |
|
111 QMenu *menus[2], *lastMenu; |
|
112 enum { num_builtins = 10 }; |
|
113 QAction *activated, *highlighted, *builtins[num_builtins]; |
|
114 QString statustip; |
|
115 }; |
|
116 |
|
117 // Testing get/set functions |
|
118 void tst_QMenu::getSetCheck() |
|
119 { |
|
120 QMenu obj1; |
|
121 // QAction * QMenu::defaultAction() |
|
122 // void QMenu::setDefaultAction(QAction *) |
|
123 QAction *var1 = new QAction(0); |
|
124 obj1.setDefaultAction(var1); |
|
125 QCOMPARE(var1, obj1.defaultAction()); |
|
126 obj1.setDefaultAction((QAction *)0); |
|
127 QCOMPARE((QAction *)0, obj1.defaultAction()); |
|
128 delete var1; |
|
129 |
|
130 // QAction * QMenu::activeAction() |
|
131 // void QMenu::setActiveAction(QAction *) |
|
132 QAction *var2 = new QAction(0); |
|
133 obj1.setActiveAction(var2); |
|
134 QCOMPARE(var2, obj1.activeAction()); |
|
135 obj1.setActiveAction((QAction *)0); |
|
136 QCOMPARE((QAction *)0, obj1.activeAction()); |
|
137 delete var2; |
|
138 } |
|
139 |
|
140 tst_QMenu::tst_QMenu() |
|
141 { |
|
142 QApplication::setEffectEnabled(Qt::UI_AnimateMenu, false); |
|
143 } |
|
144 |
|
145 tst_QMenu::~tst_QMenu() |
|
146 { |
|
147 |
|
148 } |
|
149 |
|
150 void |
|
151 tst_QMenu::initTestCase() |
|
152 { |
|
153 for(int i = 0; i < num_builtins; i++) |
|
154 builtins[i] = 0; |
|
155 for(int i = 0; i < 2; i++) { |
|
156 menus[i] = new QMenu; |
|
157 QObject::connect(menus[i], SIGNAL(triggered(QAction*)), this, SLOT(onActivated(QAction*))); |
|
158 QObject::connect(menus[i], SIGNAL(hovered(QAction*)), this, SLOT(onHighlighted(QAction*))); |
|
159 } |
|
160 } |
|
161 |
|
162 void |
|
163 tst_QMenu::cleanupTestCase() |
|
164 { |
|
165 for(int i = 0; i < 2; i++) |
|
166 menus[i]->clear(); |
|
167 for(int i = 0; i < num_builtins; i++) { |
|
168 bool menuAction = false; |
|
169 for (int j = 0; j < 2; ++j) |
|
170 if (menus[j]->menuAction() == builtins[i]) |
|
171 menuAction = true; |
|
172 if (!menuAction) |
|
173 delete builtins[i]; |
|
174 } |
|
175 delete menus[0]; |
|
176 delete menus[1]; |
|
177 } |
|
178 |
|
179 void |
|
180 tst_QMenu::init() |
|
181 { |
|
182 activated = highlighted = 0; |
|
183 lastMenu = 0; |
|
184 } |
|
185 |
|
186 void |
|
187 tst_QMenu::cleanup() |
|
188 { |
|
189 } |
|
190 |
|
191 void |
|
192 tst_QMenu::createActions() |
|
193 { |
|
194 if(!builtins[0]) |
|
195 builtins[0] = new QAction("New", 0); |
|
196 menus[0]->addAction(builtins[0]); |
|
197 |
|
198 if(!builtins[1]) { |
|
199 builtins[1] = new QAction(0); |
|
200 builtins[1]->setSeparator(true); |
|
201 } |
|
202 menus[0]->addAction(builtins[1]); |
|
203 |
|
204 if(!builtins[2]) { |
|
205 builtins[2] = menus[1]->menuAction(); |
|
206 builtins[2]->setText("&Open.."); |
|
207 builtins[8] = new QAction("Close", 0); |
|
208 menus[1]->addAction(builtins[8]); |
|
209 builtins[9] = new QAction("Quit", 0); |
|
210 menus[1]->addAction(builtins[9]); |
|
211 } |
|
212 menus[0]->addAction(builtins[2]); |
|
213 |
|
214 if(!builtins[3]) |
|
215 builtins[3] = new QAction("Open &as..", 0); |
|
216 menus[0]->addAction(builtins[3]); |
|
217 |
|
218 if(!builtins[4]) { |
|
219 builtins[4] = new QAction("Save", 0); |
|
220 builtins[4]->setEnabled(false); |
|
221 } |
|
222 menus[0]->addAction(builtins[4]); |
|
223 |
|
224 if(!builtins[5]) |
|
225 builtins[5] = new QAction("Sa&ve as..", 0); |
|
226 menus[0]->addAction(builtins[5]); |
|
227 |
|
228 if(!builtins[6]) { |
|
229 builtins[6] = new QAction(0); |
|
230 builtins[6]->setSeparator(true); |
|
231 } |
|
232 menus[0]->addAction(builtins[6]); |
|
233 |
|
234 if(!builtins[7]) |
|
235 builtins[7] = new QAction("Prin&t", 0); |
|
236 menus[0]->addAction(builtins[7]); |
|
237 } |
|
238 |
|
239 void |
|
240 tst_QMenu::onHighlighted(QAction *action) |
|
241 { |
|
242 highlighted = action; |
|
243 lastMenu = qobject_cast<QMenu*>(sender()); |
|
244 } |
|
245 |
|
246 void |
|
247 tst_QMenu::onActivated(QAction *action) |
|
248 { |
|
249 activated = action; |
|
250 lastMenu = qobject_cast<QMenu*>(sender()); |
|
251 } |
|
252 |
|
253 void tst_QMenu::onStatusMessageChanged(const QString &s) |
|
254 { |
|
255 statustip=s; |
|
256 } |
|
257 |
|
258 |
|
259 //actual tests |
|
260 void |
|
261 tst_QMenu::addActionsAndClear() |
|
262 { |
|
263 #ifdef QT_SOFTKEYS_ENABLED |
|
264 // Softkeys add extra "Select" and "Back" actions to menu by default. |
|
265 // Two first actions will be Select and Back when softkeys are enabled |
|
266 int numSoftkeyActions = 2; |
|
267 #else |
|
268 int numSoftkeyActions = 0; |
|
269 #endif |
|
270 |
|
271 QCOMPARE(menus[0]->actions().count(), 0 + numSoftkeyActions); |
|
272 createActions(); |
|
273 QCOMPARE(menus[0]->actions().count(), 8 + numSoftkeyActions); |
|
274 menus[0]->clear(); |
|
275 QCOMPARE(menus[0]->actions().count(), 0); |
|
276 } |
|
277 |
|
278 void tst_QMenu::mouseActivation() |
|
279 { |
|
280 #ifdef Q_OS_WINCE_WM |
|
281 QSKIP("We have a separate mouseActivation test for Windows mobile.", SkipAll); |
|
282 #endif |
|
283 QMenu menu; |
|
284 menu.addAction("Menu Action"); |
|
285 menu.show(); |
|
286 QTest::mouseClick(&menu, Qt::LeftButton, 0, QPoint(5, 5), 300); |
|
287 QVERIFY(!menu.isVisible()); |
|
288 |
|
289 //context menus can allways be accessed with right click except on windows |
|
290 menu.show(); |
|
291 QTest::mouseClick(&menu, Qt::RightButton, 0, QPoint(5, 5), 300); |
|
292 QVERIFY(!menu.isVisible()); |
|
293 |
|
294 #ifdef Q_OS_WIN |
|
295 //on windows normal mainwindow menus Can only be accessed with left mouse button |
|
296 QMenuBar menubar; |
|
297 QMenu submenu("Menu"); |
|
298 submenu.addAction("action"); |
|
299 QAction *action = menubar.addMenu(&submenu); |
|
300 menubar.show(); |
|
301 |
|
302 QTest::mouseClick(&menubar, Qt::LeftButton, 0, menubar.actionGeometry(action).center(), 300); |
|
303 QVERIFY(submenu.isVisible()); |
|
304 QTest::mouseClick(&submenu, Qt::LeftButton, 0, QPoint(5, 5), 300); |
|
305 QVERIFY(!submenu.isVisible()); |
|
306 |
|
307 QTest::mouseClick(&menubar, Qt::LeftButton, 0, menubar.actionGeometry(action).center(), 300); |
|
308 QVERIFY(submenu.isVisible()); |
|
309 QTest::mouseClick(&submenu, Qt::RightButton, 0, QPoint(5, 5), 300); |
|
310 QVERIFY(submenu.isVisible()); |
|
311 #endif |
|
312 } |
|
313 |
|
314 |
|
315 void |
|
316 tst_QMenu::keyboardNavigation_data() |
|
317 { |
|
318 QTest::addColumn<int>("key"); |
|
319 QTest::addColumn<int>("expected_action"); |
|
320 QTest::addColumn<int>("expected_menu"); |
|
321 QTest::addColumn<bool>("init"); |
|
322 QTest::addColumn<bool>("expected_activated"); |
|
323 QTest::addColumn<bool>("expected_highlighted"); |
|
324 |
|
325 //test up and down (order is important here) |
|
326 QTest::newRow("data0") << int(Qt::Key_Down) << 0 << 0 << true << false << true; |
|
327 QTest::newRow("data1") << int(Qt::Key_Down) << 2 << 0 << false << false << true; //skips the separator |
|
328 QTest::newRow("data2") << int(Qt::Key_Down) << 3 << 0 << false << false << true; |
|
329 |
|
330 if (QApplication::style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled)) |
|
331 QTest::newRow("data3_noMac") << int(Qt::Key_Down) << 4 << 0 << false << false << true; |
|
332 else |
|
333 QTest::newRow("data3_Mac") << int(Qt::Key_Down) << 5 << 0 << false << false << true; |
|
334 QTest::newRow("data4") << int(Qt::Key_Up) << 3 << 0 << false << false << true; |
|
335 QTest::newRow("data5") << int(Qt::Key_Up) << 2 << 0 << false << false << true; |
|
336 QTest::newRow("data6") << int(Qt::Key_Right) << 8 << 1 << false << false << true; |
|
337 QTest::newRow("data7") << int(Qt::Key_Down) << 9 << 1 << false << false << true; |
|
338 QTest::newRow("data8") << int(Qt::Key_Escape) << 2 << 0 << false << false << false; |
|
339 QTest::newRow("data9") << int(Qt::Key_Down) << 3 << 0 << false << false<< true; |
|
340 QTest::newRow("data10") << int(Qt::Key_Return) << 3 << 0 << false << true << false; |
|
341 |
|
342 //test shortcuts |
|
343 #if 0 |
|
344 QTest::newRow("shortcut0") << (Qt::ALT | Qt::Key_A) << 2 << 0 << true << true << false; |
|
345 #endif |
|
346 } |
|
347 |
|
348 void |
|
349 tst_QMenu::keyboardNavigation() |
|
350 { |
|
351 DEPENDS_ON( "addActionsAndClear" ); //if add/clear fails... |
|
352 QFETCH(int, key); |
|
353 QFETCH(int, expected_action); |
|
354 QFETCH(int, expected_menu); |
|
355 QFETCH(bool, init); |
|
356 QFETCH(bool, expected_activated); |
|
357 QFETCH(bool, expected_highlighted); |
|
358 |
|
359 if(init) { |
|
360 lastMenu = menus[0]; |
|
361 lastMenu->clear(); |
|
362 createActions(); |
|
363 lastMenu->popup(QPoint(0, 0)); |
|
364 } |
|
365 |
|
366 QTest::keyClick(lastMenu, (Qt::Key)key); |
|
367 if(expected_activated) { |
|
368 QCOMPARE(activated, builtins[expected_action]); |
|
369 QCOMPARE(menus[expected_menu]->activeAction(), (QAction *)0); |
|
370 } else { |
|
371 QCOMPARE(menus[expected_menu]->activeAction(), builtins[expected_action]); |
|
372 if(expected_highlighted) |
|
373 QCOMPARE(menus[expected_menu]->activeAction(), highlighted); |
|
374 } |
|
375 } |
|
376 |
|
377 |
|
378 #ifdef Q_WS_MAC |
|
379 QT_BEGIN_NAMESPACE |
|
380 extern bool qt_tab_all_widgets; // qapplication_mac.cpp |
|
381 QT_END_NAMESPACE |
|
382 #endif |
|
383 |
|
384 void tst_QMenu::focus() |
|
385 { |
|
386 QMenu menu; |
|
387 menu.addAction("One"); |
|
388 menu.addAction("Two"); |
|
389 menu.addAction("Three"); |
|
390 bool fullKeyboardControl = true; |
|
391 |
|
392 #ifdef Q_WS_MAC |
|
393 fullKeyboardControl = qt_tab_all_widgets; |
|
394 #endif |
|
395 |
|
396 if (!fullKeyboardControl) |
|
397 QSKIP("Computer is currently set up to NOT tab to all widgets," |
|
398 " this test assumes you can tab to all widgets", SkipAll); |
|
399 |
|
400 QWidget window; |
|
401 QPushButton button("Push me", &window); |
|
402 window.show(); |
|
403 qApp->setActiveWindow(&window); |
|
404 |
|
405 QVERIFY(button.hasFocus()); |
|
406 QCOMPARE(QApplication::focusWidget(), (QWidget *)&button); |
|
407 QCOMPARE(QApplication::activeWindow(), &window); |
|
408 menu.show(); |
|
409 #if 0 |
|
410 QVERIFY(!button.hasFocus()); |
|
411 QCOMPARE(QApplication::focusWidget(), &menu); |
|
412 QCOMPARE(QApplication::activeWindow(), &window); |
|
413 #else |
|
414 QVERIFY(button.hasFocus()); |
|
415 QCOMPARE(QApplication::focusWidget(), (QWidget *)&button); |
|
416 QCOMPARE(QApplication::activeWindow(), &window); |
|
417 #endif |
|
418 menu.hide(); |
|
419 QVERIFY(button.hasFocus()); |
|
420 QCOMPARE(QApplication::focusWidget(), (QWidget *)&button); |
|
421 QCOMPARE(QApplication::activeWindow(), &window); |
|
422 } |
|
423 |
|
424 void tst_QMenu::overrideMenuAction() |
|
425 { |
|
426 //test the override menu action by first creating an action to which we set its menu |
|
427 QMainWindow w; |
|
428 |
|
429 QAction *aFileMenu = new QAction("&File", &w); |
|
430 w.menuBar()->addAction(aFileMenu); |
|
431 |
|
432 QMenu *m = new QMenu(&w); |
|
433 QAction *menuaction = m->menuAction(); |
|
434 connect(m, SIGNAL(triggered(QAction*)), SLOT(onActivated(QAction*))); |
|
435 aFileMenu->setMenu(m); //this sets the override menu action for the QMenu |
|
436 QCOMPARE(m->menuAction(), aFileMenu); |
|
437 |
|
438 #ifdef Q_WS_MAC |
|
439 QSKIP("On Mac, we need to create native key events to test menu action activation", SkipAll); |
|
440 #elif defined(Q_OS_WINCE) |
|
441 QSKIP("On Windows CE, we need to create native key events to test menu action activation", SkipAll); |
|
442 #elif defined(Q_OS_SYMBIAN) |
|
443 QSKIP("On Symbian OS, we need to create native key events to test menu action activation", SkipAll); |
|
444 #endif |
|
445 |
|
446 QAction *aQuit = new QAction("Quit", &w); |
|
447 aQuit->setShortcut(QKeySequence("Ctrl+X")); |
|
448 m->addAction(aQuit); |
|
449 |
|
450 w.show(); |
|
451 QApplication::setActiveWindow(&w); |
|
452 w.setFocus(); |
|
453 QTest::qWaitForWindowShown(&w); |
|
454 QTRY_VERIFY(w.hasFocus()); |
|
455 |
|
456 //test of the action inside the menu |
|
457 QTest::keyClick(&w, Qt::Key_X, Qt::ControlModifier); |
|
458 QTRY_COMPARE(activated, aQuit); |
|
459 |
|
460 //test if the menu still pops out |
|
461 QTest::keyClick(&w, Qt::Key_F, Qt::AltModifier); |
|
462 QTRY_VERIFY(m->isVisible()); |
|
463 |
|
464 delete aFileMenu; |
|
465 |
|
466 //after the deletion of the override menu action, |
|
467 //the menu should have its default menu action back |
|
468 QCOMPARE(m->menuAction(), menuaction); |
|
469 |
|
470 } |
|
471 |
|
472 void tst_QMenu::statusTip() |
|
473 { |
|
474 //check that the statustip of actions inserted into the menu are displayed |
|
475 QMainWindow w; |
|
476 connect(w.statusBar(), SIGNAL(messageChanged(const QString &)), SLOT(onStatusMessageChanged(const QString &)));; //creates the status bar |
|
477 QToolBar tb; |
|
478 QAction a("main action", &tb); |
|
479 a.setStatusTip("main action"); |
|
480 QMenu m(&tb); |
|
481 QAction subact("sub action", &m); |
|
482 subact.setStatusTip("sub action"); |
|
483 m.addAction(&subact); |
|
484 a.setMenu(&m); |
|
485 tb.addAction(&a); |
|
486 |
|
487 w.addToolBar(&tb); |
|
488 w.show(); |
|
489 |
|
490 QRect rect1 = tb.actionGeometry(&a); |
|
491 QToolButton *btn = qobject_cast<QToolButton*>(tb.childAt(rect1.center())); |
|
492 |
|
493 QVERIFY(btn != NULL); |
|
494 |
|
495 //because showMenu calls QMenu::exec, we need to use a singleshot |
|
496 //to continue the test |
|
497 QTimer::singleShot(200,this, SLOT(onStatusTipTimer())); |
|
498 btn->showMenu(); |
|
499 QVERIFY(statustip.isEmpty()); |
|
500 } |
|
501 |
|
502 //2nd part of the test |
|
503 void tst_QMenu::onStatusTipTimer() |
|
504 { |
|
505 QMenu *menu = qobject_cast<QMenu*>(QApplication::activePopupWidget()); |
|
506 QVERIFY(menu != 0); |
|
507 QVERIFY(menu->isVisible()); |
|
508 QTest::keyClick(menu, Qt::Key_Down); |
|
509 |
|
510 //we store the statustip to press escape in any case |
|
511 //otherwise, if the test fails it blocks (never gets out of QMenu::exec |
|
512 const QString st=statustip; |
|
513 |
|
514 menu->close(); //goes out of the menu |
|
515 |
|
516 QCOMPARE(st, QString("sub action")); |
|
517 QVERIFY(menu->isVisible() == false); |
|
518 } |
|
519 |
|
520 void tst_QMenu::widgetActionFocus() |
|
521 { |
|
522 //test if the focus is correctly handled with a QWidgetAction |
|
523 QMenu m; |
|
524 QListWidget *l = new QListWidget(&m); |
|
525 for(int i = 1; i<3 ; i++) |
|
526 l->addItem(QString("item%1").arg(i)); |
|
527 QWidgetAction *wa = new QWidgetAction(&m); |
|
528 wa->setDefaultWidget(l); |
|
529 m.addAction(wa); |
|
530 m.setActiveAction(wa); |
|
531 l->setFocus(); //to ensure it has primarily the focus |
|
532 QAction *menuitem1=m.addAction("menuitem1"); |
|
533 QAction *menuitem2=m.addAction("menuitem2"); |
|
534 |
|
535 m.popup(QPoint()); |
|
536 |
|
537 QVERIFY(m.isVisible()); |
|
538 QVERIFY(l->hasFocus()); |
|
539 QVERIFY(l->currentItem()); |
|
540 QCOMPARE(l->currentItem()->text(), QString("item1")); |
|
541 |
|
542 QTest::keyClick(QApplication::focusWidget(), Qt::Key_Down); |
|
543 QVERIFY(l->currentItem()); |
|
544 QCOMPARE(l->currentItem()->text(), QString("item2")); |
|
545 |
|
546 QTest::keyClick(QApplication::focusWidget(), Qt::Key_Down); |
|
547 QVERIFY(m.hasFocus()); |
|
548 QCOMPARE(m.activeAction(), menuitem1); |
|
549 |
|
550 QTest::keyClick(QApplication::focusWidget(), Qt::Key_Down); |
|
551 QVERIFY(m.hasFocus()); |
|
552 QCOMPARE(m.activeAction(), menuitem2); |
|
553 |
|
554 QTest::keyClick(QApplication::focusWidget(), Qt::Key_Up); |
|
555 QVERIFY(m.hasFocus()); |
|
556 QCOMPARE(m.activeAction(), menuitem1); |
|
557 |
|
558 QTest::keyClick(QApplication::focusWidget(), Qt::Key_Up); |
|
559 QVERIFY(l->hasFocus()); |
|
560 QCOMPARE(m.activeAction(), (QAction *)wa); |
|
561 } |
|
562 |
|
563 void tst_QMenu::tearOff() |
|
564 { |
|
565 QWidget widget; |
|
566 QMenu *menu = new QMenu(&widget); |
|
567 QVERIFY(!menu->isTearOffEnabled()); //default value |
|
568 menu->setTearOffEnabled(true); |
|
569 menu->addAction("aaa"); |
|
570 menu->addAction("bbb"); |
|
571 QVERIFY(menu->isTearOffEnabled()); |
|
572 |
|
573 widget.show(); |
|
574 menu->popup(QPoint(0,0)); |
|
575 QTest::qWait(50); |
|
576 QVERIFY(!menu->isTearOffMenuVisible()); |
|
577 |
|
578 QTest::mouseClick(menu, Qt::LeftButton, 0, QPoint(3, 3), 10); |
|
579 QTest::qWait(100); |
|
580 |
|
581 QVERIFY(menu->isTearOffMenuVisible()); |
|
582 QPointer<QMenu> torn = 0; |
|
583 foreach (QWidget *w, QApplication::allWidgets()) { |
|
584 if (w->inherits("QTornOffMenu")) { |
|
585 torn = static_cast<QMenu *>(w); |
|
586 break; |
|
587 } |
|
588 } |
|
589 QVERIFY(torn); |
|
590 QVERIFY(torn->isVisible()); |
|
591 |
|
592 menu->hideTearOffMenu(); |
|
593 QVERIFY(!menu->isTearOffMenuVisible()); |
|
594 QVERIFY(!torn->isVisible()); |
|
595 } |
|
596 |
|
597 |
|
598 #if defined(QT3_SUPPORT) |
|
599 void tst_QMenu::indexBasedInsertion_data() |
|
600 { |
|
601 QTest::addColumn<int>("indexForInsertion"); |
|
602 QTest::addColumn<int>("expectedIndex"); |
|
603 |
|
604 QTest::newRow("negative-index-appends") << -1 << 1; |
|
605 QTest::newRow("prepend") << 0 << 0; |
|
606 QTest::newRow("append") << 1 << 1; |
|
607 } |
|
608 |
|
609 void tst_QMenu::indexBasedInsertion() |
|
610 { |
|
611 // test the compat'ed index based insertion |
|
612 |
|
613 QFETCH(int, indexForInsertion); |
|
614 QFETCH(int, expectedIndex); |
|
615 |
|
616 { |
|
617 QMenu menu; |
|
618 menu.addAction("Regular Item"); |
|
619 |
|
620 menu.insertItem("New Item", -1 /*id*/, indexForInsertion); |
|
621 |
|
622 QAction *act = menu.actions().value(expectedIndex); |
|
623 QVERIFY(act); |
|
624 QCOMPARE(act->text(), QString("New Item")); |
|
625 } |
|
626 { |
|
627 QMenu menu; |
|
628 menu.addAction("Regular Item"); |
|
629 |
|
630 menu.insertSeparator(indexForInsertion); |
|
631 |
|
632 QAction *act = menu.actions().value(expectedIndex); |
|
633 QVERIFY(act); |
|
634 QVERIFY(act->isSeparator()); |
|
635 } |
|
636 } |
|
637 #endif |
|
638 |
|
639 void tst_QMenu::task208001_stylesheet() |
|
640 { |
|
641 //test if it crash |
|
642 QMainWindow main; |
|
643 main.setStyleSheet("QMenu [title =\"File\"] { color: red;}"); |
|
644 main.menuBar()->addMenu("File"); |
|
645 } |
|
646 |
|
647 void tst_QMenu::activeSubMenuPosition() |
|
648 { |
|
649 QPushButton lab("subMenuPosition test"); |
|
650 |
|
651 QMenu *sub = new QMenu("Submenu", &lab); |
|
652 sub->addAction("Sub-Item1"); |
|
653 QAction *subAction = sub->addAction("Sub-Item2"); |
|
654 |
|
655 QMenu *main = new QMenu("Menu-Title", &lab); |
|
656 (void)main->addAction("Item 1"); |
|
657 QAction *menuAction = main->addMenu(sub); |
|
658 (void)main->addAction("Item 3"); |
|
659 (void)main->addAction("Item 4"); |
|
660 |
|
661 main->setActiveAction(menuAction); |
|
662 sub->setActiveAction(subAction); |
|
663 #ifdef Q_OS_SYMBIAN |
|
664 main->popup(QPoint(50,200)); |
|
665 #else |
|
666 main->popup(QPoint(200,200)); |
|
667 #endif |
|
668 |
|
669 QVERIFY(main->isVisible()); |
|
670 QCOMPARE(main->activeAction(), menuAction); |
|
671 QVERIFY(sub->isVisible()); |
|
672 QVERIFY(sub->pos() != QPoint(0,0)); |
|
673 // well, it's enough to check the pos is not (0,0) but it's more safe |
|
674 // to check that submenu is to the right of the main menu too. |
|
675 #ifdef Q_OS_WINCE_WM |
|
676 QSKIP("Not true for Windows Mobile Soft Keys", SkipSingle); |
|
677 #endif |
|
678 |
|
679 #ifdef Q_OS_SYMBIAN |
|
680 // On Symbian, QS60Style::pixelMetric(QStyle::PM_SubMenuOverlap) is different with other styles. |
|
681 QVERIFY(sub->pos().x() < main->pos().x()); |
|
682 #else |
|
683 QVERIFY(sub->pos().x() > main->pos().x()); |
|
684 #endif |
|
685 QCOMPARE(sub->activeAction(), subAction); |
|
686 } |
|
687 |
|
688 void tst_QMenu::task242454_sizeHint() |
|
689 { |
|
690 QMenu menu; |
|
691 QString s = QLatin1String("foo\nfoo\nfoo\nfoo"); |
|
692 menu.addAction(s); |
|
693 QVERIFY(menu.sizeHint().width() > menu.fontMetrics().boundingRect(QRect(), Qt::TextSingleLine, s).width()); |
|
694 } |
|
695 |
|
696 |
|
697 class Menu : public QMenu |
|
698 { |
|
699 Q_OBJECT |
|
700 public slots: |
|
701 void clear() |
|
702 { |
|
703 QMenu::clear(); |
|
704 } |
|
705 }; |
|
706 |
|
707 void tst_QMenu::task176201_clear() |
|
708 { |
|
709 //this test used to crash |
|
710 Menu menu; |
|
711 QAction *action = menu.addAction("test"); |
|
712 menu.connect(action, SIGNAL(triggered()), SLOT(clear())); |
|
713 menu.popup(QPoint()); |
|
714 QTest::mouseClick(&menu, Qt::LeftButton, 0, menu.rect().center()); |
|
715 } |
|
716 |
|
717 void tst_QMenu::task250673_activeMultiColumnSubMenuPosition() |
|
718 { |
|
719 class MyMenu : public QMenu |
|
720 { |
|
721 public: |
|
722 int columnCount() const { return QMenu::columnCount(); } |
|
723 }; |
|
724 |
|
725 QMenu sub; |
|
726 |
|
727 if (sub.style()->styleHint(QStyle::SH_Menu_Scrollable, 0, &sub)) { |
|
728 //the style prevents the menus from getting columns |
|
729 QSKIP("the style doesn't support multiple columns, it makes the menu scrollable", SkipSingle); |
|
730 } |
|
731 |
|
732 sub.addAction("Sub-Item1"); |
|
733 QAction *subAction = sub.addAction("Sub-Item2"); |
|
734 |
|
735 MyMenu main; |
|
736 main.addAction("Item 1"); |
|
737 QAction *menuAction = main.addMenu(&sub); |
|
738 main.popup(QPoint(200,200)); |
|
739 |
|
740 uint i = 2; |
|
741 while (main.columnCount() < 2) { |
|
742 main.addAction(QString("Item %1").arg(i)); |
|
743 ++i; |
|
744 Q_ASSERT(i<1000); |
|
745 } |
|
746 main.setActiveAction(menuAction); |
|
747 sub.setActiveAction(subAction); |
|
748 |
|
749 QVERIFY(main.isVisible()); |
|
750 QCOMPARE(main.activeAction(), menuAction); |
|
751 QVERIFY(sub.isVisible()); |
|
752 QVERIFY(sub.pos().x() > main.pos().x()); |
|
753 |
|
754 const int subMenuOffset = main.style()->pixelMetric(QStyle::PM_SubMenuOverlap, 0, &main); |
|
755 QVERIFY((sub.geometry().left() - subMenuOffset + 5) < main.geometry().right()); |
|
756 } |
|
757 |
|
758 |
|
759 void tst_QMenu::task256918_setFont() |
|
760 { |
|
761 QMenu menu; |
|
762 QAction *action = menu.addAction("foo"); |
|
763 QFont f; |
|
764 f.setPointSize(30); |
|
765 action->setFont(f); |
|
766 menu.show(); //ensures that the actiongeometry are calculated |
|
767 QVERIFY(menu.actionGeometry(action).height() > f.pointSize()); |
|
768 } |
|
769 |
|
770 void tst_QMenu::menuSizeHint() |
|
771 { |
|
772 QMenu menu; |
|
773 //this is a list of arbitrary strings so that we check the geometry |
|
774 QStringList list = QStringList() << "trer" << "ezrfgtgvqd" << "sdgzgzerzerzer" << "eerzertz" << "er"; |
|
775 foreach(QString str, list) |
|
776 menu.addAction(str); |
|
777 |
|
778 int left, top, right, bottom; |
|
779 menu.getContentsMargins(&left, &top, &right, &bottom); |
|
780 const int panelWidth = menu.style()->pixelMetric(QStyle::PM_MenuPanelWidth, 0, &menu); |
|
781 const int hmargin = menu.style()->pixelMetric(QStyle::PM_MenuHMargin, 0, &menu), |
|
782 vmargin = menu.style()->pixelMetric(QStyle::PM_MenuVMargin, 0, &menu); |
|
783 |
|
784 int maxWidth =0; |
|
785 QRect result; |
|
786 foreach(QAction *action, menu.actions()) { |
|
787 #ifdef QT_SOFTKEYS_ENABLED |
|
788 // Softkey actions are not widgets and have no geometry. |
|
789 if (menu.actionGeometry(action).topLeft() == QPoint(0,0)) |
|
790 continue; |
|
791 #endif |
|
792 maxWidth = qMax(maxWidth, menu.actionGeometry(action).width()); |
|
793 result |= menu.actionGeometry(action); |
|
794 QCOMPARE(result.x(), left + hmargin + panelWidth); |
|
795 QCOMPARE(result.y(), top + vmargin + panelWidth); |
|
796 } |
|
797 |
|
798 QStyleOption opt(0); |
|
799 opt.rect = menu.rect(); |
|
800 opt.state = QStyle::State_None; |
|
801 |
|
802 QSize resSize = QSize(result.x(), result.y()) + result.size() + QSize(hmargin + right + panelWidth, vmargin + top + panelWidth); |
|
803 |
|
804 resSize = menu.style()->sizeFromContents(QStyle::CT_Menu, &opt, |
|
805 resSize.expandedTo(QApplication::globalStrut()), &menu); |
|
806 |
|
807 QCOMPARE(resSize, menu.sizeHint()); |
|
808 } |
|
809 |
|
810 class Menu258920 : public QMenu |
|
811 { |
|
812 Q_OBJECT |
|
813 public slots: |
|
814 void paintEvent(QPaintEvent *e) |
|
815 { |
|
816 QMenu::paintEvent(e); |
|
817 painted = true; |
|
818 } |
|
819 |
|
820 public: |
|
821 bool painted; |
|
822 }; |
|
823 |
|
824 void tst_QMenu::task258920_mouseBorder() |
|
825 { |
|
826 #ifdef Q_OS_WINCE_WM |
|
827 QSKIP("Mouse move related signals for Windows Mobile unavailable", SkipAll); |
|
828 #endif |
|
829 Menu258920 menu; |
|
830 // On Symbian, styleHint(QStyle::SH_Menu_MouseTracking) in QS60Style is false. |
|
831 // For other styles which inherit from QWindowsStyle, the value is true. |
|
832 menu.setMouseTracking(true); |
|
833 QAction *action = menu.addAction("test"); |
|
834 |
|
835 menu.popup(QApplication::desktop()->availableGeometry().center()); |
|
836 QTest::qWaitForWindowShown(&menu); |
|
837 QTest::qWait(100); |
|
838 QRect actionRect = menu.actionGeometry(action); |
|
839 QTest::mouseMove(&menu, actionRect.center()); |
|
840 QTest::qWait(30); |
|
841 QTest::mouseMove(&menu, actionRect.center() + QPoint(10, 0)); |
|
842 QTest::qWait(30); |
|
843 QCOMPARE(action, menu.activeAction()); |
|
844 menu.painted = false; |
|
845 QTest::mouseMove(&menu, QPoint(actionRect.center().x(), actionRect.bottom() + 1)); |
|
846 QTest::qWait(30); |
|
847 QCOMPARE(static_cast<QAction*>(0), menu.activeAction()); |
|
848 QVERIFY(menu.painted); |
|
849 } |
|
850 |
|
851 void tst_QMenu::setFixedWidth() |
|
852 { |
|
853 QMenu menu; |
|
854 menu.addAction("action"); |
|
855 menu.setFixedWidth(300); |
|
856 //the sizehint should reflect the minimumwidth because the action will try to |
|
857 //get as much space as possible |
|
858 QCOMPARE(menu.sizeHint().width(), menu.minimumWidth()); |
|
859 } |
|
860 |
|
861 |
|
862 |
|
863 QTEST_MAIN(tst_QMenu) |
|
864 #include "tst_qmenu.moc" |