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

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

trunk: Merged in qt 4.6.2 sources.

File size: 111.8 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 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 sets the default action to \a act. The default action may have
1592 a visual cue, depending on the current QStyle. A default action
1593 usually indicates what will happen by default when a drop occurs.
1594
1595 \sa defaultAction()
1596*/
1597void QMenu::setDefaultAction(QAction *act)
1598{
1599 d_func()->defaultAction = act;
1600}
1601
1602/*!
1603 Returns the current default action.
1604
1605 \sa setDefaultAction()
1606*/
1607QAction *QMenu::defaultAction() const
1608{
1609 return d_func()->defaultAction;
1610}
1611
1612/*!
1613 \property QMenu::tearOffEnabled
1614 \brief whether the menu supports being torn off
1615
1616 When true, the menu contains a special tear-off item (often shown as a dashed
1617 line at the top of the menu) that creates a copy of the menu when it is
1618 triggered.
1619
1620 This "torn-off" copy lives in a separate window. It contains the same menu
1621 items as the original menu, with the exception of the tear-off handle.
1622
1623 By default, this property is false.
1624*/
1625void QMenu::setTearOffEnabled(bool b)
1626{
1627 Q_D(QMenu);
1628 if (d->tearoff == b)
1629 return;
1630 if (!b)
1631 hideTearOffMenu();
1632 d->tearoff = b;
1633
1634 d->itemsDirty = true;
1635 if (isVisible())
1636 resize(sizeHint());
1637}
1638
1639bool QMenu::isTearOffEnabled() const
1640{
1641 return d_func()->tearoff;
1642}
1643
1644/*!
1645 When a menu is torn off a second menu is shown to display the menu
1646 contents in a new window. When the menu is in this mode and the menu
1647 is visible returns true; otherwise false.
1648
1649 \sa hideTearOffMenu() isTearOffEnabled()
1650*/
1651bool QMenu::isTearOffMenuVisible() const
1652{
1653 if (d_func()->tornPopup)
1654 return d_func()->tornPopup->isVisible();
1655 return false;
1656}
1657
1658/*!
1659 This function will forcibly hide the torn off menu making it
1660 disappear from the users desktop.
1661
1662 \sa isTearOffMenuVisible() isTearOffEnabled()
1663*/
1664void QMenu::hideTearOffMenu()
1665{
1666 if (QWidget *w = d_func()->tornPopup)
1667 w->close();
1668}
1669
1670
1671/*!
1672 Sets the currently highlighted action to \a act.
1673*/
1674void QMenu::setActiveAction(QAction *act)
1675{
1676 Q_D(QMenu);
1677 d->setCurrentAction(act, 0);
1678 if (d->scroll)
1679 d->scrollMenu(act, QMenuPrivate::QMenuScroller::ScrollCenter);
1680}
1681
1682
1683/*!
1684 Returns the currently highlighted action, or 0 if no
1685 action is currently highlighted.
1686*/
1687QAction *QMenu::activeAction() const
1688{
1689 return d_func()->currentAction;
1690}
1691
1692/*!
1693 \since 4.2
1694
1695 Returns true if there are no visible actions inserted into the menu, false
1696 otherwise.
1697
1698 \sa QWidget::actions()
1699*/
1700
1701bool QMenu::isEmpty() const
1702{
1703 bool ret = true;
1704 for(int i = 0; ret && i < actions().count(); ++i) {
1705 const QAction *action = actions().at(i);
1706 if (!action->isSeparator() && action->isVisible()) {
1707 ret = false;
1708 }
1709 }
1710 return ret;
1711}
1712
1713/*!
1714 Removes all the menu's actions. Actions owned by the menu and not
1715 shown in any other widget are deleted.
1716
1717 \sa removeAction()
1718*/
1719void QMenu::clear()
1720{
1721 QList<QAction*> acts = actions();
1722 for(int i = 0; i < acts.size(); i++) {
1723 removeAction(acts[i]);
1724 if (acts[i]->parent() == this && acts[i]->d_func()->widgets.isEmpty())
1725 delete acts[i];
1726 }
1727}
1728
1729/*!
1730 If a menu does not fit on the screen it lays itself out so that it
1731 does fit. It is style dependent what layout means (for example, on
1732 Windows it will use multiple columns).
1733
1734 This functions returns the number of columns necessary.
1735*/
1736int QMenu::columnCount() const
1737{
1738 return d_func()->ncols;
1739}
1740
1741/*!
1742 Returns the item at \a pt; returns 0 if there is no item there.
1743*/
1744QAction *QMenu::actionAt(const QPoint &pt) const
1745{
1746 if (QAction *ret = d_func()->actionAt(pt))
1747 return ret;
1748 return 0;
1749}
1750
1751/*!
1752 Returns the geometry of action \a act.
1753*/
1754QRect QMenu::actionGeometry(QAction *act) const
1755{
1756 return d_func()->actionRect(act);
1757}
1758
1759/*!
1760 \reimp
1761*/
1762QSize QMenu::sizeHint() const
1763{
1764 Q_D(const QMenu);
1765 d->updateActionRects();
1766
1767 QSize s;
1768 for (int i = 0; i < d->actionRects.count(); ++i) {
1769 const QRect &rect = d->actionRects.at(i);
1770 if (rect.isNull())
1771 continue;
1772 if (rect.bottom() >= s.height())
1773 s.setHeight(rect.y() + rect.height());
1774 if (rect.right() >= s.width())
1775 s.setWidth(rect.x() + rect.width());
1776 }
1777 // Note that the action rects calculated above already include
1778 // the top and left margins, so we only need to add margins for
1779 // the bottom and right.
1780 QStyleOption opt(0);
1781 opt.init(this);
1782 const int fw = style()->pixelMetric(QStyle::PM_MenuPanelWidth, &opt, this);
1783 s.rwidth() += style()->pixelMetric(QStyle::PM_MenuHMargin, &opt, this) + fw + d->rightmargin;
1784 s.rheight() += style()->pixelMetric(QStyle::PM_MenuVMargin, &opt, this) + fw + d->bottommargin;
1785
1786 return style()->sizeFromContents(QStyle::CT_Menu, &opt,
1787 s.expandedTo(QApplication::globalStrut()), this);
1788}
1789
1790/*!
1791 Displays the menu so that the action \a atAction will be at the
1792 specified \e global position \a p. To translate a widget's local
1793 coordinates into global coordinates, use QWidget::mapToGlobal().
1794
1795 When positioning a menu with exec() or popup(), bear in mind that
1796 you cannot rely on the menu's current size(). For performance
1797 reasons, the menu adapts its size only when necessary, so in many
1798 cases, the size before and after the show is different. Instead,
1799 use sizeHint() which calculates the proper size depending on the
1800 menu's current contents.
1801
1802 \sa QWidget::mapToGlobal(), exec()
1803*/
1804void QMenu::popup(const QPoint &p, QAction *atAction)
1805{
1806 Q_D(QMenu);
1807 if (d->scroll) { //reset scroll state from last popup
1808 d->scroll->scrollOffset = 0;
1809 d->scroll->scrollFlags = QMenuPrivate::QMenuScroller::ScrollNone;
1810 }
1811 d->tearoffHighlighted = 0;
1812 d->motions = 0;
1813 d->doChildEffects = true;
1814 d->updateLayoutDirection();
1815
1816#ifndef QT_NO_MENUBAR
1817 // if this menu is part of a chain attached to a QMenuBar, set the
1818 // _NET_WM_WINDOW_TYPE_DROPDOWN_MENU X11 window type
1819 setAttribute(Qt::WA_X11NetWmWindowTypeDropDownMenu, qobject_cast<QMenuBar *>(d->topCausedWidget()) != 0);
1820#endif
1821
1822 ensurePolished(); // Get the right font
1823 emit aboutToShow();
1824 const bool actionListChanged = d->itemsDirty;
1825 d->updateActionRects();
1826 QPoint pos;
1827 QPushButton *causedButton = qobject_cast<QPushButton*>(d->causedPopup.widget);
1828 if (actionListChanged && causedButton)
1829 pos = QPushButtonPrivate::get(causedButton)->adjustedMenuPosition();
1830 else
1831 pos = p;
1832
1833 QSize size = sizeHint();
1834 QRect screen;
1835#ifndef QT_NO_GRAPHICSVIEW
1836 bool isEmbedded = d->nearestGraphicsProxyWidget(this);
1837 if (isEmbedded)
1838 screen = d->popupGeometry(this);
1839 else
1840#endif
1841 screen = d->popupGeometry(QApplication::desktop()->screenNumber(p));
1842
1843 const int desktopFrame = style()->pixelMetric(QStyle::PM_MenuDesktopFrameWidth, 0, this);
1844 bool adjustToDesktop = !window()->testAttribute(Qt::WA_DontShowOnScreen);
1845#ifdef QT_KEYPAD_NAVIGATION
1846 if (!atAction && QApplication::keypadNavigationEnabled()) {
1847 // Try to have one item activated
1848 if (d->defaultAction && d->defaultAction->isEnabled()) {
1849 atAction = d->defaultAction;
1850 // TODO: This works for first level menus, not yet sub menus
1851 } else {
1852 foreach (QAction *action, d->actions)
1853 if (action->isEnabled()) {
1854 atAction = action;
1855 break;
1856 }
1857 }
1858 d->currentAction = atAction;
1859 }
1860#endif
1861 if (d->ncols > 1) {
1862 pos.setY(screen.top()+desktopFrame);
1863 } else if (atAction) {
1864 for(int i = 0, above_height = 0; i < d->actions.count(); i++) {
1865 QAction *action = d->actions.at(i);
1866 if (action == atAction) {
1867 int newY = pos.y() - above_height;
1868 if (d->scroll && newY < desktopFrame) {
1869 d->scroll->scrollFlags = d->scroll->scrollFlags
1870 | QMenuPrivate::QMenuScroller::ScrollUp;
1871 d->scroll->scrollOffset = newY;
1872 newY = desktopFrame;
1873 }
1874 pos.setY(newY);
1875
1876 if (d->scroll && d->scroll->scrollFlags != QMenuPrivate::QMenuScroller::ScrollNone
1877 && !style()->styleHint(QStyle::SH_Menu_FillScreenWithScroll, 0, this)) {
1878 int below_height = above_height + d->scroll->scrollOffset;
1879 for(int i2 = i; i2 < d->actionRects.count(); i2++)
1880 below_height += d->actionRects.at(i2).height();
1881 size.setHeight(below_height);
1882 }
1883 break;
1884 } else {
1885 above_height += d->actionRects.at(i).height();
1886 }
1887 }
1888 }
1889
1890 QPoint mouse = QCursor::pos();
1891 d->mousePopupPos = mouse;
1892 const bool snapToMouse = (QRect(p.x()-3, p.y()-3, 6, 6).contains(mouse));
1893
1894 if (adjustToDesktop) {
1895 //handle popup falling "off screen"
1896 if (isRightToLeft()) {
1897 if(snapToMouse) //position flowing left from the mouse
1898 pos.setX(mouse.x()-size.width());
1899
1900#ifndef QT_NO_MENUBAR
1901 //if in a menubar, it should be right-aligned
1902 if (qobject_cast<QMenuBar*>(d->causedPopup.widget))
1903 pos.rx() -= size.width();
1904#endif //QT_NO_MENUBAR
1905
1906 if (pos.x() < screen.left()+desktopFrame)
1907 pos.setX(qMax(p.x(), screen.left()+desktopFrame));
1908 if (pos.x()+size.width()-1 > screen.right()-desktopFrame)
1909 pos.setX(qMax(p.x()-size.width(), screen.right()-desktopFrame-size.width()+1));
1910 } else {
1911 if (pos.x()+size.width()-1 > screen.right()-desktopFrame)
1912 pos.setX(screen.right()-desktopFrame-size.width()+1);
1913 if (pos.x() < screen.left()+desktopFrame)
1914 pos.setX(screen.left() + desktopFrame);
1915 }
1916 if (pos.y() + size.height() - 1 > screen.bottom() - desktopFrame) {
1917 if(snapToMouse)
1918 pos.setY(qMin(mouse.y() - (size.height() + desktopFrame), screen.bottom()-desktopFrame-size.height()+1));
1919 else
1920 pos.setY(qMax(p.y() - (size.height() + desktopFrame), screen.bottom()-desktopFrame-size.height()+1));
1921 } else if (pos.y() < screen.top() + desktopFrame) {
1922 pos.setY(screen.top() + desktopFrame);
1923 }
1924
1925 if (pos.y() < screen.top() + desktopFrame)
1926 pos.setY(screen.top() + desktopFrame);
1927 if (pos.y()+size.height()-1 > screen.bottom() - desktopFrame) {
1928 if (d->scroll) {
1929 d->scroll->scrollFlags |= uint(QMenuPrivate::QMenuScroller::ScrollDown);
1930 int y = qMax(screen.y(),pos.y());
1931 size.setHeight(screen.bottom()-(desktopFrame*2)-y);
1932 } else {
1933 // Too big for screen, bias to see bottom of menu (for some reason)
1934 pos.setY(screen.bottom()-size.height()+1);
1935 }
1936 }
1937 }
1938 setGeometry(QRect(pos, size));
1939#ifndef QT_NO_EFFECTS
1940 int hGuess = isRightToLeft() ? QEffects::LeftScroll : QEffects::RightScroll;
1941 int vGuess = QEffects::DownScroll;
1942 if (isRightToLeft()) {
1943 if ((snapToMouse && (pos.x() + size.width()/2 > mouse.x())) ||
1944 (qobject_cast<QMenu*>(d->causedPopup.widget) && pos.x() + size.width()/2 > d->causedPopup.widget->x()))
1945 hGuess = QEffects::RightScroll;
1946 } else {
1947 if ((snapToMouse && (pos.x() + size.width()/2 < mouse.x())) ||
1948 (qobject_cast<QMenu*>(d->causedPopup.widget) && pos.x() + size.width()/2 < d->causedPopup.widget->x()))
1949 hGuess = QEffects::LeftScroll;
1950 }
1951
1952#ifndef QT_NO_MENUBAR
1953 if ((snapToMouse && (pos.y() + size.height()/2 < mouse.y())) ||
1954 (qobject_cast<QMenuBar*>(d->causedPopup.widget) &&
1955 pos.y() + size.width()/2 < d->causedPopup.widget->mapToGlobal(d->causedPopup.widget->pos()).y()))
1956 vGuess = QEffects::UpScroll;
1957#endif
1958 if (QApplication::isEffectEnabled(Qt::UI_AnimateMenu)) {
1959 bool doChildEffects = true;
1960#ifndef QT_NO_MENUBAR
1961 if (QMenuBar *mb = qobject_cast<QMenuBar*>(d->causedPopup.widget)) {
1962 doChildEffects = mb->d_func()->doChildEffects;
1963 mb->d_func()->doChildEffects = false;
1964 } else
1965#endif
1966 if (QMenu *m = qobject_cast<QMenu*>(d->causedPopup.widget)) {
1967 doChildEffects = m->d_func()->doChildEffects;
1968 m->d_func()->doChildEffects = false;
1969 }
1970
1971 if (doChildEffects) {
1972 if (QApplication::isEffectEnabled(Qt::UI_FadeMenu))
1973 qFadeEffect(this);
1974 else if (d->causedPopup.widget)
1975 qScrollEffect(this, qobject_cast<QMenu*>(d->causedPopup.widget) ? hGuess : vGuess);
1976 else
1977 qScrollEffect(this, hGuess | vGuess);
1978 } else {
1979 // kill any running effect
1980 qFadeEffect(0);
1981 qScrollEffect(0);
1982
1983 show();
1984 }
1985 } else
1986#endif
1987 {
1988 show();
1989 }
1990
1991#ifndef QT_NO_ACCESSIBILITY
1992 QAccessible::updateAccessibility(this, 0, QAccessible::PopupMenuStart);
1993#endif
1994}
1995
1996/*!
1997 Executes this menu synchronously.
1998
1999 This is equivalent to \c{exec(pos())}.
2000
2001 This returns the triggered QAction in either the popup menu or one
2002 of its submenus, or 0 if no item was triggered (normally because
2003 the user pressed Esc).
2004
2005 In most situations you'll want to specify the position yourself,
2006 for example, the current mouse position:
2007 \snippet doc/src/snippets/code/src_gui_widgets_qmenu.cpp 0
2008 or aligned to a widget:
2009 \snippet doc/src/snippets/code/src_gui_widgets_qmenu.cpp 1
2010 or in reaction to a QMouseEvent *e:
2011 \snippet doc/src/snippets/code/src_gui_widgets_qmenu.cpp 2
2012*/
2013QAction *QMenu::exec()
2014{
2015 return exec(pos());
2016}
2017
2018
2019/*!
2020 \overload
2021
2022 Executes this menu synchronously.
2023
2024 Pops up the menu so that the action \a action will be at the
2025 specified \e global position \a p. To translate a widget's local
2026 coordinates into global coordinates, use QWidget::mapToGlobal().
2027
2028 This returns the triggered QAction in either the popup menu or one
2029 of its submenus, or 0 if no item was triggered (normally because
2030 the user pressed Esc).
2031
2032 Note that all signals are emitted as usual. If you connect a
2033 QAction to a slot and call the menu's exec(), you get the result
2034 both via the signal-slot connection and in the return value of
2035 exec().
2036
2037 Common usage is to position the menu at the current mouse
2038 position:
2039 \snippet doc/src/snippets/code/src_gui_widgets_qmenu.cpp 3
2040 or aligned to a widget:
2041 \snippet doc/src/snippets/code/src_gui_widgets_qmenu.cpp 4
2042 or in reaction to a QMouseEvent *e:
2043 \snippet doc/src/snippets/code/src_gui_widgets_qmenu.cpp 5
2044
2045 When positioning a menu with exec() or popup(), bear in mind that
2046 you cannot rely on the menu's current size(). For performance
2047 reasons, the menu adapts its size only when necessary. So in many
2048 cases, the size before and after the show is different. Instead,
2049 use sizeHint() which calculates the proper size depending on the
2050 menu's current contents.
2051
2052 \sa popup(), QWidget::mapToGlobal()
2053*/
2054QAction *QMenu::exec(const QPoint &p, QAction *action)
2055{
2056 Q_D(QMenu);
2057 createWinId();
2058 QEventLoop eventLoop;
2059 d->eventLoop = &eventLoop;
2060 popup(p, action);
2061
2062 QPointer<QObject> guard = this;
2063 (void) eventLoop.exec();
2064 if (guard.isNull())
2065 return 0;
2066
2067 action = d->syncAction;
2068 d->syncAction = 0;
2069 d->eventLoop = 0;
2070 return action;
2071}
2072
2073/*!
2074 \overload
2075
2076 Executes a menu synchronously.
2077
2078 The menu's actions are specified by the list of \a actions. The menu will
2079 pop up so that the specified action, \a at, appears at global position \a
2080 pos. If \a at is not specified then the menu appears at position \a
2081 pos. \a parent is the menu's parent widget; specifying the parent will
2082 provide context when \a pos alone is not enough to decide where the menu
2083 should go (e.g., with multiple desktops or when the parent is embedded in
2084 QGraphicsView).
2085
2086 The function returns the triggered QAction in either the popup
2087 menu or one of its submenus, or 0 if no item was triggered
2088 (normally because the user pressed Esc).
2089
2090 This is equivalent to:
2091 \snippet doc/src/snippets/code/src_gui_widgets_qmenu.cpp 6
2092
2093 \sa popup(), QWidget::mapToGlobal()
2094*/
2095QAction *QMenu::exec(QList<QAction*> actions, const QPoint &pos, QAction *at, QWidget *parent)
2096{
2097 QMenu menu(parent);
2098 menu.addActions(actions);
2099 return menu.exec(pos, at);
2100}
2101
2102/*!
2103 \overload
2104
2105 Executes a menu synchronously.
2106
2107 The menu's actions are specified by the list of \a actions. The menu
2108 will pop up so that the specified action, \a at, appears at global
2109 position \a pos. If \a at is not specified then the menu appears
2110 at position \a pos.
2111
2112 The function returns the triggered QAction in either the popup
2113 menu or one of its submenus, or 0 if no item was triggered
2114 (normally because the user pressed Esc).
2115
2116 This is equivalent to:
2117 \snippet doc/src/snippets/code/src_gui_widgets_qmenu.cpp 6
2118
2119 \sa popup(), QWidget::mapToGlobal()
2120*/
2121QAction *QMenu::exec(QList<QAction*> actions, const QPoint &pos, QAction *at)
2122{
2123 // ### Qt 5: merge
2124 return exec(actions, pos, at, 0);
2125}
2126
2127/*!
2128 \reimp
2129*/
2130void QMenu::hideEvent(QHideEvent *)
2131{
2132 Q_D(QMenu);
2133 emit aboutToHide();
2134 if (d->eventLoop)
2135 d->eventLoop->exit();
2136 d->setCurrentAction(0);
2137#ifndef QT_NO_ACCESSIBILITY
2138 QAccessible::updateAccessibility(this, 0, QAccessible::PopupMenuEnd);
2139#endif
2140#ifndef QT_NO_MENUBAR
2141 if (QMenuBar *mb = qobject_cast<QMenuBar*>(d->causedPopup.widget))
2142 mb->d_func()->setCurrentAction(0);
2143#endif
2144 d->mouseDown = 0;
2145 d->hasHadMouse = false;
2146 d->causedPopup.widget = 0;
2147 d->causedPopup.action = 0;
2148 if (d->scroll)
2149 d->scroll->scrollTimer.stop(); //make sure the timer stops
2150}
2151
2152/*!
2153 \reimp
2154*/
2155void QMenu::paintEvent(QPaintEvent *e)
2156{
2157 Q_D(QMenu);
2158 d->updateActionRects();
2159 QPainter p(this);
2160 QRegion emptyArea = QRegion(rect());
2161
2162 QStyleOptionMenuItem menuOpt;
2163 menuOpt.initFrom(this);
2164 menuOpt.state = QStyle::State_None;
2165 menuOpt.checkType = QStyleOptionMenuItem::NotCheckable;
2166 menuOpt.maxIconWidth = 0;
2167 menuOpt.tabWidth = 0;
2168 style()->drawPrimitive(QStyle::PE_PanelMenu, &menuOpt, &p, this);
2169
2170 //draw the items that need updating..
2171 for (int i = 0; i < d->actions.count(); ++i) {
2172 QAction *action = d->actions.at(i);
2173 QRect adjustedActionRect = d->actionRects.at(i);
2174 if (!e->rect().intersects(adjustedActionRect)
2175 || d->widgetItems.value(action))
2176 continue;
2177 //set the clip region to be extra safe (and adjust for the scrollers)
2178 QRegion adjustedActionReg(adjustedActionRect);
2179 emptyArea -= adjustedActionReg;
2180 p.setClipRegion(adjustedActionReg);
2181
2182 QStyleOptionMenuItem opt;
2183 initStyleOption(&opt, action);
2184 opt.rect = adjustedActionRect;
2185 style()->drawControl(QStyle::CE_MenuItem, &opt, &p, this);
2186 }
2187
2188 const int fw = style()->pixelMetric(QStyle::PM_MenuPanelWidth, 0, this);
2189 //draw the scroller regions..
2190 if (d->scroll) {
2191 menuOpt.menuItemType = QStyleOptionMenuItem::Scroller;
2192 menuOpt.state |= QStyle::State_Enabled;
2193 if (d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp) {
2194 menuOpt.rect.setRect(fw, fw, width() - (fw * 2), d->scrollerHeight());
2195 emptyArea -= QRegion(menuOpt.rect);
2196 p.setClipRect(menuOpt.rect);
2197 style()->drawControl(QStyle::CE_MenuScroller, &menuOpt, &p, this);
2198 }
2199 if (d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollDown) {
2200 menuOpt.rect.setRect(fw, height() - d->scrollerHeight() - fw, width() - (fw * 2),
2201 d->scrollerHeight());
2202 emptyArea -= QRegion(menuOpt.rect);
2203 menuOpt.state |= QStyle::State_DownArrow;
2204 p.setClipRect(menuOpt.rect);
2205 style()->drawControl(QStyle::CE_MenuScroller, &menuOpt, &p, this);
2206 }
2207 }
2208 //paint the tear off..
2209 if (d->tearoff) {
2210 menuOpt.menuItemType = QStyleOptionMenuItem::TearOff;
2211 menuOpt.rect.setRect(fw, fw, width() - (fw * 2),
2212 style()->pixelMetric(QStyle::PM_MenuTearoffHeight, 0, this));
2213 if (d->scroll && d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp)
2214 menuOpt.rect.translate(0, d->scrollerHeight());
2215 emptyArea -= QRegion(menuOpt.rect);
2216 p.setClipRect(menuOpt.rect);
2217 menuOpt.state = QStyle::State_None;
2218 if (d->tearoffHighlighted)
2219 menuOpt.state |= QStyle::State_Selected;
2220 style()->drawControl(QStyle::CE_MenuTearoff, &menuOpt, &p, this);
2221 }
2222 //draw border
2223 if (fw) {
2224 QRegion borderReg;
2225 borderReg += QRect(0, 0, fw, height()); //left
2226 borderReg += QRect(width()-fw, 0, fw, height()); //right
2227 borderReg += QRect(0, 0, width(), fw); //top
2228 borderReg += QRect(0, height()-fw, width(), fw); //bottom
2229 p.setClipRegion(borderReg);
2230 emptyArea -= borderReg;
2231 QStyleOptionFrame frame;
2232 frame.rect = rect();
2233 frame.palette = palette();
2234 frame.state = QStyle::State_None;
2235 frame.lineWidth = style()->pixelMetric(QStyle::PM_MenuPanelWidth);
2236 frame.midLineWidth = 0;
2237 style()->drawPrimitive(QStyle::PE_FrameMenu, &frame, &p, this);
2238 }
2239
2240 //finally the rest of the space
2241 p.setClipRegion(emptyArea);
2242 menuOpt.state = QStyle::State_None;
2243 menuOpt.menuItemType = QStyleOptionMenuItem::EmptyArea;
2244 menuOpt.checkType = QStyleOptionMenuItem::NotCheckable;
2245 menuOpt.rect = rect();
2246 menuOpt.menuRect = rect();
2247 style()->drawControl(QStyle::CE_MenuEmptyArea, &menuOpt, &p, this);
2248}
2249
2250#ifndef QT_NO_WHEELEVENT
2251/*!
2252 \reimp
2253*/
2254void QMenu::wheelEvent(QWheelEvent *e)
2255{
2256 Q_D(QMenu);
2257 if (d->scroll && rect().contains(e->pos()))
2258 d->scrollMenu(e->delta() > 0 ?
2259 QMenuPrivate::QMenuScroller::ScrollUp : QMenuPrivate::QMenuScroller::ScrollDown);
2260}
2261#endif
2262
2263/*!
2264 \reimp
2265*/
2266void QMenu::mousePressEvent(QMouseEvent *e)
2267{
2268 Q_D(QMenu);
2269 if (d->aboutToHide || d->mouseEventTaken(e))
2270 return;
2271 if (!rect().contains(e->pos())) {
2272 if (d->noReplayFor
2273 && QRect(d->noReplayFor->mapToGlobal(QPoint()), d->noReplayFor->size()).contains(e->globalPos()))
2274 setAttribute(Qt::WA_NoMouseReplay);
2275 if (d->eventLoop) // synchronous operation
2276 d->syncAction = 0;
2277 d->hideUpToMenuBar();
2278 return;
2279 }
2280 d->mouseDown = this;
2281
2282 QAction *action = d->actionAt(e->pos());
2283 d->setCurrentAction(action, 20);
2284 update();
2285}
2286
2287/*!
2288 \reimp
2289*/
2290void QMenu::mouseReleaseEvent(QMouseEvent *e)
2291{
2292 Q_D(QMenu);
2293 if (d->aboutToHide || d->mouseEventTaken(e))
2294 return;
2295 if(d->mouseDown != this) {
2296 d->mouseDown = 0;
2297 return;
2298 }
2299
2300 d->mouseDown = 0;
2301 d->setSyncAction();
2302 QAction *action = d->actionAt(e->pos());
2303
2304 if (action && action == d->currentAction) {
2305 if (action->menu())
2306 action->menu()->d_func()->setFirstActionActive();
2307 else {
2308#if defined(Q_WS_WIN)
2309 //On Windows only context menus can be activated with the right button
2310 if (e->button() == Qt::LeftButton || d->topCausedWidget() == 0)
2311#endif
2312 d->activateAction(action, QAction::Trigger);
2313 }
2314 } else if (d->hasMouseMoved(e->globalPos())) {
2315 d->hideUpToMenuBar();
2316 }
2317}
2318
2319/*!
2320 \reimp
2321*/
2322void QMenu::changeEvent(QEvent *e)
2323{
2324 Q_D(QMenu);
2325 if (e->type() == QEvent::StyleChange || e->type() == QEvent::FontChange ||
2326 e->type() == QEvent::LayoutDirectionChange) {
2327 d->itemsDirty = 1;
2328 setMouseTracking(style()->styleHint(QStyle::SH_Menu_MouseTracking, 0, this));
2329 if (isVisible())
2330 resize(sizeHint());
2331 if (!style()->styleHint(QStyle::SH_Menu_Scrollable, 0, this)) {
2332 delete d->scroll;
2333 d->scroll = 0;
2334 } else if (!d->scroll) {
2335 d->scroll = new QMenuPrivate::QMenuScroller;
2336 d->scroll->scrollFlags = QMenuPrivate::QMenuScroller::ScrollNone;
2337 }
2338 } else if (e->type() == QEvent::EnabledChange) {
2339 if (d->tornPopup) // torn-off menu
2340 d->tornPopup->setEnabled(isEnabled());
2341 d->menuAction->setEnabled(isEnabled());
2342#ifdef Q_WS_MAC
2343 if (d->mac_menu)
2344 d->setMacMenuEnabled(isEnabled());
2345#endif
2346 }
2347 QWidget::changeEvent(e);
2348}
2349
2350
2351/*!
2352 \reimp
2353*/
2354bool
2355QMenu::event(QEvent *e)
2356{
2357 Q_D(QMenu);
2358 switch (e->type()) {
2359 case QEvent::Polish:
2360 d->updateLayoutDirection();
2361 break;
2362 case QEvent::ShortcutOverride: {
2363 QKeyEvent *kev = static_cast<QKeyEvent*>(e);
2364 if (kev->key() == Qt::Key_Up || kev->key() == Qt::Key_Down
2365 || kev->key() == Qt::Key_Left || kev->key() == Qt::Key_Right
2366 || kev->key() == Qt::Key_Enter || kev->key() == Qt::Key_Return
2367 || kev->key() == Qt::Key_Escape) {
2368 e->accept();
2369 return true;
2370 }
2371 }
2372 break;
2373 case QEvent::KeyPress: {
2374 QKeyEvent *ke = (QKeyEvent*)e;
2375 if (ke->key() == Qt::Key_Tab || ke->key() == Qt::Key_Backtab) {
2376 keyPressEvent(ke);
2377 return true;
2378 }
2379 } break;
2380 case QEvent::ContextMenu:
2381 if(QMenuPrivate::menuDelayTimer.isActive()) {
2382 QMenuPrivate::menuDelayTimer.stop();
2383 internalDelayedPopup();
2384 }
2385 break;
2386 case QEvent::Resize: {
2387 QStyleHintReturnMask menuMask;
2388 QStyleOption option;
2389 option.initFrom(this);
2390 if (style()->styleHint(QStyle::SH_Menu_Mask, &option, this, &menuMask)) {
2391 setMask(menuMask.region);
2392 }
2393 d->itemsDirty = 1;
2394 d->updateActionRects();
2395 break; }
2396 case QEvent::Show:
2397 d->mouseDown = 0;
2398 d->updateActionRects();
2399 if (d->currentAction)
2400 d->popupAction(d->currentAction, 0, false);
2401 break;
2402#ifndef QT_NO_WHATSTHIS
2403 case QEvent::QueryWhatsThis:
2404 e->setAccepted(d->whatsThis.size());
2405 if (QAction *action = d->actionAt(static_cast<QHelpEvent*>(e)->pos())) {
2406 if (action->whatsThis().size() || action->menu())
2407 e->accept();
2408 }
2409 return true;
2410#endif
2411 default:
2412 break;
2413 }
2414 return QWidget::event(e);
2415}
2416
2417/*!
2418 \reimp
2419*/
2420bool QMenu::focusNextPrevChild(bool next)
2421{
2422 setFocus();
2423 QKeyEvent ev(QEvent::KeyPress, next ? Qt::Key_Tab : Qt::Key_Backtab, Qt::NoModifier);
2424 keyPressEvent(&ev);
2425 return true;
2426}
2427
2428/*!
2429 \reimp
2430*/
2431void QMenu::keyPressEvent(QKeyEvent *e)
2432{
2433 Q_D(QMenu);
2434 d->updateActionRects();
2435 int key = e->key();
2436 if (isRightToLeft()) { // in reverse mode open/close key for submenues are reversed
2437 if (key == Qt::Key_Left)
2438 key = Qt::Key_Right;
2439 else if (key == Qt::Key_Right)
2440 key = Qt::Key_Left;
2441 }
2442#ifndef Q_WS_MAC
2443 if (key == Qt::Key_Tab) //means down
2444 key = Qt::Key_Down;
2445 if (key == Qt::Key_Backtab) //means up
2446 key = Qt::Key_Up;
2447#endif
2448
2449 bool key_consumed = false;
2450 switch(key) {
2451 case Qt::Key_Home:
2452 key_consumed = true;
2453 if (d->scroll)
2454 d->scrollMenu(QMenuPrivate::QMenuScroller::ScrollTop, true);
2455 break;
2456 case Qt::Key_End:
2457 key_consumed = true;
2458 if (d->scroll)
2459 d->scrollMenu(QMenuPrivate::QMenuScroller::ScrollBottom, true);
2460 break;
2461 case Qt::Key_PageUp:
2462 key_consumed = true;
2463 if (d->currentAction && d->scroll) {
2464 if(d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp)
2465 d->scrollMenu(QMenuPrivate::QMenuScroller::ScrollUp, true, true);
2466 else
2467 d->scrollMenu(QMenuPrivate::QMenuScroller::ScrollTop, true);
2468 }
2469 break;
2470 case Qt::Key_PageDown:
2471 key_consumed = true;
2472 if (d->currentAction && d->scroll) {
2473 if(d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollDown)
2474 d->scrollMenu(QMenuPrivate::QMenuScroller::ScrollDown, true, true);
2475 else
2476 d->scrollMenu(QMenuPrivate::QMenuScroller::ScrollBottom, true);
2477 }
2478 break;
2479 case Qt::Key_Up:
2480 case Qt::Key_Down: {
2481 key_consumed = true;
2482 QAction *nextAction = 0;
2483 QMenuPrivate::QMenuScroller::ScrollLocation scroll_loc = QMenuPrivate::QMenuScroller::ScrollStay;
2484 if (!d->currentAction) {
2485 if(key == Qt::Key_Down) {
2486 for(int i = 0; i < d->actions.count(); ++i) {
2487 QAction *act = d->actions.at(i);
2488 if (d->actionRects.at(i).isNull())
2489 continue;
2490 if (!act->isSeparator() &&
2491 (style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled, 0, this)
2492 || act->isEnabled())) {
2493 nextAction = act;
2494 break;
2495 }
2496 }
2497 } else {
2498 for(int i = d->actions.count()-1; i >= 0; --i) {
2499 QAction *act = d->actions.at(i);
2500 if (d->actionRects.at(i).isNull())
2501 continue;
2502 if (!act->isSeparator() &&
2503 (style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled, 0, this)
2504 || act->isEnabled())) {
2505 nextAction = act;
2506 break;
2507 }
2508 }
2509 }
2510 } else {
2511 for(int i = 0, y = 0; !nextAction && i < d->actions.count(); i++) {
2512 QAction *act = d->actions.at(i);
2513 if (act == d->currentAction) {
2514 if (key == Qt::Key_Up) {
2515 for(int next_i = i-1; true; next_i--) {
2516 if (next_i == -1) {
2517 if(!style()->styleHint(QStyle::SH_Menu_SelectionWrap, 0, this))
2518 break;
2519 if (d->scroll)
2520 scroll_loc = QMenuPrivate::QMenuScroller::ScrollBottom;
2521 next_i = d->actionRects.count()-1;
2522 }
2523 QAction *next = d->actions.at(next_i);
2524 if (next == d->currentAction)
2525 break;
2526 if (d->actionRects.at(next_i).isNull())
2527 continue;
2528 if (next->isSeparator() ||
2529 (!next->isEnabled() &&
2530 !style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled, 0, this)))
2531 continue;
2532 nextAction = next;
2533 if (d->scroll && (d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp)) {
2534 int topVisible = d->scrollerHeight();
2535 if (d->tearoff)
2536 topVisible += style()->pixelMetric(QStyle::PM_MenuTearoffHeight, 0, this);
2537 if (((y + d->scroll->scrollOffset) - topVisible) <= d->actionRects.at(next_i).height())
2538 scroll_loc = QMenuPrivate::QMenuScroller::ScrollTop;
2539 }
2540 break;
2541 }
2542 if (!nextAction && d->tearoff)
2543 d->tearoffHighlighted = 1;
2544 } else {
2545 y += d->actionRects.at(i).height();
2546 for(int next_i = i+1; true; next_i++) {
2547 if (next_i == d->actionRects.count()) {
2548 if(!style()->styleHint(QStyle::SH_Menu_SelectionWrap, 0, this))
2549 break;
2550 if (d->scroll)
2551 scroll_loc = QMenuPrivate::QMenuScroller::ScrollTop;
2552 next_i = 0;
2553 }
2554 QAction *next = d->actions.at(next_i);
2555 if (next == d->currentAction)
2556 break;
2557 if (d->actionRects.at(next_i).isNull())
2558 continue;
2559 if (next->isSeparator() ||
2560 (!next->isEnabled() &&
2561 !style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled, 0, this)))
2562 continue;
2563 nextAction = next;
2564 if (d->scroll && (d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollDown)) {
2565 int bottomVisible = height() - d->scrollerHeight();
2566 if (d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp)
2567 bottomVisible -= d->scrollerHeight();
2568 if (d->tearoff)
2569 bottomVisible -= style()->pixelMetric(QStyle::PM_MenuTearoffHeight, 0, this);
2570 if ((y + d->scroll->scrollOffset + d->actionRects.at(next_i).height()) > bottomVisible)
2571 scroll_loc = QMenuPrivate::QMenuScroller::ScrollBottom;
2572 }
2573 break;
2574 }
2575 }
2576 break;
2577 }
2578 y += d->actionRects.at(i).height();
2579 }
2580 }
2581 if (nextAction) {
2582 if (d->scroll && scroll_loc != QMenuPrivate::QMenuScroller::ScrollStay) {
2583 d->scroll->scrollTimer.stop();
2584 d->scrollMenu(nextAction, scroll_loc);
2585 }
2586 d->setCurrentAction(nextAction, /*popup*/-1, QMenuPrivate::SelectedFromKeyboard);
2587 }
2588 break; }
2589
2590 case Qt::Key_Right:
2591 if (d->currentAction && d->currentAction->isEnabled() && d->currentAction->menu()) {
2592 d->popupAction(d->currentAction, 0, true);
2593 key_consumed = true;
2594 break;
2595 }
2596 //FALL THROUGH
2597 case Qt::Key_Left: {
2598 if (d->currentAction && !d->scroll) {
2599 QAction *nextAction = 0;
2600 if (key == Qt::Key_Left) {
2601 QRect actionR = d->actionRect(d->currentAction);
2602 for(int x = actionR.left()-1; !nextAction && x >= 0; x--)
2603 nextAction = d->actionAt(QPoint(x, actionR.center().y()));
2604 } else {
2605 QRect actionR = d->actionRect(d->currentAction);
2606 for(int x = actionR.right()+1; !nextAction && x < width(); x++)
2607 nextAction = d->actionAt(QPoint(x, actionR.center().y()));
2608 }
2609 if (nextAction) {
2610 d->setCurrentAction(nextAction, /*popup*/-1, QMenuPrivate::SelectedFromKeyboard);
2611 key_consumed = true;
2612 }
2613 }
2614 if (!key_consumed && key == Qt::Key_Left && qobject_cast<QMenu*>(d->causedPopup.widget)) {
2615 QPointer<QWidget> caused = d->causedPopup.widget;
2616 d->hideMenu(this);
2617 if (caused)
2618 caused->setFocus();
2619 key_consumed = true;
2620 }
2621 break; }
2622
2623 case Qt::Key_Alt:
2624 if (d->tornoff)
2625 break;
2626
2627 key_consumed = true;
2628 if (style()->styleHint(QStyle::SH_MenuBar_AltKeyNavigation, 0, this))
2629 {
2630 d->hideMenu(this);
2631#ifndef QT_NO_MENUBAR
2632 if (QMenuBar *mb = qobject_cast<QMenuBar*>(QApplication::focusWidget())) {
2633 mb->d_func()->setKeyboardMode(false);
2634 }
2635#endif
2636 }
2637 break;
2638
2639 case Qt::Key_Escape:
2640#ifdef QT_KEYPAD_NAVIGATION
2641 case Qt::Key_Back:
2642#endif
2643 key_consumed = true;
2644 if (d->tornoff) {
2645 close();
2646 return;
2647 }
2648 {
2649 QPointer<QWidget> caused = d->causedPopup.widget;
2650 d->hideMenu(this); // hide after getting causedPopup
2651#ifndef QT_NO_MENUBAR
2652 if (QMenuBar *mb = qobject_cast<QMenuBar*>(caused)) {
2653 mb->d_func()->setCurrentAction(d->menuAction);
2654 mb->d_func()->setKeyboardMode(true);
2655 }
2656#endif
2657 }
2658 break;
2659
2660 case Qt::Key_Space:
2661 if (!style()->styleHint(QStyle::SH_Menu_SpaceActivatesItem, 0, this))
2662 break;
2663 // for motif, fall through
2664#ifdef QT_KEYPAD_NAVIGATION
2665 case Qt::Key_Select:
2666#endif
2667 case Qt::Key_Return:
2668 case Qt::Key_Enter: {
2669 if (!d->currentAction) {
2670 d->setFirstActionActive();
2671 key_consumed = true;
2672 break;
2673 }
2674
2675 d->setSyncAction();
2676
2677 if (d->currentAction->menu())
2678 d->popupAction(d->currentAction, 0, true);
2679 else
2680 d->activateAction(d->currentAction, QAction::Trigger);
2681 key_consumed = true;
2682 break; }
2683
2684#ifndef QT_NO_WHATSTHIS
2685 case Qt::Key_F1:
2686 if (!d->currentAction || d->currentAction->whatsThis().isNull())
2687 break;
2688 QWhatsThis::enterWhatsThisMode();
2689 d->activateAction(d->currentAction, QAction::Trigger);
2690 return;
2691#endif
2692 default:
2693 key_consumed = false;
2694 }
2695
2696 if (!key_consumed) { // send to menu bar
2697 if ((!e->modifiers() || e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ShiftModifier) &&
2698 e->text().length()==1) {
2699 bool activateAction = false;
2700 QAction *nextAction = 0;
2701 if (style()->styleHint(QStyle::SH_Menu_KeyboardSearch, 0, this) && !e->modifiers()) {
2702 int best_match_count = 0;
2703 d->searchBufferTimer.start(2000, this);
2704 d->searchBuffer += e->text();
2705 for(int i = 0; i < d->actions.size(); ++i) {
2706 int match_count = 0;
2707 if (d->actionRects.at(i).isNull())
2708 continue;
2709 QAction *act = d->actions.at(i);
2710 const QString act_text = act->text();
2711 for(int c = 0; c < d->searchBuffer.size(); ++c) {
2712 if(act_text.indexOf(d->searchBuffer.at(c), 0, Qt::CaseInsensitive) != -1)
2713 ++match_count;
2714 }
2715 if(match_count > best_match_count) {
2716 best_match_count = match_count;
2717 nextAction = act;
2718 }
2719 }
2720 }
2721#ifndef QT_NO_SHORTCUT
2722 else {
2723 int clashCount = 0;
2724 QAction *first = 0, *currentSelected = 0, *firstAfterCurrent = 0;
2725 QChar c = e->text().at(0).toUpper();
2726 for(int i = 0; i < d->actions.size(); ++i) {
2727 if (d->actionRects.at(i).isNull())
2728 continue;
2729 QAction *act = d->actions.at(i);
2730 QKeySequence sequence = QKeySequence::mnemonic(act->text());
2731 int key = sequence[0] & 0xffff;
2732 if (key == c.unicode()) {
2733 clashCount++;
2734 if (!first)
2735 first = act;
2736 if (act == d->currentAction)
2737 currentSelected = act;
2738 else if (!firstAfterCurrent && currentSelected)
2739 firstAfterCurrent = act;
2740 }
2741 }
2742 if (clashCount == 1)
2743 activateAction = true;
2744 if (clashCount >= 1) {
2745 if (clashCount == 1 || !currentSelected || !firstAfterCurrent)
2746 nextAction = first;
2747 else
2748 nextAction = firstAfterCurrent;
2749 }
2750 }
2751#endif
2752 if (nextAction) {
2753 key_consumed = true;
2754 if(d->scroll)
2755 d->scrollMenu(nextAction, QMenuPrivate::QMenuScroller::ScrollCenter, false);
2756 d->setCurrentAction(nextAction, 20, QMenuPrivate::SelectedFromElsewhere, true);
2757 if (!nextAction->menu() && activateAction) {
2758 d->setSyncAction();
2759 d->activateAction(nextAction, QAction::Trigger);
2760 }
2761 }
2762 }
2763 if (!key_consumed) {
2764#ifndef QT_NO_MENUBAR
2765 if (QMenuBar *mb = qobject_cast<QMenuBar*>(d->topCausedWidget())) {
2766 QAction *oldAct = mb->d_func()->currentAction;
2767 QApplication::sendEvent(mb, e);
2768 if (mb->d_func()->currentAction != oldAct)
2769 key_consumed = true;
2770 }
2771#endif
2772 }
2773
2774#ifdef Q_OS_WIN32
2775 if (key_consumed && (e->key() == Qt::Key_Control || e->key() == Qt::Key_Shift || e->key() == Qt::Key_Meta))
2776 QApplication::beep();
2777#endif // Q_OS_WIN32
2778 }
2779 if (key_consumed)
2780 e->accept();
2781 else
2782 e->ignore();
2783}
2784
2785/*!
2786 \reimp
2787*/
2788void QMenu::mouseMoveEvent(QMouseEvent *e)
2789{
2790 Q_D(QMenu);
2791 if (!isVisible() || d->aboutToHide || d->mouseEventTaken(e))
2792 return;
2793 d->motions++;
2794 if (d->motions == 0) // ignore first mouse move event (see enterEvent())
2795 return;
2796 d->hasHadMouse = d->hasHadMouse || rect().contains(e->pos());
2797
2798 QAction *action = d->actionAt(e->pos());
2799 if (!action) {
2800 if (d->hasHadMouse)
2801 d->setCurrentAction(0);
2802 return;
2803 } else if(e->buttons()) {
2804 d->mouseDown = this;
2805 }
2806 if (d->sloppyRegion.contains(e->pos())) {
2807 d->sloppyAction = action;
2808 QMenuPrivate::sloppyDelayTimer.start(style()->styleHint(QStyle::SH_Menu_SubMenuPopupDelay, 0, this)*6, this);
2809 } else {
2810 d->setCurrentAction(action, style()->styleHint(QStyle::SH_Menu_SubMenuPopupDelay, 0, this));
2811 }
2812}
2813
2814/*!
2815 \reimp
2816*/
2817void QMenu::enterEvent(QEvent *)
2818{
2819 d_func()->motions = -1; // force us to ignore the generate mouse move in mouseMoveEvent()
2820}
2821
2822/*!
2823 \reimp
2824*/
2825void QMenu::leaveEvent(QEvent *)
2826{
2827 Q_D(QMenu);
2828 d->sloppyAction = 0;
2829 if (!d->sloppyRegion.isEmpty())
2830 d->sloppyRegion = QRegion();
2831 if (!d->activeMenu && d->currentAction)
2832 setActiveAction(0);
2833}
2834
2835/*!
2836 \reimp
2837*/
2838void
2839QMenu::timerEvent(QTimerEvent *e)
2840{
2841 Q_D(QMenu);
2842 if (d->scroll && d->scroll->scrollTimer.timerId() == e->timerId()) {
2843 d->scrollMenu((QMenuPrivate::QMenuScroller::ScrollDirection)d->scroll->scrollDirection);
2844 if (d->scroll->scrollFlags == QMenuPrivate::QMenuScroller::ScrollNone)
2845 d->scroll->scrollTimer.stop();
2846 } else if(QMenuPrivate::menuDelayTimer.timerId() == e->timerId()) {
2847 QMenuPrivate::menuDelayTimer.stop();
2848 internalDelayedPopup();
2849 } else if(QMenuPrivate::sloppyDelayTimer.timerId() == e->timerId()) {
2850 QMenuPrivate::sloppyDelayTimer.stop();
2851 internalSetSloppyAction();
2852 } else if(d->searchBufferTimer.timerId() == e->timerId()) {
2853 d->searchBuffer.clear();
2854 }
2855}
2856
2857/*!
2858 \reimp
2859*/
2860void QMenu::actionEvent(QActionEvent *e)
2861{
2862 Q_D(QMenu);
2863 d->itemsDirty = 1;
2864 setAttribute(Qt::WA_Resized, false);
2865 if (d->tornPopup)
2866 d->tornPopup->syncWithMenu(this, e);
2867 if (e->type() == QEvent::ActionAdded) {
2868 if(!d->tornoff) {
2869 connect(e->action(), SIGNAL(triggered()), this, SLOT(_q_actionTriggered()));
2870 connect(e->action(), SIGNAL(hovered()), this, SLOT(_q_actionHovered()));
2871 }
2872 if (QWidgetAction *wa = qobject_cast<QWidgetAction *>(e->action())) {
2873 QWidget *widget = wa->requestWidget(this);
2874 if (widget)
2875 d->widgetItems.insert(wa, widget);
2876 }
2877 } else if (e->type() == QEvent::ActionRemoved) {
2878 e->action()->disconnect(this);
2879 if (e->action() == d->currentAction)
2880 d->currentAction = 0;
2881 if (QWidgetAction *wa = qobject_cast<QWidgetAction *>(e->action())) {
2882 if (QWidget *widget = d->widgetItems.value(wa))
2883 wa->releaseWidget(widget);
2884 }
2885 d->widgetItems.remove(e->action());
2886 }
2887
2888#ifdef Q_WS_MAC
2889 if (d->mac_menu) {
2890 if (e->type() == QEvent::ActionAdded)
2891 d->mac_menu->addAction(e->action(), d->mac_menu->findAction(e->before()), d);
2892 else if (e->type() == QEvent::ActionRemoved)
2893 d->mac_menu->removeAction(e->action());
2894 else if (e->type() == QEvent::ActionChanged)
2895 d->mac_menu->syncAction(e->action());
2896 }
2897#endif
2898
2899#if defined(Q_WS_WINCE) && !defined(QT_NO_MENUBAR)
2900 if (!d->wce_menu)
2901 d->wce_menu = new QMenuPrivate::QWceMenuPrivate;
2902 if (e->type() == QEvent::ActionAdded)
2903 d->wce_menu->addAction(e->action(), d->wce_menu->findAction(e->before()));
2904 else if (e->type() == QEvent::ActionRemoved)
2905 d->wce_menu->removeAction(e->action());
2906 else if (e->type() == QEvent::ActionChanged)
2907 d->wce_menu->syncAction(e->action());
2908#endif
2909
2910#ifdef Q_WS_S60
2911 if (!d->symbian_menu)
2912 d->symbian_menu = new QMenuPrivate::QSymbianMenuPrivate;
2913 if (e->type() == QEvent::ActionAdded)
2914 d->symbian_menu->addAction(e->action(), d->symbian_menu->findAction(e->before()));
2915 else if (e->type() == QEvent::ActionRemoved)
2916 d->symbian_menu->removeAction(e->action());
2917 else if (e->type() == QEvent::ActionChanged)
2918 d->symbian_menu->syncAction(e->action());
2919#endif
2920 if (isVisible()) {
2921 d->updateActionRects();
2922 resize(sizeHint());
2923 update();
2924 }
2925}
2926
2927/*!
2928 \internal
2929*/
2930void QMenu::internalSetSloppyAction()
2931{
2932 if (d_func()->sloppyAction)
2933 d_func()->setCurrentAction(d_func()->sloppyAction, 0);
2934}
2935
2936/*!
2937 \internal
2938*/
2939void QMenu::internalDelayedPopup()
2940{
2941 Q_D(QMenu);
2942
2943 //hide the current item
2944 if (QMenu *menu = d->activeMenu) {
2945 d->activeMenu = 0;
2946 d->hideMenu(menu);
2947 }
2948
2949 if (!d->currentAction || !d->currentAction->isEnabled() || !d->currentAction->menu() ||
2950 !d->currentAction->menu()->isEnabled() || d->currentAction->menu()->isVisible())
2951 return;
2952
2953 //setup
2954 d->activeMenu = d->currentAction->menu();
2955 d->activeMenu->d_func()->causedPopup.widget = this;
2956 d->activeMenu->d_func()->causedPopup.action = d->currentAction;
2957
2958 int subMenuOffset = style()->pixelMetric(QStyle::PM_SubMenuOverlap, 0, this);
2959 const QRect actionRect(d->actionRect(d->currentAction));
2960 const QSize menuSize(d->activeMenu->sizeHint());
2961 const QPoint rightPos(mapToGlobal(QPoint(actionRect.right() + subMenuOffset + 1, actionRect.top())));
2962 const QPoint leftPos(mapToGlobal(QPoint(actionRect.left() - subMenuOffset - menuSize.width(), actionRect.top())));
2963
2964 QPoint pos(rightPos);
2965 QMenu *caused = qobject_cast<QMenu*>(d->activeMenu->d_func()->causedPopup.widget);
2966
2967 const QRect availGeometry(d->popupGeometry(caused));
2968 if (isRightToLeft()) {
2969 pos = leftPos;
2970 if ((caused && caused->x() < x()) || pos.x() < availGeometry.left()) {
2971 if(rightPos.x() + menuSize.width() < availGeometry.right())
2972 pos = rightPos;
2973 else
2974 pos.rx() = availGeometry.left();
2975 }
2976 } else {
2977 if ((caused && caused->x() > x()) || pos.x() + menuSize.width() > availGeometry.right()) {
2978 if(leftPos.x() < availGeometry.left())
2979 pos.rx() = availGeometry.right() - menuSize.width();
2980 else
2981 pos = leftPos;
2982 }
2983 }
2984
2985 //calc sloppy focus buffer
2986 if (style()->styleHint(QStyle::SH_Menu_SloppySubMenus, 0, this)) {
2987 QPoint cur = QCursor::pos();
2988 if (actionRect.contains(mapFromGlobal(cur))) {
2989 QPoint pts[4];
2990 pts[0] = QPoint(cur.x(), cur.y() - 2);
2991 pts[3] = QPoint(cur.x(), cur.y() + 2);
2992 if (pos.x() >= cur.x()) {
2993 pts[1] = QPoint(geometry().right(), pos.y());
2994 pts[2] = QPoint(geometry().right(), pos.y() + menuSize.height());
2995 } else {
2996 pts[1] = QPoint(pos.x() + menuSize.width(), pos.y());
2997 pts[2] = QPoint(pos.x() + menuSize.width(), pos.y() + menuSize.height());
2998 }
2999 QPolygon points(4);
3000 for(int i = 0; i < 4; i++)
3001 points.setPoint(i, mapFromGlobal(pts[i]));
3002 d->sloppyRegion = QRegion(points);
3003 }
3004 }
3005
3006 //do the popup
3007 d->activeMenu->popup(pos);
3008}
3009
3010/*!
3011 \fn void QMenu::addAction(QAction *action)
3012 \overload
3013
3014 Appends the action \a action to the menu's list of actions.
3015
3016 \sa QMenuBar::addAction(), QWidget::addAction()
3017*/
3018
3019/*!
3020 \fn void QMenu::aboutToHide()
3021 \since 4.2
3022
3023 This signal is emitted just before the menu is hidden from the user.
3024
3025 \sa aboutToShow(), hide()
3026*/
3027
3028/*!
3029 \fn void QMenu::aboutToShow()
3030
3031 This signal is emitted just before the menu is shown to the user.
3032
3033 \sa aboutToHide(), show()
3034*/
3035
3036/*!
3037 \fn void QMenu::triggered(QAction *action)
3038
3039 This signal is emitted when an action in this menu is triggered.
3040
3041 \a action is the action that caused the signal to be emitted.
3042
3043 Normally, you connect each menu action's \l{QAction::}{triggered()} signal
3044 to its own custom slot, but sometimes you will want to connect several
3045 actions to a single slot, for example, when you have a group of closely
3046 related actions, such as "left justify", "center", "right justify".
3047
3048 \note This signal is emitted for the main parent menu in a hierarchy.
3049 Hence, only the parent menu needs to be connected to a slot; sub-menus need
3050 not be connected.
3051
3052 \sa hovered(), QAction::triggered()
3053*/
3054
3055/*!
3056 \fn void QMenu::hovered(QAction *action)
3057
3058 This signal is emitted when a menu action is highlighted; \a action
3059 is the action that caused the signal to be emitted.
3060
3061 Often this is used to update status information.
3062
3063 \sa triggered(), QAction::hovered()
3064*/
3065
3066
3067/*!\internal
3068*/
3069void QMenu::setNoReplayFor(QWidget *noReplayFor)
3070{
3071#if defined(Q_WS_WIN) || defined(Q_WS_PM)
3072 d_func()->noReplayFor = noReplayFor;
3073#else
3074 Q_UNUSED(noReplayFor);
3075#endif
3076}
3077
3078/*!
3079 \property QMenu::separatorsCollapsible
3080 \since 4.2
3081
3082 \brief whether consecutive separators should be collapsed
3083
3084 This property specifies whether consecutive separators in the menu
3085 should be visually collapsed to a single one. Separators at the
3086 beginning or the end of the menu are also hidden.
3087
3088 By default, this property is true.
3089*/
3090bool QMenu::separatorsCollapsible() const
3091{
3092 Q_D(const QMenu);
3093 return d->collapsibleSeparators;
3094}
3095
3096void QMenu::setSeparatorsCollapsible(bool collapse)
3097{
3098 Q_D(QMenu);
3099 if (d->collapsibleSeparators == collapse)
3100 return;
3101
3102 d->collapsibleSeparators = collapse;
3103 d->itemsDirty = 1;
3104 if (isVisible()) {
3105 d->updateActionRects();
3106 update();
3107 }
3108#ifdef Q_WS_MAC
3109 if (d->mac_menu)
3110 d->syncSeparatorsCollapsible(collapse);
3111#endif
3112}
3113
3114#ifdef QT3_SUPPORT
3115
3116int QMenu::insertAny(const QIcon *icon, const QString *text, const QObject *receiver, const char *member,
3117 const QKeySequence *shortcut, const QMenu *popup, int id, int index)
3118{
3119 QAction *act = popup ? popup->menuAction() : new QAction(this);
3120 if (id != -1)
3121 static_cast<QMenuItem*>(act)->setId(id);
3122 if (icon)
3123 act->setIcon(*icon);
3124 if (text)
3125 act->setText(*text);
3126 if (shortcut)
3127 act->setShortcut(*shortcut);
3128 if (receiver && member)
3129 QObject::connect(act, SIGNAL(activated(int)), receiver, member);
3130 if (index == -1 || index >= actions().count())
3131 addAction(act);
3132 else
3133 insertAction(actions().value(index), act);
3134 return findIdForAction(act);
3135}
3136
3137/*!
3138 Use insertAction() or one of the addAction() overloads instead.
3139*/
3140int QMenu::insertItem(QMenuItem *item, int id, int index)
3141{
3142 if (index == -1 || index >= actions().count())
3143 addAction(item);
3144 else
3145 insertAction(actions().value(index), item);
3146 if (id > -1)
3147 item->d_func()->id = id;
3148 return findIdForAction(item);
3149}
3150
3151/*!
3152 Use the insertSeparator() overload that takes a QAction *
3153 parameter instead.
3154*/
3155int QMenu::insertSeparator(int index)
3156{
3157 QAction *act = new QAction(this);
3158 act->setSeparator(true);
3159 if (index == -1 || index >= actions().count())
3160 addAction(act);
3161 else
3162 insertAction(actions().value(index), act);
3163 return findIdForAction(act);
3164}
3165
3166QAction *QMenu::findActionForId(int id) const
3167{
3168 Q_D(const QMenu);
3169 for (int i = 0; i < d->actions.size(); ++i) {
3170 QAction *act = d->actions.at(i);
3171 if (findIdForAction(act)== id)
3172 return act;
3173 }
3174 return 0;
3175}
3176
3177/*!
3178 Use QAction and actions() instead.
3179*/
3180QMenuItem *QMenu::findPopup( QMenu *popup, int *index )
3181{
3182 QList<QAction *> list = actions();
3183 for (int i = 0; i < list.size(); ++i) {
3184 QAction *act = list.at(i);
3185 if (act->menu() == popup) {
3186 QMenuItem *item = static_cast<QMenuItem *>(act);
3187 if (index)
3188 *index = act->d_func()->id;
3189 return item;
3190 }
3191 }
3192 return 0;
3193}
3194
3195
3196/*!
3197 Use QAction::setData() instead.
3198*/
3199bool QMenu::setItemParameter(int id, int param)
3200{
3201 if (QAction *act = findActionForId(id)) {
3202 act->d_func()->param = param;
3203 return true;
3204 }
3205 return false;
3206}
3207
3208/*!
3209 Use QAction::data() instead.
3210*/
3211int QMenu::itemParameter(int id) const
3212{
3213 if (QAction *act = findActionForId(id))
3214 return act->d_func()->param;
3215 return id;
3216}
3217
3218/*!
3219 Use actions instead.
3220*/
3221void QMenu::setId(int index, int id)
3222{
3223 if(QAction *act = actions().value(index))
3224 act->d_func()->id = id;
3225}
3226
3227/*!
3228 Use style()->pixelMetric(QStyle::PM_MenuPanelWidth, this) instead.
3229*/
3230int QMenu::frameWidth() const
3231{
3232 return style()->pixelMetric(QStyle::PM_MenuPanelWidth, 0, this);
3233}
3234
3235int QMenu::findIdForAction(QAction *act) const
3236{
3237 if (!act)
3238 return -1;
3239 return act->d_func()->id;
3240}
3241#endif // QT3_SUPPORT
3242
3243/*!
3244 \fn uint QMenu::count() const
3245
3246 Use actions().count() instead.
3247*/
3248
3249/*!
3250 \fn int QMenu::insertItem(const QString &text, const QObject *receiver, const char* member, const QKeySequence& shortcut, int id, int index)
3251
3252 Use insertAction() or one of the addAction() overloads instead.
3253*/
3254
3255/*!
3256 \fn int QMenu::insertItem(const QIcon& icon, const QString &text, const QObject *receiver, const char* member, const QKeySequence& shortcut, int id, int index)
3257
3258 Use insertAction() or one of the addAction() overloads instead.
3259*/
3260
3261/*!
3262 \fn int QMenu::insertItem(const QPixmap &pixmap, const QObject *receiver, const char* member, const QKeySequence& shortcut, int id, int index)
3263
3264 Use insertAction() or one of the addAction() overloads instead.
3265*/
3266
3267/*!
3268 \fn int QMenu::insertItem(const QString &text, int id, int index)
3269
3270 Use insertAction() or one of the addAction() overloads instead.
3271*/
3272
3273/*!
3274 \fn int QMenu::insertItem(const QIcon& icon, const QString &text, int id, int index)
3275
3276 Use insertAction() or one of the addAction() overloads instead.
3277*/
3278
3279/*!
3280 \fn int QMenu::insertItem(const QString &text, QMenu *popup, int id, int index)
3281
3282 Use insertMenu() or one of the addMenu() overloads instead.
3283*/
3284
3285/*!
3286 \fn int QMenu::insertItem(const QIcon& icon, const QString &text, QMenu *popup, int id, int index)
3287
3288 Use insertMenu() or one of the addMenu() overloads instead.
3289*/
3290
3291/*!
3292 \fn int QMenu::insertItem(const QPixmap &pixmap, int id, int index)
3293
3294 Use insertAction() or one of the addAction() overloads instead.
3295*/
3296
3297/*!
3298 \fn int QMenu::insertItem(const QPixmap &pixmap, QMenu *popup, int id, int index)
3299
3300 Use insertMenu() or one of the addMenu() overloads instead.
3301*/
3302
3303/*!
3304 \fn void QMenu::removeItem(int id)
3305
3306 Use removeAction() instead.
3307*/
3308
3309/*!
3310 \fn void QMenu::removeItemAt(int index)
3311
3312 Use removeAction() instead.
3313*/
3314
3315/*!
3316 \fn QKeySequence QMenu::accel(int id) const
3317
3318 Use shortcut() on the relevant QAction instead.
3319*/
3320
3321/*!
3322 \fn void QMenu::setAccel(const QKeySequence& key, int id)
3323
3324 Use setShortcut() on the relevant QAction instead.
3325*/
3326
3327/*!
3328 \fn QIcon QMenu::iconSet(int id) const
3329
3330 Use icon() on the relevant QAction instead.
3331*/
3332
3333/*!
3334 \fn QString QMenu::text(int id) const
3335
3336 Use text() on the relevant QAction instead.
3337*/
3338
3339/*!
3340 \fn QPixmap QMenu::pixmap(int id) const
3341
3342 Use QPixmap(icon()) on the relevant QAction instead.
3343*/
3344
3345/*!
3346 \fn void QMenu::setWhatsThis(int id, const QString &w)
3347
3348 Use setWhatsThis() on the relevant QAction instead.
3349*/
3350
3351/*!
3352 \fn QString QMenu::whatsThis(int id) const
3353
3354 Use whatsThis() on the relevant QAction instead.
3355*/
3356
3357/*!
3358 \fn void QMenu::changeItem(int id, const QString &text)
3359
3360 Use setText() on the relevant QAction instead.
3361*/
3362
3363/*!
3364 \fn void QMenu::changeItem(int id, const QPixmap &pixmap)
3365
3366 Use setText() on the relevant QAction instead.
3367*/
3368
3369/*!
3370 \fn void QMenu::changeItem(int id, const QIcon &icon, const QString &text)
3371
3372 Use setIcon() and setText() on the relevant QAction instead.
3373*/
3374
3375/*!
3376 \fn bool QMenu::isItemActive(int id) const
3377
3378 Use activeAction() instead.
3379*/
3380
3381/*!
3382 \fn bool QMenu::isItemEnabled(int id) const
3383
3384 Use isEnabled() on the relevant QAction instead.
3385*/
3386
3387/*!
3388 \fn void QMenu::setItemEnabled(int id, bool enable)
3389
3390 Use setEnabled() on the relevant QAction instead.
3391*/
3392
3393/*!
3394 \fn bool QMenu::isItemChecked(int id) const
3395
3396 Use isChecked() on the relevant QAction instead.
3397*/
3398
3399/*!
3400 \fn void QMenu::setItemChecked(int id, bool check)
3401
3402 Use setChecked() on the relevant QAction instead.
3403*/
3404
3405/*!
3406 \fn bool QMenu::isItemVisible(int id) const
3407
3408 Use isVisible() on the relevant QAction instead.
3409*/
3410
3411/*!
3412 \fn void QMenu::setItemVisible(int id, bool visible)
3413
3414 Use setVisible() on the relevant QAction instead.
3415*/
3416
3417/*!
3418 \fn QRect QMenu::itemGeometry(int index)
3419
3420 Use actionGeometry() on the relevant QAction instead.
3421*/
3422
3423/*!
3424 \fn QFont QMenu::itemFont(int id) const
3425
3426 Use font() on the relevant QAction instead.
3427*/
3428
3429/*!
3430 \fn void QMenu::setItemFont(int id, const QFont &font)
3431
3432 Use setFont() on the relevant QAction instead.
3433*/
3434
3435/*!
3436 \fn int QMenu::indexOf(int id) const
3437
3438 Use actions().indexOf(action) on the relevant QAction instead.
3439*/
3440
3441/*!
3442 \fn int QMenu::idAt(int index) const
3443
3444 Use actions instead.
3445*/
3446
3447/*!
3448 \fn void QMenu::activateItemAt(int index)
3449
3450 Use activate() on the relevant QAction instead.
3451*/
3452
3453/*!
3454 \fn bool QMenu::connectItem(int id, const QObject *receiver, const char* member)
3455
3456 Use connect() on the relevant QAction instead.
3457*/
3458
3459/*!
3460 \fn bool QMenu::disconnectItem(int id,const QObject *receiver, const char* member)
3461 Use disconnect() on the relevant QAction instead.
3462
3463*/
3464
3465/*!
3466 \fn QMenuItem *QMenu::findItem(int id) const
3467
3468 Use actions instead.
3469*/
3470
3471/*!
3472 \fn void QMenu::popup(const QPoint & pos, int indexAtPoint)
3473
3474 Use popup() on the relevant QAction instead.
3475*/
3476
3477/*!
3478 \fn int QMenu::insertTearOffHandle(int a, int b)
3479
3480 Use setTearOffEnabled() instead.
3481*/
3482
3483/*!
3484 \fn int QMenu::itemAtPos(const QPoint &p, bool ignoreSeparator)
3485
3486 Use actions instead.
3487*/
3488
3489/*!
3490 \fn int QMenu::columns() const
3491
3492 Use columnCount() instead.
3493*/
3494
3495/*!
3496 \fn int QMenu::itemHeight(int index)
3497
3498 Use actionGeometry(actions().value(index)).height() instead.
3499*/
3500
3501/*!
3502 \fn int QMenu::itemHeight(QMenuItem *mi)
3503
3504 Use actionGeometry() instead.
3505*/
3506
3507/*!
3508 \fn void QMenu::activated(int itemId);
3509
3510 Use triggered() instead.
3511*/
3512
3513/*!
3514 \fn void QMenu::highlighted(int itemId);
3515
3516 Use hovered() instead.
3517*/
3518
3519/*!
3520 \fn void QMenu::setCheckable(bool checkable)
3521
3522 Not necessary anymore. The \a checkable parameter is ignored.
3523*/
3524
3525/*!
3526 \fn bool QMenu::isCheckable() const
3527
3528 Not necessary anymore. Always returns true.
3529*/
3530
3531/*!
3532 \fn void QMenu::setActiveItem(int id)
3533
3534 Use setActiveAction() instead.
3535*/
3536
3537QT_END_NAMESPACE
3538
3539// for private slots
3540#include "moc_qmenu.cpp"
3541#include "qmenu.moc"
3542
3543#endif // QT_NO_MENU
Note: See TracBrowser for help on using the repository browser.