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