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

Last change on this file since 138 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

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