--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hbcore/gui/hbmenu.cpp Mon Apr 19 14:02:13 2010 +0300
@@ -0,0 +1,915 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (developer.feedback@nokia.com)
+**
+** This file is part of the HbCore module of the UI Extensions for Mobile.
+**
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at developer.feedback@nokia.com.
+**
+****************************************************************************/
+
+#include "hbmenu.h"
+#include "hbmenu_p.h"
+#include "hbmenuitem_p.h"
+#include "hbaction.h"
+#include <hbwidgetfeedback.h>
+#include "hbinstance.h"
+#include "hbmenucontainer_p.h"
+#ifdef HB_EFFECTS
+#include "hbeffect.h"
+#include "hbeffectinternal_p.h"
+bool HbMenuPrivate::menuEffectsLoaded = false;
+#endif
+
+#include <QPointer>
+
+Q_DECLARE_METATYPE (QAction*)// krazy:exclude=qclasses
+
+HbMenuPrivate::HbMenuPrivate():
+ HbPopupPrivate(),
+ menuItemView(0),
+ subMenuAction(0),
+ activeSubMenu(0),
+ resultAction(0),
+ actionTriggered(false),
+ menuType(HbMenu::ContextMenu),
+ mSubMenuItem(0),
+ mRightMargin(0.0),
+ mDownMargin(0.0),
+ delayMenuConstruction(true),
+ receiverToDisconnectOnClose(0)
+{
+}
+
+HbMenuPrivate::~HbMenuPrivate()
+{
+}
+
+void HbMenuPrivate::init()
+{
+ Q_Q(HbMenu);
+
+ subMenuAction = new HbAction(q);
+ subMenuAction->setMenu(q);
+ q->setTimeout(HbPopup::ContextMenuTimeout);
+
+ q->setBackgroundFaded(false);
+ q->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
+}
+
+void HbMenuPrivate::addPopupEffects()
+{
+#ifdef HB_EFFECTS
+ effectType = "HB_MENU";
+ hasEffects = menuEffectsLoaded;
+ if (menuEffectsLoaded)
+ return;
+ menuEffectsLoaded = true;
+ hasEffects = HbEffectInternal::add("HB_MENU", "menu_appear", "appear");
+ if (hasEffects) {
+ //We load the disappear effect only if appear effect was also loaded
+ hasEffects = HbEffectInternal::add("HB_MENU", "menu_disappear", "disappear");
+
+ if (hasEffects) {
+ hasEffects = HbEffectInternal::add("HB_menuitem", "menuitem_press", "clicked");
+ }
+ if (hasEffects ) {
+ hasEffects = HbEffectInternal::add("HB_POPUP",
+ "dialog_rotate",
+ "orientationswitch");
+ }
+ }
+#endif
+}
+
+void HbMenuPrivate::_q_triggerAction(HbMenuItem *currentItem)
+{
+ Q_Q(HbMenu);
+ if (currentItem && currentItem->action()){
+ HbWidgetFeedback::triggered(currentItem, Hb::InstantClicked);
+#ifdef HB_EFFECTS
+ if (hasEffects) {
+ HbEffect::start(currentItem, "HB_menuitem", "clicked");
+ }
+#endif
+ HbAction *hbAction = qobject_cast<HbAction *>(currentItem->action());
+ if (hbAction && hbAction->menu()) {
+ hbAction->trigger();
+ stopTimeout();
+ openSubmenu(currentItem);
+ } else {
+ q->close();
+
+ resultAction = hbAction;
+
+ if (!actionTriggered) { // prevent duplicate events
+ currentItem->action()->trigger();
+ }
+ actionTriggered = true;
+ }
+ }
+}
+
+void HbMenuPrivate::createMenuView()
+{
+ Q_Q(HbMenu);
+ if (!menuItemView && q->actions().count()){
+ menuItemView = new HbMenuListView(q, q);
+ HbStyle::setItemName(menuItemView, "content");
+ /* This is for qt versions 4.5,which had the clipping problem.
+ FOR http://www.qtsoftware.com/developer/task-tracker/index_html?id=257232&method=entry
+ see also HbMenu constructor */
+#if QT_VERSION < 0x040600
+ menuItemView->setFlag( QGraphicsItem::ItemClipsChildrenToShape, false );
+#endif
+ //This optimises case of options menu which otherwise updates its primitives twice.
+ if (menuType == HbMenu::OptionsMenu)
+ q->setFrameType(HbPopup::Strong);
+ else
+ q->setFrameType(HbPopup::Weak);
+ if (polished)//This check can be removed once base class repolish is fixed.
+ q->repolish();
+ }
+}
+
+void HbMenuPrivate::delayedLayout()
+{
+ createMenuView();
+ if(menuItemView)
+ menuItemView->doDelayedLayout();
+ delayMenuConstruction = false;
+}
+
+void HbMenuPrivate::changeToOptionsMenu()
+{
+ menuType = HbMenu::OptionsMenu;
+}
+
+HbMenuItem *HbMenuPrivate::subMenuItem()
+{
+ return mSubMenuItem;
+}
+
+void HbMenuPrivate::setSubMenuItem(HbMenuItem *menuItem)
+{
+ mSubMenuItem = menuItem;
+}
+
+void HbMenuPrivate::_q_onActionTriggered()
+{
+ Q_Q(HbMenu);
+ HbAction *action = qobject_cast<HbAction *>(q->sender());
+ if (action && !action->menu() ) { // do not trigger from opening submenu
+ emit q->triggered(action);
+ }
+}
+
+void HbMenuPrivate::_q_subMenuItemTriggered(HbAction *action)
+{
+ Q_Q(HbMenu);
+
+ // do not close the menu tree if the triggered action is
+ // submenu item
+ if (!action->menu()) {
+ q->close();
+ } else {
+ stopTimeout();
+ }
+}
+
+void HbMenuPrivate::actionAdded(QActionEvent *actionEvent)
+{
+ if (delayMenuConstruction)
+ return;
+ if (actionEvent->action()->isVisible()){
+ Q_Q(HbMenu);
+ createMenuView();
+ QObject::connect(actionEvent->action(), SIGNAL(triggered()), q, SLOT(_q_onActionTriggered()));
+ menuItemView->addActionItem(actionEvent->action());
+ }
+}
+
+void HbMenuPrivate::actionRemoved(QActionEvent *actionEvent)
+{
+ if (delayMenuConstruction)
+ return;
+ Q_Q(HbMenu);
+ QObject::disconnect(actionEvent->action(), 0, q, 0);
+ if (menuItemView)
+ menuItemView->removeActionItem(actionEvent->action());
+}
+
+void HbMenuPrivate::actionChanged(QActionEvent *actionEvent)
+{
+ if (delayMenuConstruction)
+ return;
+ if (menuItemView)
+ menuItemView->updateActionItem(actionEvent->action());
+}
+
+/*
+ Returns current focusable action based on current row of the menuItemView or index if specified.
+ If there is no focusable action it returns 0.
+ Also returns the active item representing the active action or 0.
+*/
+HbAction *HbMenuPrivate::activeAction(HbMenuItem *&activeItem) const
+{
+ if(!menuItemView)
+ return 0;
+ HbAction *action = 0;
+ HbMenuItem *currentItem = menuItemView->currentItem();
+ if(currentItem && currentItem->action() && currentItem->action()->isVisible() &&
+ currentItem->action()->isEnabled() && !currentItem->action()->isSeparator()) {
+ action = static_cast<HbAction*>(currentItem->action());
+ activeItem = currentItem;
+ }
+ return action;
+}
+
+/*
+ Convenience overload
+*/
+HbAction *HbMenuPrivate::activeAction() const
+{
+ HbMenuItem* activeItem = 0;
+ return activeAction(activeItem);
+}
+
+/*
+ Opens a submenu for activeItem. If activeItem is 0 it uses activeAction() to determine active item
+ and opens submenu for it if active action has submenu.
+*/
+void HbMenuPrivate::openSubmenu(HbMenuItem *activeItem)
+{
+ Q_Q(HbMenu);
+
+ if (!activeItem) {
+ activeAction(activeItem);
+ }
+
+ if (activeItem && activeItem->action() && activeItem->action()->isEnabled()) {
+ HbAction *hbAction = qobject_cast<HbAction *>(activeItem->action());
+ if (!hbAction)
+ return;
+ HbMenu *subMenu = hbAction->menu();
+ if ( subMenu ) {
+ subMenu->setLayoutDirection(q->layoutDirection());
+
+ activeSubMenu = subMenu;
+ subMenu->setTimeout(timeout);
+ QObject::disconnect(subMenu, SIGNAL(aboutToClose()), q, SLOT(_q_subMenuTimedOut()));
+ QObject::connect(subMenu, SIGNAL(aboutToClose()), q, SLOT(_q_subMenuTimedOut()));
+ QObject::connect(subMenu, SIGNAL(triggered(HbAction*)), q, SLOT(_q_subMenuItemTriggered(HbAction*)));
+ subMenu->show();
+
+ // Reset the active submenu so that mouse event handling works.
+ // huh ? activeSubMenu = 0;
+ }
+ }
+}
+
+void HbMenuPrivate::_q_subMenuTimedOut()
+{
+ Q_Q(HbMenu);
+ if( menuTimedOut (activeSubMenu) ) {
+ if ( activeSubMenu ) {
+ activeSubMenu->disconnect();
+ }
+ q->close();
+ }
+}
+
+bool HbMenuPrivate::menuTimedOut(HbMenu* menu)
+{
+ return (menu && menu->timeout() > 0 && HbMenuPrivate::d_ptr(menu)->timedOut);
+}
+
+void HbMenuPrivate::closeSubmenu()
+{
+ // Check whether this is a submenu.
+ if (activeSubMenu) {
+ activeSubMenu->close();
+ }
+}
+
+void HbMenuPrivate::setSubMenuPosition()
+{
+ Q_Q(HbMenu);
+ if (mSubMenuItem) {
+ qreal upperEdge = mSubMenuItem->scenePos().y() + mSubMenuItem->size().height() * 2 / 3;
+ QSizeF windowSize = QSizeF(0,0);
+ if (q->mainWindow()) {
+ QGraphicsWidget *viewPortItem = q->mainWindow()->element(HbMainWindow::ViewportItem);
+ if (viewPortItem) {
+ windowSize = viewPortItem->size();
+ }
+ }
+ if (windowSize.height() - mDownMargin - q->preferredHeight() < upperEdge) {
+ upperEdge = windowSize.height() - mDownMargin - q->preferredHeight();
+ }
+ if (q->layoutDirection() == Qt::LeftToRight) {
+ qreal leftEdge = mSubMenuItem->scenePos().x() +
+ mSubMenuItem->size().width() - mRightMargin;
+ if ((windowSize.width() - q->size().width()) < leftEdge) {
+ leftEdge = mSubMenuItem->scenePos().x() +
+ mSubMenuItem->size().width() +
+ mRightMargin - q->size().width();
+ }
+ q->setPreferredPos(QPointF(leftEdge, upperEdge));
+ } else {
+ qreal rightEdge = mSubMenuItem->scenePos().x() + mRightMargin;
+ if ((rightEdge - q->size().width()) < 0) {
+ rightEdge = mSubMenuItem->scenePos().x() - mRightMargin +
+ q->size().width();
+ }
+ q->setPreferredPos(QPointF(rightEdge, upperEdge), HbPopup::TopRightCorner);
+ }
+ }
+}
+
+/*!
+ @stable
+ @hbcore
+ \class HbMenu
+ \brief HbMenu is a menu widget for use in HbView.
+
+ \image html hbmenu.png A menu with checkable items and a sub-menu.
+
+ Use an HbMenu to show a list of options. There are two main types of menus:
+
+ - The view options menu
+ - Context menus (popup menus)
+
+ There is one view options menu for each view.
+ It is shown by tapping the title bar. You can access the view options menu by calling
+ HbView::menu() which returns a pointer to a new empty menu if one does not already exist.
+
+ You can create any number of context menus.
+ Context menus are usually invoked by a user action, such as tapping a widget.
+
+ A menu contains a list of items. You can add three kinds of items to a menu:
+
+ - Actions
+ - Sub-menus
+ - Separators
+
+ An action is an object of class HbAction that performs an action when it is triggered.
+ Use addAction() to add an action to a menu. Actions can be checkable (QAction::setCheckable).
+ Use clearActions() to clear all actions from a menu.
+ Use removeAction() to remove individual actions from a menu.
+
+ A sub-menu is a menu that is nested within another menu. Use addMenu() or insertMenu() to add a sub-menu to a menu.
+ Sub-menus can be nested within sub-menus.
+
+ Separators group related items in a menu.
+ Use addSeparator() or insertSeparator() to create and add a separator to a menu.
+
+ \image html hbmenu.png A menu with checkable actions and a sub-menu.
+
+ After you add an action to your menu, you specify a receiver object and its slot (you can also
+ add an action and specify a receiver slot at the same time).
+ The receiver is notifed when the action is triggered (QAction::triggered()).
+ HbMenu also has a triggered() menu signal, which signals which HbAction was triggered in the menu.
+
+ Context menu example:
+
+ A menu and a few actions are created. The triggered() signal of the menu is connected to
+ the mute() function of the enclosing class (implementation not shown).
+ The exec() function shows the menu.
+
+ User needs to connect to "longPress" signal and implement corresponding slot. This enables
+ longpress events to be received from list.
+
+ \dontinclude decoratorlistdemo/contentwidget.cpp
+ \skip // Create new menu
+ \until ( coords );
+
+ \sa HbDialog, HbView
+*/
+
+/*!
+ \property HbMenu::menuType
+ \brief
+*/
+
+/*!
+ \fn void HbMenu::triggered(HbAction *action)
+
+ This signal is emitted when one of the action items is selected.
+ \param action the action that was triggered in the menu.
+ */
+
+/*!
+ \enum HbMenu::MenuType
+
+ This enum describes different types of HbMenu.
+*/
+/*!
+ \var HbMenu::ContextMenu
+
+ ContextMenu is a menu which position is set by user.
+*/
+/*!
+ \var HbMenu::OptionMenu
+
+ OptionMenu is set by HbView. Its position cannot be changed.
+*/
+/*!
+ \var HbMenu::SubMenu
+
+ Menu becomes SubMenu when it is added to another menu.
+*/
+
+/*!
+ Constructs a menu with \a parent graphics item.
+
+ \param parent is the parent graphics item.
+*/
+HbMenu::HbMenu(QGraphicsItem *parent) :
+ HbPopup(*new HbMenuPrivate, parent)
+{
+ Q_D(HbMenu);
+ d->q_ptr = this;
+ d->init();
+ /* This is for qt versions 4.5,which had the clipping problem.
+ FOR http://www.qtsoftware.com/developer/task-tracker/index_html?id=257232&method=entry
+ */
+#if QT_VERSION < 0x040600
+ setFlag( QGraphicsItem::ItemClipsChildrenToShape, true );
+#endif
+}
+
+/*!
+ Constructs a menu with \a title and \a parent graphics item.
+ \param title is the menu title.
+ \param parent is the parent graphics item.
+*/
+HbMenu::HbMenu(const QString &title, QGraphicsItem *parent) :
+ HbPopup(*new HbMenuPrivate, parent)
+{
+ Q_D(HbMenu);
+ d->q_ptr = this;
+ d->init();
+ setTitle(title);
+}
+
+HbMenu::HbMenu(HbMenuPrivate &dd, QGraphicsItem *parent) :
+ HbPopup(dd, parent)
+{
+ Q_D(HbMenu);
+ d->q_ptr = this;
+ d->init();
+}
+
+HbMenu::~HbMenu()
+{
+ if (!scene() || !scene()->property("destructed").isValid()) {
+ foreach (QAction *action, actions()) {// krazy:exclude=qclasses
+ HbAction* hbAction = qobject_cast<HbAction *>(action);
+ if (hbAction){
+ if (hbAction->menu()) {
+ hbAction->menu()->deleteLater();
+ }
+ hbAction->setMenu((HbMenu*)0);
+ }
+ }
+ }
+}
+
+/*!
+ \deprecated HbMenu::exec(HbAction*)
+ is deprecated. Please use void HbMenu::open( QObject *receiver, const char *member )
+ or HbMenu::show() instead.
+
+ Executes the menu synchronously so that given \a action
+ is active.
+
+ \param action is the action that is active when the menu is shown.
+
+ Example usage:
+ \code
+ void MyGraphicsItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
+ {
+ HbMenu menu();
+ menu.addAction(...);
+ ...
+ menu.setPreferredPos(event->scenePos(), HbPopup::BottomEdgeCenter);
+ menu.exec();
+ }
+ \endcode
+
+ \return the triggered HbAction in either the popup menu or one
+ of its sub-menus, or 0 if no item was triggered (normally because
+ the user closed or cancelled the menu).
+ */
+HbAction *HbMenu::exec(HbAction *action)
+{
+ Q_D(HbMenu);
+ if (actions().count() == 0) {
+ return 0;
+ }
+
+ if(!action)
+ action = qobject_cast<HbAction*>(actions().first());
+
+ setActiveAction(action);
+
+ // Reset state variables
+ d->resultAction = 0;
+ d->actionTriggered = false;
+
+ if (d->menuType == SubMenu && d->polished) {
+ d->setSubMenuPosition();
+ }
+ QPointer<HbMenu> menuAlive(this);
+ HbPopup::exec();
+
+ // HbMenu can be deleted while exec
+ if (menuAlive) {
+ return d->resultAction;
+ } else {
+ return 0;
+ }
+}
+
+/*!
+ \deprecated HbMenu::exec(const QPointF&, HbAction*)
+ is deprecated. Please use void HbMenu::open( QObject *receiver, const char *member )
+ or HbMenu::show() and setPreferredPos() instead.
+
+ Executes the menu synchronously at \a pos so that given \a action
+ is active.
+
+ \param pos is the position at which the menu is shown.
+ \param action is the action that is active when the menu is shown.
+
+ Example usage:
+ \code
+ void MyGraphicsItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
+ {
+ HbMenu menu();
+ menu.addAction(...);
+ ...
+ menu.exec(event->scenePos());
+ }
+ \endcode
+
+ \return the triggered HbAction in either the popup menu or one
+ of its sub-menus, or 0 if no item was triggered (normally because
+ the user closed or cancelled the menu).
+ */
+HbAction *HbMenu::exec(const QPointF &pos, HbAction *action )
+{
+ Q_D(HbMenu);
+ if (d->menuType == ContextMenu) {
+ setPreferredPos(pos);
+ }
+ return exec(action);
+}
+
+void HbMenu::showEvent(QShowEvent *event)
+{
+ Q_UNUSED(event);
+ Q_D(HbMenu);
+ d->actionTriggered = false;
+
+ if (d->menuType == SubMenu && d->polished) {
+ d->setSubMenuPosition();
+ }
+
+ HbPopup::showEvent(event);
+}
+
+/*!
+ Creates a new action with title \a text. It adds the newly created action to the menu's list of actions.
+ \param text is the text for the new action.
+ \return the new action.
+*/
+HbAction *HbMenu::addAction(const QString &text)
+{
+ HbAction *action = new HbAction(text, this);
+ addAction(action);
+ return action;
+}
+
+/*!
+ Creates a new action with \a text.
+ The action's triggered() signal is connected to the
+ \a receiver's \a member slot. The function adds the newly created
+ action to the menu's list of actions.
+ \return the new action.
+ */
+HbAction *HbMenu::addAction(const QString &text, const QObject *receiver, const char *member)
+{
+ HbAction *action = new HbAction(text, this);
+ connect(action, SIGNAL(triggered(bool)), receiver, member);
+ addAction(action);
+ return action;
+}
+
+/*!
+ Adds \a menu as a sub-menu.
+ \param menu is the menu that is added to this one.
+ \return the action for the added sub-menu.
+ */
+HbAction *HbMenu::addMenu(HbMenu *menu)
+{
+ return insertMenu(0, menu);
+}
+
+/*!
+ Creates a new HbMenu with \a title and adds it to this menu.
+ \param title is the menu title.
+ \return the new menu.
+*/
+HbMenu *HbMenu::addMenu(const QString &title)
+{
+ HbMenu *menu = new HbMenu(title);
+ addMenu(menu);
+ return menu;
+}
+
+/*!
+ Inserts \a menu before action \a before.
+ \param before is the action before which this new menu is inserted.
+ \param menu is the menu that is inserted.
+ \return the action associated with the inserted menu.
+ */
+HbAction *HbMenu::insertMenu(HbAction *before, HbMenu *menu)
+{
+ QObject::connect(menu, SIGNAL(triggered(HbAction*)), this, SLOT(_q_subMenuItemTriggered(HbAction*)));
+ QObject::connect(menu, SIGNAL(triggered(HbAction*)), this, SIGNAL(triggered(HbAction*)));
+
+ menu->d_func()->menuType = HbMenu::SubMenu;
+ insertAction(before, menu->menuAction());
+ return menu->menuAction();
+}
+
+/*!
+ \return the action associated with this menu.
+ */
+HbAction *HbMenu::menuAction() const
+{
+ Q_D(const HbMenu);
+ return d->subMenuAction;
+}
+
+/*!
+ Creates a new separator action, which is an action that returns \c true from HbAction::isSeparator(),
+ and adds it to this menu's list of actions.
+ \return the new separator action
+
+ \sa insertSeparator
+ */
+HbAction *HbMenu::addSeparator()
+{
+ return insertSeparator(0);
+}
+
+/*!
+ Inserts a new separator action and inserts it into this menu's list of actions before \a action.
+ \param before is the action before which the separator is inserted.
+ \return the new action.
+
+ \sa addSeparator
+ */
+HbAction *HbMenu::insertSeparator(HbAction *before)
+{
+ HbAction *action = new HbAction(this);
+ action->setSeparator(true);
+ action->setEnabled(false);
+ insertAction(before, action);
+ return action;
+}
+
+/*!
+ \return the current active action, or 0 if no action item is currently active.
+ */
+HbAction *HbMenu::activeAction() const
+{
+ Q_D(const HbMenu);
+ return d->activeAction();
+}
+
+/*!
+ Sets the active action in menu. If \a action is not found from the list of
+ menu actions then the current active action remains active.
+
+ \sa activeAction()
+*/
+void HbMenu::setActiveAction(HbAction *action)
+{
+ Q_D(HbMenu);
+ if (d->menuItemView && action && action->isVisible() && !action->isSeparator()) {
+ d->menuItemView->setCurrentItem(action);
+ }
+}
+
+/*!
+ \return \c true if the menu is empty (contains no actions) and \c false otherwise.
+
+ \sa clear()
+ */
+bool HbMenu::isEmpty() const
+{
+ return actions().isEmpty();
+}
+
+/*!
+ Sets the menu title. For a sub-menu, the title is the sub-menu action text.
+
+ \sa title()
+*/
+void HbMenu::setTitle(const QString &title)
+{
+ menuAction()->setText(title);
+}
+
+/*!
+ \return the menu title. For a sub-menu, the title is the sub-menu action text.
+
+ \sa setTitle()
+*/
+QString HbMenu::title() const
+{
+ return menuAction()->text();
+}
+
+/*!
+ \return the menu type. By default a menu is a context menu.
+*/
+HbMenu::MenuType HbMenu::menuType() const
+{
+ Q_D(const HbMenu);
+ return d->menuType;
+}
+
+/*!
+ \reimp
+ */
+QVariant HbMenu::itemChange( GraphicsItemChange change, const QVariant & value )
+{
+ Q_D(HbMenu);
+
+ if (change == QGraphicsItem::ItemVisibleChange) {
+ if (value.toBool() && d->delayMenuConstruction) {
+ d->delayedLayout();
+ }
+ if (value.toBool()) {
+ d->resultAction = 0;
+ d->actionTriggered = false;
+ }
+ else if (!value.toBool() && !d->menuItemView){
+ d->delayMenuConstruction = true;
+ }
+ }
+ return HbPopup::itemChange(change,value);
+}
+
+/*!
+ \reimp
+ */
+void HbMenu::keyPressEvent(QKeyEvent *event)
+{
+ //TODO: check if non-touch version works with the key bindings below
+ Q_D(HbMenu);
+ switch( event->key() ) {
+ case Qt::Key_Up:
+ case Qt::Key_Down:
+ break;
+ case Qt::Key_Right:
+ layoutDirection() == Qt::LeftToRight
+ ? d->openSubmenu()
+ : d->closeSubmenu();
+ break;
+ case Qt::Key_Left:
+ layoutDirection() == Qt::LeftToRight
+ ? d->closeSubmenu()
+ : d->openSubmenu();
+ break;
+ case Qt::Key_Backspace:
+ d->closeSubmenu();
+ break;
+ case Qt::Key_Escape:
+ close();
+ break;
+ default:
+ HbPopup::keyPressEvent( event );
+ break;
+ }
+}
+
+/*!
+ \reimp
+ */
+void HbMenu::keyReleaseEvent(QKeyEvent *event)
+{
+ //TODO do we need this method?
+ QGraphicsWidget::keyReleaseEvent( event );
+}
+
+/*!
+ \reimp
+*/
+bool HbMenu::event(QEvent *event)
+{
+ Q_D(HbMenu);
+
+ if(!d->inDestruction) {
+ if (event->type() == QEvent::ActionAdded) {
+ QActionEvent *actionEvent = static_cast<QActionEvent *>(event);
+ d->actionAdded(actionEvent);
+ return true;
+ } else if (event->type() == QEvent::ActionRemoved) {
+ QActionEvent *actionEvent = static_cast<QActionEvent *>(event);
+ d->actionRemoved(actionEvent);
+ return true;
+ } else if (event->type() == QEvent::ActionChanged) {
+ QActionEvent *actionEvent = static_cast<QActionEvent *>(event);
+ d->actionChanged(actionEvent);
+ return true;
+ }
+ }
+ if (event->type() == QEvent::LayoutRequest) {
+ resize(preferredSize());
+ if(d->menuItemView)
+ d->menuItemView->contentWidget()->adjustSize();
+ if (d->mSubMenuItem)
+ d->setSubMenuPosition();
+ }
+
+ return HbPopup::event(event);
+}
+
+void HbMenu::polish(HbStyleParameters ¶ms)
+{
+ Q_D(HbMenu);
+ if (d->mSubMenuItem) {
+ const QString RightMargin = "submenu-right-offset";
+ const QString DownMargin = "submenu-bottom-margin";
+ params.addParameter(RightMargin);
+ params.addParameter(DownMargin);
+
+ HbPopup::polish(params);
+
+ if (!params.value(RightMargin).isNull()) {
+ d->mRightMargin = params.value(RightMargin).toDouble();
+ }
+ if (!params.value(DownMargin).isNull()) {
+ d->mDownMargin = params.value(DownMargin).toDouble();
+ }
+ d->setSubMenuPosition();
+ } else {
+ HbPopup::polish(params);
+ }
+}
+
+QPainterPath HbMenu::shape() const
+{
+ QRectF sceneRect = mapRectToScene(boundingRect());
+ QRectF clipRect = sceneRect.intersected(geometry());
+ QPainterPath path;
+ path.addRect(mapRectFromScene(clipRect));
+ return path;
+}
+
+/*! @alpha
+ *
+ * Opens the menu and returns immediately.
+ */
+void HbMenu::open( QObject *receiver, const char *member )
+{
+ Q_D(HbMenu);
+ if ( d->receiverToDisconnectOnClose ) { // cant do on closeevent
+ disconnect(this, SIGNAL(triggered(HbAction*)),
+ d->receiverToDisconnectOnClose, d->memberToDisconnectOnClose);
+ d->receiverToDisconnectOnClose = 0;
+ }
+ d->memberToDisconnectOnClose.clear();
+
+ if ( receiver ) {
+ connect(this, SIGNAL(triggered(HbAction*)), receiver, member);
+ d->receiverToDisconnectOnClose = receiver;
+ d->memberToDisconnectOnClose = member;
+ } else {
+ d->receiverToDisconnectOnClose = 0;
+ }
+ HbMenu::show();
+}
+
+#include "moc_hbmenu.cpp"