src/hbcore/gui/hbmenu.cpp
changeset 0 16d8024aca5e
child 1 f7ac710697a9
equal deleted inserted replaced
-1:000000000000 0:16d8024aca5e
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2008-2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (developer.feedback@nokia.com)
       
     6 **
       
     7 ** This file is part of the HbCore module of the UI Extensions for Mobile.
       
     8 **
       
     9 ** GNU Lesser General Public License Usage
       
    10 ** This file may be used under the terms of the GNU Lesser General Public
       
    11 ** License version 2.1 as published by the Free Software Foundation and
       
    12 ** appearing in the file LICENSE.LGPL included in the packaging of this file.
       
    13 ** Please review the following information to ensure the GNU Lesser General
       
    14 ** Public License version 2.1 requirements will be met:
       
    15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    16 **
       
    17 ** In addition, as a special exception, Nokia gives you certain additional
       
    18 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    20 **
       
    21 ** If you have questions regarding the use of this file, please contact
       
    22 ** Nokia at developer.feedback@nokia.com.
       
    23 **
       
    24 ****************************************************************************/
       
    25 
       
    26 #include "hbmenu.h"
       
    27 #include "hbmenu_p.h"
       
    28 #include "hbmenuitem_p.h"
       
    29 #include "hbaction.h"
       
    30 #include <hbwidgetfeedback.h>
       
    31 #include "hbinstance.h"
       
    32 #include "hbmenucontainer_p.h"
       
    33 #ifdef HB_EFFECTS
       
    34 #include "hbeffect.h"
       
    35 #include "hbeffectinternal_p.h"
       
    36 bool HbMenuPrivate::menuEffectsLoaded = false;
       
    37 #endif
       
    38 
       
    39 #include <QPointer>
       
    40 
       
    41 Q_DECLARE_METATYPE (QAction*)// krazy:exclude=qclasses
       
    42 
       
    43 HbMenuPrivate::HbMenuPrivate():
       
    44     HbPopupPrivate(),
       
    45     menuItemView(0),
       
    46     subMenuAction(0),
       
    47     activeSubMenu(0),
       
    48     resultAction(0),
       
    49     actionTriggered(false),
       
    50     menuType(HbMenu::ContextMenu),
       
    51     mSubMenuItem(0),
       
    52     mRightMargin(0.0),
       
    53     mDownMargin(0.0),
       
    54     delayMenuConstruction(true),
       
    55     receiverToDisconnectOnClose(0)
       
    56 {
       
    57 }
       
    58 
       
    59 HbMenuPrivate::~HbMenuPrivate()
       
    60 {
       
    61 }
       
    62 
       
    63 void HbMenuPrivate::init()
       
    64 {
       
    65     Q_Q(HbMenu);
       
    66 
       
    67     subMenuAction = new HbAction(q);
       
    68     subMenuAction->setMenu(q);
       
    69     q->setTimeout(HbPopup::ContextMenuTimeout);
       
    70 
       
    71     q->setBackgroundFaded(false);
       
    72     q->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
       
    73 }
       
    74 
       
    75 void HbMenuPrivate::addPopupEffects()
       
    76 {
       
    77 #ifdef HB_EFFECTS
       
    78     effectType = "HB_MENU";
       
    79     hasEffects = menuEffectsLoaded;
       
    80     if (menuEffectsLoaded)
       
    81         return;
       
    82     menuEffectsLoaded = true;
       
    83     hasEffects = HbEffectInternal::add("HB_MENU", "menu_appear", "appear");
       
    84     if (hasEffects) {
       
    85         //We load the disappear effect only if appear effect was also loaded
       
    86         hasEffects = HbEffectInternal::add("HB_MENU", "menu_disappear", "disappear");
       
    87 
       
    88         if (hasEffects) {
       
    89             hasEffects = HbEffectInternal::add("HB_menuitem", "menuitem_press", "clicked");
       
    90         }
       
    91         if (hasEffects ) {
       
    92             hasEffects = HbEffectInternal::add("HB_POPUP",
       
    93                                                "dialog_rotate",
       
    94                                                "orientationswitch");
       
    95         }
       
    96     }
       
    97 #endif
       
    98 }
       
    99 
       
   100 void HbMenuPrivate::_q_triggerAction(HbMenuItem *currentItem)
       
   101 {
       
   102     Q_Q(HbMenu);
       
   103     if (currentItem && currentItem->action()){
       
   104         HbWidgetFeedback::triggered(currentItem, Hb::InstantClicked);
       
   105 #ifdef HB_EFFECTS
       
   106         if (hasEffects) {
       
   107             HbEffect::start(currentItem, "HB_menuitem", "clicked");
       
   108         }
       
   109 #endif
       
   110         HbAction *hbAction = qobject_cast<HbAction *>(currentItem->action());
       
   111         if (hbAction && hbAction->menu()) {
       
   112             hbAction->trigger();
       
   113             stopTimeout();
       
   114             openSubmenu(currentItem);
       
   115         } else {
       
   116             q->close();
       
   117             
       
   118             resultAction = hbAction;
       
   119 
       
   120             if (!actionTriggered) { // prevent duplicate events
       
   121                 currentItem->action()->trigger();
       
   122             }
       
   123             actionTriggered = true;
       
   124         }
       
   125     }
       
   126 }
       
   127 
       
   128 void HbMenuPrivate::createMenuView()
       
   129 {
       
   130     Q_Q(HbMenu);
       
   131     if (!menuItemView && q->actions().count()){
       
   132         menuItemView = new HbMenuListView(q, q);
       
   133         HbStyle::setItemName(menuItemView, "content");
       
   134         /* This is for qt versions 4.5,which had the clipping problem.
       
   135            FOR http://www.qtsoftware.com/developer/task-tracker/index_html?id=257232&method=entry
       
   136           see also HbMenu constructor */
       
   137 #if QT_VERSION < 0x040600
       
   138         menuItemView->setFlag( QGraphicsItem::ItemClipsChildrenToShape, false );
       
   139 #endif
       
   140    //This optimises case of options menu which otherwise updates its primitives twice.
       
   141         if (menuType ==  HbMenu::OptionsMenu)
       
   142             q->setFrameType(HbPopup::Strong);
       
   143     	else
       
   144             q->setFrameType(HbPopup::Weak);
       
   145         if (polished)//This check can be removed once base class repolish is fixed.
       
   146             q->repolish();
       
   147     }	
       
   148 }
       
   149 
       
   150 void HbMenuPrivate::delayedLayout()
       
   151 {
       
   152     createMenuView();
       
   153     if(menuItemView)
       
   154         menuItemView->doDelayedLayout();
       
   155     delayMenuConstruction = false;
       
   156 }
       
   157 
       
   158 void HbMenuPrivate::changeToOptionsMenu()
       
   159 {
       
   160     menuType = HbMenu::OptionsMenu;
       
   161 }
       
   162 
       
   163 HbMenuItem *HbMenuPrivate::subMenuItem()
       
   164 {
       
   165     return mSubMenuItem;
       
   166 }
       
   167 
       
   168 void HbMenuPrivate::setSubMenuItem(HbMenuItem *menuItem)
       
   169 {
       
   170     mSubMenuItem = menuItem;
       
   171 }
       
   172 
       
   173 void HbMenuPrivate::_q_onActionTriggered()
       
   174 {
       
   175     Q_Q(HbMenu);
       
   176        HbAction *action = qobject_cast<HbAction *>(q->sender());
       
   177     if (action && !action->menu() ) { // do not trigger from opening submenu
       
   178         emit q->triggered(action);
       
   179     }
       
   180 }
       
   181 
       
   182 void HbMenuPrivate::_q_subMenuItemTriggered(HbAction *action)
       
   183 {
       
   184     Q_Q(HbMenu);    
       
   185  
       
   186     // do not close the menu tree if the triggered action is
       
   187     // submenu item
       
   188     if (!action->menu()) { 
       
   189         q->close();
       
   190     } else {
       
   191         stopTimeout();
       
   192     }
       
   193 }
       
   194 
       
   195 void HbMenuPrivate::actionAdded(QActionEvent *actionEvent)
       
   196 {
       
   197     if (delayMenuConstruction)
       
   198         return;
       
   199     if (actionEvent->action()->isVisible()){
       
   200         Q_Q(HbMenu);
       
   201         createMenuView();
       
   202         QObject::connect(actionEvent->action(), SIGNAL(triggered()), q, SLOT(_q_onActionTriggered()));
       
   203         menuItemView->addActionItem(actionEvent->action());
       
   204     }
       
   205 }
       
   206 
       
   207 void HbMenuPrivate::actionRemoved(QActionEvent *actionEvent)
       
   208 {
       
   209     if (delayMenuConstruction)
       
   210         return;
       
   211     Q_Q(HbMenu);
       
   212     QObject::disconnect(actionEvent->action(), 0, q, 0);
       
   213     if (menuItemView)
       
   214         menuItemView->removeActionItem(actionEvent->action());
       
   215 }
       
   216 
       
   217 void HbMenuPrivate::actionChanged(QActionEvent *actionEvent)
       
   218 {
       
   219     if (delayMenuConstruction)
       
   220         return;
       
   221     if (menuItemView)
       
   222         menuItemView->updateActionItem(actionEvent->action());
       
   223 }
       
   224 
       
   225 /*
       
   226    Returns current focusable action based on current row of the menuItemView or index if specified.
       
   227    If there is no focusable action it returns 0.
       
   228    Also returns the active item representing the active action or 0.
       
   229 */
       
   230 HbAction *HbMenuPrivate::activeAction(HbMenuItem *&activeItem) const
       
   231 {
       
   232     if(!menuItemView)
       
   233         return 0;
       
   234     HbAction *action = 0;
       
   235     HbMenuItem *currentItem = menuItemView->currentItem();
       
   236     if(currentItem && currentItem->action() && currentItem->action()->isVisible() &&
       
   237        currentItem->action()->isEnabled() && !currentItem->action()->isSeparator()) {
       
   238         action = static_cast<HbAction*>(currentItem->action());
       
   239         activeItem = currentItem;
       
   240     }
       
   241     return action;
       
   242 }
       
   243 
       
   244 /*
       
   245   Convenience overload
       
   246 */
       
   247 HbAction *HbMenuPrivate::activeAction() const
       
   248 {
       
   249     HbMenuItem* activeItem = 0;
       
   250     return activeAction(activeItem);
       
   251 }
       
   252 
       
   253 /*
       
   254   Opens a submenu for activeItem. If activeItem is 0 it uses activeAction() to determine active item
       
   255   and opens submenu for it if active action has submenu.
       
   256 */
       
   257 void HbMenuPrivate::openSubmenu(HbMenuItem *activeItem)
       
   258 {
       
   259     Q_Q(HbMenu);
       
   260 
       
   261     if (!activeItem) {
       
   262         activeAction(activeItem);
       
   263     }
       
   264 
       
   265     if (activeItem && activeItem->action() && activeItem->action()->isEnabled()) {
       
   266         HbAction *hbAction = qobject_cast<HbAction *>(activeItem->action());
       
   267         if (!hbAction)
       
   268             return;
       
   269         HbMenu *subMenu = hbAction->menu();
       
   270         if ( subMenu ) {
       
   271             subMenu->setLayoutDirection(q->layoutDirection());
       
   272 
       
   273             activeSubMenu = subMenu; 
       
   274             subMenu->setTimeout(timeout); 
       
   275             QObject::disconnect(subMenu, SIGNAL(aboutToClose()), q, SLOT(_q_subMenuTimedOut()));
       
   276             QObject::connect(subMenu, SIGNAL(aboutToClose()), q, SLOT(_q_subMenuTimedOut()));
       
   277             QObject::connect(subMenu, SIGNAL(triggered(HbAction*)), q, SLOT(_q_subMenuItemTriggered(HbAction*)));
       
   278             subMenu->show();
       
   279 
       
   280             // Reset the active submenu so that mouse event handling works.
       
   281             // huh ? activeSubMenu = 0;
       
   282         }
       
   283     }
       
   284 }
       
   285 
       
   286 void HbMenuPrivate::_q_subMenuTimedOut()
       
   287 {
       
   288     Q_Q(HbMenu);
       
   289     if( menuTimedOut (activeSubMenu) ) {
       
   290         if ( activeSubMenu ) {
       
   291             activeSubMenu->disconnect();
       
   292         }
       
   293         q->close();
       
   294     }
       
   295 }
       
   296 
       
   297 bool HbMenuPrivate::menuTimedOut(HbMenu* menu)
       
   298 {
       
   299     return (menu && menu->timeout() > 0 && HbMenuPrivate::d_ptr(menu)->timedOut);
       
   300 }
       
   301 
       
   302 void HbMenuPrivate::closeSubmenu()
       
   303 {
       
   304     // Check whether this is a submenu.
       
   305     if (activeSubMenu) {
       
   306         activeSubMenu->close();
       
   307     }
       
   308 }
       
   309 
       
   310 void HbMenuPrivate::setSubMenuPosition()
       
   311 {
       
   312     Q_Q(HbMenu);
       
   313     if (mSubMenuItem) {        
       
   314         qreal upperEdge = mSubMenuItem->scenePos().y() + mSubMenuItem->size().height() * 2 / 3;
       
   315         QSizeF windowSize = QSizeF(0,0);
       
   316         if (q->mainWindow()) {
       
   317             QGraphicsWidget *viewPortItem = q->mainWindow()->element(HbMainWindow::ViewportItem);
       
   318             if (viewPortItem) {
       
   319                 windowSize = viewPortItem->size();
       
   320             }
       
   321         }
       
   322         if (windowSize.height() - mDownMargin - q->preferredHeight() < upperEdge) {
       
   323             upperEdge = windowSize.height() - mDownMargin - q->preferredHeight();
       
   324         }
       
   325         if (q->layoutDirection() == Qt::LeftToRight) {
       
   326             qreal leftEdge = mSubMenuItem->scenePos().x() +
       
   327                              mSubMenuItem->size().width() - mRightMargin;
       
   328             if ((windowSize.width() - q->size().width()) < leftEdge) {
       
   329                 leftEdge = mSubMenuItem->scenePos().x() +
       
   330                            mSubMenuItem->size().width() +
       
   331                            mRightMargin - q->size().width();
       
   332             }
       
   333             q->setPreferredPos(QPointF(leftEdge, upperEdge));
       
   334         } else {
       
   335             qreal rightEdge = mSubMenuItem->scenePos().x() + mRightMargin;
       
   336             if ((rightEdge - q->size().width()) < 0) {
       
   337                 rightEdge = mSubMenuItem->scenePos().x() - mRightMargin +
       
   338                             q->size().width();
       
   339             }
       
   340             q->setPreferredPos(QPointF(rightEdge, upperEdge), HbPopup::TopRightCorner);
       
   341         }
       
   342     }
       
   343 }
       
   344 
       
   345 /*!
       
   346     @stable
       
   347     @hbcore
       
   348     \class HbMenu
       
   349     \brief HbMenu is a menu widget for use in HbView.
       
   350 
       
   351     \image html hbmenu.png A menu with checkable items and a sub-menu.
       
   352 
       
   353     Use an HbMenu to show a list of options. There are two main types of menus:
       
   354 
       
   355     - The view options menu
       
   356     - Context menus (popup menus)
       
   357 
       
   358     There is one view options menu for each view.
       
   359     It is shown by tapping the title bar. You can access the view options menu by calling
       
   360     HbView::menu() which returns a pointer to a new empty menu if one does not already exist.
       
   361 
       
   362     You can create any number of context menus.
       
   363     Context menus are usually invoked by a user action, such as tapping a widget.
       
   364 
       
   365     A menu contains a list of items. You can add three kinds of items to a menu:
       
   366 
       
   367     - Actions
       
   368     - Sub-menus
       
   369     - Separators
       
   370 
       
   371     An action is an object of class HbAction that performs an action when it is triggered.
       
   372     Use addAction() to add an action to a menu. Actions can be checkable (QAction::setCheckable).
       
   373     Use clearActions() to clear all actions from a menu.
       
   374     Use removeAction() to remove individual actions from a menu.
       
   375 
       
   376     A sub-menu is a menu that is nested within another menu. Use addMenu() or insertMenu() to add a sub-menu to a menu.
       
   377     Sub-menus can be nested within sub-menus.
       
   378 
       
   379     Separators group related items in a menu.
       
   380     Use addSeparator() or insertSeparator() to create and add a separator to a menu.
       
   381 
       
   382     \image html hbmenu.png A menu with checkable actions and a sub-menu.
       
   383 
       
   384     After you add an action to your menu, you specify a receiver object and its slot (you can also
       
   385     add an action and specify a receiver slot at the same time).
       
   386     The receiver is notifed when the action is triggered (QAction::triggered()).
       
   387     HbMenu also has a triggered() menu signal, which signals which HbAction was triggered in the menu.
       
   388 
       
   389     Context menu example:
       
   390 
       
   391     A menu and a few actions are created. The triggered() signal of the menu is connected to
       
   392     the mute() function of the enclosing class (implementation not shown).
       
   393     The exec() function shows the menu.
       
   394 
       
   395     User needs to connect to "longPress" signal and implement corresponding slot. This enables
       
   396     longpress events to be received from list.
       
   397 
       
   398     \dontinclude decoratorlistdemo/contentwidget.cpp
       
   399     \skip // Create new menu
       
   400     \until ( coords );
       
   401 
       
   402     \sa HbDialog, HbView
       
   403 */
       
   404 
       
   405 /*!
       
   406     \property HbMenu::menuType
       
   407     \brief
       
   408 */
       
   409 
       
   410 /*!
       
   411     \fn void HbMenu::triggered(HbAction *action)
       
   412 
       
   413     This signal is emitted when one of the action items is selected.
       
   414     \param action the action that was triggered in the menu.
       
   415  */
       
   416 
       
   417 /*!
       
   418     \enum HbMenu::MenuType
       
   419 
       
   420     This enum describes different types of HbMenu.
       
   421 */
       
   422 /*!
       
   423     \var HbMenu::ContextMenu
       
   424 
       
   425     ContextMenu is a menu which position is set by user.
       
   426 */
       
   427 /*!
       
   428     \var HbMenu::OptionMenu
       
   429 
       
   430     OptionMenu is set by HbView. Its position cannot be changed.
       
   431 */
       
   432 /*!
       
   433     \var HbMenu::SubMenu
       
   434 
       
   435     Menu becomes SubMenu when it is added to another menu.
       
   436 */
       
   437 
       
   438 /*!
       
   439     Constructs a menu with \a parent graphics item.
       
   440 
       
   441     \param parent is the parent graphics item.
       
   442 */
       
   443 HbMenu::HbMenu(QGraphicsItem *parent) :
       
   444         HbPopup(*new HbMenuPrivate, parent)
       
   445 {
       
   446     Q_D(HbMenu);
       
   447     d->q_ptr = this;
       
   448     d->init();
       
   449     /* This is for qt versions 4.5,which had the clipping problem.
       
   450            FOR http://www.qtsoftware.com/developer/task-tracker/index_html?id=257232&method=entry
       
   451            */
       
   452 #if QT_VERSION < 0x040600
       
   453     setFlag( QGraphicsItem::ItemClipsChildrenToShape, true );
       
   454 #endif
       
   455 }
       
   456 
       
   457 /*!
       
   458     Constructs a menu with \a title and \a parent graphics item.
       
   459     \param title is the menu title.
       
   460     \param parent is the parent graphics item.
       
   461 */
       
   462 HbMenu::HbMenu(const QString &title, QGraphicsItem *parent) :
       
   463         HbPopup(*new HbMenuPrivate, parent)
       
   464 {
       
   465     Q_D(HbMenu);
       
   466     d->q_ptr = this;
       
   467     d->init();
       
   468     setTitle(title);
       
   469 }
       
   470 
       
   471 HbMenu::HbMenu(HbMenuPrivate &dd, QGraphicsItem *parent) :
       
   472         HbPopup(dd, parent)
       
   473 {
       
   474     Q_D(HbMenu);
       
   475     d->q_ptr = this;
       
   476     d->init();
       
   477 }
       
   478 
       
   479 HbMenu::~HbMenu()
       
   480 {
       
   481     if (!scene() || !scene()->property("destructed").isValid()) {
       
   482         foreach (QAction *action, actions()) {// krazy:exclude=qclasses
       
   483             HbAction* hbAction = qobject_cast<HbAction *>(action);
       
   484             if (hbAction){
       
   485                 if (hbAction->menu()) {
       
   486                     hbAction->menu()->deleteLater();
       
   487                 }
       
   488                 hbAction->setMenu((HbMenu*)0);
       
   489             }
       
   490         }
       
   491     }
       
   492 }
       
   493 
       
   494 /*!
       
   495     \deprecated HbMenu::exec(HbAction*)
       
   496         is deprecated. Please use void HbMenu::open( QObject *receiver, const char *member )
       
   497         or HbMenu::show() instead.
       
   498 
       
   499     Executes the menu synchronously so that given \a action
       
   500     is active.
       
   501 
       
   502     \param action is the action that is active when the menu is shown.
       
   503 
       
   504     Example usage:
       
   505     \code
       
   506     void MyGraphicsItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
       
   507     {
       
   508         HbMenu menu();
       
   509         menu.addAction(...);
       
   510         ...
       
   511         menu.setPreferredPos(event->scenePos(), HbPopup::BottomEdgeCenter);
       
   512         menu.exec();
       
   513     }
       
   514     \endcode
       
   515 
       
   516     \return the triggered HbAction in either the popup menu or one
       
   517     of its sub-menus, or 0 if no item was triggered (normally because
       
   518     the user closed or cancelled the menu).
       
   519  */
       
   520 HbAction *HbMenu::exec(HbAction *action)
       
   521 {
       
   522     Q_D(HbMenu);
       
   523     if (actions().count() == 0) {
       
   524         return 0;
       
   525     }
       
   526 
       
   527     if(!action)
       
   528         action = qobject_cast<HbAction*>(actions().first());
       
   529 
       
   530     setActiveAction(action);
       
   531 
       
   532     // Reset state variables
       
   533     d->resultAction = 0;
       
   534     d->actionTriggered = false;
       
   535 
       
   536     if (d->menuType == SubMenu && d->polished) {
       
   537         d->setSubMenuPosition();
       
   538     }
       
   539     QPointer<HbMenu> menuAlive(this);
       
   540     HbPopup::exec();
       
   541 
       
   542     // HbMenu can be deleted while exec
       
   543     if (menuAlive) {
       
   544         return d->resultAction;
       
   545     } else {
       
   546         return 0;
       
   547     }
       
   548 }
       
   549 
       
   550 /*!
       
   551     \deprecated HbMenu::exec(const QPointF&, HbAction*)
       
   552         is deprecated. Please use void HbMenu::open( QObject *receiver, const char *member )
       
   553         or HbMenu::show() and setPreferredPos() instead.
       
   554 
       
   555     Executes the menu synchronously at \a pos so that given \a action
       
   556     is active.
       
   557 
       
   558     \param pos is the position at which the menu is shown.
       
   559     \param action is the action that is active when the menu is shown.
       
   560 
       
   561     Example usage:
       
   562     \code
       
   563     void MyGraphicsItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
       
   564     {
       
   565         HbMenu menu();
       
   566         menu.addAction(...);
       
   567         ...
       
   568         menu.exec(event->scenePos());
       
   569     }
       
   570     \endcode
       
   571 
       
   572     \return the triggered HbAction in either the popup menu or one
       
   573     of its sub-menus, or 0 if no item was triggered (normally because
       
   574     the user closed or cancelled the menu).
       
   575  */
       
   576 HbAction *HbMenu::exec(const QPointF &pos, HbAction *action )
       
   577 {
       
   578     Q_D(HbMenu);
       
   579     if (d->menuType == ContextMenu) {
       
   580         setPreferredPos(pos);
       
   581     }
       
   582     return exec(action);
       
   583 }
       
   584 
       
   585 void HbMenu::showEvent(QShowEvent *event)
       
   586 {
       
   587     Q_UNUSED(event);
       
   588     Q_D(HbMenu);
       
   589     d->actionTriggered = false;
       
   590 
       
   591     if (d->menuType == SubMenu && d->polished) {
       
   592         d->setSubMenuPosition();
       
   593     }
       
   594 
       
   595     HbPopup::showEvent(event);
       
   596 }
       
   597 
       
   598 /*!
       
   599     Creates a new action with title \a text. It adds the newly created action to the menu's list of actions.
       
   600     \param text is the text for the new action.
       
   601     \return the new action.
       
   602 */
       
   603 HbAction *HbMenu::addAction(const QString &text)
       
   604 {
       
   605     HbAction *action = new HbAction(text, this);
       
   606     addAction(action);
       
   607     return action;
       
   608 }
       
   609 
       
   610 /*!
       
   611     Creates a new action with \a text.
       
   612     The action's triggered() signal is connected to the
       
   613     \a receiver's \a member slot. The function adds the newly created
       
   614     action to the menu's list of actions.
       
   615     \return the new action.
       
   616  */
       
   617 HbAction *HbMenu::addAction(const QString &text, const QObject *receiver, const char *member)
       
   618 {
       
   619     HbAction *action = new HbAction(text, this);
       
   620     connect(action, SIGNAL(triggered(bool)), receiver, member);
       
   621     addAction(action);
       
   622     return action;
       
   623 }
       
   624 
       
   625 /*!
       
   626     Adds \a menu as a sub-menu.
       
   627     \param menu is the menu that is added to this one.
       
   628     \return the action for the added sub-menu.
       
   629  */
       
   630 HbAction *HbMenu::addMenu(HbMenu *menu)
       
   631 {
       
   632     return insertMenu(0, menu);
       
   633 }
       
   634 
       
   635 /*!
       
   636     Creates a new HbMenu with \a title and adds it to this menu.
       
   637     \param title is the menu title.
       
   638     \return the new menu.
       
   639 */
       
   640 HbMenu *HbMenu::addMenu(const QString &title)
       
   641 {
       
   642     HbMenu *menu = new HbMenu(title);
       
   643     addMenu(menu);
       
   644     return menu;
       
   645 }
       
   646 
       
   647 /*!
       
   648     Inserts \a menu before action \a before.
       
   649     \param before is the action before which this new menu is inserted.
       
   650     \param menu is the menu that is inserted.
       
   651     \return the action associated with the inserted menu.
       
   652  */
       
   653 HbAction *HbMenu::insertMenu(HbAction *before, HbMenu *menu)
       
   654 {    
       
   655     QObject::connect(menu, SIGNAL(triggered(HbAction*)), this, SLOT(_q_subMenuItemTriggered(HbAction*)));
       
   656     QObject::connect(menu, SIGNAL(triggered(HbAction*)), this, SIGNAL(triggered(HbAction*)));
       
   657 
       
   658     menu->d_func()->menuType = HbMenu::SubMenu;
       
   659     insertAction(before, menu->menuAction());
       
   660     return menu->menuAction();
       
   661 }
       
   662 
       
   663 /*!
       
   664     \return the action associated with this menu.
       
   665  */
       
   666 HbAction *HbMenu::menuAction() const
       
   667 {
       
   668     Q_D(const HbMenu);
       
   669     return d->subMenuAction;
       
   670 }
       
   671 
       
   672 /*!
       
   673     Creates a new separator action, which is an action that returns \c true from HbAction::isSeparator(),
       
   674     and adds it to this menu's list of actions.
       
   675     \return the new separator action
       
   676 
       
   677     \sa insertSeparator
       
   678  */
       
   679 HbAction *HbMenu::addSeparator()
       
   680 {
       
   681     return insertSeparator(0);
       
   682 }
       
   683 
       
   684 /*!
       
   685     Inserts a new separator action and inserts it into this menu's list of actions before \a action.
       
   686     \param before is the action before which the separator is inserted.
       
   687     \return the new action.
       
   688 
       
   689     \sa addSeparator
       
   690  */
       
   691 HbAction *HbMenu::insertSeparator(HbAction *before)
       
   692 {
       
   693     HbAction *action = new HbAction(this);
       
   694     action->setSeparator(true);
       
   695     action->setEnabled(false);
       
   696     insertAction(before, action);
       
   697     return action;
       
   698 }
       
   699 
       
   700 /*!
       
   701     \return the current active action, or 0 if no action item is currently active.
       
   702  */
       
   703 HbAction *HbMenu::activeAction() const
       
   704 {
       
   705     Q_D(const HbMenu);
       
   706     return d->activeAction();
       
   707 }
       
   708 
       
   709 /*!
       
   710     Sets the active action in menu. If \a action is not found from the list of
       
   711     menu actions then the current active action remains active.
       
   712 
       
   713     \sa activeAction()
       
   714 */
       
   715 void HbMenu::setActiveAction(HbAction *action)
       
   716 {
       
   717     Q_D(HbMenu);
       
   718     if (d->menuItemView && action && action->isVisible() && !action->isSeparator()) {
       
   719         d->menuItemView->setCurrentItem(action);
       
   720     }
       
   721 }
       
   722 
       
   723 /*!
       
   724     \return \c true if the menu is empty (contains no actions) and \c false otherwise.
       
   725 
       
   726     \sa clear()
       
   727  */
       
   728 bool HbMenu::isEmpty() const
       
   729 {
       
   730     return actions().isEmpty();
       
   731 }
       
   732 
       
   733 /*!
       
   734     Sets the menu title. For a sub-menu, the title is the sub-menu action text.
       
   735 
       
   736     \sa title()
       
   737 */
       
   738 void HbMenu::setTitle(const QString &title)
       
   739 {
       
   740     menuAction()->setText(title);
       
   741 }
       
   742 
       
   743 /*!
       
   744     \return the menu title. For a sub-menu, the title is the sub-menu action text.
       
   745 
       
   746     \sa setTitle()
       
   747 */
       
   748 QString HbMenu::title() const
       
   749 {
       
   750     return menuAction()->text();
       
   751 }
       
   752 
       
   753 /*!
       
   754     \return the menu type. By default a menu is a context menu.
       
   755 */
       
   756 HbMenu::MenuType HbMenu::menuType() const
       
   757 {
       
   758     Q_D(const HbMenu);
       
   759     return d->menuType;
       
   760 }
       
   761 
       
   762 /*!
       
   763     \reimp
       
   764  */
       
   765 QVariant HbMenu::itemChange( GraphicsItemChange change, const QVariant & value )
       
   766 {
       
   767     Q_D(HbMenu);
       
   768 
       
   769     if (change == QGraphicsItem::ItemVisibleChange) {
       
   770         if (value.toBool() && d->delayMenuConstruction) {
       
   771             d->delayedLayout();
       
   772         }
       
   773         if (value.toBool()) {
       
   774             d->resultAction = 0;
       
   775             d->actionTriggered = false;
       
   776         }
       
   777         else if (!value.toBool() && !d->menuItemView){
       
   778             d->delayMenuConstruction = true;
       
   779         }
       
   780     }
       
   781     return HbPopup::itemChange(change,value);
       
   782 }
       
   783 
       
   784 /*!
       
   785     \reimp
       
   786  */
       
   787 void HbMenu::keyPressEvent(QKeyEvent *event)
       
   788 {
       
   789     //TODO: check if non-touch version works with the key bindings below
       
   790     Q_D(HbMenu);
       
   791     switch( event->key() ) {
       
   792             case Qt::Key_Up:
       
   793             case Qt::Key_Down:
       
   794         break;
       
   795             case Qt::Key_Right:
       
   796         layoutDirection() == Qt::LeftToRight
       
   797                 ? d->openSubmenu()
       
   798                     : d->closeSubmenu();
       
   799         break;
       
   800             case Qt::Key_Left:
       
   801         layoutDirection() == Qt::LeftToRight
       
   802                 ? d->closeSubmenu()
       
   803                     : d->openSubmenu();
       
   804         break;
       
   805             case Qt::Key_Backspace:
       
   806         d->closeSubmenu();
       
   807         break;
       
   808             case Qt::Key_Escape:
       
   809         close();
       
   810         break;
       
   811             default:
       
   812         HbPopup::keyPressEvent( event );
       
   813         break;
       
   814     }
       
   815 }
       
   816 
       
   817 /*!
       
   818     \reimp
       
   819  */
       
   820 void HbMenu::keyReleaseEvent(QKeyEvent *event)
       
   821 {
       
   822     //TODO do we need this method?
       
   823     QGraphicsWidget::keyReleaseEvent( event );
       
   824 }
       
   825 
       
   826 /*!
       
   827    \reimp
       
   828 */
       
   829 bool HbMenu::event(QEvent *event)
       
   830 {
       
   831     Q_D(HbMenu);
       
   832 
       
   833     if(!d->inDestruction) {
       
   834         if (event->type() == QEvent::ActionAdded) {
       
   835             QActionEvent *actionEvent = static_cast<QActionEvent *>(event);
       
   836             d->actionAdded(actionEvent);            
       
   837             return true;
       
   838         } else if (event->type() == QEvent::ActionRemoved) {
       
   839             QActionEvent *actionEvent = static_cast<QActionEvent *>(event);
       
   840             d->actionRemoved(actionEvent);
       
   841             return true;
       
   842         } else if (event->type() == QEvent::ActionChanged) {
       
   843             QActionEvent *actionEvent = static_cast<QActionEvent *>(event);
       
   844             d->actionChanged(actionEvent);
       
   845             return true;
       
   846         }
       
   847     }
       
   848     if (event->type() == QEvent::LayoutRequest) {
       
   849         resize(preferredSize());
       
   850         if(d->menuItemView)
       
   851             d->menuItemView->contentWidget()->adjustSize();
       
   852         if (d->mSubMenuItem)
       
   853             d->setSubMenuPosition();
       
   854     }
       
   855 
       
   856     return HbPopup::event(event);
       
   857 }
       
   858 
       
   859 void HbMenu::polish(HbStyleParameters &params)
       
   860 {
       
   861     Q_D(HbMenu);
       
   862     if (d->mSubMenuItem) {
       
   863         const QString RightMargin = "submenu-right-offset";
       
   864         const QString DownMargin = "submenu-bottom-margin";
       
   865         params.addParameter(RightMargin);
       
   866         params.addParameter(DownMargin);
       
   867 
       
   868         HbPopup::polish(params);
       
   869 
       
   870         if (!params.value(RightMargin).isNull()) {
       
   871             d->mRightMargin = params.value(RightMargin).toDouble();
       
   872         }
       
   873         if (!params.value(DownMargin).isNull()) {
       
   874             d->mDownMargin = params.value(DownMargin).toDouble();
       
   875         }
       
   876         d->setSubMenuPosition();
       
   877     } else {
       
   878         HbPopup::polish(params);
       
   879     }
       
   880 }
       
   881 
       
   882 QPainterPath HbMenu::shape() const
       
   883 {
       
   884     QRectF sceneRect = mapRectToScene(boundingRect());
       
   885     QRectF clipRect = sceneRect.intersected(geometry());
       
   886     QPainterPath path;    
       
   887     path.addRect(mapRectFromScene(clipRect));
       
   888     return path;
       
   889 }
       
   890 
       
   891 /*!  @alpha
       
   892  *
       
   893  * Opens the menu and returns immediately.
       
   894  */
       
   895 void HbMenu::open( QObject *receiver, const char *member )
       
   896 {
       
   897     Q_D(HbMenu);
       
   898     if ( d->receiverToDisconnectOnClose ) { // cant do on closeevent
       
   899         disconnect(this, SIGNAL(triggered(HbAction*)),
       
   900                    d->receiverToDisconnectOnClose, d->memberToDisconnectOnClose);
       
   901         d->receiverToDisconnectOnClose = 0;
       
   902     }
       
   903     d->memberToDisconnectOnClose.clear();
       
   904 
       
   905     if ( receiver ) {
       
   906         connect(this, SIGNAL(triggered(HbAction*)), receiver, member);
       
   907         d->receiverToDisconnectOnClose = receiver;
       
   908         d->memberToDisconnectOnClose = member;
       
   909     } else {
       
   910         d->receiverToDisconnectOnClose = 0;
       
   911     }
       
   912     HbMenu::show();
       
   913 }
       
   914 
       
   915 #include "moc_hbmenu.cpp"