diff -r 000000000000 -r 16d8024aca5e src/hbcore/gui/hbpopup.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hbcore/gui/hbpopup.cpp Mon Apr 19 14:02:13 2010 +0300 @@ -0,0 +1,1147 @@ +/**************************************************************************** +** +** 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 "hbpopup.h" +#include "hbpopup_p.h" +#include "hbinstance.h" +#include "hbpopupmanager_p.h" +#include "hbdeviceprofile.h" +#include "hbevent.h" +#include "hbgraphicsscene.h" +#include "hbgraphicsscene_p.h" +#include "hbtooltip.h" +#include +#include +#include +#include +#include +#include +#include // krazy:exclude=qclasses + +#include + +#ifdef HB_EFFECTS +#include "hbeffectinternal_p.h" +bool HbPopupPrivate::popupEffectsLoaded = false; +#endif +/*! + @stable + @hbcore + \class HbPopup + \brief HbPopup is a base class for different popup notes in Hb library. + + \image html hbpopup.png A popup with a header widget, a list as a content widget, and two + action buttons. + + HbPopup is a concrete class. The content for a custom popup is implemented in + a separate widget, which is set to the popup with method setContentWidget(). + + Lastly shown popup is always positioned in Z order on the the top of already visible popups. + A popup can be permanent or automatically dismissed after a time-out. + Modal popups interrupt any other user interaction outside of the popup while they are visible, + whereas non-modal popups do not. + + An example of how to create a simple modal popup and show it. + \snippet{ultimatecodesnippet/ultimatecodesnippet.cpp,13} + + An example of how to create a non-modal popup and show it. + \snippet{ultimatecodesnippet/ultimatecodesnippet.cpp,26} + +*/ + +/*! + \reimp + \fn int HbPopup::type() const + */ + +/*! + \enum HbPopup::DefaultTimeout + + This enum defines available default timeout values to be used in method + setTimeout(HbPopup::DefaultTimeout). + */ + +/*! + \var HbPopup::NoTimeout + + No timeout is defined for automatically closing the popup. i.e. the popup is permanent. + */ + +/*! + \var HbPopup::ConfirmationNoteTimeout + + Timeout value intended to be used by confirmation notes. + */ + +/*! + \var HbPopup::StandardTimeout + + The default timeout value intended to be used by most non-permanent popups e.g. by notes. + */ + +/*! + \var HbPopup::ContextMenuTimeout + + The default timeout value intended to be used by context menus. + */ + +/*! + \enum HbPopup::DismissPolicy + + This enum defines available dismiss policy values. + + The dismiss policy defines what user actions will cause the popup to be dismissed i.e. closed. + */ + +/*! + \var HbPopup::NoDismiss + + The popup cannot be dismissed automatically by user interaction. + */ + +/*! + \var HbPopup::TapInside + + The popup is dismissed when user taps within the bounding rectangle of the popup. + */ + +/*! + \var HbPopup::TapOutside + + The popup is dismissed when user taps outside of the bounding rectangle of the popup. + */ + +/*! + \var HbPopup::TapAnywhere + + The popup is dismissed when user taps either within or outside + of the bounding rectangle of the popup. + */ + +/*! + \enum HbPopup::FrameType + + This enum defines available frame type values. + + The frame types defines what frame item backgrounds will be used by the popup. + */ + +/*! + \var HbPopup::Strong + + The popup is using strong frame. + */ + +/*! + \var HbPopup::Weak + + The popup is using weak frame. + */ + +/*! + \fn void HbPopup::aboutToShow(); + + This signal is emitted when the popup is about to be shown i.e. when method show() is called. + */ + +/*! + \fn void HbPopup::aboutToHide(); + + This signal is emitted when the popup is about to be hidden i.e. when method hide() is called. + */ + + +/*! + \fn void HbPopup::aboutToClose(); + + This signal is emitted when the popup is about to be closed i.e. when method close() is called + or the popup is + dismissed by the user or timeout. + */ + +static const struct { HbPopup::DefaultTimeout timeout; int value; } timeoutValues[] = +{ + {HbPopup::NoTimeout,0}, + {HbPopup::ConfirmationNoteTimeout,1500}, + {HbPopup::StandardTimeout,3000}, + {HbPopup::ContextMenuTimeout,6000}, +}; + +HbPopupBackGround::HbPopupBackGround(HbPopup * popup, QGraphicsItem *parent) : + QGraphicsItem(parent), + popup(popup) +{ + // This is needed to be able to block moving the focus to items behind background item by + // clicking on them. + setFlag(QGraphicsItem::ItemIsFocusable); + +#if QT_VERSION >= 0x040600 + setFlag(QGraphicsItem::ItemHasNoContents, true); +#endif +} + +HbPopupBackGround::~HbPopupBackGround() +{ + // Set backgroundItem to 0 to avoid double deletion + // e.g. when backgroundItem is deleted by scene before its popup + if (popup) { + HbPopupPrivate::d_ptr(popup)->backgroundItem = 0; + } +} + +void HbPopupBackGround::setRect(QRectF rect) +{ + mRect = rect; +} + +QRectF HbPopupBackGround::boundingRect() const +{ + if(!mRect.isValid()){ + // set backgroundItem's size so that it is big enough + // to cover the screen both landscape and portrait mode + const QSizeF screenSize = HbDeviceProfile::profile(this).logicalSize(); + qreal dim = qMax(screenSize.width(), screenSize.height()); + mRect.adjust(0,0,dim,dim); + } + return mRect; +} + +void HbPopupBackGround::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget ) +{ + Q_UNUSED(option) + Q_UNUSED(widget); + Q_UNUSED(painter); +} + +bool HbPopupBackGround::sceneEvent(QEvent *event) +{ + if (event->type() == QEvent::GraphicsSceneMousePress) { + HbPopupPrivate::d_ptr(popup)->handleBackgroundMousePressEvent(); + } + if (event->type() == QEvent::GraphicsSceneMouseRelease) { + HbPopupPrivate::d_ptr(popup)->handleBackgroundMouseReleaseEvent(static_cast(event)); + } + if (event->type() == QEvent::FocusIn && scene()) { + // Prevents last focus item losing its focus + // This event is received only when popup is modal + QFocusEvent restoreLastFocus(QEvent::FocusIn,Qt::OtherFocusReason); + QApplication::sendEvent(scene(),&restoreLastFocus); // krazy:exclude=qclasses + } + // accept events only for modal popups + if(popup->isModal()){ + event->accept(); + return true; + } else { + event->ignore(); + } + return QGraphicsItem::sceneEvent(event); +} + +HbPopupPrivate::HbPopupPrivate( ) : + eventLoop(0), + hasEffects(false), + closed(false), + hidingInProgress(true), + delayedHide(false), + deleteOnClose(false), + modal(true), // must be in sync QGraphicsItem::ItemIsFocusable of backgroundItem + fadeBackground(true), + inDestruction(false), + aboutToShowSignalGuard(false), + duplicateShowEvent(false), + timedOut(false), + timeout(HbPopupPrivate::timeoutValue(HbPopup::StandardTimeout)), + // priorityValue(HbPopup::Default), + priorityValue(0), + dismissPolicy(HbPopup::TapOutside), + backgroundItem(0), + mousePressLocation(None), + frameType(HbPopup::Strong), + preferredPosSet(false), + mStartEffect(false), + timeoutTimerInstance(0) +{ +} + +HbPopupPrivate::~HbPopupPrivate() +{ +} + +void HbPopupPrivate::init() +{ + Q_Q(HbPopup); + + q->setAttribute(Hb::InsidePopup); + + // By default popups are focusable + q->setFocusPolicy(Qt::StrongFocus); + q->setBackgroundItem(HbStyle::P_Popup_background); + + // Only for popup without parent + if (!q->parentItem()) { + backgroundItem = new HbPopupBackGround(q); + backgroundItem->setVisible(false); + + // Popup is invisible by default (explicit show or exec call is required) + q->setVisible(false); + } + hidingInProgress = false; +} + +/* +* *********** Begin of private features *********** +*/ + +/* +* Sets the priority for a popup. +* A popup with higher priority is always shown on top of a popup with lower priority. +* In case of popups with same priority the lastly shown will be on top. +* Default priority is HbPopup::Default +* \sa priority() +*/ +void HbPopupPrivate::setPriority(quint8 priority) +{ + //TODO: consider implementing dynamic change of prorities + // i.e. if the priority changes while the popup is registered to popupManager + // then re-register it to get its Z value updated + priorityValue=priority; +} + +/* +* *********** End of private features *********** +*/ +#ifdef HB_EFFECTS +void HbPopupPrivate::_q_delayedHide(HbEffect::EffectStatus status) +{ + Q_UNUSED(status); + + Q_Q(HbPopup); + + // Apply forceHide only if the effect started successfully + if (status.reason != Hb::EffectNotStarted) { + forceHide(); + } else { + delayedHide = false; + } + + if (deleteOnClose) { + q->deleteLater(); + } + hidingInProgress = false; +} + +void HbPopupPrivate::_q_orientationChange(Qt::Orientation orient, bool animate) +{ + Q_UNUSED(orient); + if (animate) { + Q_Q(HbPopup); + HbEffect::start(q, "HB_POPUP", "orientationswitch"); + } + +} +#endif // HB_EFFECTS + +void HbPopupPrivate::_q_timeoutFinished() +{ + Q_Q(HbPopup); + timedOut = true; + q->close(); +} + +void HbPopupPrivate::stopTimeout() +{ + if (timeoutTimerInstance) + timeoutTimerInstance->stop(); +} + +void HbPopupPrivate::startTimeout() +{ + if (timeout > 0) { + timeoutTimer()->start(); + timedOut = false; + } +} + +QTimer *HbPopupPrivate::timeoutTimer() +{ + Q_Q(HbPopup); + if (!timeoutTimerInstance) { + timeoutTimerInstance = new QTimer(q); + timeoutTimerInstance->setSingleShot(true); + q->connect(timeoutTimerInstance, SIGNAL(timeout()), q, SLOT(_q_timeoutFinished())); + } + + return timeoutTimerInstance; +} + +void HbPopupPrivate::handleKeyEvent(QKeyEvent *event) +{ + Q_Q(HbPopup); + event->accept(); + + // Any key event dismisses the popup if dismissPolicy includes TapInside flag + if (dismissPolicy & HbPopup::TapInside && !q->parentItem()) { + q->close(); + } +} + +//returns true if popup has been added to scene here. +bool HbPopupPrivate::addPopupToScene() +{ + Q_Q(HbPopup); + bool popupAdded(false); + if (!q->parentItem()) { + if (!q->scene() && !HbInstance::instance()->allMainWindows().isEmpty()) { + HbInstance::instance()->allMainWindows().at(0)->scene()->addItem(q); + popupAdded = true; + if (backgroundItem) { + q->scene()->addItem(backgroundItem); + } + } else if (q->scene() && backgroundItem && backgroundItem->scene() != q->scene()) { + q->scene()->addItem(backgroundItem); + } + } + return popupAdded; +} + +void HbPopupPrivate::handleBackgroundMousePressEvent() +{ + mousePressLocation = Background; +} + +void HbPopupPrivate::handleBackgroundMouseReleaseEvent(QGraphicsSceneMouseEvent *event) +{ + Q_Q(HbPopup); + + // Handle cases only for Background or Popup originated mouse presses and when + // any dismiss policy defined + if (mousePressLocation != None && dismissPolicy != HbPopup::NoDismiss) { + + MouseEventLocationType mouseReleaseLocation = Background; + + if (q->contains (q->mapFromScene(event->scenePos()))) { + mouseReleaseLocation = Popup; + } + + // Mouse is released within popup + if (mouseReleaseLocation == Popup) { + // Handle cases only when TapInside is set + if (dismissPolicy & HbPopup::TapInside) { + // Close popup if mouse press is initiated within popup or TapOutside is set + if (mousePressLocation == Popup || dismissPolicy & HbPopup::TapOutside) { + q->close(); + } + } + } + // Mouse is released within popup background + else { + // Handle cases only when TapOutside is set + if (dismissPolicy & HbPopup::TapOutside) { + // Close popup if mouse press is initiated within popup background + // or TapInside is set + if (mousePressLocation == Background || dismissPolicy & HbPopup::TapInside) { + q->close(); + } + } + } + } + + // reset mousePressLocation + mousePressLocation = None; +} + + +int HbPopupPrivate::timeoutValue(HbPopup::DefaultTimeout timeout) +{ + int count = sizeof(timeoutValues) / sizeof(timeoutValues[0]); + if (timeout < 0 || timeout >= count) { + return timeoutValues[HbPopup::NoTimeout].value; + } + return timeoutValues[timeout].value; +} + +void HbPopupPrivate::forceHide() +{ + Q_Q(HbPopup); + + delayedHide = false; + q->hide(); + delayedHide = hasEffects; +} + +void HbPopupPrivate::addPopupEffects() +{ + +#ifdef HB_EFFECTS + effectType = "HB_POPUP"; + hasEffects = popupEffectsLoaded; + if (popupEffectsLoaded) + return; + popupEffectsLoaded = true; + hasEffects = HbEffectInternal::add("HB_POPUP", + "popup_appear", + "appear"); + if (hasEffects) { + hasEffects = HbEffectInternal::add("HB_POPUP", + "popup_disappear", + "disappear"); + } + if (hasEffects ) { + hasEffects = HbEffectInternal::add("HB_POPUP", + "dialog_rotate", + "orientationswitch"); + } +#endif +} + + +void HbPopupPrivate::doSetModal( bool modal ) { + if(backgroundItem) { + // When the popup is modal background item must receive focus + // events to be able to prevent last focus item losing its + // focus + backgroundItem->setFlag(QGraphicsItem::ItemIsFocusable, modal); + } +} + +/*! +* Constructs a popup with given \a parent graphics item.\n +* Note: popups with \a parent set as 0 are behaving as real popups. +* This is actually the intended use. +* +* However in some situation could be useful to embedd a popup into a QGraphicsItem. +* In this case a non zero \a parent value must be passed. +* Popups with parent items behaving just like any other QGraphicsWidget. +* The following features are not supported (i.e. ignored) for popup with parents: +* +* - modality +* - timeout +* - unfadedItems +* - dismissPolicy +* - signal aboutToClose +*/ +HbPopup::HbPopup(QGraphicsItem *parent) : + HbWidget(*new HbPopupPrivate,parent) +{ + Q_D(HbPopup); + d->q_ptr = this; + d->init(); +} + + +/*! + \internal + */ +HbPopup::HbPopup(HbPopupPrivate &dd, QGraphicsItem *parent) : + HbWidget(dd, parent) +{ + Q_D(HbPopup); + d->q_ptr = this; + d->init(); +} +/*! +* Destroys the popup. +*/ +HbPopup::~HbPopup() +{ + Q_D(HbPopup); + d->inDestruction = true; + + // Deregister popup from HbPopupManager in case hideEvent() was not called + // before destruction + HbGraphicsScene *hbScene = qobject_cast(scene()); + if (hbScene) { + hbScene->d_ptr->hidePopup(this); + } + + if (d->eventLoop) { + d->eventLoop->exit(); + } + if (d->backgroundItem) { + // Set backgroundItem->popup to 0 to avoid double deletion + // e.g. when popup is deleted by scene before its backgroundItem + d->backgroundItem->popup = 0; + + // Delete the background item only and only if it's not going + // to be cleaned up by the destructing graphics scene + QGraphicsScene *scene = d->backgroundItem->scene(); // krazy:exclude=qclasses + if (!scene || !scene->property("destructed").isValid()) { + delete d->backgroundItem; + } + } +} + + +/*! +* Returns the popup timeout property in milliseconds. +* If this property is not set the deafult is HbPopup::StandardTimeout. +* \sa setTimeout() +*/ +int HbPopup::timeout() const +{ + Q_D(const HbPopup); + return d->timeout; +} + +/*! +* Sets the popup timeout property in milliseconds. +* If timeout <= 0 then the popup is permanent and not closed automatically. +* \sa timeout() setTimeout(HbPopup::DefaultTimeout) QGraphicsWidget::close() +*/ +void HbPopup::setTimeout(int timeout) +{ + Q_D(HbPopup); + d->timeout = timeout; +} + +/*! +* It is a convenience overload of \a timeout() for setting HbPopup::DefaultTimeout values +* to achieve common look & feel. +* \sa enum DefaultTimeout +* \sa timeout() setTimeout(int) QGraphicsWidget::close() +*/ +void HbPopup::setTimeout(HbPopup::DefaultTimeout timeout) +{ + setTimeout(HbPopupPrivate::timeoutValue(timeout)); +} + +/*! +* Returns the popup modality property. +* A modal popup blocks any user initiated events outside of the popup +* until it is closed. +* \sa setModal() +*/ +bool HbPopup::isModal() const +{ + Q_D(const HbPopup); + return d->modal; +} + +/*! +* Sets the popup modality property. +* \sa isModal() +*/ +void HbPopup::setModal(bool enabled) +{ + Q_D(HbPopup); + d->modal = enabled; + d->doSetModal( d->modal ); +} + +/*! +* Sets the background of popup faded if \a fadeBackground is true otherwise +* the background will not be faded. +* \sa isBackgroundFaded() +*/ +void HbPopup::setBackgroundFaded(bool fadeBackground) +{ + Q_D(HbPopup); + d->fadeBackground = fadeBackground; +} + +/*! +* Returns if the background of the popup is faded or not. +* Default: true +* \sa isBackgroundFaded() +*/ +bool HbPopup::isBackgroundFaded() const +{ + Q_D(const HbPopup); + return d->backgroundItem && d->fadeBackground; +} + +/*! +* Returns the dismiss policy of the popup. +* Default is HbPopup::TapOutside. +* \sa setDismissPolicy() +*/ +HbPopup::DismissPolicy HbPopup::dismissPolicy() const +{ + Q_D(const HbPopup); + return d->dismissPolicy; +} + +/*! +* Sets the dismiss policy property for the the popup. +* +* \sa dismissPolicy() +*/ +void HbPopup::setDismissPolicy(HbPopup::DismissPolicy dismissPolicy) +{ + Q_D(HbPopup); + d->dismissPolicy = dismissPolicy; +} + +/*! +* Returns the frame type of the popup. +* Default is HbPopup::Strong +* \sa setFrameType() +*/ +HbPopup::FrameType HbPopup::frameType() const +{ + Q_D(const HbPopup); + return d->frameType; +} + +/*! +* Sets the frame typeproperty for the the popup. +* +* \sa frameType() +*/ +void HbPopup::setFrameType(HbPopup::FrameType frameType) +{ + Q_D(HbPopup); + if ( d->frameType != frameType ) { + switch( frameType ) { + case HbPopup::Weak: + setBackgroundItem(HbStyle::P_Popup_background_weak); + break; + case HbPopup::Strong: + default: + setBackgroundItem(HbStyle::P_Popup_background); + break; + } + d->frameType = frameType; + updatePrimitives(); + } +} + + +/*! @alpha +* +* Shows the popup as modal popup returning immediately. + +* Connects aboutToClose() signal to the slot specified by \a receiver and +* \a member. The signal will be disconnected from the slot when the +* popup is closed. +* +* For non modal popups, use show(). +*/ +void HbPopup::open( QObject *receiver, const char *member ) +{ + Q_D(HbPopup); + connect(this, SIGNAL(aboutToClose()), receiver, member); + d->receiverToDisconnectOnClose = receiver; + d->memberToDisconnectOnClose = member; + +#if needed + // Ungrab the mouse if it is currently grabbed + // todo; currently needed menus to work ok, otherwise: + // - quick multiple presses on menuitem causes multiple actions (menu relaunch?) + // - closing menu with titlepane needs multiple presses (menu relaunch?) + // Ungrab was removed when trying to fix problem when button pressed()-signal + // was connected to menu launch. Button did not get anymore mouse release event. + if (scene()) { + QGraphicsItem *item = scene()->mouseGrabberItem(); + if (item) { + item->ungrabMouse(); + } + } +#endif + show(); +} + + +/*! + \deprecated HbPopup::exec() + is deprecated. Please use HbPopup::show() or + void HbPopup::open( QObject *receiver, const char *member ) instead. +* +* Executes the popup synchronously. +* Note: when popup is executed syncronously it is always modal. +* This function is deprecated. use \sa open() or \sa show() instead. +*/ +void HbPopup::exec() +{ + // Q_ASSERT(false); + Q_D(HbPopup); + + HbMainWindow* w(mainWindow()); + if (w) { + disconnect(w, SIGNAL(aboutToChangeOrientation(Qt::Orientation, bool)), this, SLOT(_q_orientationChange(Qt::Orientation, bool))); + connect( w, SIGNAL(aboutToChangeOrientation(Qt::Orientation, bool)), this, SLOT(_q_orientationChange(Qt::Orientation, bool)) ); + } + + if (!d->eventLoop) { + // Prevent deleting popup in eventloop + bool deleteOnClose = testAttribute(Qt::WA_DeleteOnClose); + setAttribute(Qt::WA_DeleteOnClose, false); + + // Set popup to modal before eventloop + bool wasShowModal = isModal(); + setModal(true); + + show(); + + // Ungrab the mouse if it is currently grabbed + // todo; currently needed menus to work ok, otherwise: + // - quick multiple presses on menuitem causes multiple actions (menu relaunch?) + // - closing menu with titlepane needs multiple presses (menu relaunch?) + // Ungrab was removed when trying to fix problem when button pressed()-signal + // was connected to menu launch. Button did not get anymore mouse release event. + if (scene()) { + QGraphicsItem *item = scene()->mouseGrabberItem(); + if (item) { + item->ungrabMouse(); + } + } + + QEventLoop eventLoop; + d->eventLoop = &eventLoop; + QPointer guard = this; + d->eventLoop->exec(); + if (guard.isNull()) { + return; + } + d->eventLoop = 0; + + // Reset modality + setModal(wasShowModal); + + if (deleteOnClose) { + delete this; + } + } else { + qWarning("HbPopup::exec: Recursive call detected"); + } +} + +/*! + \reimp + */ +QVariant HbPopup::itemChange ( GraphicsItemChange change, const QVariant & value ) +{ + Q_D(HbPopup); + + if (change == QGraphicsItem::ItemVisibleChange) { + if (value.toBool()) { + if(!d->hasEffects){ + d->addPopupEffects(); + } + if (!d->aboutToShowSignalGuard) + { + d->aboutToShowSignalGuard = true; + emit aboutToShow(); + } + // Note: when visibility changes to "visible" base class implementation needs + // to be called otherwise showEvent() is not called. + + } else { + d->aboutToShowSignalGuard = false; + if (!d->hidingInProgress) { + emit aboutToHide(); + } + + if (d->delayedHide && // about to hide and we wanna delay hiding + d->hasEffects && !parentItem()) { // only for popup without parent + if (!d->hidingInProgress) { // Prevent reentrance + d->hidingInProgress = true; +#ifdef HB_EFFECTS + QRectF extRect(0.0, + -boundingRect().height(), + boundingRect().width(), + 0); + if (!HbEffect::start(this, d->effectType, "disappear", + this, "_q_delayedHide", + QVariant(), extRect)) { + d->delayedHide = false; + } +#endif + } + if (d->delayedHide) { + return true; + } else { + d->delayedHide = d->hasEffects; + d->hidingInProgress = false; + // fallback to base class imp + } + } + } + } else if (change == QGraphicsItem::ItemSceneHasChanged) { + HbMainWindow* w(mainWindow()); + if ( w ){ + disconnect(this, SLOT(handlePopupPos())); + connect( w, SIGNAL(orientationChanged(Qt::Orientation)), + this, SLOT(handlePopupPos()) ); + } + } + return HbWidget::itemChange(change, value); +} + +/*! +* Handles the popup position when Orientation changes +*/ +void HbPopup::handlePopupPos() +{ + QEvent userEvent(QEvent::ContextMenu); + QCoreApplication::sendEvent(this, &userEvent); +} + +/*! + \reimp + */ +void HbPopup::mousePressEvent(QGraphicsSceneMouseEvent *event ) +{ + Q_D(HbPopup); + + Q_UNUSED(event); + + d->mousePressLocation = HbPopupPrivate::Popup; + + // We need to reimplement this function otherwise this events will be + // ignored by default and we wont get further mouse events + // not even mouseReleaseEvent. See doc of QGraphicsItem::mousePressEvent() + // for more info. + QGraphicsItem::mousePressEvent(event); + + // Event has to be accepted cause QGraphicsItem::mousePressEvent can mark it + // to ignored + event->accept(); +} + +/*! + \reimp + */ +void HbPopup::mouseReleaseEvent(QGraphicsSceneMouseEvent *event ) +{ + QGraphicsItem::mouseReleaseEvent(event); + event->accept(); + // Note: Mouse release event is always handled in handleBackgroundMouseReleaseEvent +} + +/*! + \reimp + */ +void HbPopup::keyPressEvent(QKeyEvent *event) +{ + Q_D(HbPopup); + d->handleKeyEvent(event); +} + +/*! + \reimp + */ +// +// Shows the popup with an animation and starts the timer to dismiss the popup, +// unless it is a permanent popup. +// +void HbPopup::showEvent(QShowEvent *event) +{ + Q_D(HbPopup); + + HbWidget::showEvent(event); + + // Only for popup without parent + // Note: + // popups without parent are treated as popups i.e.: + // - can have background item + // - timeout + // - and registered to HbPopupManager + // otherwise popup is treated as normal widget + if(d->duplicateShowEvent){ + d->duplicateShowEvent = false; + return; + } + if (!parentItem()) { + //check if popup needs to be added to scene.This can result in duplciate show event, + // if popup is added to scene here. + if(d->addPopupToScene()) + d->duplicateShowEvent = true; + + // Popup clears closed state + d->closed = false; + if (d->backgroundItem) { + d->backgroundItem->setVisible(true); + d->backgroundItem->setAcceptHoverEvents(isModal()); + // Let the background be a panel if the popup is one + // However if the popup is not modal we don't want the background + // to be a panel. A panel provides contained focus handling + if ((flags() & QGraphicsItem::ItemIsPanel) && isModal()) { + d->backgroundItem->setFlag(QGraphicsItem::ItemIsPanel); + } + } + if (qobject_cast(scene())) { + qobject_cast(scene())->d_ptr->showPopup(this); + HbWidgetFeedback::triggered(this, Hb::InstantPopupOpened); + } + + /*if(d->hasEffects && boundingRect().isValid()) { + + #ifdef HB_EFFECTS + QRectF extRect(0.0, + -boundingRect().height(), + boundingRect().width(), + 0); + HbEffect::start(this, d->effectType, "appear", 0, 0, QVariant(), extRect); + #endif//HB_EFFECTS + d->mStartEffect = false; + } else { + d->mStartEffect = true; + }*/ + + //workaround + resetTransform(); + setOpacity(1); + //workaround ends + + // delay hiding if effects are enabled + d->delayedHide = d->hasEffects; + + // If it is not permanent launch a timer for closing the popup + if (0 < d->timeout) { + d->timeoutTimer()->setInterval(d->timeout); + d->timeoutTimer()->start(); + } + } +} + +/*! + \reimp + */ +void HbPopup::hideEvent(QHideEvent *event) +{ + Q_D(HbPopup); + + HbWidget::hideEvent(event); + + // Only for popup without parent + if (!parentItem()) { + if (d->backgroundItem) { + d->backgroundItem->setVisible(false); + } + qobject_cast(scene())->d_ptr->hidePopup(this); + } + + HbWidgetFeedback::triggered(this, Hb::InstantPopupClosed); + if (d->eventLoop) { + d->eventLoop->exit(); + } + + d->doSetModal( d->modal ); + +} + +/*! + \reimp + */ +void HbPopup::resizeEvent( QGraphicsSceneResizeEvent * event ) +{ + HbWidget::resizeEvent(event); + updatePrimitives(); +} + +/*! + \reimp + */ +void HbPopup::closeEvent ( QCloseEvent * event ) +{ + Q_D(HbPopup); + d->stopTimeout(); + // Only for popup without parent + if (!d->closed && !parentItem()) { + // Popup goes to closed state + d->closed = true; + + emit aboutToClose(); + + // prevent delete on close before effects are finished + if (d->hasEffects && isVisible()) { + d->deleteOnClose = testAttribute(Qt::WA_DeleteOnClose); + setAttribute(Qt::WA_DeleteOnClose,false); + } + HbToolTip::hideText(qobject_cast(scene())); + } + if (d->receiverToDisconnectOnClose) { + disconnect(this, SIGNAL(aboutToClose()), + d->receiverToDisconnectOnClose, d->memberToDisconnectOnClose); + d->receiverToDisconnectOnClose = 0; + } + d->memberToDisconnectOnClose.clear(); + HbWidget::closeEvent(event); +} + +/*! + \reimp + */ +bool HbPopup::event(QEvent *event) +{ + /*Q_D(HbPopup); + if (event->type() == QEvent::GraphicsSceneResize) { + //Workaround when showing first time + #ifdef HB_EFFECTS + if(d->mStartEffect && boundingRect().isValid()) { + QRectF extRect(0.0, + -boundingRect().height(), + boundingRect().width(), + 0); + HbEffect::start(this, d->effectType, "appear", 0, 0, QVariant(), extRect); + d->mStartEffect = false; + } + #endif//HB_EFFECTS + //workaround ends + }*/ + return HbWidget::event(event); +} + + +/*! + Sets preferred position\a position for popup with \a placement + as origin. + + \param position is the position at which the popup is shown. + \param placement is the corner or edge which \a position refers to + + Example usage: + \code + HbDialog popup; + ... + popup.setPreferredPosition( QPointF(x,y), HbPopupBase::BottomEdgeCenter ); + popup.exec(); + \endcode + + */ + +void HbPopup::setPreferredPos( const QPointF& preferredPos, + HbPopup::Placement placement ) + +{ + Q_D(HbPopup); + bool layoutFlag = false; + if (d->preferredPos != preferredPos ) { + d->preferredPos = preferredPos; + layoutFlag = true; + } + if (d->placement != placement) { + d->placement = placement; + layoutFlag = true; + } + d->preferredPosSet = true; + //If position updated, informing layoutproxy with layoutrequest + if (layoutFlag) { + QApplication::postEvent(this, new QEvent(QEvent::LayoutRequest)); + } +} + +#include "moc_hbpopup.cpp"