--- /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 <QTimer>
+#include <QGraphicsSceneMouseEvent>
+#include <QShowEvent>
+#include <QHideEvent>
+#include <QEventLoop>
+#include <QPointer>
+#include <QApplication> // krazy:exclude=qclasses
+
+#include <hbwidgetfeedback.h>
+
+#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<QGraphicsSceneMouseEvent *>(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<HbGraphicsScene *>(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<QObject> 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<HbGraphicsScene *>(scene())) {
+ qobject_cast<HbGraphicsScene *>(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<HbGraphicsScene *>(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<HbGraphicsScene *>(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"