src/hbcore/gui/hbpopup.cpp
author hgs
Tue, 13 Jul 2010 22:03:02 +0300
changeset 13 5168dbe2168a
parent 7 923ff622b8b9
child 21 4633027730f5
child 34 ed14f46c0e55
permissions -rw-r--r--
201027_1

/****************************************************************************
**
** 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 "hbglobal_p.h"
#include "hbvgmaskeffect_p.h"
#include "hbvgchainedeffect_p.h"
#include <QTimer>
#include <QGraphicsSceneMouseEvent>
#include <QShowEvent>
#include <QHideEvent>
#include <QEventLoop>
#include <QPointer>
#include <QDebug>
#include <QBitmap>
#include <hbinstance_p.h>
#include <QApplication> // krazy:exclude=qclasses

#include <hbwidgetfeedback.h>

#ifdef HB_EFFECTS
#include "hbeffectinternal_p.h"
bool HbPopupPrivate::popupEffectsLoaded = false;
#endif
/*!
    @beta
    @hbcore
    \class HbPopup
    \brief HbPopup is a base class for different popups in Hb library.

    Popup is a widget that is displayed above other widgets in the view.

    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.

    \sa HbDialog
*/

/*!
    \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. Actual appearance is dependent on theme.
 */

/*!
    \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.
 */

/*!
    \enum HbPopup::Placement

    Placement is the corner or edge to which position of the popup refers to.
  */

/*!
    \primitives
    \primitive{background} HbFrameItem representing the popup background. The background can be weak or strong (different graphical styles) depending on popup type.
    \primitive{P_Popup_heading_frame} HbFrameItem representing the popup heading text background
  */

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),
    mScreenMargin(0.0),
    mAutoLayouting(true),
    mOriginalAutoLayouting(mAutoLayouting),
    mVgMaskEffect(0),
    mOrientationEffectHide(false),
    timeoutTimerInstance(0)
{
}

HbPopupPrivate::~HbPopupPrivate()
{
    stopTimeout();
    delete timeoutTimerInstance;
}

void HbPopupPrivate::init()
{
    Q_Q(HbPopup);

    q->setAttribute(Hb::InsidePopup);

    // By default popups are focusable
    q->setFocusPolicy(Qt::StrongFocus);    
    setBackgroundItem(HbStyle::P_Popup_background);
    q->updatePrimitives();


    // Only for popup without parent
    if (!q->parentItem()) {
        backgroundItem = new HbPopupBackGround(q);
        backgroundItem->setVisible(false);

        // Popup is invisible by default (explicit show or open call is required)
        q->setVisible(false);
    }
    hidingInProgress = false; 
    QGraphicsItem::GraphicsItemFlags itemFlags = q->flags();
    itemFlags |= QGraphicsItem::ItemClipsToShape;
    itemFlags |= QGraphicsItem::ItemClipsChildrenToShape;
    itemFlags |= QGraphicsItem::ItemSendsGeometryChanges;
    //itemFlags |= QGraphicsItem::ItemIsPanel;
    q->setFlags(itemFlags);  
}
void HbPopupPrivate::_q_appearEffectEnded(HbEffect::EffectStatus status)
{
	Q_UNUSED(status);
}

CSystemToneService* HbPopupPrivate::systemToneService()
{
	return HbInstancePrivate::d_ptr()->systemTone();
}
/*
 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;
}

#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_orientationAboutToChange(Qt::Orientation orient, bool animate)
{
    Q_UNUSED(orient);    
    Q_Q(HbPopup);
    if (animate && q->isVisible()) {
        HbEffect::start(q, "HB_POPUP", "orient_disappear");
        mOrientationEffectHide = true;
    }
}

#endif // HB_EFFECTS

void HbPopupPrivate::_q_orientationChanged()
{
    Q_Q(HbPopup);
    if (q->isVisible()) {
        QEvent userEvent(QEvent::ContextMenu);
        QCoreApplication::sendEvent(q, &userEvent);
    }
#ifdef HB_EFFECTS
    if (mOrientationEffectHide) {
        HbEffect::cancel(q);
        HbEffect::start(q, "HB_POPUP", "orient_appear");
        mOrientationEffectHide = false;
    }
#endif
}

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;
    }
}

void HbPopupPrivate::setTimeout(int msec)
{
    Q_Q(HbPopup);

    int prevTimeout = timeout;
    timeout = msec;
    if (msec > 0) {
        timeoutTimer()->setInterval(msec);
        // If timeout was 0 and it is now set to something > 0 then start the timer.
        if (q->isVisible() && prevTimeout <= 0)
            startTimeout();
    } else {
        stopTimeout();
    }
}

QTimer *HbPopupPrivate::timeoutTimer()
{
    Q_Q(HbPopup);
    if (!timeoutTimerInstance) {
        timeoutTimerInstance = new QTimer();
        timeoutTimerInstance->setSingleShot(true);
        q->connect(timeoutTimerInstance, SIGNAL(timeout()), q, SLOT(_q_timeoutFinished()));
    }

    return timeoutTimerInstance;
}

//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()
{
    Q_Q(HbPopup);
    mousePressLocation = Background;
    if (dismissPolicy & HbPopup::TapOutside) {
        q->close();
    }
}

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();
                }
            }
        }
    }

    // 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",
                                           "popup_orient_disappear",
                                           "orient_disappear");
    }
    if (hasEffects ) {
        hasEffects = HbEffectInternal::add("HB_POPUP",
                                           "popup_orient_appear",
                                           "orient_appear");
    }
    hasEffects = true; //Workaround until orient appear effects are in place
#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);
        backgroundItem->setFlag(QGraphicsItem::ItemIsPanel, modal);
        if(modal) {
            backgroundItem->setPanelModality(QGraphicsItem::PanelModal);
        } else {
            backgroundItem->setPanelModality(QGraphicsItem::NonModal);
        }
    }
}

void HbPopupPrivate::calculateShape()
{
#if 0
    Q_Q(HbPopup);
    // Contrary to the name, HbVgMaskEffect has a software
    // implementation too, and we will actually force the usage of
    // that here, ignoring the pure OpenVG version.
    if (!mVgMaskEffect) {
        mVgMaskEffect = new HbVgMaskEffect;
        // Masking does not work reliably on HW.
        mVgMaskEffect->setForceSwMode(true);
        // There may be children (like the scroll area in menus) that
        // would mess up the masking so exclude those.
        mVgMaskEffect->setIncludeSourceItemOnly(true);
        if (!q->graphicsEffect()) {
            // Attach the effect. Ownership is transferred to q.
            mVgMaskEffect->install(q);
        } else {
            // Avoid replacing already set effects. Do not mask if
            // this is not possible, otherwise we would unexpectedly
            // delete the previously set graphics effect.
            HbVgChainedEffect *c = qobject_cast<HbVgChainedEffect *>(q->graphicsEffect());
            if (c) {
                c->add(mVgMaskEffect);
            } else {
                delete mVgMaskEffect;
            }
        }
    }
    QPixmap image(QSize(static_cast<int>(q->backgroundItem()->boundingRect().width()),
                        static_cast<int>(q->backgroundItem()->boundingRect().height())));
    image.fill(Qt::transparent);
    QPainter imagePainter(&image);
    q->backgroundItem()->paint(&imagePainter, 0, 0);
    imagePainter.end();
    mVgMaskEffect->setMask(image);
#endif
}

/*!
 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->setTimeout(timeout);
    //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:
            d->setBackgroundItem(HbStyle::P_Popup_background_weak);
            break;
        case HbPopup::Strong:
        default:
            d->setBackgroundItem(HbStyle::P_Popup_background);
            break;
        }
        d->frameType = frameType;
        updatePrimitives();
    }
}


/*!
 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);
    if (receiver) {
        connect(this, SIGNAL(aboutToClose()), receiver, member);
    }
    d->receiverToDisconnectOnClose = receiver;
    d->memberToDisconnectOnClose = member;

    show();
}

/*!
    \reimp
 */
QVariant HbPopup::itemChange ( GraphicsItemChange change, const QVariant & value )
{
    Q_D(HbPopup);

    if (change == QGraphicsItem::ItemPositionChange) {
        d->mAutoLayouting = false;
    }
    if (change == QGraphicsItem::ItemVisibleHasChanged) {
        if (value.toBool()) {
            if(d->hasEffects && boundingRect().isValid()) {

#ifdef HB_EFFECTS
                QRectF extRect(0.0,
                               -boundingRect().height(),
                               boundingRect().width(),
                               0);
                d->mStartEffect = true;
                HbEffect::cancel(this);
                d->mStartEffect = false;
                HbEffect::start(this, d->effectType, "appear", this, "_q_appearEffectEnded", QVariant(), extRect);
#endif//HB_EFFECTS
            } else {
                d->mStartEffect = true;
            }
        }
    }

    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
                bool hideDelayed = d->delayedHide;
                if (!d->hidingInProgress) { // Prevent reentrance
                    d->hidingInProgress = true;
#ifdef HB_EFFECTS
                    QRectF extRect(0.0,
                                   -boundingRect().height(),
                                   boundingRect().width(),
                                   0);
                    HbEffect::cancel(this);
                    if (!HbEffect::start(this, d->effectType, "disappear",
                                         this, "_q_delayedHide",
                                         QVariant(), extRect)) {
                        d->delayedHide = false;
                        return HbWidget::itemChange(change, value);
                    }
#endif
                }
                if (hideDelayed) {
                    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(_q_orientationAboutToChange(Qt::Orientation, bool)));
            connect( w, SIGNAL(aboutToChangeOrientation(Qt::Orientation, bool)),
                     this, SLOT(_q_orientationAboutToChange(Qt::Orientation, bool)) );
            disconnect(this, SLOT(_q_orientationChanged()));
            connect( w, SIGNAL(orientationChanged(Qt::Orientation)),
                     this, SLOT(_q_orientationChanged()) );
        }

    }
    return HbWidget::itemChange(change, value);
}

/*!
 \deprecated HbPopup::handlePopupPos()
         is deprecated. This function should not be used from the application side.
 Handles the popup position when Orientation changes
*/
void HbPopup::handlePopupPos()
{
    HB_DEPRECATED("HbPopup::handlePopupPos() is deprecated.");
    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
 */
//
// 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;
        }
        //setActive(true);
        // Popup clears closed state
        d->closed = false;
        if (d->backgroundItem) {
            d->backgroundItem->setVisible(true);
            d->backgroundItem->setAcceptHoverEvents(isModal());
            if (isModal()) {
                d->backgroundItem->setFlag(QGraphicsItem::ItemIsPanel);
             }
        }
        if (qobject_cast<HbGraphicsScene *>(scene())) {
            qobject_cast<HbGraphicsScene *>(scene())->d_ptr->showPopup(this);
            HbWidgetFeedback::triggered(this, Hb::InstantPopupOpened);
        }

        //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->startTimeout();
        }
    }
}

/*!
    \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();
    Q_D(HbPopup);
    if (d->polished) {
        d->calculateShape();
    }
}

/*!
    \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);
}


/* Currently, virtual keyboard must be able to position a popup
   containing a editor to an arbitrary place. VKB does it's best to
   reposition popup back to original position when needed. At least in
   orientation switch the old position naturally is wrong, hence popup
   must be relayouted.

   It would be unreasonable to make special checks for popup in vkb
   side. It also would be unreasonable to do special checks for vkb in
   popup side. Hence this semi-hidden dynamic property for
   communicating this special case.

   WARNING: Do not count on this special behaviour, we might remove it
   without prior notice. If you do require such a behavior, please
   raise a feature request and we might make this a proper API.
 */
const char* KPositionManagedByVKB("PositionManagedByVKB");

/*!
    \reimp
 */
bool HbPopup::event(QEvent *event)
{
    Q_D(HbPopup);
    if ( event->type() == QEvent::DynamicPropertyChange ) {
        QVariant v(property(KPositionManagedByVKB));
        if (v.isValid() ){
            if (v.toBool()) {
                // position is now managed by vkb
                d->mOriginalAutoLayouting = d->mAutoLayouting;
                d->mAutoLayouting = false;
            } else {
                d->mAutoLayouting = d->mOriginalAutoLayouting;

                // vkb has finished, and we might be on totally wrong
                // place.
                QEvent layoutRequest = QEvent::LayoutRequest;
                QApplication::sendEvent(this, &layoutRequest);
            }
        }
    } else if (event->type() == QEvent::LayoutRequest) {
        //Workaround when showing first time                           
#ifdef HB_EFFECTS
        if(d->mStartEffect && boundingRect().isValid()) {
            d->mStartEffect = false;
            QCoreApplication::sendPostedEvents(this, QEvent::LayoutRequest);
            QRectF extRect(0.0,
                           -boundingRect().height(),
                           boundingRect().width(),
                           0);
            d->mStartEffect = true;
            HbEffect::cancel(this);
            d->mStartEffect = false;
            HbEffect::start(this, d->effectType, "appear", this, "_q_appearEffectEnded", QVariant(), extRect);            
        }
#endif//HB_EFFECTS
        //workaround ends
    }
    return HbWidget::event(event);
}

/*!
  Sets preferred position\a position for popup with \a placement
  as origin.

  By default popup is placed in the middle of the screen. If other positions are needed please
  ensure that the preferred position is working properly with different screen sizes.

  \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
  HbPopup *popup = new HbPopup();
  ...
  popup->setPreferredPosition( QPointF(x,y), HbPopupBase::BottomEdgeCenter );
  popup->show();
  \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) {
        QEvent layoutRequest = QEvent::LayoutRequest;
        QApplication::sendEvent(this, &layoutRequest);
    }
}

/*!
  \reimp
  Returns the shape of this item as a QPainterPath.
  */
QPainterPath HbPopup::shape() const
{    
#if 0
   /*Q_D(const HbPopup);
    if (backgroundItem() && d->mPath) {
        return *d->mPath;
    } else {
        return HbWidget::shape();
    }*/
#else
    return HbWidget::shape();
#endif
}

#include "moc_hbpopup.cpp"