diff -r c743ef5928ba -r f9ce957a272c homescreenapp/hsdomainmodel/src/hswidgethost.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/homescreenapp/hsdomainmodel/src/hswidgethost.cpp Fri Mar 19 09:27:44 2010 +0200 @@ -0,0 +1,592 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "hswidgethost.h" +#include "hsdatabase.h" +#include "hswidgetdata.h" +#include "hspage.h" +#include "hsapp_defs.h" +#include "hsscene.h" +#include "cadefs.h" +#include "canotifier.h" +#include "canotifierfilter.h" +#include "caservice.h" +#include "caquery.h" +#include "caentry.h" + +QTM_USE_NAMESPACE + +/*! + \class HsWidgetHost + \ingroup group_hsutils + \brief Homescreen widget runner. + Is responsible of running a homescreen widget. Each + homescreen widget has its own host. +*/ + +HsWidgetHost* HsWidgetHost::createInstance(const HsWidgetData &widgetData, + const QVariantMap &preferences) +{ + HsWidgetHost *host = NULL; + + HsDatabase* db = HsDatabase::instance(); + Q_ASSERT(db); + + int databaseId = -1; + if (db->insertWidget(widgetData, databaseId)) { + db->setWidgetPreferences(databaseId, preferences); + host = new HsWidgetHost(databaseId); + } + + return host; +} +/*! + Construct a widget host for the given \a databaseId. + \a parent becomes the parent item for the host. +*/ +HsWidgetHost::HsWidgetHost(int databaseId, QGraphicsItem *parent) + : HbWidget(parent), + mWidget(0), + mPage(0), + mDatabaseId(databaseId) +{ + CaQuery query; + query.setEntryTypeNames(QStringList(widgetTypeName())); + CaNotifierFilter filter(query); + CaNotifier *notifier = CaService::instance()->createNotifier(filter); + notifier->setParent(this); + connect(notifier, + SIGNAL(entryChanged(const CaEntry&, ChangeType)), + SLOT(onEntryChanged(const CaEntry&, ChangeType)), Qt::QueuedConnection); + + /* TODO: Uncomment after the Qt bug has been fixed. + QGraphicsDropShadowEffect *effect = + new QGraphicsDropShadowEffect(this); + effect->setColor(QColor(0, 0, 0, 150)); + effect->setBlurRadius(5); + effect->setOffset(3); + setGraphicsEffect(effect); + */ +} + +/*! + Destructor. +*/ +HsWidgetHost::~HsWidgetHost() +{ +} +/*! + Load hosted widget from plugin and validate it. + Returns true if widget construction is successfull. +*/ +bool HsWidgetHost::load() +{ + if (mWidget) { + return false; + } + + HsDatabase *db = HsDatabase::instance(); + Q_ASSERT(db); + + // Find the widget data. + HsWidgetData widgetData; + if (!db->widget(mDatabaseId, widgetData, false)) { + return false; + } + + mUri = widgetData.uri(); + + // Create the hosted widget. + QServiceManager manager; + QServiceFilter filter("com.nokia.IHomeScreenWidget"); + filter.setServiceName(widgetData.uri()); + QList interfaces = manager.findInterfaces(filter); + if(interfaces.isEmpty()) { + return false; + } + + QObject *widgetObject = manager.loadInterface(interfaces.first()); + mWidget = qobject_cast(widgetObject); + + if (!mWidget || + !setMethod("onShow()", mOnShowMethod) || + !setMethod("onHide()", mOnHideMethod)) { + mWidget = 0; + delete widgetObject; + return false; + } + + setProperty("isOnline", mIsOnlineProperty); + setMethod("onInitialize()", mOnInitializeMethod); + setMethod("onUninitialize()", mOnUninitializeMethod); + + if (hasSignal("setPreferences(const QStringList&)")) { + connect(mWidget, SIGNAL(setPreferences(QStringList)), + SLOT(onSetPreferences(QStringList))); + } + if (hasSignal("finished()")) { + connect(mWidget, SIGNAL(finished()), + SLOT(onFinished())); + } + if (hasSignal("error()")) { + connect(mWidget, SIGNAL(error()), + SLOT(onError())); + } + + loadWidgetPresentation(); + + QGraphicsLinearLayout *layout = new QGraphicsLinearLayout; + layout->setContentsMargins(0, 0, 0, 0); + layout->addItem(mWidget); + setLayout(layout); + + return true; +} + +bool HsWidgetHost::setPage(HsPage *page) +{ + HsDatabase* db = HsDatabase::instance(); + Q_ASSERT(db); + + HsWidgetData data; + if (db->widget(mDatabaseId, data, false)) { + if (!page) { + data.setPageId(-1); + } else { + data.setPageId(page->databaseId()); + } + if (!db->updateWidget(data, false)) { + return false; + } + } else { + return false; + } + + mPage = page; + return true; +} + +HsPage *HsWidgetHost::page() const +{ + return mPage; +} + +/*! + Returns true if this host has a valid widget set. + Otherwise, return false. +*/ +bool HsWidgetHost::isValid() const +{ + return mWidget; +} + +/*! + Returns database id +*/ +int HsWidgetHost::databaseId() const +{ + return mDatabaseId; +} + +/*! + Returns true if this the database operation succeeds, + false otherwise +*/ +bool HsWidgetHost::deleteFromDatabase() +{ + if (HsDatabase::instance()->deleteWidget(mDatabaseId)) { + mDatabaseId = -1; + return true; + } + return false; +} + +/*! + Set widget presentation by using current values. + Return true if successfull. +*/ +bool HsWidgetHost::setWidgetPresentation() +{ + HsDatabase *db = HsDatabase::instance(); + Q_ASSERT(db); + + QString key = hbInstance->orientation() == Qt::Vertical ? + "portrait" : "landscape"; + + HsWidgetPresentationData data; + data.setWidgetId(databaseId()); + data.setKey(key); + data.setPosition(pos()); + data.setSize(size()); + data.setZValue(zValue()); + + HsWidgetPresentationData temp; + if (!db->widgetPresentation(databaseId(), key, temp)) { + if (!db->insertWidgetPresentation(data)) { + return false; + } + } else { + data.setId(temp.id()); + if (!db->updateWidgetPresentation(data)) { + return false; + } + } + + return true; +} + +/*! + Set widget presentation data. Return true if successfull + +*/ +bool HsWidgetHost::setWidgetPresentationData(HsWidgetPresentationData &presentationData) +{ + presentationData.setWidgetId(mDatabaseId); + return HsDatabase::instance()->insertWidgetPresentation(presentationData); +} +/*! + Get widget presentation data matching given \a key. + Data is returned on given empty \a presentationData. Return true if successfull +*/ +bool HsWidgetHost::widgetPresentationData( + const QString &key, + HsWidgetPresentationData &presentationData) +{ + return HsDatabase::instance()->widgetPresentation(mDatabaseId,key,presentationData); +} + +/*! + Return HsWidgetPresentationData for given \a orientation +*/ +HsWidgetPresentationData HsWidgetHost::widgetPresentation(Qt::Orientation orientation) +{ + HsDatabase *db = HsDatabase::instance(); + Q_ASSERT(db); + + QString key = orientation == Qt::Vertical ? + "portrait" : "landscape"; + + HsWidgetPresentationData data; + if (db->widgetPresentation(databaseId(), key, data)) { + return data; + } else { + return HsWidgetPresentationData(); + } + +} + +/*! + Load HsWidgetPresentationData for current orientation +*/ +bool HsWidgetHost::loadWidgetPresentation() +{ + HsDatabase *db = HsDatabase::instance(); + Q_ASSERT(db); + + QString key = hbInstance->orientation() == Qt::Vertical ? + "portrait" : "landscape"; + + HsWidgetPresentationData data; + if (!db->widgetPresentation(databaseId(), key, data)) { + return false; + } + + setGeometry(QRectF(data.position(), data.size())); + setZValue(data.zValue()); + + return true; +} + +/*! + Delete HsWidgetPresentationData for given \a orientation. + Return true if successfull. +*/ +bool HsWidgetHost::deleteWidgetPresentation(Qt::Orientation orientation) +{ + HsDatabase *db = HsDatabase::instance(); + Q_ASSERT(db); + + QString key = orientation == Qt::Vertical ? + "portrait" : "landscape"; + + HsWidgetPresentationData data; + if (!db->widgetPresentation(databaseId(), key, data)) { + return true; + } else { + if (!db->deleteWidgetPresentation(data.id())) { + return false; + } + } + + return true; +} + +/*! + \fn void HsWidgetHost::finished() + This signal is emitten after the contained widget + hs reported is completion. +*/ + +/*! + \fn void HsWidgetHost::error() + This signal is emitten after the contained widget + hs reported an error. +*/ + +/*! + Calls the widget's onInitialize() slot if the + widget defines it. +*/ +void HsWidgetHost::initializeWidget() +{ + setPreferencesToWidget(); + setOnline(HsScene::instance()->isOnline()); + mOnInitializeMethod.invoke(mWidget); +} + +/*! + Calls the widget's onShow() slot if the + widget defines it. +*/ +void HsWidgetHost::showWidget() +{ + mOnShowMethod.invoke(mWidget); +} + +/*! + Calls the widget's onHide() slot if the + widget defines it. +*/ +void HsWidgetHost::hideWidget() +{ + mOnHideMethod.invoke(mWidget); +} + +/*! + Calls the widget's onUninitialize() slot if the + widget defines it. +*/ +void HsWidgetHost::uninitializeWidget() +{ + mOnUninitializeMethod.invoke(mWidget); +} + +/*! + Calls the widget's widgetOnlineState property if the + widget defines it. +*/ +void HsWidgetHost::setOnline(bool online) +{ + mIsOnlineProperty.write(mWidget, online); +} + +/*! + Starts the widget drag animation. +*/ +void HsWidgetHost::startDragAnimation() +{ + /* TODO: Uncomment after the Qt bug has been fixed. + QGraphicsDropShadowEffect *effect = + static_cast(graphicsEffect()); + */ + + setTransformOriginPoint(rect().center()); + + QParallelAnimationGroup *animationGroup = new QParallelAnimationGroup(); + + QPropertyAnimation *animation = new QPropertyAnimation(this, "scale"); + animation->setDuration(200); + animation->setEndValue(1.1); + animationGroup->addAnimation(animation); + + /* TODO: Uncomment after the Qt bug has been fixed. + animation = new QPropertyAnimation(effect, "offset"); + animation->setDuration(200); + animation->setEndValue(QPointF(8 ,8)); + animationGroup->addAnimation(animation); + */ + + animationGroup->start(QAbstractAnimation::DeleteWhenStopped); +} + +/*! + Starts the widget drop animation. +*/ +void HsWidgetHost::startDropAnimation() +{ + /* TODO: Uncomment after the Qt bug has been fixed. + QGraphicsDropShadowEffect *effect = + static_cast(graphicsEffect()); + */ + + QParallelAnimationGroup *animationGroup = new QParallelAnimationGroup; + + QPropertyAnimation *animation = new QPropertyAnimation(this, "scale"); + animation->setDuration(200); + animation->setEndValue(1); + animationGroup->addAnimation(animation); + + /* TODO: Uncomment after the Qt bug has been fixed. + animation = new QPropertyAnimation(effect, "offset"); + animation->setDuration(200); + animation->setEndValue(QPointF(3, 3)); + animationGroup->addAnimation(animation); + */ + + animationGroup->start(QAbstractAnimation::DeleteWhenStopped); +} + +/*! + Checks if a property with the given \a name + in the contained widget. If the property exists the \a + metaProperty is made to reference to it. Returns true if + the property was found. Otherwise, returns false. +*/ +bool HsWidgetHost::setProperty(const char *name, QMetaProperty &property) +{ + const QMetaObject *object = mWidget->metaObject(); + int index = object->indexOfProperty(name); + property = object->property(index); + return index >= 0; +} + +/*! + Checks if a slot with the given \a signature exists + in the contained widget. If the slot exists the \a + method is made to reference to it. Returns true if + the slot was found. Otherwise, returns false. +*/ +bool HsWidgetHost::setMethod(const char *signature, QMetaMethod &method) +{ + const QMetaObject *object = mWidget->metaObject(); + int index = object->indexOfMethod( + QMetaObject::normalizedSignature(signature)); + method = object->method(index); + return index >= 0; +} + +/*! + Returns true if a signal with the given \a signature + exists in the contained widget. Otherwise, returns + false. +*/ +bool HsWidgetHost::hasSignal(const char *signature) +{ + const QMetaObject *object = mWidget->metaObject(); + int index = object->indexOfSignal( + QMetaObject::normalizedSignature(signature)); + return index >= 0; +} +/*! + Returns true if fetching widget preferences from db and setting those + to widget is successfull +*/ +bool HsWidgetHost::setPreferencesToWidget() +{ + HsDatabase *db = HsDatabase::instance(); + Q_ASSERT(db); + + QVariantMap preferences; + if (!db->widgetPreferences(mDatabaseId, preferences)) { + return false; + } + + QStringList names = preferences.keys(); + foreach(QString name, names) { + mWidget->setProperty(name.toLatin1(), + preferences.value(name)); + } + + return true; +} + +/*! + This slot is connected to the contained widget's + setPreferences() signal, if it was defined for + the widget. The widget emits the signal for persisting + its preferences named with \a names. The given + preferences are read, validated, and written to + the database. +*/ +void HsWidgetHost::onSetPreferences(const QStringList &names) +{ + if (names.isEmpty()) { + return; + } + + QVariantMap preferences; + + foreach (QString name, names) { + QVariant value = mWidget->property(name.toLatin1()); + preferences.insert(name, value); + } + + HsDatabase *db = HsDatabase::instance(); + Q_ASSERT(db); + + if (!db->setWidgetPreferences(mDatabaseId, preferences)) { + onError(); + } +} + +/*! + This slot reacts to the widgets finished() signal, if + it was defined for the widget. The widget emits the signal + when it has finished its execution and is ready for + removal from the homescreen. +*/ +void HsWidgetHost::onFinished() +{ + emit widgetFinished(this); +} + +/*! + This slot reacts to the widgets error() signal, if it was + defined for the widget. The widget emits the signal in + failure cases. +*/ +void HsWidgetHost::onError() +{ + emit widgetError(this); +} + +/*! + This slot reacts to \a entry change that is described with + \a changeType. On remove change type, onFinished() signal is + emitted. +*/ +void HsWidgetHost::onEntryChanged(const CaEntry &entry, + ChangeType changeType) +{ + if (changeType == RemoveChangeType) { + QString uri = entry.attribute(widgetUriAttributeName()); + if (uri == mUri) { + onFinished(); + } + } +}