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