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

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

trunk: Merged in qt 4.6.3 sources from branches/vendor/nokia/qt.

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