homescreenapp/hsdomainmodel/src/hswidgethost.cpp
changeset 55 03646e8da489
parent 51 4785f57bf3d4
child 60 30f14686fb04
child 62 341166945d65
equal deleted inserted replaced
51:4785f57bf3d4 55:03646e8da489
    13 *
    13 *
    14 * Description:
    14 * Description:
    15 *
    15 *
    16 */
    16 */
    17 
    17 
    18 #include <QMetaObject>
    18 #include <QApplication>
       
    19 #include <QStateMachine>
       
    20 #include <QState>
       
    21 #include <QFinalState>
    19 #include <QGraphicsLinearLayout>
    22 #include <QGraphicsLinearLayout>
    20 #include <QParallelAnimationGroup>
    23 #include <QParallelAnimationGroup>
    21 #include <QPropertyAnimation>
    24 #include <QPropertyAnimation>
    22 #include <QGraphicsDropShadowEffect>
    25 #include <QGraphicsDropShadowEffect>
    23 #include <QGraphicsSceneResizeEvent>
    26 #include <QGraphicsSceneResizeEvent>
       
    27 #include <QGesture>
       
    28 #include <QGraphicsScene>
    24 
    29 
    25 #include <qservicemanager.h>
    30 #include <qservicemanager.h>
    26 #include <qservicefilter.h>
    31 #include <qservicefilter.h>
    27 #include <qserviceinterfacedescriptor.h>
    32 #include <qserviceinterfacedescriptor.h>
    28 
    33 
    29 #include <HbInstance>
       
    30 #include <HbInstantFeedback>
    34 #include <HbInstantFeedback>
    31 
    35 
    32 #include "hswidgethost.h"
       
    33 #include "hsdatabase.h"
    36 #include "hsdatabase.h"
    34 #include "hsdomainmodeldatastructures.h"
    37 #include "hsdomainmodeldatastructures.h"
       
    38 #include "hsscene.h"
    35 #include "hspage.h"
    39 #include "hspage.h"
    36 #include "hsapp_defs.h"
    40 #include "hswidgethost.h"
    37 #include "hsscene.h"
       
    38 #include "hswidgetcomponentregistry.h"
    41 #include "hswidgetcomponentregistry.h"
    39 #include "hswidgetcomponent.h"
    42 #include "hswidgetcomponent.h"
       
    43 #include "hsconfiguration.h"
       
    44 
       
    45 // Helper macros for connecting state entry and exit actions.
       
    46 #define ENTRY_ACTION(state, action) \
       
    47     connect(state, SIGNAL(entered()), SLOT(action()));
       
    48 #define EXIT_ACTION(state, action) \
       
    49     connect(state, SIGNAL(exited()), SLOT(action()));
    40 
    50 
    41 QTM_USE_NAMESPACE
    51 QTM_USE_NAMESPACE
    42 
    52 
    43 /*!
    53 HsWidgetHost::HsWidgetHost(int databaseId, QGraphicsItem *parent)
    44     \class HsWidgetHost
    54   : HbWidget(parent),
    45     \ingroup group_hsutils
    55     mDatabaseId(databaseId),
    46     \brief Homescreen widget runner.
    56     mStateMachine(0),
    47     Is responsible of running a homescreen widget. Each
    57     mWidget(0),
    48     homescreen widget has its own host.
    58     mPage(0),
    49 */
    59     mComponent(0),
    50 
    60     mIsFinishing(false)
    51 HsWidgetHost* HsWidgetHost::createInstance(HsWidgetData &widgetData,
    61 {
       
    62     setFlag(QGraphicsItem::ItemClipsChildrenToShape);
       
    63     setFlag(QGraphicsItem::ItemHasNoContents);
       
    64 
       
    65     grabGesture(Qt::TapGesture);
       
    66     grabGesture(Qt::TapAndHoldGesture);
       
    67     grabGesture(Qt::PanGesture);
       
    68     grabGesture(Qt::PinchGesture);
       
    69     grabGesture(Qt::SwipeGesture);
       
    70     grabGesture(Qt::CustomGesture);
       
    71 
       
    72     setupEffects();
       
    73     setupStates();
       
    74 }
       
    75 
       
    76 HsWidgetHost::~HsWidgetHost()
       
    77 {
       
    78 }
       
    79 
       
    80 HsWidgetHost *HsWidgetHost::createInstance(HsWidgetData &widgetData, 
    52                                            const QVariantHash &preferences)
    81                                            const QVariantHash &preferences)
    53 {
    82 {
    54     HsDatabase* db = HsDatabase::instance();
    83     HsDatabase *db = HsDatabase::instance();
    55     Q_ASSERT(db);
       
    56 
    84 
    57     if (db->insertWidget(widgetData)) {
    85     if (db->insertWidget(widgetData)) {
    58         db->setWidgetPreferences(widgetData.id, preferences);
    86         db->setWidgetPreferences(widgetData.id, preferences);
    59         return new HsWidgetHost(widgetData.id);
    87         return new HsWidgetHost(widgetData.id);
    60     }
    88     } else {
    61 
    89         return 0;
    62     return 0;
    90     }
    63 }
    91 }
    64 /*!
    92 
    65     Construct a widget host for the given \a databaseId.
    93 int HsWidgetHost::databaseId() const
    66     \a parent becomes the parent item for the host.
    94 {
    67 */
    95     return mDatabaseId;
    68 HsWidgetHost::HsWidgetHost(int databaseId, QGraphicsItem *parent)
       
    69     : HbWidget(parent),
       
    70       mWidget(0),
       
    71       mPage(0),
       
    72       mState(Unloaded),
       
    73       mDatabaseId(databaseId)
       
    74 {
       
    75     setFlags(QGraphicsItem::ItemClipsChildrenToShape);
       
    76 
       
    77     HsDatabase *db = HsDatabase::instance();
       
    78 
       
    79     // Find the widget data.
       
    80     HsWidgetData data;
       
    81     data.id = mDatabaseId;
       
    82     if (!db->widget(data)) {
       
    83        return;
       
    84     }
       
    85 
       
    86     mUri = data.uri;
       
    87 
       
    88     // bind host to component
       
    89     HsWidgetComponent *component = HsWidgetComponentRegistry::instance()->component(mUri);
       
    90     connect(component, SIGNAL(uninstalled()), SLOT(onFinished()));
       
    91     connect(component, SIGNAL(aboutToUninstall()), SLOT(onAboutToUninstall()));
       
    92     connect(component, SIGNAL(updated()), SLOT(onUpdated()));
       
    93     connect(component, SIGNAL(unavailable()), SLOT(onUnavailable()));
       
    94     connect(component, SIGNAL(available()), SLOT(onAvailable()));
       
    95 
       
    96     /* TODO: Uncomment after the Qt bug has been fixed.
       
    97     QGraphicsDropShadowEffect *effect =
       
    98         new QGraphicsDropShadowEffect(this);
       
    99     effect->setColor(QColor(0, 0, 0, 150));
       
   100     effect->setBlurRadius(5);
       
   101     effect->setOffset(3);
       
   102     setGraphicsEffect(effect);
       
   103     */
       
   104 }
       
   105 
       
   106 /*!
       
   107     Destructor.
       
   108 */
       
   109 HsWidgetHost::~HsWidgetHost()
       
   110 {
       
   111 }
       
   112 
       
   113 /*!
       
   114     Load hosted widget from plugin and validate it.
       
   115     Returns true if widget construction is successfull.
       
   116 */
       
   117 bool HsWidgetHost::load()
       
   118 {
       
   119     if (mState != Unloaded) {
       
   120         return false;
       
   121     }
       
   122     if (mWidget) {
       
   123         return false;
       
   124     }
       
   125 
       
   126 
       
   127     // Create the hosted widget.
       
   128     QServiceManager manager;
       
   129     QServiceFilter filter("com.nokia.symbian.IHomeScreenWidget");
       
   130     filter.setServiceName(mUri);
       
   131     QList<QServiceInterfaceDescriptor> interfaces = manager.findInterfaces(filter);
       
   132     if (interfaces.isEmpty()) {
       
   133         return false;
       
   134     }
       
   135 
       
   136     QObject *widgetObject = manager.loadInterface(interfaces.first());
       
   137     mWidget = qobject_cast<QGraphicsWidget *>(widgetObject);
       
   138 
       
   139     if (!mWidget ||
       
   140         !setMethod("onShow()", mOnShowMethod) ||
       
   141         !setMethod("onHide()", mOnHideMethod)) {
       
   142         mWidget = 0;
       
   143         delete widgetObject;
       
   144         return false;
       
   145     }
       
   146 
       
   147     setProperty("isOnline", mIsOnlineProperty);
       
   148 	setProperty("rootPath", mRootPathProperty);
       
   149     
       
   150     setMethod("isPannable(QGraphicsSceneMouseEvent*)", mIsPannable);
       
   151     setMethod("onInitialize()", mOnInitializeMethod);
       
   152     setMethod("onUninitialize()", mOnUninitializeMethod);
       
   153 
       
   154     if (hasSignal("setPreferences(const QStringList&)")) {
       
   155         connect(mWidget, SIGNAL(setPreferences(QStringList)),
       
   156                 SLOT(onSetPreferences(QStringList)));
       
   157     }
       
   158     if (hasSignal("finished()")) {
       
   159         connect(mWidget, SIGNAL(finished()),
       
   160                 SLOT(onFinished()));
       
   161     }
       
   162     if (hasSignal("error()")) {
       
   163         connect(mWidget, SIGNAL(error()),
       
   164                 SLOT(onError()));
       
   165     }
       
   166 
       
   167     mWidget->installEventFilter(this);
       
   168 
       
   169 	loadWidgetPresentation();
       
   170 
       
   171     HsScene *scene = HsScene::instance();
       
   172     setMaximumSize(scene->maximumWidgetSizeInPixels());
       
   173     setMinimumSize(scene->minimumWidgetSizeInPixels());
       
   174 
       
   175     mWidget->setParentItem(this);
       
   176 
       
   177     setNewSize(mWidget->size());
       
   178     mState = Loaded;
       
   179 
       
   180     return true;
       
   181 }
       
   182 
       
   183 void HsWidgetHost::unload()
       
   184 {
       
   185     if (mState != Uninitialized) {
       
   186         return;
       
   187     }
       
   188     if (mWidget) {
       
   189         mWidget->setParentItem(0);
       
   190     }
       
   191     delete mWidget;
       
   192     QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
       
   193     mWidget = 0;
       
   194     mState = Unloaded;
       
   195 }
    96 }
   196 
    97 
   197 bool HsWidgetHost::setPage(HsPage *page)
    98 bool HsWidgetHost::setPage(HsPage *page)
   198 {
    99 {
   199     HsDatabase* db = HsDatabase::instance();
   100     HsDatabase *db = HsDatabase::instance();
   200     Q_ASSERT(db);
   101     
   201 
       
   202     HsWidgetData data;
   102     HsWidgetData data;
   203     data.id = mDatabaseId;
   103     data.id = mDatabaseId;
   204     if (db->widget(data)) {
   104     if (db->widget(data)) {
   205         if (!page) {
   105         if (!page) {
   206             data.pageId = -1;
   106             data.pageId = -1;
   215     }
   115     }
   216 
   116 
   217     mPage = page;
   117     mPage = page;
   218     return true;
   118     return true;
   219 }
   119 }
   220 
   120  
   221 HsPage *HsWidgetHost::page() const
   121 HsPage *HsWidgetHost::page() const
   222 {
   122 {
   223     return mPage;
   123     return mPage;
   224 }
   124 }
   225 
   125 
   226 /*!
   126 bool HsWidgetHost::isPannable(QGraphicsSceneMouseEvent *event)
   227     Returns true if this host has a valid widget set.
   127 {
   228     Otherwise, return false.
   128     bool result = false;
   229 */
   129     mIsPannableMethod.invoke(mWidget, Q_RETURN_ARG(bool, result), Q_ARG(QGraphicsSceneMouseEvent *,event));
   230 bool HsWidgetHost::isValid() const
   130     return result;
   231 {
   131 }
   232     return mWidget;
   132 
   233 }
   133 bool HsWidgetHost::loadPresentation()
   234 
   134 {
   235 /*!
   135     return loadPresentation(HsScene::orientation());
   236     Returns database id
   136 }
   237 */
   137 
   238 int HsWidgetHost::databaseId() const
   138 bool HsWidgetHost::loadPresentation(Qt::Orientation orientation)
   239 {
   139 {
   240     return mDatabaseId;
   140     HsDatabase *db = HsDatabase::instance();
   241 }
   141         
   242 
       
   243 /*!
       
   244     Returns true if this the database operation succeeds,
       
   245     false otherwise
       
   246 */
       
   247 bool HsWidgetHost::deleteFromDatabase()
       
   248 {
       
   249     HsDatabase *db = HsDatabase::instance();
       
   250 
       
   251     if (!db->deleteWidget(mDatabaseId)) {
       
   252         return false;
       
   253     }
       
   254 
       
   255     mDatabaseId = -1;
       
   256     return true;
       
   257 }
       
   258 
       
   259 /*!
       
   260     Set widget presentation by using current values.
       
   261     Return true if successfull.
       
   262 */
       
   263 bool HsWidgetHost::setWidgetPresentation()
       
   264 {
       
   265     HsDatabase *db = HsDatabase::instance();
       
   266     Q_ASSERT(db);
       
   267 
       
   268     QString key = HsScene::orientation() == Qt::Vertical ?
       
   269         "portrait" : "landscape";
       
   270 
       
   271     HsWidgetPresentationData data;
   142     HsWidgetPresentationData data;
   272     data.key      = key;
   143     data.orientation = orientation;
   273     data.setPos(pos());
       
   274     data.zValue   = zValue();
       
   275     data.widgetId = databaseId();
       
   276 
       
   277     return db->setWidgetPresentation(data);
       
   278 }
       
   279 
       
   280 /*!
       
   281     Set widget presentation data. Return true if successfull.
       
   282 */
       
   283 bool HsWidgetHost::setWidgetPresentationData(HsWidgetPresentationData &presentationData)
       
   284 {
       
   285     HsDatabase *db = HsDatabase::instance();
       
   286     Q_ASSERT(db);
       
   287 
       
   288     presentationData.widgetId = mDatabaseId;
       
   289     return db->setWidgetPresentation(presentationData);
       
   290 }
       
   291 
       
   292 /*!
       
   293     Get widget presentation data matching given \a key.
       
   294     Data is returned on given empty \a presentationData. Return true if successfull
       
   295 */
       
   296 bool HsWidgetHost::widgetPresentationData(const QString &key,
       
   297                                           HsWidgetPresentationData &presentationData)
       
   298 {
       
   299     HsDatabase *db = HsDatabase::instance();
       
   300     Q_ASSERT(db);
       
   301 
       
   302     presentationData.key = key;
       
   303     presentationData.widgetId = mDatabaseId;
       
   304     return db->widgetPresentation(presentationData);
       
   305 }
       
   306 
       
   307 /*!
       
   308     Return HsWidgetPresentationData for given \a orientation
       
   309 */
       
   310 HsWidgetPresentationData HsWidgetHost::widgetPresentation(Qt::Orientation orientation)
       
   311 {
       
   312     HsDatabase *db = HsDatabase::instance();
       
   313     Q_ASSERT(db);
       
   314 
       
   315     QString key = orientation == Qt::Vertical ?
       
   316         "portrait" : "landscape";
       
   317 
       
   318     HsWidgetPresentationData data;
       
   319     data.key = key;
       
   320     data.widgetId = mDatabaseId;
       
   321     if (db->widgetPresentation(data)) {
       
   322         return data;
       
   323     } else {
       
   324         return HsWidgetPresentationData();
       
   325     }
       
   326 }
       
   327 
       
   328 /*!
       
   329     Load HsWidgetPresentationData for current orientation
       
   330 */
       
   331 bool HsWidgetHost::loadWidgetPresentation()
       
   332 {
       
   333     HsDatabase *db = HsDatabase::instance();
       
   334 
       
   335     QString key = HsScene::orientation() == Qt::Vertical ?
       
   336         "portrait" : "landscape";
       
   337 
       
   338     HsWidgetPresentationData data;
       
   339     data.key = key;
       
   340     data.widgetId = mDatabaseId;
   144     data.widgetId = mDatabaseId;
   341     if (!db->widgetPresentation(data)) {
   145     if (!db->widgetPresentation(data)) {
   342         return false;
   146         return false;
   343     }
   147     }
   344 
       
   345     setPos(data.x, data.y);
   148     setPos(data.x, data.y);
   346     setZValue(data.zValue);
   149     setZValue(data.zValue);
   347 
       
   348     return true;
   150     return true;
   349 }
   151 }
   350 
   152 
   351 /*!
   153 bool HsWidgetHost::savePresentation()
   352     Delete HsWidgetPresentationData for given \a orientation.
   154 {
   353     Return true if successfull.
   155     return savePresentation(HsScene::orientation());
   354 */
   156 }
   355 bool HsWidgetHost::deleteWidgetPresentation(Qt::Orientation orientation)
   157 
   356 {
   158 bool HsWidgetHost::savePresentation(Qt::Orientation orientation)
   357     HsDatabase *db = HsDatabase::instance();
   159 {
   358     Q_ASSERT(db);
   160     HsDatabase *db = HsDatabase::instance();
   359 
   161         
   360     QString key = orientation == Qt::Vertical ?
   162     HsWidgetPresentationData data;
   361         "portrait" : "landscape";
   163     data.orientation = orientation;
   362 
   164     data.setPos(pos());
   363     return db->deleteWidgetPresentation(mDatabaseId, key);
   165     data.zValue = zValue();
   364 }
   166     data.widgetId = mDatabaseId;
   365 /*!
   167     return db->setWidgetPresentation(data);
   366     Check wheter widget uses pan gestures
   168 }
   367     Return true if successfull.
   169 
   368 */
   170 bool HsWidgetHost::savePresentation(HsWidgetPresentationData &presentation)
   369 bool HsWidgetHost::isPannable(QGraphicsSceneMouseEvent *event)
   171 {
   370 {
   172     HsDatabase *db = HsDatabase::instance();
   371     bool ret(false);
   173     
   372     mIsPannable.invoke(mWidget,Q_RETURN_ARG(bool,ret),Q_ARG(QGraphicsSceneMouseEvent *,event));
   174     presentation.widgetId = mDatabaseId;
   373     return ret;
   175     return db->setWidgetPresentation(presentation);
   374 }
   176 }
   375 /*!
   177 
   376     \fn void HsWidgetHost::widgetFinished()
   178 bool HsWidgetHost::getPresentation(HsWidgetPresentationData &presentation)
   377     This signal is emitted after the contained widget
   179 {
   378     reported is completion.
   180     HsDatabase *db = HsDatabase::instance();
   379 */
   181         
   380 
   182     presentation.widgetId = mDatabaseId;
   381 /*!
   183     return db->widgetPresentation(presentation);
   382     \fn void HsWidgetHost::widgetError()
   184 }
   383     This signal is emitted after the contained widget
   185 
   384     reported an error.
   186 bool HsWidgetHost::removePresentation(Qt::Orientation orientation)
   385 */
   187 {
   386 
   188     HsDatabase *db = HsDatabase::instance();
   387 /*!
   189     return db->deleteWidgetPresentation(mDatabaseId, orientation);
   388     \fn void HsWidgetHost::widgetResized()
   190 }
   389     This signal is emitted after the contained widget
   191 
   390     sends a resize event.
   192 void HsWidgetHost::startWidget(bool show)
   391 */
   193 {
   392 /*!
   194     if (!mStateMachine->isRunning()) {
   393     \fn void HsWidgetHost::mousePressEventIgnored()
   195         mStateMachine->start();
   394     This signal is emitted if managed widget ignores mouse press event
   196         // This is needed because QStateMachine::start() starts
   395 
   197         // the state machine asynchronously via the eventloop. 
   396 */
   198         // Here we want the machine to start synchronously.
   397 
   199         QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
   398 /*!
   200     }
   399     Calls the widget's onInitialize() slot if the
   201 
   400     widget defines it.
   202     if (show) {
   401 */
   203         emit event_startAndShow();
   402 void HsWidgetHost::initializeWidget()
   204     } else {
   403 {
   205         emit event_startAndHide();
   404     if (mState != Loaded) {
   206     }
   405         return;
   207 }
   406     }
   208  
   407     HsWidgetComponent *component = HsWidgetComponentRegistry::instance()->component(mUri);
       
   408     Q_ASSERT(component);
       
   409     mRootPathProperty.write(mWidget, component->rootPath());
       
   410     setPreferencesToWidget();
       
   411     setOnline(HsScene::instance()->isOnline());
       
   412     mOnInitializeMethod.invoke(mWidget);
       
   413 
       
   414     if (mState != Finished &&
       
   415         mState != Faulted) {
       
   416         mState = Initialized;
       
   417     }
       
   418 }
       
   419 
       
   420 /*!
       
   421     Calls the widget's onShow() slot if the
       
   422     widget defines it.
       
   423 */
       
   424 void HsWidgetHost::showWidget()
   209 void HsWidgetHost::showWidget()
   425 {
   210 {
   426     if (mState != Initialized &&
   211     emit event_show();
   427         mState != Hidden ) {
   212 }
   428         return;
   213     
   429     }
       
   430 
       
   431     mOnShowMethod.invoke(mWidget);
       
   432 
       
   433     mState = Visible;
       
   434 }
       
   435 
       
   436 /*!
       
   437     Calls the widget's onHide() slot if the
       
   438     widget defines it.
       
   439 */
       
   440 void HsWidgetHost::hideWidget()
   214 void HsWidgetHost::hideWidget()
   441 {
   215 {
   442     if (mState != Initialized &&
   216     emit event_hide();
   443         mState != Visible) {
   217 }
   444         return;
   218 
   445     }
       
   446 
       
   447     mOnHideMethod.invoke(mWidget);
       
   448 
       
   449     mState = Hidden;
       
   450 }
       
   451 
       
   452 /*!
       
   453     Calls the widget's onUninitialize() slot if the
       
   454     widget defines it.
       
   455 */
       
   456 void HsWidgetHost::uninitializeWidget()
       
   457 {
       
   458     if (mState != Visible &&
       
   459         mState != Hidden) {
       
   460         return;
       
   461     }
       
   462 
       
   463     mOnUninitializeMethod.invoke(mWidget);
       
   464 
       
   465     mState = Uninitialized;
       
   466 }
       
   467 
       
   468 /*!
       
   469     Calls the widget's widgetOnlineState property if the
       
   470     widget defines it.
       
   471 */
       
   472 void HsWidgetHost::setOnline(bool online)
   219 void HsWidgetHost::setOnline(bool online)
   473 {
   220 {
   474     mIsOnlineProperty.write(mWidget, online);
   221     mIsOnlineProperty.write(mWidget, online);
   475 }
   222 }
   476 
   223 
   477 /*!
   224 void HsWidgetHost::remove()
   478     Starts the widget drag animation.
   225 {
   479 */
   226     if (mStateMachine->isRunning()) {
       
   227         emit event_remove();
       
   228     } else {
       
   229         action_remove();
       
   230         deleteLater();
       
   231     }
       
   232 }
       
   233  
       
   234 void HsWidgetHost::close()
       
   235 {
       
   236     if (mStateMachine->isRunning()) {
       
   237         emit event_close();
       
   238     } else {
       
   239         deleteLater();
       
   240     }
       
   241 }
       
   242 
   480 void HsWidgetHost::startDragEffect()
   243 void HsWidgetHost::startDragEffect()
   481 {
   244 {
   482     /* TODO: Uncomment after the Qt bug has been fixed.
   245     /* TODO: Uncomment after the Qt bug has been fixed.
   483     QGraphicsDropShadowEffect *effect =
   246     QGraphicsDropShadowEffect *effect =
   484         static_cast<QGraphicsDropShadowEffect *>(graphicsEffect());
   247         static_cast<QGraphicsDropShadowEffect *>(graphicsEffect());
   488     setTransformOriginPoint(rect().center());
   251     setTransformOriginPoint(rect().center());
   489 
   252 
   490     QParallelAnimationGroup *animationGroup = new QParallelAnimationGroup();
   253     QParallelAnimationGroup *animationGroup = new QParallelAnimationGroup();
   491 
   254 
   492     QPropertyAnimation *animation = new QPropertyAnimation(this, "scale");
   255     QPropertyAnimation *animation = new QPropertyAnimation(this, "scale");
   493     animation->setDuration(200);
   256     animation->setDuration(HsConfiguration::widgetDragEffectDuration());
   494     animation->setEndValue(1.1);
   257     animation->setEndValue(1.1);
   495     animationGroup->addAnimation(animation);
   258     animationGroup->addAnimation(animation);
   496 
   259 
   497     /* TODO: Uncomment after the Qt bug has been fixed.
   260     /* TODO: Uncomment after the Qt bug has been fixed.
   498     animation = new QPropertyAnimation(effect, "offset");
   261     animation = new QPropertyAnimation(effect, "offset");
   502     */
   265     */
   503 
   266 
   504     animationGroup->start(QAbstractAnimation::DeleteWhenStopped);
   267     animationGroup->start(QAbstractAnimation::DeleteWhenStopped);
   505 }
   268 }
   506 
   269 
   507 /*!
       
   508     Starts the widget drop animation.
       
   509 */
       
   510 void HsWidgetHost::startDropEffect()
   270 void HsWidgetHost::startDropEffect()
   511 {
   271 {
   512     /* TODO: Uncomment after the Qt bug has been fixed.
   272     /* TODO: Uncomment after the Qt bug has been fixed.
   513     QGraphicsDropShadowEffect *effect =
   273     QGraphicsDropShadowEffect *effect =
   514         static_cast<QGraphicsDropShadowEffect *>(graphicsEffect());
   274         static_cast<QGraphicsDropShadowEffect *>(graphicsEffect());
   516     HbInstantFeedback::play(HbFeedback::ItemDrop);
   276     HbInstantFeedback::play(HbFeedback::ItemDrop);
   517 
   277 
   518     QParallelAnimationGroup *animationGroup = new QParallelAnimationGroup;
   278     QParallelAnimationGroup *animationGroup = new QParallelAnimationGroup;
   519 
   279 
   520     QPropertyAnimation *animation = new QPropertyAnimation(this, "scale");
   280     QPropertyAnimation *animation = new QPropertyAnimation(this, "scale");
   521     animation->setDuration(200);
   281     animation->setDuration(HsConfiguration::widgetDropEffectDuration());
   522     animation->setEndValue(1);
   282     animation->setEndValue(1);
   523     animationGroup->addAnimation(animation);
   283     animationGroup->addAnimation(animation);
   524 
   284 
   525     /* TODO: Uncomment after the Qt bug has been fixed.
   285     /* TODO: Uncomment after the Qt bug has been fixed.
   526     animation = new QPropertyAnimation(effect, "offset");
   286     animation = new QPropertyAnimation(effect, "offset");
   529     animationGroup->addAnimation(animation);
   289     animationGroup->addAnimation(animation);
   530     */
   290     */
   531 
   291 
   532     animationGroup->start(QAbstractAnimation::DeleteWhenStopped);
   292     animationGroup->start(QAbstractAnimation::DeleteWhenStopped);
   533 }
   293 }
   534 /*!
   294 
   535     Overwritten to stop event propogation
   295 bool HsWidgetHost::eventFilter(QObject *watched, QEvent *event)
   536 */
       
   537 void HsWidgetHost::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) 
       
   538 { 
       
   539     Q_UNUSED(event) 
       
   540 }
       
   541 /*!
       
   542     Overwritten to stop event propogation
       
   543 */
       
   544 void HsWidgetHost::mouseMoveEvent(QGraphicsSceneMouseEvent *event) 
       
   545 { 
       
   546     Q_UNUSED(event)  
       
   547 }
       
   548 /*!
       
   549     Overwritten to stop event propogation
       
   550 */
       
   551 void HsWidgetHost::mousePressEvent(QGraphicsSceneMouseEvent *event) 
       
   552 { 
       
   553     Q_UNUSED(event)  
       
   554     
       
   555 }
       
   556 /*!
       
   557     Overwritten to stop event propogation
       
   558 */
       
   559 void HsWidgetHost::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { 
       
   560     Q_UNUSED(event)
       
   561 }    
       
   562 /*!
       
   563     Filters resize events from widgets and resizes inside max/min size boundaries if needed.
       
   564 */
       
   565 bool HsWidgetHost::eventFilter(QObject *obj, QEvent *event)
       
   566 {
   296 {
   567     if (event->type() == QEvent::GraphicsSceneResize ) {
   297     if (event->type() == QEvent::GraphicsSceneResize ) {
   568         QGraphicsSceneResizeEvent *resizeEvent = static_cast<QGraphicsSceneResizeEvent*>(event);
   298         QGraphicsSceneResizeEvent *resizeEvent = 
       
   299             static_cast<QGraphicsSceneResizeEvent *>(event);
   569         setNewSize(resizeEvent->newSize());
   300         setNewSize(resizeEvent->newSize());
   570         emit widgetResized(this);
   301         emit resized();
   571         return true;
   302     }
   572     } else {
   303     return HbWidget::eventFilter(watched, event);
   573          // standard event processing
   304 }
   574          return HbWidget::eventFilter(obj, event);
   305 
   575     }
   306 void HsWidgetHost::setupEffects()
   576 }
   307 {
   577 
   308     /* TODO: Uncomment after the Qt bug has been fixed.
   578 /*!
   309     QGraphicsDropShadowEffect *effect =
   579     Checks if a property with the given \a name
   310         new QGraphicsDropShadowEffect(this);
   580     in the contained widget. If the property exists the \a
   311     effect->setColor(QColor(0, 0, 0, 150));
   581     metaProperty is made to reference to it. Returns true if
   312     effect->setBlurRadius(5);
   582     the property was found. Otherwise, returns false.
   313     effect->setOffset(3);
   583 */
   314     setGraphicsEffect(effect);
       
   315     */
       
   316 }
       
   317 
       
   318 void HsWidgetHost::setupStates()
       
   319 {
       
   320     // State machine
       
   321 
       
   322     mStateMachine = new QStateMachine(this);
       
   323     mStateMachine->setAnimated(false);
       
   324     
       
   325     // States
       
   326 
       
   327     QState *state_component = new QState;
       
   328     QState *state_unloaded = new QState(state_component);
       
   329     QState *state_running = new QState(state_component);
       
   330     QState *state_show = new QState(state_running);
       
   331     QState *state_hide = new QState(state_running);
       
   332     QState *state_finished = new QState;
       
   333     QState *state_faulted = new QState;
       
   334     QState *state_remove = new QState;
       
   335     QFinalState *state_final = new QFinalState;
       
   336 
       
   337     mStateMachine->addState(state_component);
       
   338     mStateMachine->addState(state_finished);
       
   339     mStateMachine->addState(state_faulted);
       
   340     mStateMachine->addState(state_remove);
       
   341     mStateMachine->addState(state_final);
       
   342 
       
   343     mStateMachine->setInitialState(state_component);
       
   344     state_component->setInitialState(state_unloaded);
       
   345     state_running->setInitialState(state_hide);
       
   346 
       
   347     // Transitions
       
   348 
       
   349     state_component->addTransition(
       
   350         this, SIGNAL(event_close()), state_final);
       
   351     state_component->addTransition(
       
   352         this, SIGNAL(event_remove()), state_remove);
       
   353     state_component->addTransition(
       
   354         this, SIGNAL(event_finished()), state_finished);
       
   355     state_component->addTransition(
       
   356         this, SIGNAL(event_faulted()), state_faulted);
       
   357 
       
   358     state_unloaded->addTransition(
       
   359         this, SIGNAL(event_startAndShow()), state_show);
       
   360     state_unloaded->addTransition(
       
   361         this, SIGNAL(event_startAndHide()), state_hide);
       
   362 
       
   363     state_running->addTransition(
       
   364         this, SIGNAL(event_unload()), state_unloaded);
       
   365     
       
   366     state_show->addTransition(
       
   367         this, SIGNAL(event_hide()), state_hide);
       
   368 
       
   369     state_hide->addTransition(
       
   370         this, SIGNAL(event_show()), state_show);
       
   371 
       
   372     state_finished->addTransition(
       
   373         this, SIGNAL(event_remove()), state_remove);
       
   374     state_finished->addTransition(
       
   375         this, SIGNAL(event_close()), state_final);
       
   376 
       
   377     state_faulted->addTransition(
       
   378         this, SIGNAL(event_remove()), state_remove);
       
   379     state_faulted->addTransition(
       
   380         this, SIGNAL(event_close()), state_final);
       
   381 
       
   382     state_remove->addTransition(state_final);
       
   383 
       
   384     // Actions
       
   385 
       
   386     ENTRY_ACTION(state_component, action_connectComponent)
       
   387     EXIT_ACTION(state_component, action_disconnectComponent)
       
   388 
       
   389     ENTRY_ACTION(state_running, action_load)
       
   390     ENTRY_ACTION(state_running, action_initialize)
       
   391     EXIT_ACTION(state_running, action_uninitialize)
       
   392     EXIT_ACTION(state_running, action_unload)
       
   393 
       
   394     ENTRY_ACTION(state_show, action_show)
       
   395 
       
   396     ENTRY_ACTION(state_hide, action_hide)
       
   397 
       
   398     ENTRY_ACTION(state_finished, action_finished)
       
   399 
       
   400     ENTRY_ACTION(state_faulted, action_faulted)
       
   401 
       
   402     ENTRY_ACTION(state_remove, action_remove)
       
   403 
       
   404     // Delete on finish.
       
   405 
       
   406     connect(mStateMachine, SIGNAL(finished()), SLOT(deleteLater()), 
       
   407             Qt::QueuedConnection);
       
   408 }
       
   409 
   584 bool HsWidgetHost::setProperty(const char *name, QMetaProperty &property)
   410 bool HsWidgetHost::setProperty(const char *name, QMetaProperty &property)
   585 {
   411 {
   586     const QMetaObject *object = mWidget->metaObject();
   412     const QMetaObject *object = mWidget->metaObject();
   587     int index = object->indexOfProperty(name);
   413     int index = object->indexOfProperty(name);
   588     property = object->property(index);
   414     property = object->property(index);
   589     return index >= 0;
   415     return index >= 0;
   590 }
   416 }
   591 
   417 
   592 /*!
       
   593     Checks if a slot with the given \a signature exists
       
   594     in the contained widget. If the slot exists the \a
       
   595     method is made to reference to it. Returns true if
       
   596     the slot was found. Otherwise, returns false.
       
   597 */
       
   598 bool HsWidgetHost::setMethod(const char *signature, QMetaMethod &method)
   418 bool HsWidgetHost::setMethod(const char *signature, QMetaMethod &method)
   599 {
   419 {
   600     const QMetaObject *object = mWidget->metaObject();
   420     const QMetaObject *object = mWidget->metaObject();
   601     int index = object->indexOfMethod(
   421     int index = object->indexOfMethod(
   602         QMetaObject::normalizedSignature(signature));
   422         QMetaObject::normalizedSignature(signature));
   603     method = object->method(index);
   423     method = object->method(index);
   604     return index >= 0;
   424     return index >= 0;
   605 }
   425 }
   606 
   426 
   607 /*!
       
   608     Returns true if a signal with the given \a signature
       
   609     exists in the contained widget. Otherwise, returns
       
   610     false.
       
   611 */
       
   612 bool HsWidgetHost::hasSignal(const char *signature)
   427 bool HsWidgetHost::hasSignal(const char *signature)
   613 {
   428 {
   614     const QMetaObject *object = mWidget->metaObject();
   429     const QMetaObject *object = mWidget->metaObject();
   615     int index = object->indexOfSignal(
   430     int index = object->indexOfSignal(
   616         QMetaObject::normalizedSignature(signature));
   431         QMetaObject::normalizedSignature(signature));
   617     return index >= 0;
   432     return index >= 0;
   618 }
   433 }
   619 /*!
   434 
   620     Returns true if fetching widget preferences from db and setting those
   435 void HsWidgetHost::setNewSize(const QSizeF &size)
   621     to widget is successfull
   436 {
   622 */
   437     resize(size);
       
   438     setPreferredSize(size);
       
   439 }
       
   440 
   623 bool HsWidgetHost::setPreferencesToWidget()
   441 bool HsWidgetHost::setPreferencesToWidget()
   624 {
   442 {
   625     HsDatabase *db = HsDatabase::instance();
   443     HsDatabase *db = HsDatabase::instance();
   626     Q_ASSERT(db);
   444     
   627 
       
   628     QVariantHash preferences;
   445     QVariantHash preferences;
   629     if (!db->widgetPreferences(mDatabaseId, preferences)) {
   446     if (!db->widgetPreferences(mDatabaseId, preferences)) {
   630         return false;
   447         return false;
   631     }
   448     }
   632 
   449 
   633     QStringList names = preferences.keys();
   450     QStringList names = preferences.keys();
   634     foreach(QString name, names) {
   451     foreach (QString name, names) {
   635         mWidget->setProperty(name.toLatin1(),
   452         mWidget->setProperty(name.toLatin1(),
   636                              preferences.value(name));
   453                              preferences.value(name));
   637     }
   454     }
   638 
   455 
   639     return true;
   456     return true;
   640 }
   457 }
   641 
   458 
   642 /*!
   459 void HsWidgetHost::action_connectComponent()
   643     Resizes and sets preferred size for widget layouts
   460 {
   644 */
   461     HsDatabase *db = HsDatabase::instance();
   645 void HsWidgetHost::setNewSize(const QSizeF &newSize)
   462     
   646 {
   463     HsWidgetData data;
   647     resize(newSize);
   464     data.id = mDatabaseId;
   648     setPreferredSize(newSize);
   465     if (!db->widget(data)) {
   649 }
   466         emit event_faulted();
   650 
   467         return;
   651 /*!
   468     }
   652     This slot is connected to the contained widget's
   469     
   653     setPreferences() signal, if it was defined for
   470     mComponent = HsWidgetComponentRegistry::instance()->component(data.uri);
   654     the widget. The widget emits the signal for persisting
   471     
   655     its preferences named with \a names. The given
   472     connect(mComponent, SIGNAL(aboutToUninstall()), SIGNAL(event_unload()));
   656     preferences are read, validated, and written to
   473     connect(mComponent, SIGNAL(uninstalled()), SIGNAL(event_finished()));
   657     the database.
   474     connect(mComponent, SIGNAL(unavailable()), SIGNAL(event_unload()));
   658 */
   475     connect(mComponent, SIGNAL(unavailable()), SIGNAL(unavailable()));
       
   476     connect(mComponent, SIGNAL(available()), SIGNAL(available()));
       
   477     connect(mComponent, SIGNAL(updated()), SIGNAL(available()));
       
   478 }
       
   479 
       
   480 void HsWidgetHost::action_disconnectComponent()
       
   481 {
       
   482     mComponent->disconnect(this);
       
   483 }
       
   484 
       
   485 void HsWidgetHost::action_load()
       
   486 {
       
   487     QServiceManager manager;
       
   488     QServiceFilter filter("com.nokia.symbian.IHomeScreenWidget");
       
   489     filter.setServiceName(mComponent->uri());
       
   490     QList<QServiceInterfaceDescriptor> interfaces = manager.findInterfaces(filter);
       
   491     if (interfaces.isEmpty()) {
       
   492         emit event_faulted();
       
   493         return;
       
   494     }
       
   495 
       
   496     QObject *widgetObject = manager.loadInterface(interfaces.first());
       
   497     mWidget = qobject_cast<QGraphicsWidget *>(widgetObject);
       
   498 
       
   499     if (!mWidget ||
       
   500         !setMethod("onShow()", mOnShowMethod) ||
       
   501         !setMethod("onHide()", mOnHideMethod)) {
       
   502         mWidget = 0;
       
   503         delete widgetObject;
       
   504         emit event_faulted();
       
   505         return;
       
   506     }
       
   507 
       
   508     setMethod("onInitialize()", mOnInitializeMethod);
       
   509     setMethod("onUninitialize()", mOnUninitializeMethod);
       
   510     setMethod("isPannable(QGraphicsSceneMouseEvent*)", mIsPannableMethod);
       
   511 
       
   512     setProperty("isOnline", mIsOnlineProperty);
       
   513 	setProperty("rootPath", mRootPathProperty);
       
   514     
       
   515     if (hasSignal("setPreferences(const QStringList&)")) {
       
   516         connect(mWidget, SIGNAL(setPreferences(QStringList)),
       
   517                 SLOT(onSetPreferences(QStringList)));
       
   518     }
       
   519     if (hasSignal("finished()")) {
       
   520         connect(mWidget, SIGNAL(finished()),
       
   521                 SLOT(onFinished()));
       
   522     }
       
   523     if (hasSignal("error()")) {
       
   524         connect(mWidget, SIGNAL(error()),
       
   525                 SLOT(onError()));
       
   526     }
       
   527 
       
   528     mWidget->installEventFilter(this);
       
   529 
       
   530     HsScene *scene = HsScene::instance();
       
   531     setMaximumSize(scene->maximumWidgetSizeInPixels());
       
   532     setMinimumSize(scene->minimumWidgetSizeInPixels());
       
   533 
       
   534     loadPresentation();
       
   535 
       
   536     mWidget->setParentItem(this);
       
   537 
       
   538     setNewSize(mWidget->size());
       
   539 }
       
   540 
       
   541 void HsWidgetHost::action_unload()
       
   542 {
       
   543     delete mWidget;
       
   544     mWidget = 0;
       
   545 
       
   546     mOnInitializeMethod = QMetaMethod();
       
   547     mOnShowMethod = QMetaMethod();
       
   548     mOnHideMethod = QMetaMethod();
       
   549     mOnUninitializeMethod = QMetaMethod();
       
   550     mIsPannableMethod = QMetaMethod();
       
   551     mIsOnlineProperty = QMetaProperty();
       
   552 	mRootPathProperty = QMetaProperty();    
       
   553 }
       
   554 
       
   555 void HsWidgetHost::action_initialize()
       
   556 {    
       
   557     mRootPathProperty.write(mWidget, mComponent->rootPath());
       
   558     setPreferencesToWidget();
       
   559     setOnline(HsScene::instance()->isOnline());
       
   560     mOnInitializeMethod.invoke(mWidget);
       
   561 }
       
   562 
       
   563 void HsWidgetHost::action_uninitialize()
       
   564 {
       
   565     mOnUninitializeMethod.invoke(mWidget);
       
   566 }
       
   567 
       
   568 void HsWidgetHost::action_show()
       
   569 {
       
   570     if (!mIsFinishing) {
       
   571         mOnShowMethod.invoke(mWidget);
       
   572     }
       
   573 }
       
   574 
       
   575 void HsWidgetHost::action_hide()
       
   576 {
       
   577     if (!mIsFinishing) {
       
   578         mOnHideMethod.invoke(mWidget);
       
   579     }
       
   580 }
       
   581 
       
   582 void HsWidgetHost::action_finished()
       
   583 {
       
   584     emit finished();
       
   585 }
       
   586 
       
   587 void HsWidgetHost::action_faulted()
       
   588 {
       
   589     emit faulted();
       
   590 }
       
   591 
       
   592 void HsWidgetHost::action_remove()
       
   593 {
       
   594     HsDatabase *db = HsDatabase::instance();
       
   595     
       
   596     db->deleteWidget(mDatabaseId);
       
   597     mDatabaseId = -1;
       
   598 }
       
   599 
       
   600 void HsWidgetHost::onFinished()
       
   601 {
       
   602     mIsFinishing = true;
       
   603     emit event_finished();
       
   604 }
       
   605  
       
   606 void HsWidgetHost::onError()
       
   607 {
       
   608     mIsFinishing = true;
       
   609     emit event_faulted();
       
   610 }
       
   611 
   659 void HsWidgetHost::onSetPreferences(const QStringList &names)
   612 void HsWidgetHost::onSetPreferences(const QStringList &names)
   660 {
   613 {
   661     if (names.isEmpty()) {
   614     if (names.isEmpty()) {
   662         return;
   615         return;
   663     }
   616     }
   667     foreach (QString name, names) {
   620     foreach (QString name, names) {
   668         QVariant value = mWidget->property(name.toLatin1());
   621         QVariant value = mWidget->property(name.toLatin1());
   669         preferences.insert(name, value);
   622         preferences.insert(name, value);
   670     }
   623     }
   671 
   624 
   672     HsDatabase *db = HsDatabase::instance();
   625     HsDatabase *db = HsDatabase::instance();    
   673     Q_ASSERT(db);
       
   674 
       
   675     if (!db->setWidgetPreferences(mDatabaseId, preferences)) {
   626     if (!db->setWidgetPreferences(mDatabaseId, preferences)) {
   676         onError();
   627         onError();
   677     }
   628     }
   678 }
   629 }
   679 
       
   680 /*!
       
   681     This slot reacts to the widgets finished() signal, if
       
   682     it was defined for the widget. The widget emits the signal
       
   683     when it has finished its execution and is ready for
       
   684     removal from the homescreen.
       
   685 */
       
   686 void HsWidgetHost::onFinished()
       
   687 {
       
   688     mState = Finished;
       
   689     emit widgetFinished(this);
       
   690 }
       
   691 
       
   692 /*!
       
   693     This slot reacts to the widgets error() signal, if it was
       
   694     defined for the widget. The widget emits the signal in
       
   695     failure cases.
       
   696 */
       
   697 void HsWidgetHost::onError()
       
   698 {
       
   699     mState = Faulted;
       
   700     emit widgetError(this);
       
   701 }
       
   702 /*!
       
   703     This slot is called when component is about to uninstall or
       
   704     update. Widget need to release all handles to resources installing
       
   705     to succeed.
       
   706 */
       
   707 void HsWidgetHost::onAboutToUninstall()
       
   708 {
       
   709     uninitializeWidget();
       
   710     unload();
       
   711 }
       
   712 
       
   713 void HsWidgetHost::onUpdated()
       
   714 {
       
   715     if(mState != Unloaded) {
       
   716         return;
       
   717     }
       
   718     load();
       
   719     initializeWidget();
       
   720     if (HsScene::instance()->activePage() == mPage) {
       
   721        showWidget();
       
   722     } else {
       
   723         hideWidget();
       
   724     }
       
   725 
       
   726 }
       
   727 void HsWidgetHost::onUnavailable()
       
   728 {
       
   729     if (mState != Visible && mState != Hidden) {
       
   730         return;
       
   731     }
       
   732     uninitializeWidget();
       
   733     unload();
       
   734 }
       
   735 
       
   736 void HsWidgetHost::onAvailable()
       
   737 {
       
   738     if (mState != Unloaded) {
       
   739         return;
       
   740     }
       
   741     load();
       
   742     initializeWidget();
       
   743     if (HsScene::instance()->activePage() == mPage) {
       
   744         showWidget();
       
   745     } else {
       
   746         hideWidget();
       
   747     }
       
   748 }
       
   749 
       
   750 
       
   751 
       
   752 
       
   753