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