source: trunk/src/gui/widgets/qmenu.cpp@ 561

Last change on this file since 561 was 561, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.1 sources.

File size: 111.8 KB
Line 
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 QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
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** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qmenu.h"
43
44#ifndef QT_NO_MENU
45
46#include "qdebug.h"
47#include "qstyle.h"
48#include "qevent.h"
49#include "qtimer.h"
50#include "qlayout.h"
51#include "qpainter.h"
52#include "qapplication.h"
53#include "qdesktopwidget.h"
54#ifndef QT_NO_ACCESSIBILITY
55# include "qaccessible.h"
56#endif
57#ifndef QT_NO_EFFECTS
58# include <private/qeffects_p.h>
59#endif
60#ifndef QT_NO_WHATSTHIS
61# include <qwhatsthis.h>
62#endif
63
64#include "qmenu_p.h"
65#include "qmenubar_p.h"
66#include "qwidgetaction.h"
67#include "qtoolbutton.h"
68#include "qpushbutton.h"
69#include <private/qpushbutton_p.h>
70#include <private/qaction_p.h>
71#include <private/qsoftkeymanager_p.h>
72#ifdef QT3_SUPPORT
73#include <qmenudata.h>
74#endif // QT3_SUPPORT
75
76#ifdef Q_WS_X11
77# include <private/qt_x11_p.h>
78#endif
79
80#if defined(Q_WS_MAC) && !defined(QT_NO_EFFECTS)
81# include <private/qcore_mac_p.h>
82# include <private/qt_cocoa_helpers_mac_p.h>
83#endif
84
85
86QT_BEGIN_NAMESPACE
87
88QPointer<QMenu> QMenuPrivate::mouseDown;
89QBasicTimer QMenuPrivate::menuDelayTimer;
90QBasicTimer QMenuPrivate::sloppyDelayTimer;
91
92/* QMenu code */
93// internal class used for the torn off popup
94class QTornOffMenu : public QMenu
95{
96 Q_OBJECT
97 class QTornOffMenuPrivate : public QMenuPrivate
98 {
99 Q_DECLARE_PUBLIC(QMenu)
100 public:
101 QTornOffMenuPrivate(QMenu *p) : causedMenu(p) {
102 tornoff = 1;
103 causedPopup.widget = 0;
104 causedPopup.action = ((QTornOffMenu*)p)->d_func()->causedPopup.action;
105 causedStack = ((QTornOffMenu*)p)->d_func()->calcCausedStack();
106 }
107 QList<QPointer<QWidget> > calcCausedStack() const { return causedStack; }
108 QPointer<QMenu> causedMenu;
109 QList<QPointer<QWidget> > causedStack;
110 };
111public:
112 QTornOffMenu(QMenu *p) : QMenu(*(new QTornOffMenuPrivate(p)))
113 {
114 Q_D(QTornOffMenu);
115 // make the torn-off menu a sibling of p (instead of a child)
116 QWidget *parentWidget = d->causedStack.isEmpty() ? p : d->causedStack.last();
117 if (parentWidget->parentWidget())
118 parentWidget = parentWidget->parentWidget();
119 setParent(parentWidget, Qt::Window | Qt::Tool);
120 setAttribute(Qt::WA_DeleteOnClose, true);
121 setAttribute(Qt::WA_X11NetWmWindowTypeMenu, true);
122 setWindowTitle(p->windowTitle());
123 setEnabled(p->isEnabled());
124 //QObject::connect(this, SIGNAL(triggered(QAction*)), this, SLOT(onTrigger(QAction*)));
125 //QObject::connect(this, SIGNAL(hovered(QAction*)), this, SLOT(onHovered(QAction*)));
126 QList<QAction*> items = p->actions();
127 for(int i = 0; i < items.count(); i++)
128 addAction(items.at(i));
129 }
130 void syncWithMenu(QMenu *menu, QActionEvent *act)
131 {
132 Q_D(QTornOffMenu);
133 if(menu != d->causedMenu)
134 return;
135 if (act->type() == QEvent::ActionAdded) {
136 insertAction(act->before(), act->action());
137 } else if (act->type() == QEvent::ActionRemoved)
138 removeAction(act->action());
139 }
140 void actionEvent(QActionEvent *e)
141 {
142 QMenu::actionEvent(e);
143 setFixedSize(sizeHint());
144 }
145public slots:
146 void onTrigger(QAction *action) { d_func()->activateAction(action, QAction::Trigger, false); }
147 void onHovered(QAction *action) { d_func()->activateAction(action, QAction::Hover, false); }
148private:
149 Q_DECLARE_PRIVATE(QTornOffMenu)
150 friend class QMenuPrivate;
151};
152
153void QMenuPrivate::init()
154{
155 Q_Q(QMenu);
156#ifndef QT_NO_WHATSTHIS
157 q->setAttribute(Qt::WA_CustomWhatsThis);
158#endif
159 q->setAttribute(Qt::WA_X11NetWmWindowTypePopupMenu);
160 defaultMenuAction = menuAction = new QAction(q);
161 menuAction->d_func()->menu = q;
162 q->setMouseTracking(q->style()->styleHint(QStyle::SH_Menu_MouseTracking, 0, q));
163 if (q->style()->styleHint(QStyle::SH_Menu_Scrollable, 0, q)) {
164 scroll = new QMenuPrivate::QMenuScroller;
165 scroll->scrollFlags = QMenuPrivate::QMenuScroller::ScrollNone;
166 }
167
168#ifdef QT_SOFTKEYS_ENABLED
169 selectAction = QSoftKeyManager::createKeyedAction(QSoftKeyManager::SelectSoftKey, Qt::Key_Select, q);
170 cancelAction = QSoftKeyManager::createKeyedAction(QSoftKeyManager::CancelSoftKey, Qt::Key_Back, q);
171 selectAction->setVisible(false); // Don't show these in the menu
172 cancelAction->setVisible(false);
173 q->addAction(selectAction);
174 q->addAction(cancelAction);
175#endif
176}
177
178int QMenuPrivate::scrollerHeight() const
179{
180 Q_Q(const QMenu);
181 return qMax(QApplication::globalStrut().height(), q->style()->pixelMetric(QStyle::PM_MenuScrollerHeight, 0, q));
182}
183
184// Windows, OS/2 and KDE allows menus to cover the taskbar, while GNOME and Mac don't
185QRect QMenuPrivate::popupGeometry(const QWidget *widget) const
186{
187#if defined(Q_WS_WIN) || defined(Q_WS_PM)
188 return QApplication::desktop()->screenGeometry(widget);
189#elif defined Q_WS_X11
190 if (X11->desktopEnvironment == DE_KDE)
191 return QApplication::desktop()->screenGeometry(widget);
192 else
193 return QApplication::desktop()->availableGeometry(widget);
194#else
195 return QApplication::desktop()->availableGeometry(widget);
196#endif
197}
198
199// Windows, OS/2 and KDE allows menus to cover the taskbar, while GNOME and Mac don't
200QRect QMenuPrivate::popupGeometry(int screen) const
201{
202#if defined(Q_WS_WIN) || defined(Q_WS_PM)
203 return QApplication::desktop()->screenGeometry(screen);
204#elif defined Q_WS_X11
205 if (X11->desktopEnvironment == DE_KDE)
206 return QApplication::desktop()->screenGeometry(screen);
207 else
208 return QApplication::desktop()->availableGeometry(screen);
209#else
210 return QApplication::desktop()->availableGeometry(screen);
211#endif
212}
213
214QList<QPointer<QWidget> > QMenuPrivate::calcCausedStack() const
215{
216 QList<QPointer<QWidget> > ret;
217 for(QWidget *widget = causedPopup.widget; widget; ) {
218 ret.append(widget);
219 if (QTornOffMenu *qtmenu = qobject_cast<QTornOffMenu*>(widget))
220 ret += qtmenu->d_func()->causedStack;
221 if (QMenu *qmenu = qobject_cast<QMenu*>(widget))
222 widget = qmenu->d_func()->causedPopup.widget;
223 else
224 break;
225 }
226 return ret;
227}
228
229void QMenuPrivate::updateActionRects() const
230{
231 Q_Q(const QMenu);
232 if (!itemsDirty)
233 return;
234
235 q->ensurePolished();
236
237 //let's reinitialize the buffer
238 actionRects.resize(actions.count());
239 actionRects.fill(QRect());
240
241 //let's try to get the last visible action
242 int lastVisibleAction = actions.count() - 1;
243 for(;lastVisibleAction >= 0; --lastVisibleAction) {
244 const QAction *action = actions.at(lastVisibleAction);
245 if (action->isVisible()) {
246 //removing trailing separators
247 if (action->isSeparator() && collapsibleSeparators)
248 continue;
249 break;
250 }
251 }
252
253 int max_column_width = 0,
254 dh = popupGeometry(q).height(),
255 y = 0;
256 QStyle *style = q->style();
257 QStyleOption opt;
258 opt.init(q);
259 const int hmargin = style->pixelMetric(QStyle::PM_MenuHMargin, &opt, q),
260 vmargin = style->pixelMetric(QStyle::PM_MenuVMargin, &opt, q),
261 icone = style->pixelMetric(QStyle::PM_SmallIconSize, &opt, q);
262 const int fw = style->pixelMetric(QStyle::PM_MenuPanelWidth, &opt, q);
263 const int deskFw = style->pixelMetric(QStyle::PM_MenuDesktopFrameWidth, &opt, q);
264
265 const int sfcMargin = style->sizeFromContents(QStyle::CT_Menu, &opt, QApplication::globalStrut(), q).width() - QApplication::globalStrut().width();
266 const int min_column_width = q->minimumWidth() - (sfcMargin + leftmargin + rightmargin + 2 * (fw + hmargin));
267 const int tearoffHeight = tearoff ? style->pixelMetric(QStyle::PM_MenuTearoffHeight, &opt, q) : 0;
268
269 //for compatability now - will have to refactor this away..
270 tabWidth = 0;
271 maxIconWidth = 0;
272 hasCheckableItems = false;
273 ncols = 1;
274 sloppyAction = 0;
275
276 for (int i = 0; i < actions.count(); ++i) {
277 QAction *action = actions.at(i);
278 if (action->isSeparator() || !action->isVisible() || widgetItems.contains(action))
279 continue;
280 //..and some members
281 hasCheckableItems |= action->isCheckable();
282 QIcon is = action->icon();
283 if (!is.isNull()) {
284 maxIconWidth = qMax<uint>(maxIconWidth, icone + 4);
285 }
286 }
287
288 //calculate size
289 QFontMetrics qfm = q->fontMetrics();
290 bool previousWasSeparator = true; // this is true to allow removing the leading separators
291 for(int i = 0; i <= lastVisibleAction; i++) {
292 QAction *action = actions.at(i);
293
294 if (!action->isVisible() ||
295 (collapsibleSeparators && previousWasSeparator && action->isSeparator()))
296 continue; // we continue, this action will get an empty QRect
297
298 previousWasSeparator = action->isSeparator();
299
300 //let the style modify the above size..
301 QStyleOptionMenuItem opt;
302 q->initStyleOption(&opt, action);
303 const QFontMetrics &fm = opt.fontMetrics;
304
305 QSize sz;
306 if (QWidget *w = widgetItems.value(action)) {
307 sz = w->sizeHint().expandedTo(w->minimumSize()).expandedTo(w->minimumSizeHint()).boundedTo(w->maximumSize());
308 } else {
309 //calc what I think the size is..
310 if (action->isSeparator()) {
311 sz = QSize(2, 2);
312 } else {
313 QString s = action->text();
314 int t = s.indexOf(QLatin1Char('\t'));
315 if (t != -1) {
316 tabWidth = qMax(int(tabWidth), qfm.width(s.mid(t+1)));
317 s = s.left(t);
318 #ifndef QT_NO_SHORTCUT
319 } else {
320 QKeySequence seq = action->shortcut();
321 if (!seq.isEmpty())
322 tabWidth = qMax(int(tabWidth), qfm.width(seq));
323 #endif
324 }
325 sz.setWidth(fm.boundingRect(QRect(), Qt::TextSingleLine | Qt::TextShowMnemonic, s).width());
326 sz.setHeight(qMax(fm.height(), qfm.height()));
327
328 QIcon is = action->icon();
329 if (!is.isNull()) {
330 QSize is_sz = QSize(icone, icone);
331 if (is_sz.height() > sz.height())
332 sz.setHeight(is_sz.height());
333 }
334 }
335 sz = style->sizeFromContents(QStyle::CT_MenuItem, &opt, sz, q);
336 }
337
338
339 if (!sz.isEmpty()) {
340 max_column_width = qMax(min_column_width, qMax(max_column_width, sz.width()));
341 //wrapping
342 if (!scroll &&
343 y+sz.height()+vmargin > dh - (deskFw * 2)) {
344 ncols++;
345 y = vmargin;
346 }
347 y += sz.height();
348 //update the item
349 actionRects[i] = QRect(0, 0, sz.width(), sz.height());
350 }
351 }
352
353 max_column_width += tabWidth; //finally add in the tab width
354
355 //calculate position
356 const int base_y = vmargin + fw + topmargin +
357 (scroll ? scroll->scrollOffset : 0) +
358 tearoffHeight;
359 int x = hmargin + fw + leftmargin;
360 y = base_y;
361
362 for(int i = 0; i < actions.count(); i++) {
363 QRect &rect = actionRects[i];
364 if (rect.isNull())
365 continue;
366 if (!scroll &&
367 y+rect.height() > dh - deskFw * 2) {
368 x += max_column_width + hmargin;
369 y = base_y;
370 }
371 rect.translate(x, y); //move
372 rect.setWidth(max_column_width); //uniform width
373
374 //we need to update the widgets geometry
375 if (QWidget *widget = widgetItems.value(actions.at(i))) {
376 widget->setGeometry(rect);
377 widget->setVisible(actions.at(i)->isVisible());
378 }
379
380 y += rect.height();
381 }
382 itemsDirty = 0;
383}
384
385QRect QMenuPrivate::actionRect(QAction *act) const
386{
387 int index = actions.indexOf(act);
388 if (index == -1)
389 return QRect();
390
391 updateActionRects();
392
393 //we found the action
394 return actionRects.at(index);
395}
396
397#if defined(Q_WS_MAC)
398static const qreal MenuFadeTimeInSec = 0.150;
399#endif
400
401void QMenuPrivate::hideUpToMenuBar()
402{
403 Q_Q(QMenu);
404 bool fadeMenus = q->style()->styleHint(QStyle::SH_Menu_FadeOutOnHide);
405 if (!tornoff) {
406 QWidget *caused = causedPopup.widget;
407 hideMenu(q); //hide after getting causedPopup
408 while(caused) {
409#ifndef QT_NO_MENUBAR
410 if (QMenuBar *mb = qobject_cast<QMenuBar*>(caused)) {
411 mb->d_func()->setCurrentAction(0);
412 mb->d_func()->setKeyboardMode(false);
413 caused = 0;
414 } else
415#endif
416 if (QMenu *m = qobject_cast<QMenu*>(caused)) {
417 caused = m->d_func()->causedPopup.widget;
418 if (!m->d_func()->tornoff)
419 hideMenu(m, fadeMenus);
420 if (!fadeMenus) // Mac doesn't clear the action until after hidden.
421 m->d_func()->setCurrentAction(0);
422 } else { caused = 0;
423 }
424 }
425#if defined(Q_WS_MAC)
426 if (fadeMenus) {
427 QEventLoop eventLoop;
428 QTimer::singleShot(int(MenuFadeTimeInSec * 1000), &eventLoop, SLOT(quit()));
429 QMacWindowFader::currentFader()->performFade();
430 eventLoop.exec();
431 }
432#endif
433 }
434 setCurrentAction(0);
435}
436
437void QMenuPrivate::hideMenu(QMenu *menu, bool justRegister)
438{
439 if (!menu)
440 return;
441#if !defined(QT_NO_EFFECTS)
442 menu->blockSignals(true);
443 aboutToHide = true;
444 // Flash item which is about to trigger (if any).
445 if (menu->style()->styleHint(QStyle::SH_Menu_FlashTriggeredItem)
446 && currentAction && currentAction == actionAboutToTrigger
447 && menu->actions().contains(currentAction)) {
448 QEventLoop eventLoop;
449 QAction *activeAction = currentAction;
450
451 menu->setActiveAction(0);
452 QTimer::singleShot(60, &eventLoop, SLOT(quit()));
453 eventLoop.exec();
454
455 // Select and wait 20 ms.
456 menu->setActiveAction(activeAction);
457 QTimer::singleShot(20, &eventLoop, SLOT(quit()));
458 eventLoop.exec();
459 }
460
461 // Fade out.
462 if (menu->style()->styleHint(QStyle::SH_Menu_FadeOutOnHide)) {
463 // ### Qt 4.4:
464 // Should be something like: q->transitionWindow(Qt::FadeOutTransition, MenuFadeTimeInSec);
465 // Hopefully we'll integrate qt/research/windowtransitions into main before 4.4.
466 // Talk to Richard, Trenton or Bjoern.
467#if defined(Q_WS_MAC)
468 if (justRegister) {
469 QMacWindowFader::currentFader()->setFadeDuration(MenuFadeTimeInSec);
470 QMacWindowFader::currentFader()->registerWindowToFade(menu);
471 } else {
472 macWindowFade(qt_mac_window_for(menu), MenuFadeTimeInSec);
473 }
474
475#endif // Q_WS_MAC
476 }
477 aboutToHide = false;
478 menu->blockSignals(false);
479#endif // QT_NO_EFFECTS
480 if (!justRegister)
481 menu->hide();
482}
483
484void QMenuPrivate::popupAction(QAction *action, int delay, bool activateFirst)
485{
486 Q_Q(QMenu);
487 if (action && action->isEnabled()) {
488 if (!delay)
489 q->internalDelayedPopup();
490 else
491 QMenuPrivate::menuDelayTimer.start(delay, q);
492 if (activateFirst && action->menu())
493 action->menu()->d_func()->setFirstActionActive();
494 } else if (QMenu *menu = activeMenu) { //hide the current item
495 activeMenu = 0;
496 hideMenu(menu);
497 }
498}
499
500void QMenuPrivate::setSyncAction()
501{
502 Q_Q(QMenu);
503 QAction *current = currentAction;
504 if(current && (!current->isEnabled() || current->menu() || current->isSeparator()))
505 current = 0;
506 for(QWidget *caused = q; caused;) {
507 if (QMenu *m = qobject_cast<QMenu*>(caused)) {
508 caused = m->d_func()->causedPopup.widget;
509 if (m->d_func()->eventLoop)
510 m->d_func()->syncAction = current; // synchronous operation
511 } else {
512 break;
513 }
514 }
515}
516
517
518void QMenuPrivate::setFirstActionActive()
519{
520 Q_Q(QMenu);
521 updateActionRects();
522 for(int i = 0, saccum = 0; i < actions.count(); i++) {
523 const QRect &rect = actionRects.at(i);
524 if (rect.isNull())
525 continue;
526 if (scroll && scroll->scrollFlags & QMenuScroller::ScrollUp) {
527 saccum -= rect.height();
528 if (saccum > scroll->scrollOffset - scrollerHeight())
529 continue;
530 }
531 QAction *act = actions.at(i);
532 if (!act->isSeparator() &&
533 (q->style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled, 0, q)
534 || act->isEnabled())) {
535 setCurrentAction(act);
536 break;
537 }
538 }
539}
540
541// popup == -1 means do not popup, 0 means immediately, others mean use a timer
542void QMenuPrivate::setCurrentAction(QAction *action, int popup, SelectionReason reason, bool activateFirst)
543{
544 Q_Q(QMenu);
545 tearoffHighlighted = 0;
546 if (action == currentAction) {
547 if (!action || !action->menu() || action->menu() == activeMenu) {
548 if(QMenu *menu = qobject_cast<QMenu*>(causedPopup.widget)) {
549 if(causedPopup.action && menu->d_func()->activeMenu == q)
550 menu->d_func()->setCurrentAction(causedPopup.action, 0, reason, false);
551 }
552 }
553 return;
554 }
555 if (currentAction)
556 q->update(actionRect(currentAction));
557
558 sloppyAction = 0;
559 if (!sloppyRegion.isEmpty())
560 sloppyRegion = QRegion();
561 QMenu *hideActiveMenu = activeMenu;
562#ifndef QT_NO_STATUSTIP
563 QAction *previousAction = currentAction;
564#endif
565#ifdef QT3_SUPPORT
566 emitHighlighted = action;
567#endif
568 currentAction = action;
569 if (action) {
570 if (!action->isSeparator()) {
571 activateAction(action, QAction::Hover);
572 if (popup != -1) {
573 hideActiveMenu = 0; //will be done "later"
574 // if the menu is visible then activate the required action,
575 // otherwise we just mark the action as currentAction
576 // and activate it when the menu will be popuped.
577 if (q->isVisible())
578 popupAction(currentAction, popup, activateFirst);
579 }
580 q->update(actionRect(action));
581
582 if (reason == SelectedFromKeyboard) {
583 QWidget *widget = widgetItems.value(action);
584 if (widget) {
585 if (widget->focusPolicy() != Qt::NoFocus)
586 widget->setFocus(Qt::TabFocusReason);
587 } else {
588 //when the action has no QWidget, the QMenu itself should
589 // get the focus
590 // Since the menu is a pop-up, it uses the popup reason.
591 if (!q->hasFocus()) {
592 q->setFocus(Qt::PopupFocusReason);
593 }
594 }
595 }
596 } else { //action is a separator
597 if (popup != -1)
598 hideActiveMenu = 0; //will be done "later"
599 }
600#ifndef QT_NO_STATUSTIP
601 } else if (previousAction) {
602 previousAction->d_func()->showStatusText(topCausedWidget(), QString());
603#endif
604 }
605 if (hideActiveMenu) {
606 activeMenu = 0;
607#ifndef QT_NO_EFFECTS
608 // kill any running effect
609 qFadeEffect(0);
610 qScrollEffect(0);
611#endif
612 hideMenu(hideActiveMenu);
613 }
614}
615
616//return the top causedPopup.widget that is not a QMenu
617QWidget *QMenuPrivate::topCausedWidget() const
618{
619 QWidget* top = causedPopup.widget;
620 while (QMenu* m = qobject_cast<QMenu *>(top))
621 top = m->d_func()->causedPopup.widget;
622 return top;
623}
624
625QAction *QMenuPrivate::actionAt(QPoint p) const
626{
627 if (!q_func()->rect().contains(p)) //sanity check
628 return 0;
629
630 for(int i = 0; i < actionRects.count(); i++) {
631 if (actionRects.at(i).contains(p))
632 return actions.at(i);
633 }
634 return 0;
635}
636
637void QMenuPrivate::setOverrideMenuAction(QAction *a)
638{
639 Q_Q(QMenu);
640 QObject::disconnect(menuAction, SIGNAL(destroyed()), q, SLOT(_q_overrideMenuActionDestroyed()));
641 if (a) {
642 menuAction = a;
643 QObject::connect(a, SIGNAL(destroyed()), q, SLOT(_q_overrideMenuActionDestroyed()));
644 } else { //we revert back to the default action created by the QMenu itself
645 menuAction = defaultMenuAction;
646 }
647}
648
649void QMenuPrivate::_q_overrideMenuActionDestroyed()
650{
651 menuAction=defaultMenuAction;
652}
653
654
655void QMenuPrivate::updateLayoutDirection()
656{
657 Q_Q(QMenu);
658 //we need to mimic the cause of the popup's layout direction
659 //to allow setting it on a mainwindow for example
660 //we call setLayoutDirection_helper to not overwrite a user-defined value
661 if (!q->testAttribute(Qt::WA_SetLayoutDirection)) {
662 if (QWidget *w = causedPopup.widget)
663 setLayoutDirection_helper(w->layoutDirection());
664 else if (QWidget *w = q->parentWidget())
665 setLayoutDirection_helper(w->layoutDirection());
666 else
667 setLayoutDirection_helper(QApplication::layoutDirection());
668 }
669}
670
671
672/*!
673 Returns the action associated with this menu.
674*/
675QAction *QMenu::menuAction() const
676{
677 return d_func()->menuAction;
678}
679
680/*!
681 \property QMenu::title
682 \brief The title of the menu
683
684 This is equivalent to the QAction::text property of the menuAction().
685
686 By default, this property contains an empty string.
687*/
688QString QMenu::title() const
689{
690 return d_func()->menuAction->text();
691}
692
693void QMenu::setTitle(const QString &text)
694{
695 d_func()->menuAction->setText(text);
696}
697
698/*!
699 \property QMenu::icon
700
701 \brief The icon of the menu
702
703 This is equivalent to the QAction::icon property of the menuAction().
704
705 By default, if no icon is explicitly set, this property contains a null icon.
706*/
707QIcon QMenu::icon() const
708{
709 return d_func()->menuAction->icon();
710}
711
712void QMenu::setIcon(const QIcon &icon)
713{
714 d_func()->menuAction->setIcon(icon);
715}
716
717
718//actually performs the scrolling
719void QMenuPrivate::scrollMenu(QAction *action, QMenuScroller::ScrollLocation location, bool active)
720{
721 Q_Q(QMenu);
722 if (!scroll || !scroll->scrollFlags)
723 return;
724 updateActionRects();
725 int newOffset = 0;
726 const int topScroll = (scroll->scrollFlags & QMenuScroller::ScrollUp) ? scrollerHeight() : 0;
727 const int botScroll = (scroll->scrollFlags & QMenuScroller::ScrollDown) ? scrollerHeight() : 0;
728 const int vmargin = q->style()->pixelMetric(QStyle::PM_MenuVMargin, 0, q);
729 const int fw = q->style()->pixelMetric(QStyle::PM_MenuPanelWidth, 0, q);
730
731 if (location == QMenuScroller::ScrollTop) {
732 for(int i = 0, saccum = 0; i < actions.count(); i++) {
733 if (actions.at(i) == action) {
734 newOffset = topScroll - saccum;
735 break;
736 }
737 saccum += actionRects.at(i).height();
738 }
739 } else {
740 for(int i = 0, saccum = 0; i < actions.count(); i++) {
741 saccum += actionRects.at(i).height();
742 if (actions.at(i) == action) {
743 if (location == QMenuScroller::ScrollCenter)
744 newOffset = ((q->height() / 2) - botScroll) - (saccum - topScroll);
745 else
746 newOffset = (q->height() - botScroll) - saccum;
747 break;
748 }
749 }
750 if(newOffset)
751 newOffset -= fw * 2;
752 }
753
754 //figure out which scroll flags
755 uint newScrollFlags = QMenuScroller::ScrollNone;
756 if (newOffset < 0) //easy and cheap one
757 newScrollFlags |= QMenuScroller::ScrollUp;
758 int saccum = newOffset;
759 for(int i = 0; i < actionRects.count(); i++) {
760 saccum += actionRects.at(i).height();
761 if (saccum > q->height()) {
762 newScrollFlags |= QMenuScroller::ScrollDown;
763 break;
764 }
765 }
766
767 if (!(newScrollFlags & QMenuScroller::ScrollDown) && (scroll->scrollFlags & QMenuScroller::ScrollDown)) {
768 newOffset = q->height() - (saccum - newOffset) - fw*2 - vmargin; //last item at bottom
769 }
770
771 if (!(newScrollFlags & QMenuScroller::ScrollUp) && (scroll->scrollFlags & QMenuScroller::ScrollUp)) {
772 newOffset = 0; //first item at top
773 }
774
775 if (newScrollFlags & QMenuScroller::ScrollUp)
776 newOffset -= vmargin;
777
778 QRect screen = popupGeometry(q);
779 const int desktopFrame = q->style()->pixelMetric(QStyle::PM_MenuDesktopFrameWidth, 0, q);
780 if (q->height() < screen.height()-(desktopFrame*2)-1) {
781 QRect geom = q->geometry();
782 if (newOffset > scroll->scrollOffset && (scroll->scrollFlags & newScrollFlags & QMenuScroller::ScrollUp)) { //scroll up
783 const int newHeight = geom.height()-(newOffset-scroll->scrollOffset);
784 if(newHeight > geom.height())
785 geom.setHeight(newHeight);
786 } else if(scroll->scrollFlags & newScrollFlags & QMenuScroller::ScrollDown) {
787 int newTop = geom.top() + (newOffset-scroll->scrollOffset);
788 if (newTop < desktopFrame+screen.top())
789 newTop = desktopFrame+screen.top();
790 if (newTop < geom.top()) {
791 geom.setTop(newTop);
792 newOffset = 0;
793 newScrollFlags &= ~QMenuScroller::ScrollUp;
794 }
795 }
796 if (geom.bottom() > screen.bottom() - desktopFrame)
797 geom.setBottom(screen.bottom() - desktopFrame);
798 if (geom.top() < desktopFrame+screen.top())
799 geom.setTop(desktopFrame+screen.top());
800 if (geom != q->geometry()) {
801#if 0
802 if (newScrollFlags & QMenuScroller::ScrollDown &&
803 q->geometry().top() - geom.top() >= -newOffset)
804 newScrollFlags &= ~QMenuScroller::ScrollDown;
805#endif
806 q->setGeometry(geom);
807 }
808 }
809
810 //actually update flags
811 const int delta = qMin(0, newOffset) - scroll->scrollOffset; //make sure the new offset is always negative
812 if (!itemsDirty && delta) {
813 //we've scrolled so we need to update the action rects
814 for (int i = 0; i < actionRects.count(); ++i) {
815 QRect &current = actionRects[i];
816 current.moveTop(current.top() + delta);
817
818 //we need to update the widgets geometry
819 if (QWidget *w = widgetItems.value(actions.at(i)))
820 w->setGeometry(current);
821 }
822 }
823 scroll->scrollOffset += delta;
824 scroll->scrollFlags = newScrollFlags;
825 if (active)
826 setCurrentAction(action);
827
828 q->update(); //issue an update so we see all the new state..
829}
830
831void QMenuPrivate::scrollMenu(QMenuScroller::ScrollLocation location, bool active)
832{
833 Q_Q(QMenu);
834 updateActionRects();
835 if(location == QMenuScroller::ScrollBottom) {
836 for(int i = actions.size()-1; i >= 0; --i) {
837 QAction *act = actions.at(i);
838 if (actionRects.at(i).isNull())
839 continue;
840 if (!act->isSeparator() &&
841 (q->style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled, 0, q)
842 || act->isEnabled())) {
843 if(scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollDown)
844 scrollMenu(act, QMenuPrivate::QMenuScroller::ScrollBottom, active);
845 else if(active)
846 setCurrentAction(act, /*popup*/-1, QMenuPrivate::SelectedFromKeyboard);
847 break;
848 }
849 }
850 } else if(location == QMenuScroller::ScrollTop) {
851 for(int i = 0; i < actions.size(); ++i) {
852 QAction *act = actions.at(i);
853 if (actionRects.at(i).isNull())
854 continue;
855 if (!act->isSeparator() &&
856 (q->style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled, 0, q)
857 || act->isEnabled())) {
858 if(scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp)
859 scrollMenu(act, QMenuPrivate::QMenuScroller::ScrollTop, active);
860 else if(active)
861 setCurrentAction(act, /*popup*/-1, QMenuPrivate::SelectedFromKeyboard);
862 break;
863 }
864 }
865 }
866}
867
868//only directional
869void QMenuPrivate::scrollMenu(QMenuScroller::ScrollDirection direction, bool page, bool active)
870{
871 Q_Q(QMenu);
872 if (!scroll || !(scroll->scrollFlags & direction)) //not really possible...
873 return;
874 updateActionRects();
875 const int topScroll = (scroll->scrollFlags & QMenuScroller::ScrollUp) ? scrollerHeight() : 0;
876 const int botScroll = (scroll->scrollFlags & QMenuScroller::ScrollDown) ? scrollerHeight() : 0;
877 const int vmargin = q->style()->pixelMetric(QStyle::PM_MenuVMargin, 0, q);
878 const int fw = q->style()->pixelMetric(QStyle::PM_MenuPanelWidth, 0, q);
879 const int offset = topScroll ? topScroll-vmargin : 0;
880 if (direction == QMenuScroller::ScrollUp) {
881 for(int i = 0, saccum = 0; i < actions.count(); i++) {
882 saccum -= actionRects.at(i).height();
883 if (saccum <= scroll->scrollOffset-offset) {
884 scrollMenu(actions.at(i), page ? QMenuScroller::ScrollBottom : QMenuScroller::ScrollTop, active);
885 break;
886 }
887 }
888 } else if (direction == QMenuScroller::ScrollDown) {
889 bool scrolled = false;
890 for(int i = 0, saccum = 0; i < actions.count(); i++) {
891 const int iHeight = actionRects.at(i).height();
892 saccum -= iHeight;
893 if (saccum <= scroll->scrollOffset-offset) {
894 const int scrollerArea = q->height() - botScroll - fw*2;
895 int visible = (scroll->scrollOffset-offset) - saccum;
896 for(i++ ; i < actions.count(); i++) {
897 visible += actionRects.at(i).height();
898 if (visible > scrollerArea - topScroll) {
899 scrolled = true;
900 scrollMenu(actions.at(i), page ? QMenuScroller::ScrollTop : QMenuScroller::ScrollBottom, active);
901 break;
902 }
903 }
904 break;
905 }
906 }
907 if(!scrolled) {
908 scroll->scrollFlags &= ~QMenuScroller::ScrollDown;
909 q->update();
910 }
911 }
912}
913
914/* This is poor-mans eventfilters. This avoids the use of
915 eventFilter (which can be nasty for users of QMenuBar's). */
916bool QMenuPrivate::mouseEventTaken(QMouseEvent *e)
917{
918 Q_Q(QMenu);
919 QPoint pos = q->mapFromGlobal(e->globalPos());
920 if (scroll && !activeMenu) { //let the scroller "steal" the event
921 bool isScroll = false;
922 if (pos.x() >= 0 && pos.x() < q->width()) {
923 for(int dir = QMenuScroller::ScrollUp; dir <= QMenuScroller::ScrollDown; dir = dir << 1) {
924 if (scroll->scrollFlags & dir) {
925 if (dir == QMenuScroller::ScrollUp)
926 isScroll = (pos.y() <= scrollerHeight());
927 else if (dir == QMenuScroller::ScrollDown)
928 isScroll = (pos.y() >= q->height() - scrollerHeight());
929 if (isScroll) {
930 scroll->scrollDirection = dir;
931 break;
932 }
933 }
934 }
935 }
936 if (isScroll) {
937 scroll->scrollTimer.start(50, q);
938 return true;
939 } else {
940 scroll->scrollTimer.stop();
941 }
942 }
943
944 if (tearoff) { //let the tear off thingie "steal" the event..
945 QRect tearRect(0, 0, q->width(), q->style()->pixelMetric(QStyle::PM_MenuTearoffHeight, 0, q));
946 if (scroll && scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp)
947 tearRect.translate(0, scrollerHeight());
948 q->update(tearRect);
949 if (tearRect.contains(pos) && hasMouseMoved(e->globalPos())) {
950 setCurrentAction(0);
951 tearoffHighlighted = 1;
952 if (e->type() == QEvent::MouseButtonRelease) {
953 if (!tornPopup)
954 tornPopup = new QTornOffMenu(q);
955 tornPopup->setGeometry(q->geometry());
956 tornPopup->show();
957 hideUpToMenuBar();
958 }
959 return true;
960 }
961 tearoffHighlighted = 0;
962 }
963
964 if (q->frameGeometry().contains(e->globalPos())) //otherwise if the event is in our rect we want it..
965 return false;
966
967 for(QWidget *caused = causedPopup.widget; caused;) {
968 bool passOnEvent = false;
969 QWidget *next_widget = 0;
970 QPoint cpos = caused->mapFromGlobal(e->globalPos());
971#ifndef QT_NO_MENUBAR
972 if (QMenuBar *mb = qobject_cast<QMenuBar*>(caused)) {
973 passOnEvent = mb->rect().contains(cpos);
974 } else
975#endif
976 if (QMenu *m = qobject_cast<QMenu*>(caused)) {
977 passOnEvent = m->rect().contains(cpos);
978 next_widget = m->d_func()->causedPopup.widget;
979 }
980 if (passOnEvent) {
981 if(e->type() != QEvent::MouseButtonRelease || mouseDown == caused) {
982 QMouseEvent new_e(e->type(), cpos, e->button(), e->buttons(), e->modifiers());
983 QApplication::sendEvent(caused, &new_e);
984 return true;
985 }
986 }
987 if (!next_widget)
988 break;
989 caused = next_widget;
990 }
991 return false;
992}
993
994class ExceptionGuard
995{
996public:
997 inline ExceptionGuard(bool *w = 0) : watched(w) { Q_ASSERT(!(*watched)); *watched = true; }
998 inline ~ExceptionGuard() { *watched = false; }
999 inline operator bool() { return *watched; }
1000private:
1001 bool *watched;
1002};
1003
1004void QMenuPrivate::activateCausedStack(const QList<QPointer<QWidget> > &causedStack, QAction *action, QAction::ActionEvent action_e, bool self)
1005{
1006 ExceptionGuard guard(&activationRecursionGuard);
1007#ifdef QT3_SUPPORT
1008 const int actionId = q_func()->findIdForAction(action);
1009#endif
1010 if(self)
1011 action->activate(action_e);
1012
1013 for(int i = 0; i < causedStack.size(); ++i) {
1014 QPointer<QWidget> widget = causedStack.at(i);
1015 if (!widget)
1016 continue;
1017 //fire
1018 if (QMenu *qmenu = qobject_cast<QMenu*>(widget)) {
1019 widget = qmenu->d_func()->causedPopup.widget;
1020 if (action_e == QAction::Trigger) {
1021 emit qmenu->triggered(action);
1022 } else if (action_e == QAction::Hover) {
1023 emit qmenu->hovered(action);
1024#ifdef QT3_SUPPORT
1025 if (emitHighlighted) {
1026 emit qmenu->highlighted(actionId);
1027 emitHighlighted = false;
1028 }
1029#endif
1030 }
1031#ifndef QT_NO_MENUBAR
1032 } else if (QMenuBar *qmenubar = qobject_cast<QMenuBar*>(widget)) {
1033 if (action_e == QAction::Trigger) {
1034 emit qmenubar->triggered(action);
1035#ifdef QT3_SUPPORT
1036 emit qmenubar->activated(actionId);
1037#endif
1038 } else if (action_e == QAction::Hover) {
1039 emit qmenubar->hovered(action);
1040#ifdef QT3_SUPPORT
1041 if (emitHighlighted) {
1042 emit qmenubar->highlighted(actionId);
1043 emitHighlighted = false;
1044 }
1045#endif
1046 }
1047 break; //nothing more..
1048#endif
1049 }
1050 }
1051}
1052
1053void QMenuPrivate::activateAction(QAction *action, QAction::ActionEvent action_e, bool self)
1054{
1055 Q_Q(QMenu);
1056#ifndef QT_NO_WHATSTHIS
1057 bool inWhatsThisMode = QWhatsThis::inWhatsThisMode();
1058#endif
1059 if (!action || !q->isEnabled()
1060 || (action_e == QAction::Trigger
1061#ifndef QT_NO_WHATSTHIS
1062 && !inWhatsThisMode
1063#endif
1064 && (action->isSeparator() ||!action->isEnabled())))
1065 return;
1066
1067 /* I have to save the caused stack here because it will be undone after popup execution (ie in the hide).
1068 Then I iterate over the list to actually send the events. --Sam
1069 */
1070 const QList<QPointer<QWidget> > causedStack = calcCausedStack();
1071 if (action_e == QAction::Trigger) {
1072#ifndef QT_NO_WHATSTHIS
1073 if (!inWhatsThisMode)
1074 actionAboutToTrigger = action;
1075#endif
1076
1077 if (q->testAttribute(Qt::WA_DontShowOnScreen)) {
1078 hideUpToMenuBar();
1079 } else {
1080 for(QWidget *widget = QApplication::activePopupWidget(); widget; ) {
1081 if (QMenu *qmenu = qobject_cast<QMenu*>(widget)) {
1082 if(qmenu == q)
1083 hideUpToMenuBar();
1084 widget = qmenu->d_func()->causedPopup.widget;
1085 } else {
1086 break;
1087 }
1088 }
1089 }
1090
1091#ifndef QT_NO_WHATSTHIS
1092 if (inWhatsThisMode) {
1093 QString s = action->whatsThis();
1094 if (s.isEmpty())
1095 s = whatsThis;
1096 QWhatsThis::showText(q->mapToGlobal(actionRect(action).center()), s, q);
1097 return;
1098 }
1099#endif
1100 }
1101
1102
1103 activateCausedStack(causedStack, action, action_e, self);
1104
1105
1106 if (action_e == QAction::Hover) {
1107#ifndef QT_NO_ACCESSIBILITY
1108 if (QAccessible::isActive()) {
1109 int actionIndex = indexOf(action) + 1;
1110 QAccessible::updateAccessibility(q, actionIndex, QAccessible::Focus);
1111 QAccessible::updateAccessibility(q, actionIndex, QAccessible::Selection);
1112 }
1113#endif
1114 action->showStatusText(topCausedWidget());
1115 } else {
1116 actionAboutToTrigger = 0;
1117 }
1118}
1119
1120void QMenuPrivate::_q_actionTriggered()
1121{
1122 Q_Q(QMenu);
1123 if (QAction *action = qobject_cast<QAction *>(q->sender())) {
1124 QWeakPointer<QAction> actionGuard = action;
1125#ifdef QT3_SUPPORT
1126 //we store it here because the action might be deleted/changed by connected slots
1127 const int id = q->findIdForAction(action);
1128#endif
1129 emit q->triggered(action);
1130#ifdef QT3_SUPPORT
1131 emit q->activated(id);
1132#endif
1133
1134 if (!activationRecursionGuard && actionGuard) {
1135 //in case the action has not been activated by the mouse
1136 //we check the parent hierarchy
1137 QList< QPointer<QWidget> > list;
1138 for(QWidget *widget = q->parentWidget(); widget; ) {
1139 if (qobject_cast<QMenu*>(widget)
1140#ifndef QT_NO_MENUBAR
1141 || qobject_cast<QMenuBar*>(widget)
1142#endif
1143 ) {
1144 list.append(widget);
1145 widget = widget->parentWidget();
1146 } else {
1147 break;
1148 }
1149 }
1150 activateCausedStack(list, action, QAction::Trigger, false);
1151 }
1152 }
1153}
1154
1155void QMenuPrivate::_q_actionHovered()
1156{
1157 Q_Q(QMenu);
1158 if (QAction * action = qobject_cast<QAction *>(q->sender())) {
1159#ifdef QT3_SUPPORT
1160 //we store it here because the action might be deleted/changed by connected slots
1161 const int id = q->findIdForAction(action);
1162#endif
1163 emit q->hovered(action);
1164#ifdef QT3_SUPPORT
1165 if (emitHighlighted) {
1166 emit q->highlighted(id);
1167 emitHighlighted = false;
1168 }
1169#endif
1170 }
1171}
1172
1173bool QMenuPrivate::hasMouseMoved(const QPoint &globalPos)
1174{
1175 //determines if the mouse has moved (ie its intial position has
1176 //changed by more than QApplication::startDragDistance()
1177 //or if there were at least 6 mouse motions)
1178 return motions > 6 ||
1179 QApplication::startDragDistance() < (mousePopupPos - globalPos).manhattanLength();
1180}
1181
1182
1183/*!
1184 Initialize \a option with the values from this menu and information from \a action. This method
1185 is useful for subclasses when they need a QStyleOptionMenuItem, but don't want
1186 to fill in all the information themselves.
1187
1188 \sa QStyleOption::initFrom() QMenuBar::initStyleOption()
1189*/
1190void QMenu::initStyleOption(QStyleOptionMenuItem *option, const QAction *action) const
1191{
1192 if (!option || !action)
1193 return;
1194
1195 Q_D(const QMenu);
1196 option->initFrom(this);
1197 option->palette = palette();
1198 option->state = QStyle::State_None;
1199
1200 if (window()->isActiveWindow())
1201 option->state |= QStyle::State_Active;
1202 if (isEnabled() && action->isEnabled()
1203 && (!action->menu() || action->menu()->isEnabled()))
1204 option->state |= QStyle::State_Enabled;
1205 else
1206 option->palette.setCurrentColorGroup(QPalette::Disabled);
1207
1208 option->font = action->font().resolve(font());
1209 option->fontMetrics = QFontMetrics(option->font);
1210
1211 if (d->currentAction && d->currentAction == action && !d->currentAction->isSeparator()) {
1212 option->state |= QStyle::State_Selected
1213 | (d->mouseDown ? QStyle::State_Sunken : QStyle::State_None);
1214 }
1215
1216 option->menuHasCheckableItems = d->hasCheckableItems;
1217 if (!action->isCheckable()) {
1218 option->checkType = QStyleOptionMenuItem::NotCheckable;
1219 } else {
1220 option->checkType = (action->actionGroup() && action->actionGroup()->isExclusive())
1221 ? QStyleOptionMenuItem::Exclusive : QStyleOptionMenuItem::NonExclusive;
1222 option->checked = action->isChecked();
1223 }
1224 if (action->menu())
1225 option->menuItemType = QStyleOptionMenuItem::SubMenu;
1226 else if (action->isSeparator())
1227 option->menuItemType = QStyleOptionMenuItem::Separator;
1228 else if (d->defaultAction == action)
1229 option->menuItemType = QStyleOptionMenuItem::DefaultItem;
1230 else
1231 option->menuItemType = QStyleOptionMenuItem::Normal;
1232 if (action->isIconVisibleInMenu())
1233 option->icon = action->icon();
1234 QString textAndAccel = action->text();
1235#ifndef QT_NO_SHORTCUT
1236 if (textAndAccel.indexOf(QLatin1Char('\t')) == -1) {
1237 QKeySequence seq = action->shortcut();
1238 if (!seq.isEmpty())
1239 textAndAccel += QLatin1Char('\t') + QString(seq);
1240 }
1241#endif
1242 option->text = textAndAccel;
1243 option->tabWidth = d->tabWidth;
1244 option->maxIconWidth = d->maxIconWidth;
1245 option->menuRect = rect();
1246}
1247
1248/*!
1249 \class QMenu
1250 \brief The QMenu class provides a menu widget for use in menu
1251 bars, context menus, and other popup menus.
1252
1253 \ingroup mainwindow-classes
1254 \ingroup basicwidgets
1255
1256
1257 A menu widget is a selection menu. It can be either a pull-down
1258 menu in a menu bar or a standalone context menu. Pull-down menus
1259 are shown by the menu bar when the user clicks on the respective
1260 item or presses the specified shortcut key. Use
1261 QMenuBar::addMenu() to insert a menu into a menu bar. Context
1262 menus are usually invoked by some special keyboard key or by
1263 right-clicking. They can be executed either asynchronously with
1264 popup() or synchronously with exec(). Menus can also be invoked in
1265 response to button presses; these are just like context menus
1266 except for how they are invoked.
1267
1268 \raw HTML
1269 <table align="center" cellpadding="0">
1270 <tr>
1271 <td>
1272 \endraw
1273 \inlineimage plastique-menu.png
1274 \raw HTML
1275 </td>
1276 <td>
1277 \endraw
1278 \inlineimage windowsxp-menu.png
1279 \raw HTML
1280 </td>
1281 <td>
1282 \endraw
1283 \inlineimage macintosh-menu.png
1284 \raw HTML
1285 </td>
1286
1287 </tr>
1288 <tr>
1289 <td colspan="3">
1290 \endraw
1291 A menu shown in \l{Plastique Style Widget Gallery}{Plastique widget style},
1292 \l{Windows XP Style Widget Gallery}{Windows XP widget style},
1293 and \l{Macintosh Style Widget Gallery}{Macintosh widget style}.
1294 \raw HTML
1295 </td>
1296 </tr>
1297 </table>
1298 \endraw
1299
1300 \section1 Actions
1301
1302 A menu consists of a list of action items. Actions are added with
1303 the addAction(), addActions() and insertAction() functions. An action
1304 is represented vertically and rendered by QStyle. In addition, actions
1305 can have a text label, an optional icon drawn on the very left side,
1306 and shortcut key sequence such as "Ctrl+X".
1307
1308 The existing actions held by a menu can be found with actions().
1309
1310 There are four kinds of action items: separators, actions that
1311 show a submenu, widgets, and actions that perform an action.
1312 Separators are inserted with addSeparator(), submenus with addMenu(),
1313 and all other items are considered action items.
1314
1315 When inserting action items you usually specify a receiver and a
1316 slot. The receiver will be notifed whenever the item is
1317 \l{QAction::triggered()}{triggered()}. In addition, QMenu provides
1318 two signals, activated() and highlighted(), which signal the
1319 QAction that was triggered from the menu.
1320
1321 You clear a menu with clear() and remove individual action items
1322 with removeAction().
1323
1324 A QMenu can also provide a tear-off menu. A tear-off menu is a
1325 top-level window that contains a copy of the menu. This makes it
1326 possible for the user to "tear off" frequently used menus and
1327 position them in a convenient place on the screen. If you want
1328 this functionality for a particular menu, insert a tear-off handle
1329 with setTearOffEnabled(). When using tear-off menus, bear in mind
1330 that the concept isn't typically used on Microsoft Windows so
1331 some users may not be familiar with it. Consider using a QToolBar
1332 instead.
1333
1334 Widgets can be inserted into menus with the QWidgetAction class.
1335 Instances of this class are used to hold widgets, and are inserted
1336 into menus with the addAction() overload that takes a QAction.
1337
1338 Conversely, actions can be added to widgets with the addAction(),
1339 addActions() and insertAction() functions.
1340
1341 \section1 QMenu on Qt for Windows CE
1342
1343 If a menu is integrated into the native menubar on Windows Mobile we
1344 do not support the signals: aboutToHide (), aboutToShow () and hovered ().
1345 It is not possible to display an icon in a native menu on Windows Mobile.
1346
1347 \section1 QMenu on Mac OS X with Qt build against Cocoa
1348
1349 QMenu can be inserted only once in a menu/menubar. Subsequent insertions will
1350 have no effect or will result in a disabled menu item.
1351
1352 See the \l{mainwindows/menus}{Menus} example for an example of how
1353 to use QMenuBar and QMenu in your application.
1354
1355 \bold{Important inherited functions:} addAction(), removeAction(), clear(),
1356 addSeparator(), and addMenu().
1357
1358 \sa QMenuBar, {fowler}{GUI Design Handbook: Menu, Drop-Down and Pop-Up},
1359 {Application Example}, {Menus Example}, {Recent Files Example}
1360*/
1361
1362
1363/*!
1364 Constructs a menu with parent \a parent.
1365
1366 Although a popup menu is always a top-level widget, if a parent is
1367 passed the popup menu will be deleted when that parent is
1368 destroyed (as with any other QObject).
1369*/
1370QMenu::QMenu(QWidget *parent)
1371 : QWidget(*new QMenuPrivate, parent, Qt::Popup)
1372{
1373 Q_D(QMenu);
1374 d->init();
1375}
1376
1377/*!
1378 Constructs a menu with a \a title and a \a parent.
1379
1380 Although a popup menu is always a top-level widget, if a parent is
1381 passed the popup menu will be deleted when that parent is
1382 destroyed (as with any other QObject).
1383
1384 \sa title
1385*/
1386QMenu::QMenu(const QString &title, QWidget *parent)
1387 : QWidget(*new QMenuPrivate, parent, Qt::Popup)
1388{
1389 Q_D(QMenu);
1390 d->init();
1391 d->menuAction->setText(title);
1392}
1393
1394/*! \internal
1395 */
1396QMenu::QMenu(QMenuPrivate &dd, QWidget *parent)
1397 : QWidget(dd, parent, Qt::Popup)
1398{
1399 Q_D(QMenu);
1400 d->init();
1401}
1402
1403/*!
1404 Destroys the menu.
1405*/
1406QMenu::~QMenu()
1407{
1408 Q_D(QMenu);
1409 QHash<QAction *, QWidget *>::iterator it = d->widgetItems.begin();
1410 for (; it != d->widgetItems.end(); ++it) {
1411 if (QWidget *widget = it.value()) {
1412 QWidgetAction *action = static_cast<QWidgetAction *>(it.key());
1413 action->releaseWidget(widget);
1414 *it = 0;
1415 }
1416 }
1417
1418 if (d->eventLoop)
1419 d->eventLoop->exit();
1420 hideTearOffMenu();
1421}
1422
1423/*!
1424 \overload
1425
1426 This convenience function creates a new action with \a text.
1427 The function adds the newly created action to the menu's
1428 list of actions, and returns it.
1429
1430 \sa QWidget::addAction()
1431*/
1432QAction *QMenu::addAction(const QString &text)
1433{
1434 QAction *ret = new QAction(text, this);
1435 addAction(ret);
1436 return ret;
1437}
1438
1439/*!
1440 \overload
1441
1442 This convenience function creates a new action with an \a icon
1443 and some \a text. The function adds the newly created action to
1444 the menu's list of actions, and returns it.
1445
1446 \sa QWidget::addAction()
1447*/
1448QAction *QMenu::addAction(const QIcon &icon, const QString &text)
1449{
1450 QAction *ret = new QAction(icon, text, this);
1451 addAction(ret);
1452 return ret;
1453}
1454
1455/*!
1456 \overload
1457
1458 This convenience function creates a new action with the text \a
1459 text and an optional shortcut \a shortcut. The action's
1460 \l{QAction::triggered()}{triggered()} signal is connected to the
1461 \a receiver's \a member slot. The function adds the newly created
1462 action to the menu's list of actions and returns it.
1463
1464 \sa QWidget::addAction()
1465*/
1466QAction *QMenu::addAction(const QString &text, const QObject *receiver, const char* member, const QKeySequence &shortcut)
1467{
1468 QAction *action = new QAction(text, this);
1469#ifdef QT_NO_SHORTCUT
1470 Q_UNUSED(shortcut);
1471#else
1472 action->setShortcut(shortcut);
1473#endif
1474 QObject::connect(action, SIGNAL(triggered(bool)), receiver, member);
1475 addAction(action);
1476 return action;
1477}
1478
1479/*!
1480 \overload
1481
1482 This convenience function creates a new action with an \a icon and
1483 some \a text and an optional shortcut \a shortcut. The action's
1484 \l{QAction::triggered()}{triggered()} signal is connected to the
1485 \a member slot of the \a receiver object. The function adds the
1486 newly created action to the menu's list of actions, and returns it.
1487
1488 \sa QWidget::addAction()
1489*/
1490QAction *QMenu::addAction(const QIcon &icon, const QString &text, const QObject *receiver,
1491 const char* member, const QKeySequence &shortcut)
1492{
1493 QAction *action = new QAction(icon, text, this);
1494#ifdef QT_NO_SHORTCUT
1495 Q_UNUSED(shortcut);
1496#else
1497 action->setShortcut(shortcut);
1498#endif
1499 QObject::connect(action, SIGNAL(triggered(bool)), receiver, member);
1500 addAction(action);
1501 return action;
1502}
1503
1504/*!
1505 This convenience function adds \a menu as a submenu to this menu.
1506 It returns \a menu's menuAction(). This menu does not take
1507 ownership of \a menu.
1508
1509 \sa QWidget::addAction() QMenu::menuAction()
1510*/
1511QAction *QMenu::addMenu(QMenu *menu)
1512{
1513 QAction *action = menu->menuAction();
1514 addAction(action);
1515 return action;
1516}
1517
1518/*!
1519 Appends a new QMenu with \a title to the menu. The menu
1520 takes ownership of the menu. Returns the new menu.
1521
1522 \sa QWidget::addAction() QMenu::menuAction()
1523*/
1524QMenu *QMenu::addMenu(const QString &title)
1525{
1526 QMenu *menu = new QMenu(title, this);
1527 addAction(menu->menuAction());
1528 return menu;
1529}
1530
1531/*!
1532 Appends a new QMenu with \a icon and \a title to the menu. The menu
1533 takes ownership of the menu. Returns the new menu.
1534
1535 \sa QWidget::addAction() QMenu::menuAction()
1536*/
1537QMenu *QMenu::addMenu(const QIcon &icon, const QString &title)
1538{
1539 QMenu *menu = new QMenu(title, this);
1540 menu->setIcon(icon);
1541 addAction(menu->menuAction());
1542 return menu;
1543}
1544
1545/*!
1546 This convenience function creates a new separator action, i.e. an
1547 action with QAction::isSeparator() returning true, and adds the new
1548 action to this menu's list of actions. It returns the newly
1549 created action.
1550
1551 \sa QWidget::addAction()
1552*/
1553QAction *QMenu::addSeparator()
1554{
1555 QAction *action = new QAction(this);
1556 action->setSeparator(true);
1557 addAction(action);
1558 return action;
1559}
1560
1561/*!
1562 This convenience function inserts \a menu before action \a before
1563 and returns the menus menuAction().
1564
1565 \sa QWidget::insertAction(), addMenu()
1566*/
1567QAction *QMenu::insertMenu(QAction *before, QMenu *menu)
1568{
1569 QAction *action = menu->menuAction();
1570 insertAction(before, action);
1571 return action;
1572}
1573
1574/*!
1575 This convenience function creates a new separator action, i.e. an
1576 action with QAction::isSeparator() returning true. The function inserts
1577 the newly created action into this menu's list of actions before
1578 action \a before and returns it.
1579
1580 \sa QWidget::insertAction(), addSeparator()
1581*/
1582QAction *QMenu::insertSeparator(QAction *before)
1583{
1584 QAction *action = new QAction(this);
1585 action->setSeparator(true);
1586 insertAction(before, action);
1587 return action;
1588}
1589
1590/*!
1591 This will set the default action to \a act. The default action may
1592 have a visual queue depending on the current QStyle. A default
1593 action is usually meant to indicate what will defaultly happen on a
1594 drop, as shown in a context menu.
1595
1596 \sa defaultAction()
1597*/
1598void QMenu::setDefaultAction(QAction *act)
1599{
1600 d_func()->defaultAction = act;
1601}
1602
1603/*!
1604 Returns the current default action.
1605
1606 \sa setDefaultAction()
1607*/
1608QAction *QMenu::defaultAction() const
1609{
1610 return d_func()->defaultAction;
1611}
1612
1613/*!
1614 \property QMenu::tearOffEnabled
1615 \brief whether the menu supports being torn off
1616
1617 When true, the menu contains a special tear-off item (often shown as a dashed
1618 line at the top of the menu) that creates a copy of the menu when it is
1619 triggered.
1620
1621 This "torn-off" copy lives in a separate window. It contains the same menu
1622 items as the original menu, with the exception of the tear-off handle.
1623
1624 By default, this property is false.
1625*/
1626void QMenu::setTearOffEnabled(bool b)
1627{
1628 Q_D(QMenu);
1629 if (d->tearoff == b)
1630 return;
1631 if (!b)
1632 hideTearOffMenu();
1633 d->tearoff = b;
1634
1635 d->itemsDirty = true;
1636 if (isVisible())
1637 resize(sizeHint());
1638}
1639
1640bool QMenu::isTearOffEnabled() const
1641{
1642 return d_func()->tearoff;
1643}
1644
1645/*!
1646 When a menu is torn off a second menu is shown to display the menu
1647 contents in a new window. When the menu is in this mode and the menu
1648 is visible returns true; otherwise false.
1649
1650 \sa hideTearOffMenu() isTearOffEnabled()
1651*/
1652bool QMenu::isTearOffMenuVisible() const
1653{
1654 if (d_func()->tornPopup)
1655 return d_func()->tornPopup->isVisible();
1656 return false;
1657}
1658
1659/*!
1660 This function will forcibly hide the torn off menu making it
1661 disappear from the users desktop.
1662
1663 \sa isTearOffMenuVisible() isTearOffEnabled()
1664*/
1665void QMenu::hideTearOffMenu()
1666{
1667 if (QWidget *w = d_func()->tornPopup)
1668 w->close();
1669}
1670
1671
1672/*!
1673 Sets the currently highlighted action to \a act.
1674*/
1675void QMenu::setActiveAction(QAction *act)
1676{
1677 Q_D(QMenu);
1678 d->setCurrentAction(act, 0);
1679 if (d->scroll)
1680 d->scrollMenu(act, QMenuPrivate::QMenuScroller::ScrollCenter);
1681}
1682
1683
1684/*!
1685 Returns the currently highlighted action, or 0 if no
1686 action is currently highlighted.
1687*/
1688QAction *QMenu::activeAction() const
1689{
1690 return d_func()->currentAction;
1691}
1692
1693/*!
1694 \since 4.2
1695
1696 Returns true if there are no visible actions inserted into the menu, false
1697 otherwise.
1698
1699 \sa QWidget::actions()
1700*/
1701
1702bool QMenu::isEmpty() const
1703{
1704 bool ret = true;
1705 for(int i = 0; ret && i < actions().count(); ++i) {
1706 const QAction *action = actions().at(i);
1707 if (!action->isSeparator() && action->isVisible()) {
1708 ret = false;
1709 }
1710 }
1711 return ret;
1712}
1713
1714/*!
1715 Removes all the menu's actions. Actions owned by the menu and not
1716 shown in any other widget are deleted.
1717
1718 \sa removeAction()
1719*/
1720void QMenu::clear()
1721{
1722 QList<QAction*> acts = actions();
1723 for(int i = 0; i < acts.size(); i++) {
1724 removeAction(acts[i]);
1725 if (acts[i]->parent() == this && acts[i]->d_func()->widgets.isEmpty())
1726 delete acts[i];
1727 }
1728}
1729
1730/*!
1731 If a menu does not fit on the screen it lays itself out so that it
1732 does fit. It is style dependent what layout means (for example, on
1733 Windows it will use multiple columns).
1734
1735 This functions returns the number of columns necessary.
1736*/
1737int QMenu::columnCount() const
1738{
1739 return d_func()->ncols;
1740}
1741
1742/*!
1743 Returns the item at \a pt; returns 0 if there is no item there.
1744*/
1745QAction *QMenu::actionAt(const QPoint &pt) const
1746{
1747 if (QAction *ret = d_func()->actionAt(pt))
1748 return ret;
1749 return 0;
1750}
1751
1752/*!
1753 Returns the geometry of action \a act.
1754*/
1755QRect QMenu::actionGeometry(QAction *act) const
1756{
1757 return d_func()->actionRect(act);
1758}
1759
1760/*!
1761 \reimp
1762*/
1763QSize QMenu::sizeHint() const
1764{
1765 Q_D(const QMenu);
1766 d->updateActionRects();
1767
1768 QSize s;
1769 for (int i = 0; i < d->actionRects.count(); ++i) {
1770 const QRect &rect = d->actionRects.at(i);
1771 if (rect.isNull())
1772 continue;
1773 if (rect.bottom() >= s.height())
1774 s.setHeight(rect.y() + rect.height());
1775 if (rect.right() >= s.width())
1776 s.setWidth(rect.x() + rect.width());
1777 }
1778 // Note that the action rects calculated above already include
1779 // the top and left margins, so we only need to add margins for
1780 // the bottom and right.
1781 QStyleOption opt(0);
1782 opt.init(this);
1783 const int fw = style()->pixelMetric(QStyle::PM_MenuPanelWidth, &opt, this);
1784 s.rwidth() += style()->pixelMetric(QStyle::PM_MenuHMargin, &opt, this) + fw + d->rightmargin;
1785 s.rheight() += style()->pixelMetric(QStyle::PM_MenuVMargin, &opt, this) + fw + d->bottommargin;
1786
1787 return style()->sizeFromContents(QStyle::CT_Menu, &opt,
1788 s.expandedTo(QApplication::globalStrut()), this);
1789}
1790
1791/*!
1792 Displays the menu so that the action \a atAction will be at the
1793 specified \e global position \a p. To translate a widget's local
1794 coordinates into global coordinates, use QWidget::mapToGlobal().
1795
1796 When positioning a menu with exec() or popup(), bear in mind that
1797 you cannot rely on the menu's current size(). For performance
1798 reasons, the menu adapts its size only when necessary, so in many
1799 cases, the size before and after the show is different. Instead,
1800 use sizeHint() which calculates the proper size depending on the
1801 menu's current contents.
1802
1803 \sa QWidget::mapToGlobal(), exec()
1804*/
1805void QMenu::popup(const QPoint &p, QAction *atAction)
1806{
1807 Q_D(QMenu);
1808 if (d->scroll) { //reset scroll state from last popup
1809 d->scroll->scrollOffset = 0;
1810 d->scroll->scrollFlags = QMenuPrivate::QMenuScroller::ScrollNone;
1811 }
1812 d->tearoffHighlighted = 0;
1813 d->motions = 0;
1814 d->doChildEffects = true;
1815 d->updateLayoutDirection();
1816
1817#ifndef QT_NO_MENUBAR
1818 // if this menu is part of a chain attached to a QMenuBar, set the
1819 // _NET_WM_WINDOW_TYPE_DROPDOWN_MENU X11 window type
1820 setAttribute(Qt::WA_X11NetWmWindowTypeDropDownMenu, qobject_cast<QMenuBar *>(d->topCausedWidget()) != 0);
1821#endif
1822
1823 ensurePolished(); // Get the right font
1824 emit aboutToShow();
1825 const bool actionListChanged = d->itemsDirty;
1826 d->updateActionRects();
1827 QPoint pos;
1828 QPushButton *causedButton = qobject_cast<QPushButton*>(d->causedPopup.widget);
1829 if (actionListChanged && causedButton)
1830 pos = QPushButtonPrivate::get(causedButton)->adjustedMenuPosition();
1831 else
1832 pos = p;
1833
1834 QSize size = sizeHint();
1835 QRect screen;
1836#ifndef QT_NO_GRAPHICSVIEW
1837 bool isEmbedded = d->nearestGraphicsProxyWidget(this);
1838 if (isEmbedded)
1839 screen = d->popupGeometry(this);
1840 else
1841#endif
1842 screen = d->popupGeometry(QApplication::desktop()->screenNumber(p));
1843
1844 const int desktopFrame = style()->pixelMetric(QStyle::PM_MenuDesktopFrameWidth, 0, this);
1845 bool adjustToDesktop = !window()->testAttribute(Qt::WA_DontShowOnScreen);
1846#ifdef QT_KEYPAD_NAVIGATION
1847 if (!atAction && QApplication::keypadNavigationEnabled()) {
1848 // Try to have one item activated
1849 if (d->defaultAction && d->defaultAction->isEnabled()) {
1850 atAction = d->defaultAction;
1851 // TODO: This works for first level menus, not yet sub menus
1852 } else {
1853 foreach (QAction *action, d->actions)
1854 if (action->isEnabled()) {
1855 atAction = action;
1856 break;
1857 }
1858 }
1859 d->currentAction = atAction;
1860 }
1861#endif
1862 if (d->ncols > 1) {
1863 pos.setY(screen.top()+desktopFrame);
1864 } else if (atAction) {
1865 for(int i = 0, above_height = 0; i < d->actions.count(); i++) {
1866 QAction *action = d->actions.at(i);
1867 if (action == atAction) {
1868 int newY = pos.y() - above_height;
1869 if (d->scroll && newY < desktopFrame) {
1870 d->scroll->scrollFlags = d->scroll->scrollFlags
1871 | QMenuPrivate::QMenuScroller::ScrollUp;
1872 d->scroll->scrollOffset = newY;
1873 newY = desktopFrame;
1874 }
1875 pos.setY(newY);
1876
1877 if (d->scroll && d->scroll->scrollFlags != QMenuPrivate::QMenuScroller::ScrollNone
1878 && !style()->styleHint(QStyle::SH_Menu_FillScreenWithScroll, 0, this)) {
1879 int below_height = above_height + d->scroll->scrollOffset;
1880 for(int i2 = i; i2 < d->actionRects.count(); i2++)
1881 below_height += d->actionRects.at(i2).height();
1882 size.setHeight(below_height);
1883 }
1884 break;
1885 } else {
1886 above_height += d->actionRects.at(i).height();
1887 }
1888 }
1889 }
1890
1891 QPoint mouse = QCursor::pos();
1892 d->mousePopupPos = mouse;
1893 const bool snapToMouse = (QRect(p.x()-3, p.y()-3, 6, 6).contains(mouse));
1894
1895 if (adjustToDesktop) {
1896 //handle popup falling "off screen"
1897 if (isRightToLeft()) {
1898 if(snapToMouse) //position flowing left from the mouse
1899 pos.setX(mouse.x()-size.width());
1900
1901#ifndef QT_NO_MENUBAR
1902 //if in a menubar, it should be right-aligned
1903 if (qobject_cast<QMenuBar*>(d->causedPopup.widget))
1904 pos.rx() -= size.width();
1905#endif //QT_NO_MENUBAR
1906
1907 if (pos.x() < screen.left()+desktopFrame)
1908 pos.setX(qMax(p.x(), screen.left()+desktopFrame));
1909 if (pos.x()+size.width()-1 > screen.right()-desktopFrame)
1910 pos.setX(qMax(p.x()-size.width(), screen.right()-desktopFrame-size.width()+1));
1911 } else {
1912 if (pos.x()+size.width()-1 > screen.right()-desktopFrame)
1913 pos.setX(screen.right()-desktopFrame-size.width()+1);
1914 if (pos.x() < screen.left()+desktopFrame)
1915 pos.setX(screen.left() + desktopFrame);
1916 }
1917 if (pos.y() + size.height() - 1 > screen.bottom() - desktopFrame) {
1918 if(snapToMouse)
1919 pos.setY(qMin(mouse.y() - (size.height() + desktopFrame), screen.bottom()-desktopFrame-size.height()+1));
1920 else
1921 pos.setY(qMax(p.y() - (size.height() + desktopFrame), screen.bottom()-desktopFrame-size.height()+1));
1922 } else if (pos.y() < screen.top() + desktopFrame) {
1923 pos.setY(screen.top() + desktopFrame);
1924 }
1925
1926 if (pos.y() < screen.top() + desktopFrame)
1927 pos.setY(screen.top() + desktopFrame);
1928 if (pos.y()+size.height()-1 > screen.bottom() - desktopFrame) {
1929 if (d->scroll) {
1930 d->scroll->scrollFlags |= uint(QMenuPrivate::QMenuScroller::ScrollDown);
1931 int y = qMax(screen.y(),pos.y());
1932 size.setHeight(screen.bottom()-(desktopFrame*2)-y);
1933 } else {
1934 // Too big for screen, bias to see bottom of menu (for some reason)
1935 pos.setY(screen.bottom()-size.height()+1);
1936 }
1937 }
1938 }
1939 setGeometry(QRect(pos, size));
1940#ifndef QT_NO_EFFECTS
1941 int hGuess = isRightToLeft() ? QEffects::LeftScroll : QEffects::RightScroll;
1942 int vGuess = QEffects::DownScroll;
1943 if (isRightToLeft()) {
1944 if ((snapToMouse && (pos.x() + size.width()/2 > mouse.x())) ||
1945 (qobject_cast<QMenu*>(d->causedPopup.widget) && pos.x() + size.width()/2 > d->causedPopup.widget->x()))
1946 hGuess = QEffects::RightScroll;
1947 } else {
1948 if ((snapToMouse && (pos.x() + size.width()/2 < mouse.x())) ||
1949 (qobject_cast<QMenu*>(d->causedPopup.widget) && pos.x() + size.width()/2 < d->causedPopup.widget->x()))
1950 hGuess = QEffects::LeftScroll;
1951 }
1952
1953#ifndef QT_NO_MENUBAR
1954 if ((snapToMouse && (pos.y() + size.height()/2 < mouse.y())) ||
1955 (qobject_cast<QMenuBar*>(d->causedPopup.widget) &&
1956 pos.y() + size.width()/2 < d->causedPopup.widget->mapToGlobal(d->causedPopup.widget->pos()).y()))
1957 vGuess = QEffects::UpScroll;
1958#endif
1959 if (QApplication::isEffectEnabled(Qt::UI_AnimateMenu)) {
1960 bool doChildEffects = true;
1961#ifndef QT_NO_MENUBAR
1962 if (QMenuBar *mb = qobject_cast<QMenuBar*>(d->causedPopup.widget)) {
1963 doChildEffects = mb->d_func()->doChildEffects;
1964 mb->d_func()->doChildEffects = false;
1965 } else
1966#endif
1967 if (QMenu *m = qobject_cast<QMenu*>(d->causedPopup.widget)) {
1968 doChildEffects = m->d_func()->doChildEffects;
1969 m->d_func()->doChildEffects = false;
1970 }
1971
1972 if (doChildEffects) {
1973 if (QApplication::isEffectEnabled(Qt::UI_FadeMenu))
1974 qFadeEffect(this);
1975 else if (d->causedPopup.widget)
1976 qScrollEffect(this, qobject_cast<QMenu*>(d->causedPopup.widget) ? hGuess : vGuess);
1977 else
1978 qScrollEffect(this, hGuess | vGuess);
1979 } else {
1980 // kill any running effect
1981 qFadeEffect(0);
1982 qScrollEffect(0);
1983
1984 show();
1985 }
1986 } else
1987#endif
1988 {
1989 show();
1990 }
1991
1992#ifndef QT_NO_ACCESSIBILITY
1993 QAccessible::updateAccessibility(this, 0, QAccessible::PopupMenuStart);
1994#endif
1995}
1996
1997/*!
1998 Executes this menu synchronously.
1999
2000 This is equivalent to \c{exec(pos())}.
2001
2002 This returns the triggered QAction in either the popup menu or one
2003 of its submenus, or 0 if no item was triggered (normally because
2004 the user pressed Esc).
2005
2006 In most situations you'll want to specify the position yourself,
2007 for example, the current mouse position:
2008 \snippet doc/src/snippets/code/src_gui_widgets_qmenu.cpp 0
2009 or aligned to a widget:
2010 \snippet doc/src/snippets/code/src_gui_widgets_qmenu.cpp 1
2011 or in reaction to a QMouseEvent *e:
2012 \snippet doc/src/snippets/code/src_gui_widgets_qmenu.cpp 2
2013*/
2014QAction *QMenu::exec()
2015{
2016 return exec(pos());
2017}
2018
2019
2020/*!
2021 \overload
2022
2023 Executes this menu synchronously.
2024
2025 Pops up the menu so that the action \a action will be at the
2026 specified \e global position \a p. To translate a widget's local
2027 coordinates into global coordinates, use QWidget::mapToGlobal().
2028
2029 This returns the triggered QAction in either the popup menu or one
2030 of its submenus, or 0 if no item was triggered (normally because
2031 the user pressed Esc).
2032
2033 Note that all signals are emitted as usual. If you connect a
2034 QAction to a slot and call the menu's exec(), you get the result
2035 both via the signal-slot connection and in the return value of
2036 exec().
2037
2038 Common usage is to position the menu at the current mouse
2039 position:
2040 \snippet doc/src/snippets/code/src_gui_widgets_qmenu.cpp 3
2041 or aligned to a widget:
2042 \snippet doc/src/snippets/code/src_gui_widgets_qmenu.cpp 4
2043 or in reaction to a QMouseEvent *e:
2044 \snippet doc/src/snippets/code/src_gui_widgets_qmenu.cpp 5
2045
2046 When positioning a menu with exec() or popup(), bear in mind that
2047 you cannot rely on the menu's current size(). For performance
2048 reasons, the menu adapts its size only when necessary. So in many
2049 cases, the size before and after the show is different. Instead,
2050 use sizeHint() which calculates the proper size depending on the
2051 menu's current contents.
2052
2053 \sa popup(), QWidget::mapToGlobal()
2054*/
2055QAction *QMenu::exec(const QPoint &p, QAction *action)
2056{
2057 Q_D(QMenu);
2058 createWinId();
2059 QEventLoop eventLoop;
2060 d->eventLoop = &eventLoop;
2061 popup(p, action);
2062
2063 QPointer<QObject> guard = this;
2064 (void) eventLoop.exec();
2065 if (guard.isNull())
2066 return 0;
2067
2068 action = d->syncAction;
2069 d->syncAction = 0;
2070 d->eventLoop = 0;
2071 return action;
2072}
2073
2074/*!
2075 \overload
2076
2077 Executes a menu synchronously.
2078
2079 The menu's actions are specified by the list of \a actions. The menu will
2080 pop up so that the specified action, \a at, appears at global position \a
2081 pos. If \a at is not specified then the menu appears at position \a
2082 pos. \a parent is the menu's parent widget; specifying the parent will
2083 provide context when \a pos alone is not enough to decide where the menu
2084 should go (e.g., with multiple desktops or when the parent is embedded in
2085 QGraphicsView).
2086
2087 The function returns the triggered QAction in either the popup
2088 menu or one of its submenus, or 0 if no item was triggered
2089 (normally because the user pressed Esc).
2090
2091 This is equivalent to:
2092 \snippet doc/src/snippets/code/src_gui_widgets_qmenu.cpp 6
2093
2094 \sa popup(), QWidget::mapToGlobal()
2095*/
2096QAction *QMenu::exec(QList<QAction*> actions, const QPoint &pos, QAction *at, QWidget *parent)
2097{
2098 QMenu menu(parent);
2099 menu.addActions(actions);
2100 return menu.exec(pos, at);
2101}
2102
2103/*!
2104 \overload
2105
2106 Executes a menu synchronously.
2107
2108 The menu's actions are specified by the list of \a actions. The menu
2109 will pop up so that the specified action, \a at, appears at global
2110 position \a pos. If \a at is not specified then the menu appears
2111 at position \a pos.
2112
2113 The function returns the triggered QAction in either the popup
2114 menu or one of its submenus, or 0 if no item was triggered
2115 (normally because the user pressed Esc).
2116
2117 This is equivalent to:
2118 \snippet doc/src/snippets/code/src_gui_widgets_qmenu.cpp 6
2119
2120 \sa popup(), QWidget::mapToGlobal()
2121*/
2122QAction *QMenu::exec(QList<QAction*> actions, const QPoint &pos, QAction *at)
2123{
2124 // ### Qt 5: merge
2125 return exec(actions, pos, at, 0);
2126}
2127
2128/*!
2129 \reimp
2130*/
2131void QMenu::hideEvent(QHideEvent *)
2132{
2133 Q_D(QMenu);
2134 emit aboutToHide();
2135 if (d->eventLoop)
2136 d->eventLoop->exit();
2137 d->setCurrentAction(0);
2138#ifndef QT_NO_ACCESSIBILITY
2139 QAccessible::updateAccessibility(this, 0, QAccessible::PopupMenuEnd);
2140#endif
2141#ifndef QT_NO_MENUBAR
2142 if (QMenuBar *mb = qobject_cast<QMenuBar*>(d->causedPopup.widget))
2143 mb->d_func()->setCurrentAction(0);
2144#endif
2145 d->mouseDown = 0;
2146 d->hasHadMouse = false;
2147 d->causedPopup.widget = 0;
2148 d->causedPopup.action = 0;
2149 if (d->scroll)
2150 d->scroll->scrollTimer.stop(); //make sure the timer stops
2151}
2152
2153/*!
2154 \reimp
2155*/
2156void QMenu::paintEvent(QPaintEvent *e)
2157{
2158 Q_D(QMenu);
2159 d->updateActionRects();
2160 QPainter p(this);
2161 QRegion emptyArea = QRegion(rect());
2162
2163 QStyleOptionMenuItem menuOpt;
2164 menuOpt.initFrom(this);
2165 menuOpt.state = QStyle::State_None;
2166 menuOpt.checkType = QStyleOptionMenuItem::NotCheckable;
2167 menuOpt.maxIconWidth = 0;
2168 menuOpt.tabWidth = 0;
2169 style()->drawPrimitive(QStyle::PE_PanelMenu, &menuOpt, &p, this);
2170
2171 //draw the items that need updating..
2172 for (int i = 0; i < d->actions.count(); ++i) {
2173 QAction *action = d->actions.at(i);
2174 QRect adjustedActionRect = d->actionRects.at(i);
2175 if (!e->rect().intersects(adjustedActionRect)
2176 || d->widgetItems.value(action))
2177 continue;
2178 //set the clip region to be extra safe (and adjust for the scrollers)
2179 QRegion adjustedActionReg(adjustedActionRect);
2180 emptyArea -= adjustedActionReg;
2181 p.setClipRegion(adjustedActionReg);
2182
2183 QStyleOptionMenuItem opt;
2184 initStyleOption(&opt, action);
2185 opt.rect = adjustedActionRect;
2186 style()->drawControl(QStyle::CE_MenuItem, &opt, &p, this);
2187 }
2188
2189 const int fw = style()->pixelMetric(QStyle::PM_MenuPanelWidth, 0, this);
2190 //draw the scroller regions..
2191 if (d->scroll) {
2192 menuOpt.menuItemType = QStyleOptionMenuItem::Scroller;
2193 menuOpt.state |= QStyle::State_Enabled;
2194 if (d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp) {
2195 menuOpt.rect.setRect(fw, fw, width() - (fw * 2), d->scrollerHeight());
2196 emptyArea -= QRegion(menuOpt.rect);
2197 p.setClipRect(menuOpt.rect);
2198 style()->drawControl(QStyle::CE_MenuScroller, &menuOpt, &p, this);
2199 }
2200 if (d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollDown) {
2201 menuOpt.rect.setRect(fw, height() - d->scrollerHeight() - fw, width() - (fw * 2),
2202 d->scrollerHeight());
2203 emptyArea -= QRegion(menuOpt.rect);
2204 menuOpt.state |= QStyle::State_DownArrow;
2205 p.setClipRect(menuOpt.rect);
2206 style()->drawControl(QStyle::CE_MenuScroller, &menuOpt, &p, this);
2207 }
2208 }
2209 //paint the tear off..
2210 if (d->tearoff) {
2211 menuOpt.menuItemType = QStyleOptionMenuItem::TearOff;
2212 menuOpt.rect.setRect(fw, fw, width() - (fw * 2),
2213 style()->pixelMetric(QStyle::PM_MenuTearoffHeight, 0, this));
2214 if (d->scroll && d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp)
2215 menuOpt.rect.translate(0, d->scrollerHeight());
2216 emptyArea -= QRegion(menuOpt.rect);
2217 p.setClipRect(menuOpt.rect);
2218 menuOpt.state = QStyle::State_None;
2219 if (d->tearoffHighlighted)
2220 menuOpt.state |= QStyle::State_Selected;
2221 style()->drawControl(QStyle::CE_MenuTearoff, &menuOpt, &p, this);
2222 }
2223 //draw border
2224 if (fw) {
2225 QRegion borderReg;
2226 borderReg += QRect(0, 0, fw, height()); //left
2227 borderReg += QRect(width()-fw, 0, fw, height()); //right
2228 borderReg += QRect(0, 0, width(), fw); //top
2229 borderReg += QRect(0, height()-fw, width(), fw); //bottom
2230 p.setClipRegion(borderReg);
2231 emptyArea -= borderReg;
2232 QStyleOptionFrame frame;
2233 frame.rect = rect();
2234 frame.palette = palette();
2235 frame.state = QStyle::State_None;
2236 frame.lineWidth = style()->pixelMetric(QStyle::PM_MenuPanelWidth);
2237 frame.midLineWidth = 0;
2238 style()->drawPrimitive(QStyle::PE_FrameMenu, &frame, &p, this);
2239 }
2240
2241 //finally the rest of the space
2242 p.setClipRegion(emptyArea);
2243 menuOpt.state = QStyle::State_None;
2244 menuOpt.menuItemType = QStyleOptionMenuItem::EmptyArea;
2245 menuOpt.checkType = QStyleOptionMenuItem::NotCheckable;
2246 menuOpt.rect = rect();
2247 menuOpt.menuRect = rect();
2248 style()->drawControl(QStyle::CE_MenuEmptyArea, &menuOpt, &p, this);
2249}
2250
2251#ifndef QT_NO_WHEELEVENT
2252/*!
2253 \reimp
2254*/
2255void QMenu::wheelEvent(QWheelEvent *e)
2256{
2257 Q_D(QMenu);
2258 if (d->scroll && rect().contains(e->pos()))
2259 d->scrollMenu(e->delta() > 0 ?
2260 QMenuPrivate::QMenuScroller::ScrollUp : QMenuPrivate::QMenuScroller::ScrollDown);
2261}
2262#endif
2263
2264/*!
2265 \reimp
2266*/
2267void QMenu::mousePressEvent(QMouseEvent *e)
2268{
2269 Q_D(QMenu);
2270 if (d->aboutToHide || d->mouseEventTaken(e))
2271 return;
2272 if (!rect().contains(e->pos())) {
2273 if (d->noReplayFor
2274 && QRect(d->noReplayFor->mapToGlobal(QPoint()), d->noReplayFor->size()).contains(e->globalPos()))
2275 setAttribute(Qt::WA_NoMouseReplay);
2276 if (d->eventLoop) // synchronous operation
2277 d->syncAction = 0;
2278 d->hideUpToMenuBar();
2279 return;
2280 }
2281 d->mouseDown = this;
2282
2283 QAction *action = d->actionAt(e->pos());
2284 d->setCurrentAction(action, 20);
2285 update();
2286}
2287
2288/*!
2289 \reimp
2290*/
2291void QMenu::mouseReleaseEvent(QMouseEvent *e)
2292{
2293 Q_D(QMenu);
2294 if (d->aboutToHide || d->mouseEventTaken(e))
2295 return;
2296 if(d->mouseDown != this) {
2297 d->mouseDown = 0;
2298 return;
2299 }
2300
2301 d->mouseDown = 0;
2302 d->setSyncAction();
2303 QAction *action = d->actionAt(e->pos());
2304
2305 if (action && action == d->currentAction) {
2306 if (action->menu())
2307 action->menu()->d_func()->setFirstActionActive();
2308 else {
2309#if defined(Q_WS_WIN)
2310 //On Windows only context menus can be activated with the right button
2311 if (e->button() == Qt::LeftButton || d->topCausedWidget() == 0)
2312#endif
2313 d->activateAction(action, QAction::Trigger);
2314 }
2315 } else if (d->hasMouseMoved(e->globalPos())) {
2316 d->hideUpToMenuBar();
2317 }
2318}
2319
2320/*!
2321 \reimp
2322*/
2323void QMenu::changeEvent(QEvent *e)
2324{
2325 Q_D(QMenu);
2326 if (e->type() == QEvent::StyleChange || e->type() == QEvent::FontChange ||
2327 e->type() == QEvent::LayoutDirectionChange) {
2328 d->itemsDirty = 1;
2329 setMouseTracking(style()->styleHint(QStyle::SH_Menu_MouseTracking, 0, this));
2330 if (isVisible())
2331 resize(sizeHint());
2332 if (!style()->styleHint(QStyle::SH_Menu_Scrollable, 0, this)) {
2333 delete d->scroll;
2334 d->scroll = 0;
2335 } else if (!d->scroll) {
2336 d->scroll = new QMenuPrivate::QMenuScroller;
2337 d->scroll->scrollFlags = QMenuPrivate::QMenuScroller::ScrollNone;
2338 }
2339 } else if (e->type() == QEvent::EnabledChange) {
2340 if (d->tornPopup) // torn-off menu
2341 d->tornPopup->setEnabled(isEnabled());
2342 d->menuAction->setEnabled(isEnabled());
2343#ifdef Q_WS_MAC
2344 if (d->mac_menu)
2345 d->setMacMenuEnabled(isEnabled());
2346#endif
2347 }
2348 QWidget::changeEvent(e);
2349}
2350
2351
2352/*!
2353 \reimp
2354*/
2355bool
2356QMenu::event(QEvent *e)
2357{
2358 Q_D(QMenu);
2359 switch (e->type()) {
2360 case QEvent::Polish:
2361 d->updateLayoutDirection();
2362 break;
2363 case QEvent::ShortcutOverride: {
2364 QKeyEvent *kev = static_cast<QKeyEvent*>(e);
2365 if (kev->key() == Qt::Key_Up || kev->key() == Qt::Key_Down
2366 || kev->key() == Qt::Key_Left || kev->key() == Qt::Key_Right
2367 || kev->key() == Qt::Key_Enter || kev->key() == Qt::Key_Return
2368 || kev->key() == Qt::Key_Escape) {
2369 e->accept();
2370 return true;
2371 }
2372 }
2373 break;
2374 case QEvent::KeyPress: {
2375 QKeyEvent *ke = (QKeyEvent*)e;
2376 if (ke->key() == Qt::Key_Tab || ke->key() == Qt::Key_Backtab) {
2377 keyPressEvent(ke);
2378 return true;
2379 }
2380 } break;
2381 case QEvent::ContextMenu:
2382 if(QMenuPrivate::menuDelayTimer.isActive()) {
2383 QMenuPrivate::menuDelayTimer.stop();
2384 internalDelayedPopup();
2385 }
2386 break;
2387 case QEvent::Resize: {
2388 QStyleHintReturnMask menuMask;
2389 QStyleOption option;
2390 option.initFrom(this);
2391 if (style()->styleHint(QStyle::SH_Menu_Mask, &option, this, &menuMask)) {
2392 setMask(menuMask.region);
2393 }
2394 d->itemsDirty = 1;
2395 d->updateActionRects();
2396 break; }
2397 case QEvent::Show:
2398 d->mouseDown = 0;
2399 d->updateActionRects();
2400 if (d->currentAction)
2401 d->popupAction(d->currentAction, 0, false);
2402 break;
2403#ifndef QT_NO_WHATSTHIS
2404 case QEvent::QueryWhatsThis:
2405 e->setAccepted(d->whatsThis.size());
2406 if (QAction *action = d->actionAt(static_cast<QHelpEvent*>(e)->pos())) {
2407 if (action->whatsThis().size() || action->menu())
2408 e->accept();
2409 }
2410 return true;
2411#endif
2412 default:
2413 break;
2414 }
2415 return QWidget::event(e);
2416}
2417
2418/*!
2419 \reimp
2420*/
2421bool QMenu::focusNextPrevChild(bool next)
2422{
2423 setFocus();
2424 QKeyEvent ev(QEvent::KeyPress, next ? Qt::Key_Tab : Qt::Key_Backtab, Qt::NoModifier);
2425 keyPressEvent(&ev);
2426 return true;
2427}
2428
2429/*!
2430 \reimp
2431*/
2432void QMenu::keyPressEvent(QKeyEvent *e)
2433{
2434 Q_D(QMenu);
2435 d->updateActionRects();
2436 int key = e->key();
2437 if (isRightToLeft()) { // in reverse mode open/close key for submenues are reversed
2438 if (key == Qt::Key_Left)
2439 key = Qt::Key_Right;
2440 else if (key == Qt::Key_Right)
2441 key = Qt::Key_Left;
2442 }
2443#ifndef Q_WS_MAC
2444 if (key == Qt::Key_Tab) //means down
2445 key = Qt::Key_Down;
2446 if (key == Qt::Key_Backtab) //means up
2447 key = Qt::Key_Up;
2448#endif
2449
2450 bool key_consumed = false;
2451 switch(key) {
2452 case Qt::Key_Home:
2453 key_consumed = true;
2454 if (d->scroll)
2455 d->scrollMenu(QMenuPrivate::QMenuScroller::ScrollTop, true);
2456 break;
2457 case Qt::Key_End:
2458 key_consumed = true;
2459 if (d->scroll)
2460 d->scrollMenu(QMenuPrivate::QMenuScroller::ScrollBottom, true);
2461 break;
2462 case Qt::Key_PageUp:
2463 key_consumed = true;
2464 if (d->currentAction && d->scroll) {
2465 if(d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp)
2466 d->scrollMenu(QMenuPrivate::QMenuScroller::ScrollUp, true, true);
2467 else
2468 d->scrollMenu(QMenuPrivate::QMenuScroller::ScrollTop, true);
2469 }
2470 break;
2471 case Qt::Key_PageDown:
2472 key_consumed = true;
2473 if (d->currentAction && d->scroll) {
2474 if(d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollDown)
2475 d->scrollMenu(QMenuPrivate::QMenuScroller::ScrollDown, true, true);
2476 else
2477 d->scrollMenu(QMenuPrivate::QMenuScroller::ScrollBottom, true);
2478 }
2479 break;
2480 case Qt::Key_Up:
2481 case Qt::Key_Down: {
2482 key_consumed = true;
2483 QAction *nextAction = 0;
2484 QMenuPrivate::QMenuScroller::ScrollLocation scroll_loc = QMenuPrivate::QMenuScroller::ScrollStay;
2485 if (!d->currentAction) {
2486 if(key == Qt::Key_Down) {
2487 for(int i = 0; i < d->actions.count(); ++i) {
2488 QAction *act = d->actions.at(i);
2489 if (d->actionRects.at(i).isNull())
2490 continue;
2491 if (!act->isSeparator() &&
2492 (style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled, 0, this)
2493 || act->isEnabled())) {
2494 nextAction = act;
2495 break;
2496 }
2497 }
2498 } else {
2499 for(int i = d->actions.count()-1; i >= 0; --i) {
2500 QAction *act = d->actions.at(i);
2501 if (d->actionRects.at(i).isNull())
2502 continue;
2503 if (!act->isSeparator() &&
2504 (style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled, 0, this)
2505 || act->isEnabled())) {
2506 nextAction = act;
2507 break;
2508 }
2509 }
2510 }
2511 } else {
2512 for(int i = 0, y = 0; !nextAction && i < d->actions.count(); i++) {
2513 QAction *act = d->actions.at(i);
2514 if (act == d->currentAction) {
2515 if (key == Qt::Key_Up) {
2516 for(int next_i = i-1; true; next_i--) {
2517 if (next_i == -1) {
2518 if(!style()->styleHint(QStyle::SH_Menu_SelectionWrap, 0, this))
2519 break;
2520 if (d->scroll)
2521 scroll_loc = QMenuPrivate::QMenuScroller::ScrollBottom;
2522 next_i = d->actionRects.count()-1;
2523 }
2524 QAction *next = d->actions.at(next_i);
2525 if (next == d->currentAction)
2526 break;
2527 if (d->actionRects.at(next_i).isNull())
2528 continue;
2529 if (next->isSeparator() ||
2530 (!next->isEnabled() &&
2531 !style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled, 0, this)))
2532 continue;
2533 nextAction = next;
2534 if (d->scroll && (d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp)) {
2535 int topVisible = d->scrollerHeight();
2536 if (d->tearoff)
2537 topVisible += style()->pixelMetric(QStyle::PM_MenuTearoffHeight, 0, this);
2538 if (((y + d->scroll->scrollOffset) - topVisible) <= d->actionRects.at(next_i).height())
2539 scroll_loc = QMenuPrivate::QMenuScroller::ScrollTop;
2540 }
2541 break;
2542 }
2543 if (!nextAction && d->tearoff)
2544 d->tearoffHighlighted = 1;
2545 } else {
2546 y += d->actionRects.at(i).height();
2547 for(int next_i = i+1; true; next_i++) {
2548 if (next_i == d->actionRects.count()) {
2549 if(!style()->styleHint(QStyle::SH_Menu_SelectionWrap, 0, this))
2550 break;
2551 if (d->scroll)
2552 scroll_loc = QMenuPrivate::QMenuScroller::ScrollTop;
2553 next_i = 0;
2554 }
2555 QAction *next = d->actions.at(next_i);
2556 if (next == d->currentAction)
2557 break;
2558 if (d->actionRects.at(next_i).isNull())
2559 continue;
2560 if (next->isSeparator() ||
2561 (!next->isEnabled() &&
2562 !style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled, 0, this)))
2563 continue;
2564 nextAction = next;
2565 if (d->scroll && (d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollDown)) {
2566 int bottomVisible = height() - d->scrollerHeight();
2567 if (d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp)
2568 bottomVisible -= d->scrollerHeight();
2569 if (d->tearoff)
2570 bottomVisible -= style()->pixelMetric(QStyle::PM_MenuTearoffHeight, 0, this);
2571 if ((y + d->scroll->scrollOffset + d->actionRects.at(next_i).height()) > bottomVisible)
2572 scroll_loc = QMenuPrivate::QMenuScroller::ScrollBottom;
2573 }
2574 break;
2575 }
2576 }
2577 break;
2578 }
2579 y += d->actionRects.at(i).height();
2580 }
2581 }
2582 if (nextAction) {
2583 if (d->scroll && scroll_loc != QMenuPrivate::QMenuScroller::ScrollStay) {
2584 d->scroll->scrollTimer.stop();
2585 d->scrollMenu(nextAction, scroll_loc);
2586 }
2587 d->setCurrentAction(nextAction, /*popup*/-1, QMenuPrivate::SelectedFromKeyboard);
2588 }
2589 break; }
2590
2591 case Qt::Key_Right:
2592 if (d->currentAction && d->currentAction->isEnabled() && d->currentAction->menu()) {
2593 d->popupAction(d->currentAction, 0, true);
2594 key_consumed = true;
2595 break;
2596 }
2597 //FALL THROUGH
2598 case Qt::Key_Left: {
2599 if (d->currentAction && !d->scroll) {
2600 QAction *nextAction = 0;
2601 if (key == Qt::Key_Left) {
2602 QRect actionR = d->actionRect(d->currentAction);
2603 for(int x = actionR.left()-1; !nextAction && x >= 0; x--)
2604 nextAction = d->actionAt(QPoint(x, actionR.center().y()));
2605 } else {
2606 QRect actionR = d->actionRect(d->currentAction);
2607 for(int x = actionR.right()+1; !nextAction && x < width(); x++)
2608 nextAction = d->actionAt(QPoint(x, actionR.center().y()));
2609 }
2610 if (nextAction) {
2611 d->setCurrentAction(nextAction, /*popup*/-1, QMenuPrivate::SelectedFromKeyboard);
2612 key_consumed = true;
2613 }
2614 }
2615 if (!key_consumed && key == Qt::Key_Left && qobject_cast<QMenu*>(d->causedPopup.widget)) {
2616 QPointer<QWidget> caused = d->causedPopup.widget;
2617 d->hideMenu(this);
2618 if (caused)
2619 caused->setFocus();
2620 key_consumed = true;
2621 }
2622 break; }
2623
2624 case Qt::Key_Alt:
2625 if (d->tornoff)
2626 break;
2627
2628 key_consumed = true;
2629 if (style()->styleHint(QStyle::SH_MenuBar_AltKeyNavigation, 0, this))
2630 {
2631 d->hideMenu(this);
2632#ifndef QT_NO_MENUBAR
2633 if (QMenuBar *mb = qobject_cast<QMenuBar*>(QApplication::focusWidget())) {
2634 mb->d_func()->setKeyboardMode(false);
2635 }
2636#endif
2637 }
2638 break;
2639
2640 case Qt::Key_Escape:
2641#ifdef QT_KEYPAD_NAVIGATION
2642 case Qt::Key_Back:
2643#endif
2644 key_consumed = true;
2645 if (d->tornoff) {
2646 close();
2647 return;
2648 }
2649 {
2650 QPointer<QWidget> caused = d->causedPopup.widget;
2651 d->hideMenu(this); // hide after getting causedPopup
2652#ifndef QT_NO_MENUBAR
2653 if (QMenuBar *mb = qobject_cast<QMenuBar*>(caused)) {
2654 mb->d_func()->setCurrentAction(d->menuAction);
2655 mb->d_func()->setKeyboardMode(true);
2656 }
2657#endif
2658 }
2659 break;
2660
2661 case Qt::Key_Space:
2662 if (!style()->styleHint(QStyle::SH_Menu_SpaceActivatesItem, 0, this))
2663 break;
2664 // for motif, fall through
2665#ifdef QT_KEYPAD_NAVIGATION
2666 case Qt::Key_Select:
2667#endif
2668 case Qt::Key_Return:
2669 case Qt::Key_Enter: {
2670 if (!d->currentAction) {
2671 d->setFirstActionActive();
2672 key_consumed = true;
2673 break;
2674 }
2675
2676 d->setSyncAction();
2677
2678 if (d->currentAction->menu())
2679 d->popupAction(d->currentAction, 0, true);
2680 else
2681 d->activateAction(d->currentAction, QAction::Trigger);
2682 key_consumed = true;
2683 break; }
2684
2685#ifndef QT_NO_WHATSTHIS
2686 case Qt::Key_F1:
2687 if (!d->currentAction || d->currentAction->whatsThis().isNull())
2688 break;
2689 QWhatsThis::enterWhatsThisMode();
2690 d->activateAction(d->currentAction, QAction::Trigger);
2691 return;
2692#endif
2693 default:
2694 key_consumed = false;
2695 }
2696
2697 if (!key_consumed) { // send to menu bar
2698 if ((!e->modifiers() || e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ShiftModifier) &&
2699 e->text().length()==1) {
2700 bool activateAction = false;
2701 QAction *nextAction = 0;
2702 if (style()->styleHint(QStyle::SH_Menu_KeyboardSearch, 0, this) && !e->modifiers()) {
2703 int best_match_count = 0;
2704 d->searchBufferTimer.start(2000, this);
2705 d->searchBuffer += e->text();
2706 for(int i = 0; i < d->actions.size(); ++i) {
2707 int match_count = 0;
2708 if (d->actionRects.at(i).isNull())
2709 continue;
2710 QAction *act = d->actions.at(i);
2711 const QString act_text = act->text();
2712 for(int c = 0; c < d->searchBuffer.size(); ++c) {
2713 if(act_text.indexOf(d->searchBuffer.at(c), 0, Qt::CaseInsensitive) != -1)
2714 ++match_count;
2715 }
2716 if(match_count > best_match_count) {
2717 best_match_count = match_count;
2718 nextAction = act;
2719 }
2720 }
2721 }
2722#ifndef QT_NO_SHORTCUT
2723 else {
2724 int clashCount = 0;
2725 QAction *first = 0, *currentSelected = 0, *firstAfterCurrent = 0;
2726 QChar c = e->text().at(0).toUpper();
2727 for(int i = 0; i < d->actions.size(); ++i) {
2728 if (d->actionRects.at(i).isNull())
2729 continue;
2730 QAction *act = d->actions.at(i);
2731 QKeySequence sequence = QKeySequence::mnemonic(act->text());
2732 int key = sequence[0] & 0xffff;
2733 if (key == c.unicode()) {
2734 clashCount++;
2735 if (!first)
2736 first = act;
2737 if (act == d->currentAction)
2738 currentSelected = act;
2739 else if (!firstAfterCurrent && currentSelected)
2740 firstAfterCurrent = act;
2741 }
2742 }
2743 if (clashCount == 1)
2744 activateAction = true;
2745 if (clashCount >= 1) {
2746 if (clashCount == 1 || !currentSelected || !firstAfterCurrent)
2747 nextAction = first;
2748 else
2749 nextAction = firstAfterCurrent;
2750 }
2751 }
2752#endif
2753 if (nextAction) {
2754 key_consumed = true;
2755 if(d->scroll)
2756 d->scrollMenu(nextAction, QMenuPrivate::QMenuScroller::ScrollCenter, false);
2757 d->setCurrentAction(nextAction, 20, QMenuPrivate::SelectedFromElsewhere, true);
2758 if (!nextAction->menu() && activateAction) {
2759 d->setSyncAction();
2760 d->activateAction(nextAction, QAction::Trigger);
2761 }
2762 }
2763 }
2764 if (!key_consumed) {
2765#ifndef QT_NO_MENUBAR
2766 if (QMenuBar *mb = qobject_cast<QMenuBar*>(d->topCausedWidget())) {
2767 QAction *oldAct = mb->d_func()->currentAction;
2768 QApplication::sendEvent(mb, e);
2769 if (mb->d_func()->currentAction != oldAct)
2770 key_consumed = true;
2771 }
2772#endif
2773 }
2774
2775#ifdef Q_OS_WIN32
2776 if (key_consumed && (e->key() == Qt::Key_Control || e->key() == Qt::Key_Shift || e->key() == Qt::Key_Meta))
2777 QApplication::beep();
2778#endif // Q_OS_WIN32
2779 }
2780 if (key_consumed)
2781 e->accept();
2782 else
2783 e->ignore();
2784}
2785
2786/*!
2787 \reimp
2788*/
2789void QMenu::mouseMoveEvent(QMouseEvent *e)
2790{
2791 Q_D(QMenu);
2792 if (!isVisible() || d->aboutToHide || d->mouseEventTaken(e))
2793 return;
2794 d->motions++;
2795 if (d->motions == 0) // ignore first mouse move event (see enterEvent())
2796 return;
2797 d->hasHadMouse = d->hasHadMouse || rect().contains(e->pos());
2798
2799 QAction *action = d->actionAt(e->pos());
2800 if (!action) {
2801 if (d->hasHadMouse)
2802 d->setCurrentAction(0);
2803 return;
2804 } else if(e->buttons()) {
2805 d->mouseDown = this;
2806 }
2807 if (d->sloppyRegion.contains(e->pos())) {
2808 d->sloppyAction = action;
2809 QMenuPrivate::sloppyDelayTimer.start(style()->styleHint(QStyle::SH_Menu_SubMenuPopupDelay, 0, this)*6, this);
2810 } else {
2811 d->setCurrentAction(action, style()->styleHint(QStyle::SH_Menu_SubMenuPopupDelay, 0, this));
2812 }
2813}
2814
2815/*!
2816 \reimp
2817*/
2818void QMenu::enterEvent(QEvent *)
2819{
2820 d_func()->motions = -1; // force us to ignore the generate mouse move in mouseMoveEvent()
2821}
2822
2823/*!
2824 \reimp
2825*/
2826void QMenu::leaveEvent(QEvent *)
2827{
2828 Q_D(QMenu);
2829 d->sloppyAction = 0;
2830 if (!d->sloppyRegion.isEmpty())
2831 d->sloppyRegion = QRegion();
2832 if (!d->activeMenu && d->currentAction)
2833 setActiveAction(0);
2834}
2835
2836/*!
2837 \reimp
2838*/
2839void
2840QMenu::timerEvent(QTimerEvent *e)
2841{
2842 Q_D(QMenu);
2843 if (d->scroll && d->scroll->scrollTimer.timerId() == e->timerId()) {
2844 d->scrollMenu((QMenuPrivate::QMenuScroller::ScrollDirection)d->scroll->scrollDirection);
2845 if (d->scroll->scrollFlags == QMenuPrivate::QMenuScroller::ScrollNone)
2846 d->scroll->scrollTimer.stop();
2847 } else if(QMenuPrivate::menuDelayTimer.timerId() == e->timerId()) {
2848 QMenuPrivate::menuDelayTimer.stop();
2849 internalDelayedPopup();
2850 } else if(QMenuPrivate::sloppyDelayTimer.timerId() == e->timerId()) {
2851 QMenuPrivate::sloppyDelayTimer.stop();
2852 internalSetSloppyAction();
2853 } else if(d->searchBufferTimer.timerId() == e->timerId()) {
2854 d->searchBuffer.clear();
2855 }
2856}
2857
2858/*!
2859 \reimp
2860*/
2861void QMenu::actionEvent(QActionEvent *e)
2862{
2863 Q_D(QMenu);
2864 d->itemsDirty = 1;
2865 setAttribute(Qt::WA_Resized, false);
2866 if (d->tornPopup)
2867 d->tornPopup->syncWithMenu(this, e);
2868 if (e->type() == QEvent::ActionAdded) {
2869 if(!d->tornoff) {
2870 connect(e->action(), SIGNAL(triggered()), this, SLOT(_q_actionTriggered()));
2871 connect(e->action(), SIGNAL(hovered()), this, SLOT(_q_actionHovered()));
2872 }
2873 if (QWidgetAction *wa = qobject_cast<QWidgetAction *>(e->action())) {
2874 QWidget *widget = wa->requestWidget(this);
2875 if (widget)
2876 d->widgetItems.insert(wa, widget);
2877 }
2878 } else if (e->type() == QEvent::ActionRemoved) {
2879 e->action()->disconnect(this);
2880 if (e->action() == d->currentAction)
2881 d->currentAction = 0;
2882 if (QWidgetAction *wa = qobject_cast<QWidgetAction *>(e->action())) {
2883 if (QWidget *widget = d->widgetItems.value(wa))
2884 wa->releaseWidget(widget);
2885 }
2886 d->widgetItems.remove(e->action());
2887 }
2888
2889#ifdef Q_WS_MAC
2890 if (d->mac_menu) {
2891 if (e->type() == QEvent::ActionAdded)
2892 d->mac_menu->addAction(e->action(), d->mac_menu->findAction(e->before()), d);
2893 else if (e->type() == QEvent::ActionRemoved)
2894 d->mac_menu->removeAction(e->action());
2895 else if (e->type() == QEvent::ActionChanged)
2896 d->mac_menu->syncAction(e->action());
2897 }
2898#endif
2899
2900#if defined(Q_WS_WINCE) && !defined(QT_NO_MENUBAR)
2901 if (!d->wce_menu)
2902 d->wce_menu = new QMenuPrivate::QWceMenuPrivate;
2903 if (e->type() == QEvent::ActionAdded)
2904 d->wce_menu->addAction(e->action(), d->wce_menu->findAction(e->before()));
2905 else if (e->type() == QEvent::ActionRemoved)
2906 d->wce_menu->removeAction(e->action());
2907 else if (e->type() == QEvent::ActionChanged)
2908 d->wce_menu->syncAction(e->action());
2909#endif
2910
2911#ifdef Q_WS_S60
2912 if (!d->symbian_menu)
2913 d->symbian_menu = new QMenuPrivate::QSymbianMenuPrivate;
2914 if (e->type() == QEvent::ActionAdded)
2915 d->symbian_menu->addAction(e->action(), d->symbian_menu->findAction(e->before()));
2916 else if (e->type() == QEvent::ActionRemoved)
2917 d->symbian_menu->removeAction(e->action());
2918 else if (e->type() == QEvent::ActionChanged)
2919 d->symbian_menu->syncAction(e->action());
2920#endif
2921 if (isVisible()) {
2922 d->updateActionRects();
2923 resize(sizeHint());
2924 update();
2925 }
2926}
2927
2928/*!
2929 \internal
2930*/
2931void QMenu::internalSetSloppyAction()
2932{
2933 if (d_func()->sloppyAction)
2934 d_func()->setCurrentAction(d_func()->sloppyAction, 0);
2935}
2936
2937/*!
2938 \internal
2939*/
2940void QMenu::internalDelayedPopup()
2941{
2942 Q_D(QMenu);
2943
2944 //hide the current item
2945 if (QMenu *menu = d->activeMenu) {
2946 d->activeMenu = 0;
2947 d->hideMenu(menu);
2948 }
2949
2950 if (!d->currentAction || !d->currentAction->isEnabled() || !d->currentAction->menu() ||
2951 !d->currentAction->menu()->isEnabled() || d->currentAction->menu()->isVisible())
2952 return;
2953
2954 //setup
2955 d->activeMenu = d->currentAction->menu();
2956 d->activeMenu->d_func()->causedPopup.widget = this;
2957 d->activeMenu->d_func()->causedPopup.action = d->currentAction;
2958
2959 int subMenuOffset = style()->pixelMetric(QStyle::PM_SubMenuOverlap, 0, this);
2960 const QRect actionRect(d->actionRect(d->currentAction));
2961 const QSize menuSize(d->activeMenu->sizeHint());
2962 const QPoint rightPos(mapToGlobal(QPoint(actionRect.right() + subMenuOffset + 1, actionRect.top())));
2963 const QPoint leftPos(mapToGlobal(QPoint(actionRect.left() - subMenuOffset - menuSize.width(), actionRect.top())));
2964
2965 QPoint pos(rightPos);
2966 QMenu *caused = qobject_cast<QMenu*>(d->activeMenu->d_func()->causedPopup.widget);
2967
2968 const QRect availGeometry(d->popupGeometry(caused));
2969 if (isRightToLeft()) {
2970 pos = leftPos;
2971 if ((caused && caused->x() < x()) || pos.x() < availGeometry.left()) {
2972 if(rightPos.x() + menuSize.width() < availGeometry.right())
2973 pos = rightPos;
2974 else
2975 pos.rx() = availGeometry.left();
2976 }
2977 } else {
2978 if ((caused && caused->x() > x()) || pos.x() + menuSize.width() > availGeometry.right()) {
2979 if(leftPos.x() < availGeometry.left())
2980 pos.rx() = availGeometry.right() - menuSize.width();
2981 else
2982 pos = leftPos;
2983 }
2984 }
2985
2986 //calc sloppy focus buffer
2987 if (style()->styleHint(QStyle::SH_Menu_SloppySubMenus, 0, this)) {
2988 QPoint cur = QCursor::pos();
2989 if (actionRect.contains(mapFromGlobal(cur))) {
2990 QPoint pts[4];
2991 pts[0] = QPoint(cur.x(), cur.y() - 2);
2992 pts[3] = QPoint(cur.x(), cur.y() + 2);
2993 if (pos.x() >= cur.x()) {
2994 pts[1] = QPoint(geometry().right(), pos.y());
2995 pts[2] = QPoint(geometry().right(), pos.y() + menuSize.height());
2996 } else {
2997 pts[1] = QPoint(pos.x() + menuSize.width(), pos.y());
2998 pts[2] = QPoint(pos.x() + menuSize.width(), pos.y() + menuSize.height());
2999 }
3000 QPolygon points(4);
3001 for(int i = 0; i < 4; i++)
3002 points.setPoint(i, mapFromGlobal(pts[i]));
3003 d->sloppyRegion = QRegion(points);
3004 }
3005 }
3006
3007 //do the popup
3008 d->activeMenu->popup(pos);
3009}
3010
3011/*!
3012 \fn void QMenu::addAction(QAction *action)
3013 \overload
3014
3015 Appends the action \a action to the menu's list of actions.
3016
3017 \sa QMenuBar::addAction(), QWidget::addAction()
3018*/
3019
3020/*!
3021 \fn void QMenu::aboutToHide()
3022 \since 4.2
3023
3024 This signal is emitted just before the menu is hidden from the user.
3025
3026 \sa aboutToShow(), hide()
3027*/
3028
3029/*!
3030 \fn void QMenu::aboutToShow()
3031
3032 This signal is emitted just before the menu is shown to the user.
3033
3034 \sa aboutToHide(), show()
3035*/
3036
3037/*!
3038 \fn void QMenu::triggered(QAction *action)
3039
3040 This signal is emitted when an action in this menu is triggered.
3041
3042 \a action is the action that caused the signal to be emitted.
3043
3044 Normally, you connect each menu action's \l{QAction::}{triggered()} signal
3045 to its own custom slot, but sometimes you will want to connect several
3046 actions to a single slot, for example, when you have a group of closely
3047 related actions, such as "left justify", "center", "right justify".
3048
3049 \note This signal is emitted for the main parent menu in a hierarchy.
3050 Hence, only the parent menu needs to be connected to a slot; sub-menus need
3051 not be connected.
3052
3053 \sa hovered(), QAction::triggered()
3054*/
3055
3056/*!
3057 \fn void QMenu::hovered(QAction *action)
3058
3059 This signal is emitted when a menu action is highlighted; \a action
3060 is the action that caused the signal to be emitted.
3061
3062 Often this is used to update status information.
3063
3064 \sa triggered(), QAction::hovered()
3065*/
3066
3067
3068/*!\internal
3069*/
3070void QMenu::setNoReplayFor(QWidget *noReplayFor)
3071{
3072#if defined(Q_WS_WIN) || defined(Q_WS_PM)
3073 d_func()->noReplayFor = noReplayFor;
3074#else
3075 Q_UNUSED(noReplayFor);
3076#endif
3077}
3078
3079/*!
3080 \property QMenu::separatorsCollapsible
3081 \since 4.2
3082
3083 \brief whether consecutive separators should be collapsed
3084
3085 This property specifies whether consecutive separators in the menu
3086 should be visually collapsed to a single one. Separators at the
3087 beginning or the end of the menu are also hidden.
3088
3089 By default, this property is true.
3090*/
3091bool QMenu::separatorsCollapsible() const
3092{
3093 Q_D(const QMenu);
3094 return d->collapsibleSeparators;
3095}
3096
3097void QMenu::setSeparatorsCollapsible(bool collapse)
3098{
3099 Q_D(QMenu);
3100 if (d->collapsibleSeparators == collapse)
3101 return;
3102
3103 d->collapsibleSeparators = collapse;
3104 d->itemsDirty = 1;
3105 if (isVisible()) {
3106 d->updateActionRects();
3107 update();
3108 }
3109#ifdef Q_WS_MAC
3110 if (d->mac_menu)
3111 d->syncSeparatorsCollapsible(collapse);
3112#endif
3113}
3114
3115#ifdef QT3_SUPPORT
3116
3117int QMenu::insertAny(const QIcon *icon, const QString *text, const QObject *receiver, const char *member,
3118 const QKeySequence *shortcut, const QMenu *popup, int id, int index)
3119{
3120 QAction *act = popup ? popup->menuAction() : new QAction(this);
3121 if (id != -1)
3122 static_cast<QMenuItem*>(act)->setId(id);
3123 if (icon)
3124 act->setIcon(*icon);
3125 if (text)
3126 act->setText(*text);
3127 if (shortcut)
3128 act->setShortcut(*shortcut);
3129 if (receiver && member)
3130 QObject::connect(act, SIGNAL(activated(int)), receiver, member);
3131 if (index == -1 || index >= actions().count())
3132 addAction(act);
3133 else
3134 insertAction(actions().value(index), act);
3135 return findIdForAction(act);
3136}
3137
3138/*!
3139 Use insertAction() or one of the addAction() overloads instead.
3140*/
3141int QMenu::insertItem(QMenuItem *item, int id, int index)
3142{
3143 if (index == -1 || index >= actions().count())
3144 addAction(item);
3145 else
3146 insertAction(actions().value(index), item);
3147 if (id > -1)
3148 item->d_func()->id = id;
3149 return findIdForAction(item);
3150}
3151
3152/*!
3153 Use the insertSeparator() overload that takes a QAction *
3154 parameter instead.
3155*/
3156int QMenu::insertSeparator(int index)
3157{
3158 QAction *act = new QAction(this);
3159 act->setSeparator(true);
3160 if (index == -1 || index >= actions().count())
3161 addAction(act);
3162 else
3163 insertAction(actions().value(index), act);
3164 return findIdForAction(act);
3165}
3166
3167QAction *QMenu::findActionForId(int id) const
3168{
3169 Q_D(const QMenu);
3170 for (int i = 0; i < d->actions.size(); ++i) {
3171 QAction *act = d->actions.at(i);
3172 if (findIdForAction(act)== id)
3173 return act;
3174 }
3175 return 0;
3176}
3177
3178/*!
3179 Use QAction and actions() instead.
3180*/
3181QMenuItem *QMenu::findPopup( QMenu *popup, int *index )
3182{
3183 QList<QAction *> list = actions();
3184 for (int i = 0; i < list.size(); ++i) {
3185 QAction *act = list.at(i);
3186 if (act->menu() == popup) {
3187 QMenuItem *item = static_cast<QMenuItem *>(act);
3188 if (index)
3189 *index = act->d_func()->id;
3190 return item;
3191 }
3192 }
3193 return 0;
3194}
3195
3196
3197/*!
3198 Use QAction::setData() instead.
3199*/
3200bool QMenu::setItemParameter(int id, int param)
3201{
3202 if (QAction *act = findActionForId(id)) {
3203 act->d_func()->param = param;
3204 return true;
3205 }
3206 return false;
3207}
3208
3209/*!
3210 Use QAction::data() instead.
3211*/
3212int QMenu::itemParameter(int id) const
3213{
3214 if (QAction *act = findActionForId(id))
3215 return act->d_func()->param;
3216 return id;
3217}
3218
3219/*!
3220 Use actions instead.
3221*/
3222void QMenu::setId(int index, int id)
3223{
3224 if(QAction *act = actions().value(index))
3225 act->d_func()->id = id;
3226}
3227
3228/*!
3229 Use style()->pixelMetric(QStyle::PM_MenuPanelWidth, this) instead.
3230*/
3231int QMenu::frameWidth() const
3232{
3233 return style()->pixelMetric(QStyle::PM_MenuPanelWidth, 0, this);
3234}
3235
3236int QMenu::findIdForAction(QAction *act) const
3237{
3238 if (!act)
3239 return -1;
3240 return act->d_func()->id;
3241}
3242#endif // QT3_SUPPORT
3243
3244/*!
3245 \fn uint QMenu::count() const
3246
3247 Use actions().count() instead.
3248*/
3249
3250/*!
3251 \fn int QMenu::insertItem(const QString &text, const QObject *receiver, const char* member, const QKeySequence& shortcut, int id, int index)
3252
3253 Use insertAction() or one of the addAction() overloads instead.
3254*/
3255
3256/*!
3257 \fn int QMenu::insertItem(const QIcon& icon, const QString &text, const QObject *receiver, const char* member, const QKeySequence& shortcut, int id, int index)
3258
3259 Use insertAction() or one of the addAction() overloads instead.
3260*/
3261
3262/*!
3263 \fn int QMenu::insertItem(const QPixmap &pixmap, const QObject *receiver, const char* member, const QKeySequence& shortcut, int id, int index)
3264
3265 Use insertAction() or one of the addAction() overloads instead.
3266*/
3267
3268/*!
3269 \fn int QMenu::insertItem(const QString &text, int id, int index)
3270
3271 Use insertAction() or one of the addAction() overloads instead.
3272*/
3273
3274/*!
3275 \fn int QMenu::insertItem(const QIcon& icon, const QString &text, int id, int index)
3276
3277 Use insertAction() or one of the addAction() overloads instead.
3278*/
3279
3280/*!
3281 \fn int QMenu::insertItem(const QString &text, QMenu *popup, int id, int index)
3282
3283 Use insertMenu() or one of the addMenu() overloads instead.
3284*/
3285
3286/*!
3287 \fn int QMenu::insertItem(const QIcon& icon, const QString &text, QMenu *popup, int id, int index)
3288
3289 Use insertMenu() or one of the addMenu() overloads instead.
3290*/
3291
3292/*!
3293 \fn int QMenu::insertItem(const QPixmap &pixmap, int id, int index)
3294
3295 Use insertAction() or one of the addAction() overloads instead.
3296*/
3297
3298/*!
3299 \fn int QMenu::insertItem(const QPixmap &pixmap, QMenu *popup, int id, int index)
3300
3301 Use insertMenu() or one of the addMenu() overloads instead.
3302*/
3303
3304/*!
3305 \fn void QMenu::removeItem(int id)
3306
3307 Use removeAction() instead.
3308*/
3309
3310/*!
3311 \fn void QMenu::removeItemAt(int index)
3312
3313 Use removeAction() instead.
3314*/
3315
3316/*!
3317 \fn QKeySequence QMenu::accel(int id) const
3318
3319 Use shortcut() on the relevant QAction instead.
3320*/
3321
3322/*!
3323 \fn void QMenu::setAccel(const QKeySequence& key, int id)
3324
3325 Use setShortcut() on the relevant QAction instead.
3326*/
3327
3328/*!
3329 \fn QIcon QMenu::iconSet(int id) const
3330
3331 Use icon() on the relevant QAction instead.
3332*/
3333
3334/*!
3335 \fn QString QMenu::text(int id) const
3336
3337 Use text() on the relevant QAction instead.
3338*/
3339
3340/*!
3341 \fn QPixmap QMenu::pixmap(int id) const
3342
3343 Use QPixmap(icon()) on the relevant QAction instead.
3344*/
3345
3346/*!
3347 \fn void QMenu::setWhatsThis(int id, const QString &w)
3348
3349 Use setWhatsThis() on the relevant QAction instead.
3350*/
3351
3352/*!
3353 \fn QString QMenu::whatsThis(int id) const
3354
3355 Use whatsThis() on the relevant QAction instead.
3356*/
3357
3358/*!
3359 \fn void QMenu::changeItem(int id, const QString &text)
3360
3361 Use setText() on the relevant QAction instead.
3362*/
3363
3364/*!
3365 \fn void QMenu::changeItem(int id, const QPixmap &pixmap)
3366
3367 Use setText() on the relevant QAction instead.
3368*/
3369
3370/*!
3371 \fn void QMenu::changeItem(int id, const QIcon &icon, const QString &text)
3372
3373 Use setIcon() and setText() on the relevant QAction instead.
3374*/
3375
3376/*!
3377 \fn bool QMenu::isItemActive(int id) const
3378
3379 Use activeAction() instead.
3380*/
3381
3382/*!
3383 \fn bool QMenu::isItemEnabled(int id) const
3384
3385 Use isEnabled() on the relevant QAction instead.
3386*/
3387
3388/*!
3389 \fn void QMenu::setItemEnabled(int id, bool enable)
3390
3391 Use setEnabled() on the relevant QAction instead.
3392*/
3393
3394/*!
3395 \fn bool QMenu::isItemChecked(int id) const
3396
3397 Use isChecked() on the relevant QAction instead.
3398*/
3399
3400/*!
3401 \fn void QMenu::setItemChecked(int id, bool check)
3402
3403 Use setChecked() on the relevant QAction instead.
3404*/
3405
3406/*!
3407 \fn bool QMenu::isItemVisible(int id) const
3408
3409 Use isVisible() on the relevant QAction instead.
3410*/
3411
3412/*!
3413 \fn void QMenu::setItemVisible(int id, bool visible)
3414
3415 Use setVisible() on the relevant QAction instead.
3416*/
3417
3418/*!
3419 \fn QRect QMenu::itemGeometry(int index)
3420
3421 Use actionGeometry() on the relevant QAction instead.
3422*/
3423
3424/*!
3425 \fn QFont QMenu::itemFont(int id) const
3426
3427 Use font() on the relevant QAction instead.
3428*/
3429
3430/*!
3431 \fn void QMenu::setItemFont(int id, const QFont &font)
3432
3433 Use setFont() on the relevant QAction instead.
3434*/
3435
3436/*!
3437 \fn int QMenu::indexOf(int id) const
3438
3439 Use actions().indexOf(action) on the relevant QAction instead.
3440*/
3441
3442/*!
3443 \fn int QMenu::idAt(int index) const
3444
3445 Use actions instead.
3446*/
3447
3448/*!
3449 \fn void QMenu::activateItemAt(int index)
3450
3451 Use activate() on the relevant QAction instead.
3452*/
3453
3454/*!
3455 \fn bool QMenu::connectItem(int id, const QObject *receiver, const char* member)
3456
3457 Use connect() on the relevant QAction instead.
3458*/
3459
3460/*!
3461 \fn bool QMenu::disconnectItem(int id,const QObject *receiver, const char* member)
3462 Use disconnect() on the relevant QAction instead.
3463
3464*/
3465
3466/*!
3467 \fn QMenuItem *QMenu::findItem(int id) const
3468
3469 Use actions instead.
3470*/
3471
3472/*!
3473 \fn void QMenu::popup(const QPoint & pos, int indexAtPoint)
3474
3475 Use popup() on the relevant QAction instead.
3476*/
3477
3478/*!
3479 \fn int QMenu::insertTearOffHandle(int a, int b)
3480
3481 Use setTearOffEnabled() instead.
3482*/
3483
3484/*!
3485 \fn int QMenu::itemAtPos(const QPoint &p, bool ignoreSeparator)
3486
3487 Use actions instead.
3488*/
3489
3490/*!
3491 \fn int QMenu::columns() const
3492
3493 Use columnCount() instead.
3494*/
3495
3496/*!
3497 \fn int QMenu::itemHeight(int index)
3498
3499 Use actionGeometry(actions().value(index)).height() instead.
3500*/
3501
3502/*!
3503 \fn int QMenu::itemHeight(QMenuItem *mi)
3504
3505 Use actionGeometry() instead.
3506*/
3507
3508/*!
3509 \fn void QMenu::activated(int itemId);
3510
3511 Use triggered() instead.
3512*/
3513
3514/*!
3515 \fn void QMenu::highlighted(int itemId);
3516
3517 Use hovered() instead.
3518*/
3519
3520/*!
3521 \fn void QMenu::setCheckable(bool checkable)
3522
3523 Not necessary anymore. The \a checkable parameter is ignored.
3524*/
3525
3526/*!
3527 \fn bool QMenu::isCheckable() const
3528
3529 Not necessary anymore. Always returns true.
3530*/
3531
3532/*!
3533 \fn void QMenu::setActiveItem(int id)
3534
3535 Use setActiveAction() instead.
3536*/
3537
3538QT_END_NAMESPACE
3539
3540// for private slots
3541#include "moc_qmenu.cpp"
3542#include "qmenu.moc"
3543
3544#endif // QT_NO_MENU
Note: See TracBrowser for help on using the repository browser.