diff options
author | Martin Jones <martin.jones@nokia.com> | 2010-06-30 09:30:00 +1000 |
---|---|---|
committer | Martin Jones <martin.jones@nokia.com> | 2010-08-17 10:35:31 +1000 |
commit | 58ccc3c10f0ebc1951270be621cb113351980e1e (patch) | |
tree | 62ad1cf741f361d3dd223ea8b8940ce7d0488651 | |
parent | 26abb974c6617ecb2256b699a9e0f50ceff4a280 (diff) |
Messaging QML model/filter implementation.
-rw-r--r-- | doc/src/messaging.qdoc | 9 | ||||
-rw-r--r-- | doc/src/qtmobility.qdocconf | 1 | ||||
-rw-r--r-- | examples/declarative-messages/messaging.qml | 96 | ||||
-rw-r--r-- | plugins/declarative/declarative.pro | 1 | ||||
-rw-r--r-- | plugins/declarative/messaging/messaging.pro | 44 | ||||
-rw-r--r-- | plugins/declarative/messaging/plugin.cpp | 27 | ||||
-rw-r--r-- | plugins/declarative/messaging/qdeclarativemessagefilter.cpp | 560 | ||||
-rw-r--r-- | plugins/declarative/messaging/qdeclarativemessagefilter.h | 206 | ||||
-rw-r--r-- | plugins/declarative/messaging/qdeclarativemessagemodel.cpp | 777 | ||||
-rw-r--r-- | plugins/declarative/messaging/qdeclarativemessagemodel.h | 150 | ||||
-rw-r--r-- | plugins/declarative/messaging/qmldir | 1 |
11 files changed, 1872 insertions, 0 deletions
diff --git a/doc/src/messaging.qdoc b/doc/src/messaging.qdoc index dcbd311378..9a9535907a 100644 --- a/doc/src/messaging.qdoc +++ b/doc/src/messaging.qdoc @@ -224,6 +224,15 @@ only one thread may access the data concurrently. The library abstracts the storage method used to store messaging data. +\section1 QML Messaging Elements +\list +\o \l MessageModel +\o \l MessageFilter +\o \l MessageUnionFilter +\o \l MessageIntersectionFilter +\endlist + + \section1 Examples \section2 Keep In Touch diff --git a/doc/src/qtmobility.qdocconf b/doc/src/qtmobility.qdocconf index 0851445244..3bf89534cb 100644 --- a/doc/src/qtmobility.qdocconf +++ b/doc/src/qtmobility.qdocconf @@ -118,6 +118,7 @@ sourcedirs = ../../src/global \ ../../src/multimedia \ ../../plugins/declarative/multimedia \ ../../plugins/declarative/location \ + ../../plugins/declarative/messaging \ ../../src/messaging \ ../../src/versit \ ../../src/telephony \ diff --git a/examples/declarative-messages/messaging.qml b/examples/declarative-messages/messaging.qml new file mode 100644 index 0000000000..846ac06125 --- /dev/null +++ b/examples/declarative-messages/messaging.qml @@ -0,0 +1,96 @@ +import Qt 4.7 +import QtMobility.messaging 1.1 + +Rectangle { + width: 320 + height: 480 + ListView { + id: list + anchors.fill: parent + model: MessageModel { + sortBy: MessageModel.Timestamp + sortOrder: MessageModel.DescendingOrder + /* + filter: MessageIntersectionFilter { + MessageFilter { + type: MessageFilter.Size + value: 1024 + comparator: MessageFilter.LessThan + } + MessageUnionFilter { + MessageIntersectionFilter { + MessageFilter { + type: MessageFilter.Sender + value: "martin" + comparator: MessageFilter.Includes + } + MessageFilter { + negated: true + type: MessageFilter.Subject + value: "re:" + comparator: MessageFilter.Includes + } + } + MessageFilter { + type: MessageFilter.Sender + value: "don" + comparator: MessageFilter.Includes + } + } + } + */ + } + delegate: Item { + id: wrapper + height: 50; width: list.width + Rectangle { + id: heading + height: 50; width: list.width + MouseArea { + anchors.fill: parent + onClicked: { + wrapper.state = wrapper.state == 'Details' ? '' : 'Details'; + } + } + Text { id: subjText; text: subject; font.pixelSize: 18; x: 3 } + Text { + text: sender; color: "gray"; font.pixelSize: 10 + anchors.left: subjText.left; anchors.right: dateText.left; anchors.rightMargin: 4 + elide: Text.ElideRight; anchors.top: subjText.bottom; anchors.topMargin: 6 + } + Text { id: dateText; text: date; color: "gray"; font.pixelSize: 10 + anchors.right: parent.right; anchors.top: subjText.bottom + anchors.topMargin: 6; anchors.rightMargin: 3 + MouseArea { + anchors.fill: parent + onClicked: list.model.showMessage(index) + } + } + Rectangle { id: separator; y: wrapper.height-1; width: parent.width; height: 1; color: "lightgray" } + color: ready ? "white" : "yellow" + } + Flickable { + id: bodyView; anchors.top: heading.bottom; anchors.bottom: wrapper.bottom; width: list.width + contentHeight: bodyText.height; clip: true + Text { id: bodyText; width: list.width; wrapMode: Text.WordWrap; opacity: 0 } + } + states: State { + name: "Details" + PropertyChanges { target: wrapper; height: list.height } + PropertyChanges { target: wrapper.ListView.view; contentY: wrapper.y; interactive: false } + PropertyChanges { target: bodyText; opacity: 1; text: { body == undefined ? "Loading" : body } } + PropertyChanges { target: heading; color: "lightsteelblue" } + } + transitions: Transition { + SequentialAnimation { + ParallelAnimation { + ColorAnimation { property: "color"; duration: 500 } + NumberAnimation { duration: 300; properties: "contentY,height" } + } + PropertyAction { property: "text" } + NumberAnimation { properties: "opacity" } + } + } + } + } +} diff --git a/plugins/declarative/declarative.pro b/plugins/declarative/declarative.pro index 4bcacd0b3a..463b2d23b0 100644 --- a/plugins/declarative/declarative.pro +++ b/plugins/declarative/declarative.pro @@ -12,3 +12,4 @@ contains(mobility_modules,systeminfo): SUBDIRS += systeminfo contains(mobility_modules,gallery): SUBDIRS += gallery contains(mobility_modules,contacts):contains(mobility_modules,versit) SUBDIRS += contacts contains(mobility_modules,location): SUBDIRS += location +contains(mobility_modules,messaging): SUBDIRS += messaging diff --git a/plugins/declarative/messaging/messaging.pro b/plugins/declarative/messaging/messaging.pro new file mode 100644 index 0000000000..ee3a0e1f77 --- /dev/null +++ b/plugins/declarative/messaging/messaging.pro @@ -0,0 +1,44 @@ +INCLUDEPATH += ../../../src/messaging +INCLUDEPATH += ../../../src/global + +TARGET = $$qtLibraryTarget(declarative_messaging) +TEMPLATE = lib +CONFIG += plugin +TARGETPATH = QtMobility/messaging +PLUGIN_TYPE = declarative + +include(../../../common.pri) + +QT += declarative + +SOURCES += \ + qdeclarativemessagefilter.cpp \ + qdeclarativemessagemodel.cpp \ + plugin.cpp + +HEADERS += \ + qdeclarativemessagefilter.h \ + qdeclarativemessagemodel.h + + +CONFIG += mobility +MOBILITY += messaging + +DESTDIR = $$[QT_INSTALL_PREFIX]/imports/$$TARGETPATH +target.path = $$[QT_INSTALL_IMPORTS]/$$TARGETPATH + +qmldir.files += $$PWD/qmldir +qmldir.path += $$[QT_INSTALL_IMPORTS]/$$TARGETPATH + +INSTALLS += target qmldir + +# QMF libraries must be located at $QMF_LIBDIR +simulator|contains(qmf_enabled, yes) { + mac { + QMAKE_LFLAGS += -F$$(QMF_LIBDIR) + LIBS += -framework qtopiamail + } else { + LIBS += -L$$(QMF_LIBDIR) -l$$qtLibraryTarget(qtopiamail) + } +} + diff --git a/plugins/declarative/messaging/plugin.cpp b/plugins/declarative/messaging/plugin.cpp new file mode 100644 index 0000000000..d817f27bb0 --- /dev/null +++ b/plugins/declarative/messaging/plugin.cpp @@ -0,0 +1,27 @@ + +#include <qdeclarative.h> +#include <QDeclarativeExtensionPlugin> +#include <qdeclarativemessagefilter.h> +#include <qdeclarativemessagemodel.h> + +class QDeclarativeMessageModelPlugin : public QDeclarativeExtensionPlugin +{ + Q_OBJECT +public: + void registerTypes(const char *uri) + { + Q_ASSERT(uri == QLatin1String("QtMobility.messaging")); + qmlRegisterType<QDeclarativeMessageModel>(uri, 1, 1, "MessageModel"); + qmlRegisterType<QDeclarativeMessageIntersectionFilter>(uri, 1, 1, "MessageIntersectionFilter"); + qmlRegisterType<QDeclarativeMessageUnionFilter>(uri, 1, 1, "MessageUnionFilter"); + qmlRegisterType<QDeclarativeMessageFilter>(uri, 1, 1, "MessageFilter"); + qmlRegisterUncreatableType<QDeclarativeMessageFilterBase>(uri,1,1,"MessageFilterBase",QDeclarativeMessageFilterBase::tr("MessageFilterBase is an abstract class")); + qRegisterMetaType<QMessageId>("QMessageId"); + qRegisterMetaType<QMessageIdList>("QMessageIdList"); + } +}; + +Q_EXPORT_PLUGIN2(qmlmessaging, QDeclarativeMessageModelPlugin); + +#include "plugin.moc" + diff --git a/plugins/declarative/messaging/qdeclarativemessagefilter.cpp b/plugins/declarative/messaging/qdeclarativemessagefilter.cpp new file mode 100644 index 0000000000..4d5604e9c5 --- /dev/null +++ b/plugins/declarative/messaging/qdeclarativemessagefilter.cpp @@ -0,0 +1,560 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, 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 qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qdeclarativemessagefilter.h> +#include <qdeclarativeinfo.h> +#include <QDebug> + +QTM_USE_NAMESPACE + +QDeclarativeMessageFilterBase::QDeclarativeMessageFilterBase(QObject *parent) + : QObject(parent), m_negated(false) +{ +} + +bool QDeclarativeMessageFilterBase::negated() const +{ + return m_negated; +} + +void QDeclarativeMessageFilterBase::setNegated(bool n) +{ + if (m_negated == n) + return; + m_negated = n; + emit negatedChanged(); +} + +//=========================================================================== + + +/*! + \qmlclass MessageIntersectionFilter QDeclarativeMessageIntersectionFilter + \brief The MessageIntersectionFilter element specifies an insection of MessageFilter + + This element is part of the \bold{QtMobility.messaging 1.1} module. + + Logical AND combinations of MessageFilters can be formed using MessageIntersectionFilter. + + Setting \l negated to true will negate the filter. + + The following example creates a filter which filters for messages + less than 1024 bytes in size from \c martin. + + \qml + model: MessageModel { + sortBy: MessageModel.Timestamp + sortOrder: MessageModel.DescendingOrder + filter: MessageIntersectionFilter { + MessageFilter { + type: MessageFilter.Size + value: 1024 + comparator: MessageFilter.LessThan + } + MessageFilter { + type: MessageFilter.Sender + value: "martin" + comparator: MessageFilter.Includes + } + } + } + \endqml + + \sa MessageUnionFilter +*/ + +/*! + \qmlproperty bool MessageIntersectionFilter::negated + Setting negated to true will result in the filter being locially negated. +*/ + +/*! + \qmlproperty list<MessageFilter> MessageIntersectionFilter::filters + \default + + The filters to AND together. +*/ + +QDeclarativeMessageIntersectionFilter::QDeclarativeMessageIntersectionFilter(QObject *parent) + : QDeclarativeMessageFilterBase(parent) +{ +} + +QDeclarativeListProperty<QDeclarativeMessageFilterBase> QDeclarativeMessageIntersectionFilter::filters() +{ + return QDeclarativeListProperty<QDeclarativeMessageFilterBase>(this, m_filters); +} + +QMessageFilter QDeclarativeMessageIntersectionFilter::filter() +{ + if (m_filters.count() == 0) + return QMessageFilter(); + + QMessageFilter filter = m_filters.first()->filter(); + for (int i = 1; i < m_filters.count(); ++i) + filter &= m_filters.at(i)->filter(); + + if (m_negated) + return ~filter; + else + return filter; +} + + +/*! + \qmlclass MessageUnionFilter QDeclarativeMessageUnionFilter + \brief The MessageUnionFilter element specifies a union of MessageFilter + + This element is part of the \bold{QtMobility.messaging 1.1} module. + + Logical OR combinations of MessageFilters can be formed using MessageUnionFilter. + + Setting \l negated to true will negate the filter. + + The following example creates a filter which filters for messages + from \c martin or \c don. + + \qml + model: MessageModel { + sortBy: MessageModel.Timestamp + sortOrder: MessageModel.DescendingOrder + filter: MessageUnionFilter { + MessageFilter { + type: MessageFilter.Sender + value: "martin" + comparator: MessageFilter.Includes + } + MessageFilter { + type: MessageFilter.Sender + value: "don" + comparator: MessageFilter.Includes + } + } + } + \endqml + + \sa MessageIntersectionFilter +*/ + +/*! + \qmlproperty bool MessageUnionFilter::negated + Setting negated to true will result in the filter being locially negated. +*/ + +/*! + \qmlproperty list<MessageFilter> MessageUnionFilter::filters + \default + + The filters to OR together. +*/ +QDeclarativeMessageUnionFilter::QDeclarativeMessageUnionFilter(QObject *parent) + : QDeclarativeMessageFilterBase(parent) +{ +} + +QDeclarativeListProperty<QDeclarativeMessageFilterBase> QDeclarativeMessageUnionFilter::filters() +{ + return QDeclarativeListProperty<QDeclarativeMessageFilterBase>(this, m_filters); +} + +QMessageFilter QDeclarativeMessageUnionFilter::filter() +{ + if (m_filters.count() == 0) + return QMessageFilter(); + + QMessageFilter filter = m_filters.first()->filter(); + for (int i = 1; i < m_filters.count(); ++i) + filter |= m_filters.at(i)->filter(); + + if (m_negated) + return ~filter; + else + return filter; +} + +//=========================================================================== + +class QDeclarativeMessageFilterPrivate +{ +public: + QDeclarativeMessageFilterPrivate() + : type(QDeclarativeMessageFilter::Sender) + , comparator(QDeclarativeMessageFilter::Includes) + { + } + + QDeclarativeMessageFilter::FilterType type; + QVariant value; + QDeclarativeMessageFilter::Comparator comparator; +}; + +/*! + \qmlclass MessageFilter QDeclarativeMessageFilter + \brief The MessageFilter element specifies a message filter for MessageModel + + This element is part of the \bold{QtMobility.messaging 1.1} module. + + Logical combinations of MessageFilters can be formed using MessageIntersectionFilter + and MessageUnionFilter. + + Setting \l negated to true will negate the filter. + + The following example creates a filter which filters for messages + less than 1024 bytes in size from + \c martin or \c don, excluding replies from \c martin. The + messages will be sorted by descending timestamp. + + \qml + model: MessageModel { + sortBy: MessageModel.Timestamp + sortOrder: MessageModel.DescendingOrder + filter: MessageIntersectionFilter { + MessageFilter { + type: MessageFilter.Size + value: 1024 + comparator: MessageFilter.LessThan + } + MessageUnionFilter { + MessageIntersectionFilter { + MessageFilter { + type: MessageFilter.Sender + value: "martin" + comparator: MessageFilter.Includes + } + MessageFilter { + negated: true + type: MessageFilter.Subject + value: "re:" + comparator: MessageFilter.Includes + } + } + MessageFilter { + type: MessageFilter.Sender + value: "don" + comparator: MessageFilter.Includes + } + } + } + } + \endqml +*/ +QDeclarativeMessageFilter::QDeclarativeMessageFilter(QObject *parent) + : QDeclarativeMessageFilterBase(parent), d(new QDeclarativeMessageFilterPrivate) +{ +} + +/*! + \qmlproperty Variant MessageFilter::value + Holds the value to filter on. +*/ +QVariant QDeclarativeMessageFilter::value() const +{ + return d->value; +} + +void QDeclarativeMessageFilter::setValue(const QVariant &value) +{ + if (d->value == value) + return; + + d->value = value; + emit valueChanged(); +} + +/*! + \qmlproperty enumeration MessageFilter::type + Holds the field to filter on. + + type may be one of the following: + \table + \header \o Filter type \o value type + \row \o MessageFilter.AncestorFolder + \o string + \row \o MessageFilter.ParentFolder + \o string + \row \o MessageFilter.Priority + \o enumeration + \list + \o MessageFilter.HighPriority + \o MessageFilter.NormalPriority + \o MessageFilter.LowPriority + \endlist + \row \o MessageFilter.Recipients + \o string + \row \o MessageFilter.Sender + \o string + \row \o MessageFilter.Size + \o int + \row \o MessageFilter.StandardFolder + \o enumeration + \list + \o MessageFilter.InboxFolder + \o MessageFilter.DraftsFolder + \o MessageFilter.OutboxFolder + \o MessageFilter.SentFolder + \o MessageFilter.TrashFolder + \endlist + \row \o MessageFilter.Status + \o enumeration + \list + \o MessageFilter.Read + \o MessageFilter.HasAttachments + \o MessageFilter.Incoming + \o MessageFilter.Removed + \endlist + \row \o MessageFilter.Subject + \o string + \row \o MessageFilter.Timestamp + \o Date + \row \o MessageFilter.ReceptionTimestamp + \o Date + \row \o MessageFilter.Type + \o enumeration + \list + \o MessageFilter.Mms + \o MessageFilter.Sms + \o MessageFilter.Email + \o MessageFilter.InstantMessage + \endlist + \endtable +*/ +QDeclarativeMessageFilter::FilterType QDeclarativeMessageFilter::type() const +{ + return d->type; +} + +void QDeclarativeMessageFilter::setType(FilterType type) +{ + if (type == d->type) + return; + d->type = type; + emit typeChanged(); +} + +/*! + \qmlproperty enumeration MessageFilter::comparator + Holds the type of comparison to apply. + + comparator may be one of the following: + \list + \o MessageFilter.Includes + \o MessageFilter.Excludes + \o MessageFilter.Equality + \o MessageFilter.Equal + \o MessageFilter.NotEqual + \o MessageFilter.LessThan + \o MessageFilter.LessThanEqual + \o MessageFilter.GreaterThan + \o MessageFilter.GreaterThanEqual + \endlist + + Note that not all comparators make sense for all filter types. For example + the relational comparators (LessThan, GreaterThan, etc.) make sense for Size + filters, but the inclusion comprators (Includes, Excludes) do not. +*/ +QDeclarativeMessageFilter::Comparator QDeclarativeMessageFilter::comparator() const +{ + return d->comparator; +} + +void QDeclarativeMessageFilter::setComparator(QDeclarativeMessageFilter::Comparator comparator) +{ + if (d->comparator == comparator) + return; + + d->comparator = comparator; + emit comparatorChanged(); +} + +/*! + \qmlproperty bool MessageFilter::negated + Setting negated to true will result in the filter being locially negated. +*/ + + +QMessageFilter QDeclarativeMessageFilter::filter() +{ + QMessageDataComparator::InclusionComparator inclusion = QMessageDataComparator::Includes; + QMessageDataComparator::EqualityComparator equality = QMessageDataComparator::Equal; + QMessageDataComparator::RelationComparator relation; + + enum ComparatorType { Inclusion, Equality, Relation }; + ComparatorType compType = Inclusion; + + switch (d->comparator) { + case Includes: + compType = Inclusion; + inclusion = QMessageDataComparator::Includes; + break; + case Excludes: + compType = Inclusion; + inclusion = QMessageDataComparator::Excludes; + break; + case Equal: + compType = Equality; + equality = QMessageDataComparator::Equal; + break; + case NotEqual: + compType = Equality; + equality = QMessageDataComparator::NotEqual; + break; + case LessThan: + compType = Relation; + relation = QMessageDataComparator::LessThan; + break; + case LessThanEqual: + compType = Relation; + relation = QMessageDataComparator::LessThanEqual; + break; + case GreaterThan: + compType = Relation; + relation = QMessageDataComparator::GreaterThan; + break; + case GreaterThanEqual: + compType = Relation; + relation = QMessageDataComparator::GreaterThanEqual; + break; + } + + QMessageFilter filter; + switch (d->type) { + case AncestorFolder: + if (compType == Equality) + filter = QMessageFilter::byAncestorFolderIds(QMessageFolderFilter::byPath(d->value.toString(), equality)); + else if (compType == Inclusion) + filter = QMessageFilter::byAncestorFolderIds(QMessageFolderFilter::byPath(d->value.toString(), inclusion)); + else + qmlInfo(this) << "Relational comparators not valid for AncestorFolder filter"; + break; + case ParentFolder: + if (compType == Equality) + filter = QMessageFilter::byParentFolderId(QMessageFolderFilter::byPath(d->value.toString(), equality)); + else if (compType == Inclusion) + filter = QMessageFilter::byParentFolderId(QMessageFolderFilter::byPath(d->value.toString(), inclusion)); + else + qmlInfo(this) << "Relational comparators not valid for ParentFolder filter"; + break; + case Priority: + if (compType == Equality) + filter = QMessageFilter::byPriority(QMessage::Priority(d->value.toInt()), equality); + else + qmlInfo(this) << "Only Equal and NotEqual comparators supported by Priority filter"; + break; + case Recipients: + if (compType == Inclusion) + filter = QMessageFilter::byRecipients(d->value.toString(), inclusion); + else + qmlInfo(this) << "Only Inclusion comparators are valid for Recipients filter"; + break; + case Sender: + if (compType == Equality) + filter = QMessageFilter::bySender(d->value.toString(), equality); + else if (compType == Inclusion) + filter = QMessageFilter::bySender(d->value.toString(), inclusion); + else + qmlInfo(this) << "Relational comparators not valid for Sender filter"; + break; + case Size: + if (compType == Equality) + filter = QMessageFilter::bySize(d->value.toInt(), equality); + else if (compType == Relation) + filter = QMessageFilter::bySize(d->value.toInt(), relation); + else + qmlInfo(this) << "Includes and Excludes comparators are not valid for Size filter"; + break; + case StandardFolder: + if (compType == Equality) + filter = QMessageFilter::byStandardFolder(QMessage::StandardFolder(d->value.toInt()), equality); + else + qmlInfo(this) << "Only Equal and NotEqual comparators supported by StandardFolder filter"; + break; + case Status: + if (compType == Equality) + filter = QMessageFilter::byStatus(QMessage::Status(d->value.toInt()), equality); + else if (compType == Inclusion) + filter = QMessageFilter::byStatus(QMessage::Status(d->value.toInt()), inclusion); + else + qmlInfo(this) << "Relational comparators not valid for Status filter"; + break; + case Subject: + if (compType == Equality) + filter = QMessageFilter::bySubject(d->value.toString(), equality); + else if (compType == Inclusion) + filter = QMessageFilter::bySubject(d->value.toString(), inclusion); + else + qmlInfo(this) << "Relational comparators not valid for Subject filter"; + break; + case Timestamp: + if (compType == Equality) + filter = QMessageFilter::byTimeStamp(d->value.toDateTime(), equality); + else if (compType == Relation) + filter = QMessageFilter::byTimeStamp(d->value.toDateTime(), relation); + else + qmlInfo(this) << "Includes and Excludes comparators are not valid for Timestamp filter"; + break; + case ReceptionTimestamp: + if (compType == Equality) + filter = QMessageFilter::byReceptionTimeStamp(d->value.toDateTime(), equality); + else if (compType == Relation) + filter = QMessageFilter::byReceptionTimeStamp(d->value.toDateTime(), relation); + else + qmlInfo(this) << "Includes and Excludes comparators are not valid for Timestamp filter"; + break; + case Type: + if (compType == Equality) + filter = QMessageFilter::byType(QMessage::Type(d->value.toInt()), equality); + else if (compType == Inclusion) + filter = QMessageFilter::byType(QMessage::Type(d->value.toInt()), inclusion); + else + qmlInfo(this) << "Relational comparators not valid for Type filter"; + break; + default: + qmlInfo(this) << "filter not supported" << d->type; + break; + } + + if (m_negated) + return ~filter; + + return filter; +} + + diff --git a/plugins/declarative/messaging/qdeclarativemessagefilter.h b/plugins/declarative/messaging/qdeclarativemessagefilter.h new file mode 100644 index 0000000000..593091cbb2 --- /dev/null +++ b/plugins/declarative/messaging/qdeclarativemessagefilter.h @@ -0,0 +1,206 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, 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 qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qdeclarative.h> +#include <QDeclarativeExtensionPlugin> +#include <QAbstractListModel> +#include <qmessage.h> +#include <qmessagefilter.h> + +QTM_USE_NAMESPACE + +class QDeclarativeMessageFilterBase : public QObject +{ + Q_OBJECT + Q_PROPERTY(bool negated READ negated WRITE setNegated NOTIFY negatedChanged) + +public: + QDeclarativeMessageFilterBase(QObject *parent=0); + + bool negated() const; + void setNegated(bool); + + virtual QMessageFilter filter() = 0; + +signals: + void negatedChanged(); + +protected: + bool m_negated; +}; + +class QDeclarativeMessageIntersectionFilter : public QDeclarativeMessageFilterBase +{ + Q_OBJECT + Q_PROPERTY(QDeclarativeListProperty<QDeclarativeMessageFilterBase> filters READ filters) + Q_CLASSINFO("DefaultProperty", "filters") + +public: + QDeclarativeMessageIntersectionFilter(QObject *parent=0); + + QDeclarativeListProperty<QDeclarativeMessageFilterBase> filters(); + + virtual QMessageFilter filter(); + +private: + QList<QDeclarativeMessageFilterBase*> m_filters; +}; + +class QDeclarativeMessageUnionFilter : public QDeclarativeMessageFilterBase +{ + Q_OBJECT + Q_PROPERTY(QDeclarativeListProperty<QDeclarativeMessageFilterBase> filters READ filters) + Q_CLASSINFO("DefaultProperty", "filters") + +public: + QDeclarativeMessageUnionFilter(QObject *parent=0); + + QDeclarativeListProperty<QDeclarativeMessageFilterBase> filters(); + + virtual QMessageFilter filter(); + +private: + QList<QDeclarativeMessageFilterBase*> m_filters; +}; + + +class QDeclarativeMessageFilterPrivate; +class QDeclarativeMessageFilter : public QDeclarativeMessageFilterBase +{ + Q_OBJECT + + Q_PROPERTY(FilterType type READ type WRITE setType NOTIFY typeChanged) + Q_PROPERTY(QVariant value READ value WRITE setValue NOTIFY valueChanged) + Q_PROPERTY(Comparator comparator READ comparator WRITE setComparator NOTIFY comparatorChanged) + + Q_ENUMS(FilterType); + Q_ENUMS(Priority); + Q_ENUMS(Comparator); + Q_ENUMS(Type); + Q_ENUMS(Status); + +public: + QDeclarativeMessageFilter(QObject *parent=0); + + enum FilterType { + AncestorFolder, + ParentFolder, + Priority, + Recipients, + Sender, + Size, + StandardFolder, + Status, + Subject, + Timestamp, + ReceptionTimestamp, + Type + }; + + FilterType type() const; + void setType(FilterType type); + + QVariant value() const; + void setValue(const QVariant &value); + + enum Comparator { + // Inclusion + Includes, + Excludes, + // Equality + Equal, + NotEqual, + // Relation + LessThan, + LessThanEqual, + GreaterThan, + GreaterThanEqual + }; + + Comparator comparator() const; + void setComparator(Comparator); + + QMessageFilter filter(); + + enum Priority { + HighPriority = QMessage::HighPriority, + NormalPriority = QMessage::NormalPriority, + LowPriority = QMessage::LowPriority + }; + + enum Type { + Mms = QMessage::Mms, + Sms = QMessage::Sms, + Email = QMessage::Email, + InstantMessage = QMessage::InstantMessage, + AnyType = QMessage::AnyType + }; + + enum Status { + Read = QMessage::Read, + HasAttachments = QMessage::HasAttachments, + Incoming = QMessage::Incoming, + Removed = QMessage::Removed + }; + + enum StandardFolder { + InboxFolder = QMessage::InboxFolder, + DraftsFolder = QMessage::DraftsFolder, + OutboxFolder = QMessage::OutboxFolder, + SentFolder = QMessage::SentFolder, + TrashFolder = QMessage::TrashFolder + }; + +signals: + void typeChanged(); + void valueChanged(); + void comparatorChanged(); + +private: + QDeclarativeMessageFilterPrivate *d; +}; + + +QML_DECLARE_TYPE(QDeclarativeMessageFilter) +QML_DECLARE_TYPE(QDeclarativeMessageIntersectionFilter) +QML_DECLARE_TYPE(QDeclarativeMessageUnionFilter) +QML_DECLARE_TYPE(QDeclarativeMessageFilterBase) + diff --git a/plugins/declarative/messaging/qdeclarativemessagemodel.cpp b/plugins/declarative/messaging/qdeclarativemessagemodel.cpp new file mode 100644 index 0000000000..59a35a4312 --- /dev/null +++ b/plugins/declarative/messaging/qdeclarativemessagemodel.cpp @@ -0,0 +1,777 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, 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 qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QThread> +#include <QMutex> +#include <QCache> +#include <qdeclarativemessagemodel.h> +#include <qdeclarativemessagefilter.h> +#include <qdeclarativeinfo.h> +#include <qmessagecontentcontainer.h> +#include <QDebug> + +#define CACHE_SIZE 100 + +QTM_USE_NAMESPACE + +class MessageModelWorker : public QObject +{ + Q_OBJECT +public: + MessageModelWorker(); + + QMessage getMessage(const QMessageId &id) { + QMutexLocker locker(&mutex); + if (messageCache.contains(id)) { + return *messageCache.object(id); + } else { + if (!messageIdRequests.contains(id)) { + messageIdRequests.append(id); + if (messageIdRequests.count() == 1) + QMetaObject::invokeMethod(this, "getRequested", Qt::QueuedConnection); + } else { + messageIdRequests.removeAll(id); + messageIdRequests.append(id); + } + } + + return QMessage(); + } + + void requestBody(const QMessageId &id) { + QMutexLocker locker(&mutex); + messageBodyRequest = id; + QMetaObject::invokeMethod(this, "getRequested", Qt::QueuedConnection); + } + +public slots: + void setFilter(QMessageFilter filter, QMessageSortOrder sort, int limit); + void getBody(const QMessageId &id); + void show(const QMessageId &id); + void remove(const QMessageId &id); + +signals: + void messagesFound(const QMessageIdList&); + void serviceProgressChanged(uint, uint); + void messageAdded(const QMessageId&); + void messageRemoved(const QMessageId&); + void messageUpdated(const QMessageId&); + +private slots: + void updateFilter(); + void getRequested(); + void serviceStateChanged(QMessageService::State); + void messageAdded(const QMessageId&,const QMessageManager::NotificationFilterIdSet); + void messageRemoved(const QMessageId&,const QMessageManager::NotificationFilterIdSet); + void messageUpdated(const QMessageId&,const QMessageManager::NotificationFilterIdSet); + +private: + void init(); + QMessage *cacheMessage(const QMessageId &id) { + QMutexLocker locker(&mutex); + if (!messageCache.contains(id)) { + locker.unlock(); + QMessage *msg = new QMessage(id); + locker.relock(); + messageCache.insert(id, msg); + } + return messageCache.object(id); + } + void removeFromCache(const QMessageId &id) { + QMutexLocker locker(&mutex); + messageCache.remove(id); + } + +private: + QMessageManager *manager; + QMessageService *service; + QMessageFilter mFilter; + QMessageSortOrder mSort; + bool updatePending : 1; + bool initialized : 1; + int mLimit; + QMessageIdList messageIds; + QMessageManager::NotificationFilterId notifierId; + QMessageId serviceId; + enum QueryAction { None, Query, RetrieveBody }; + QueryAction queryAction; + QCache<QMessageId,QMessage> messageCache; + QMessageIdList messageIdRequests; + QMessageId messageBodyRequest; + QMutex mutex; +}; + +MessageModelWorker::MessageModelWorker() + : manager(0), service(0), updatePending(false), initialized(false) + , notifierId(-1), queryAction(None), messageCache(CACHE_SIZE) +{ +} + +void MessageModelWorker::init() +{ + if (!initialized) { + initialized = true; + manager = new QMessageManager(this); + service = new QMessageService(this); + QObject::connect(service, SIGNAL(stateChanged(QMessageService::State)), + this, SLOT(serviceStateChanged(QMessageService::State))); + QObject::connect(service, SIGNAL(messagesFound(const QMessageIdList&)), + this, SIGNAL(messagesFound(const QMessageIdList&))); + QObject::connect(service, SIGNAL(progressChanged(uint,uint)), + this, SIGNAL(serviceProgressChanged(uint,uint))); + QObject::connect(manager, SIGNAL(messageAdded(const QMessageId&,const QMessageManager::NotificationFilterIdSet)), + this, SLOT(messageAdded(const QMessageId&,const QMessageManager::NotificationFilterIdSet))); + QObject::connect(manager, SIGNAL(messageRemoved(const QMessageId&,const QMessageManager::NotificationFilterIdSet)), + this, SLOT(messageRemoved(const QMessageId&,const QMessageManager::NotificationFilterIdSet))); + QObject::connect(manager, SIGNAL(messageUpdated(const QMessageId&,const QMessageManager::NotificationFilterIdSet)), + this, SLOT(messageUpdated(const QMessageId&,const QMessageManager::NotificationFilterIdSet))); + } +} + +void MessageModelWorker::setFilter(QMessageFilter filter, QMessageSortOrder sort, int limit) +{ + mutex.lock(); + mFilter = filter; + mSort = sort; + mLimit = limit; + mutex.unlock(); + if (!updatePending) { + updatePending = true; + QMetaObject::invokeMethod(this, "updateFilter", Qt::QueuedConnection); + } +} + +void MessageModelWorker::updateFilter() +{ + init(); + queryAction = Query; + if (notifierId != -1) + manager->unregisterNotificationFilter(notifierId); + + mutex.lock(); + service->queryMessages(mFilter, mSort, mLimit); + mutex.unlock(); + + notifierId = manager->registerNotificationFilter(mFilter); + updatePending = false; +} + +void MessageModelWorker::getRequested() +{ + init(); + QMessageIdList ids; + mutex.lock(); + for (int i = 0; i < 3 && messageIdRequests.count(); i++) + ids.append(messageIdRequests.takeLast()); + if (messageIdRequests.count()) + QMetaObject::invokeMethod(this, "getRequested", Qt::QueuedConnection); + mutex.unlock(); + + for (int idx = 0; idx < ids.count(); ++idx) { + QMessageId id = ids.at(idx); + cacheMessage(id); + emit messageUpdated(id); + } + + QMessageId bodyId; + mutex.lock(); + bodyId = messageBodyRequest; + messageBodyRequest = QMessageId(); + mutex.unlock(); + + if (bodyId.isValid()) + getBody(bodyId); +} + +void MessageModelWorker::getBody(const QMessageId &id) +{ + QMessage message(*cacheMessage(id)); + + QMessageContentContainer b = message.find(message.bodyId()); + if (!b.isContentAvailable()) { +// qDebug() << "loading content" << id.toString(); + if (serviceId != id) { + serviceId = id; + if (service->state() == QMessageService::ActiveState) { + service->cancel(); + } else { +// qDebug() << "getting body"; + queryAction = MessageModelWorker::RetrieveBody; + service->retrieveBody(id); + } + } + } else { + emit messageUpdated(serviceId); + } +} + +void MessageModelWorker::show(const QMessageId &id) +{ + init(); + service->show(id); +} + +void MessageModelWorker::remove(const QMessageId &id) +{ + init(); + manager->removeMessage(id); +} + +void MessageModelWorker::serviceStateChanged(QMessageService::State newState) +{ +// qDebug() << "state" << newState; + switch (newState) { + case QMessageService::FinishedState: + if (queryAction == MessageModelWorker::RetrieveBody) { +// qDebug() << "body retrieved"; + cacheMessage(serviceId); + emit messageUpdated(serviceId); + } + queryAction = MessageModelWorker::None; + break; + case QMessageService::CanceledState: + if (queryAction == MessageModelWorker::RetrieveBody) { +// qDebug() << "cancelled previous, getting body"; + service->retrieveBody(serviceId); + } + break; + default: + break; + } +} + +void MessageModelWorker::messageAdded(const QMessageId &id,const QMessageManager::NotificationFilterIdSet) +{ + if (!updatePending) { + updatePending = true; + QMetaObject::invokeMethod(this, "updateFilter", Qt::QueuedConnection); + } + emit messageAdded(id); +} + +void MessageModelWorker::messageRemoved(const QMessageId &id,const QMessageManager::NotificationFilterIdSet) +{ + removeFromCache(id); + emit messageRemoved(id); +} + +void MessageModelWorker::messageUpdated(const QMessageId &id,const QMessageManager::NotificationFilterIdSet) +{ + removeFromCache(id); + cacheMessage(id); + emit messageUpdated(id); +} + +//============================================================================ + +class QDeclarativeMessageModelPrivate +{ +public: + QDeclarativeMessageModelPrivate(QDeclarativeMessageModel *model) + : q(model), filter(0), sortKey(QDeclarativeMessageModel::Timestamp) + , sortOrder(QDeclarativeMessageModel::AscendingOrder) + , componentCompleted(false) + , updatePending(false), limit(0) + { + worker = new MessageModelWorker; + worker->moveToThread(&workerThread); + QObject::connect(worker, SIGNAL(messagesFound(const QMessageIdList&)), + q, SLOT(messagesFound(const QMessageIdList&))); + QObject::connect(worker, SIGNAL(messageAdded(const QMessageId&)), + q, SIGNAL(messageAdded())); + QObject::connect(worker, SIGNAL(messageRemoved(const QMessageId&)), + q, SLOT(messageRemoved(const QMessageId&))); + QObject::connect(worker, SIGNAL(messageUpdated(const QMessageId&)), + q, SLOT(messageUpdated(const QMessageId&))); + workerThread.start(QThread::IdlePriority); + } + ~QDeclarativeMessageModelPrivate() + { + workerThread.quit(); + workerThread.wait(); + delete worker; + } + + void updateFilter(); + + QDeclarativeMessageModel *q; + QDeclarativeMessageFilterBase *filter; + QDeclarativeMessageModel::SortKey sortKey; + QDeclarativeMessageModel::SortOrder sortOrder; + QMessageIdList messageIds; + bool componentCompleted : 1; + bool updatePending : 1; + QMessage lastMessage; + int limit; + QThread workerThread; + MessageModelWorker *worker; +}; + +void QDeclarativeMessageModelPrivate::updateFilter() +{ + if (!componentCompleted) + return; + QMessageSortOrder sort; + switch (sortKey) { + case QDeclarativeMessageModel::Priority: + sort = QMessageSortOrder::byPriority(Qt::SortOrder(sortOrder)); + break; + case QDeclarativeMessageModel::Sender: + sort = QMessageSortOrder::bySender(Qt::SortOrder(sortOrder)); + break; + case QDeclarativeMessageModel::Size: + sort = QMessageSortOrder::bySize(Qt::SortOrder(sortOrder)); + break; + case QDeclarativeMessageModel::StatusRead: + sort = QMessageSortOrder::byStatus(QMessage::Read, Qt::SortOrder(sortOrder)); + break; + case QDeclarativeMessageModel::StatusIncoming: + sort = QMessageSortOrder::byStatus(QMessage::Incoming, Qt::SortOrder(sortOrder)); + break; + case QDeclarativeMessageModel::Subject: + sort = QMessageSortOrder::bySubject(Qt::SortOrder(sortOrder)); + break; + case QDeclarativeMessageModel::Timestamp: + sort = QMessageSortOrder::byTimeStamp(Qt::SortOrder(sortOrder)); + break; + case QDeclarativeMessageModel::ReceptionTimestamp: + sort = QMessageSortOrder::byReceptionTimeStamp(Qt::SortOrder(sortOrder)); + break; + case QDeclarativeMessageModel::Recipients: + sort = QMessageSortOrder::byRecipients(Qt::SortOrder(sortOrder)); + break; + case QDeclarativeMessageModel::Type: + sort = QMessageSortOrder::byType(Qt::SortOrder(sortOrder)); + break; + } + + if (filter) + worker->setFilter(filter->filter(), sort, limit); + else + worker->setFilter(QMessageFilter(), sort, limit); + + updatePending = false; +} + +/*! + \qmlclass MessageModel QDeclarativeMessageModel + \brief The MessageModel element provides access to messages. + + This element is part of the \bold{QtMobility.messaging 1.1} module. + + MessageModel provides a model of messages from the message store. + The contents of the model can be specified via a \l filter, and sorted + via the \l sortBy and \l sortOrder properties. The model is automatically + updated if the contents of the store change. + + The following roles are supported by the model: + + \table + \header \o Role \o type + \row \o subject \o string + \row \o type + \o enumeration + \list + \o MessageFilter.Mms + \o MessageFilter.Sms + \o MessageFilter.Email + \o MessageFilter.InstantMessage + \endlist + \row \o size \o int + \row \o sender \o string + \row \o to \o List<string> + \row \o date \o Date + \row \o receivedDate \o Date + \row \o priority + \o enumeration + \list + \o MessageFilter.HighPriority + \o MessageFilter.NormalPriority + \o MessageFilter.LowPriority + \endlist + \row \o body \o string + \row \o ready \o bool + \endtable + + \bold Note: since the body can be large and may need to be fetched from + the server it is recommended that viewing the body be a user action, + and the body role not be bound to until needed. If the body has not yet been + downloaded, it will be requested. \c body will remain undefined until it + has been retrieved. + + The \c ready role is true if the message meta data has been retrieved; otherwise + false. Since MessageModel threaded, all messages are initially not ready, and will + become ready once the data is available. + + The following example displays the subject, sender and date of all messages + sorted in descending order by timestamp: + + \qml + import Qt 4.7 + import QtMobility.messaging 1.1 + + Rectangle { + width: 320 + height: 480 + ListView { + id: list + anchors.fill: parent + model: MessageModel { + sortBy: MessageModel.Timestamp + sortOrder: MessageModel.DescendingOrder + } + delegate: Item { + id: wrapper + height: 32; width: list.width + Text { id: subjText; text: subject; font.pixelSize: 13; x: 3 } + Text { + text: sender; color: "gray"; font.pixelSize: 9 + x: 3; width: parent.width-100; + anchors.top: subjText.bottom; anchors.topMargin: 3 + elide: Text.ElideRight + } + Text { + text: date; color: "gray"; font.pixelSize: 9 + anchors.right: parent.right + anchors.top: subjText.bottom; anchors.topMargin: 3 + } + } + } + } + \endqml + + \sa MessageFilter +*/ +QDeclarativeMessageModel::QDeclarativeMessageModel(QObject *parent) + : QAbstractListModel(parent), d(new QDeclarativeMessageModelPrivate(this)) +{ + QHash<int, QByteArray> roleNames; + roleNames[SubjectRole] = "subject"; + roleNames[SenderRole] = "sender"; + roleNames[ToRole] = "to"; + roleNames[SizeRole] = "size"; + roleNames[TypeRole] = "type"; + roleNames[DateRole] = "date"; + roleNames[ReceivedDateRole] = "receivedDate"; + roleNames[BodyRole] = "body"; + roleNames[PriorityRole] = "priority"; + roleNames[ReadyRole] = "ready"; + setRoleNames(roleNames); +} + +QDeclarativeMessageModel::~QDeclarativeMessageModel() +{ + delete d; +} + +/*! + \qmlproperty MessageFilter MessageModel::filter + + The MessageFilter specifying the messages to provide. +*/ +QDeclarativeMessageFilterBase *QDeclarativeMessageModel::filter() const +{ + return d->filter; +} + +void QDeclarativeMessageModel::setFilter(QDeclarativeMessageFilterBase *filter) +{ + if (filter == d->filter) + return; + + d->filter = filter; + scheduleUpdate(); + emit filterChanged(); +} + +/*! + \qmlproperty enumeration MessageModel::sortBy + + Specifies the role to sort by: + + \list + \o MessageModel.Priority + \o MessageModel.Sender + \o MessageModel.Size + \o MessageModel.StatusRead + \o MessageModel.StatusIncoming + \o MessageModel.Subject + \o MessageModel.Timestamp (default) + \o MessageModel.ReceptionTimestamp + \o MessageModel.Recipients + \o MessageModel.Type + \endlist +*/ +QDeclarativeMessageModel::SortKey QDeclarativeMessageModel::sortBy() const +{ + return d->sortKey; +} + +void QDeclarativeMessageModel::setSortBy(QDeclarativeMessageModel::SortKey k) +{ + if (k == d->sortKey) + return; + d->sortKey = k; + scheduleUpdate(); + emit sortByChanged(); +} + + +/*! + \qmlproperty enumeration MessageModel::sortOrder + + Specifies the sort order: + + \list + \o MessageModel.AscendingOrder + \o MessageModel.DescendingOrder + \endlist +*/ +QDeclarativeMessageModel::SortOrder QDeclarativeMessageModel::sortOrder() const +{ + return d->sortOrder; +} + +void QDeclarativeMessageModel::setSortOrder(QDeclarativeMessageModel::SortOrder o) +{ + if (o == d->sortOrder) + return; + d->sortOrder = o; + scheduleUpdate(); + emit sortOrderChanged(); +} + +/*! + \qmlproperty int MessageModel::count + Holds the number of messages matching the filter. + + If \l limit is set then there will be at most \l limit messages. +*/ + +/*! + \qmlproperty int MessageModel::limit + Holds the maximum number of messages to retrieve. + + A value of zero (default) will retrieve all messages. +*/ +int QDeclarativeMessageModel::limit() const +{ + return d->limit; +} + +void QDeclarativeMessageModel::setLimit(int l) +{ + if (l == d->limit) + return; + d->limit = l; + scheduleUpdate(); + emit limitChanged(); +} + +void QDeclarativeMessageModel::componentComplete() +{ + d->componentCompleted = true; + d->updateFilter(); +} + +void QDeclarativeMessageModel::scheduleUpdate() +{ + if (!d->componentCompleted) + return; + if (!d->updatePending) { + d->updatePending = true; + QMetaObject::invokeMethod(this, "updateFilter", Qt::QueuedConnection); + } +} + +void QDeclarativeMessageModel::messagesFound(const QMessageIdList &ids) +{ +// qDebug() << "found messages"; + beginResetModel(); + d->messageIds = ids; + d->lastMessage = QMessage(); + endResetModel(); + emit countChanged(); +} + +void QDeclarativeMessageModel::serviceProgressChanged(uint value, uint total) +{ + /* + if (total) { + qDebug() << "progress" << qreal(value)/total; + } else { + qDebug() << "No progress available"; + } + */ +} + +int QDeclarativeMessageModel::rowCount(const QModelIndex &) const +{ + return d->messageIds.count(); +} + +QVariant QDeclarativeMessageModel::data(const QModelIndex &index, int role) const +{ + QVariant rv; + int idx = index.row(); + if (d->lastMessage.id() != d->messageIds.at(idx)) + d->lastMessage = d->worker->getMessage(d->messageIds.at(idx)); + if (!d->lastMessage.id().isValid()) { + if (role == ReadyRole) + rv = false; + else + rv = QString(); + return rv; + } + + switch (role) { + case SubjectRole: + rv = d->lastMessage.subject(); + break; + case SizeRole: + rv = d->lastMessage.size(); + break; + case TypeRole: + rv = d->lastMessage.type(); + break; + case SenderRole: + rv = d->lastMessage.from().addressee(); + break; + case ToRole: { + QStringList to; + foreach (QMessageAddress addr, d->lastMessage.to()) + to += addr.addressee(); + rv = to; + } + break; + case DateRole: + rv = d->lastMessage.date(); + break; + case ReceivedDateRole: + rv = d->lastMessage.receivedDate(); + break; + case BodyRole: +// qDebug() << "!!!!!body " << d->lastMessage.bodyId().toString(); + if (d->lastMessage.bodyId().isValid()) { + QMessageContentContainer b = d->lastMessage.find(d->lastMessage.bodyId()); + if (b.isContentAvailable()) { + rv = b.textContent(); + } else { + d->worker->requestBody(d->lastMessage.id()); + } + } else { + // Why is the body id sometimes invalid? + rv = QString(); + } + break; + case PriorityRole: + rv = d->lastMessage.priority(); + break; + case ReadyRole: + rv = true; + break; + default: + break; + } + return rv; +} + +/*! + \qmlmethod MessageModel::showMessage(index) + + Displays the message at \a index using the system message client. +*/ +void QDeclarativeMessageModel::showMessage(int index) const +{ + if (index < 0 || index >= d->messageIds.count()) + return; + QMetaObject::invokeMethod(d->worker, "show", Qt::QueuedConnection, Q_ARG(QMessageId,d->messageIds.at(index))); +} + +/*! + \qmlmethod MessageModel::removeMessage(index) + + Remove the message at \a index from the mail store and the originating server (if applicable). +*/ +void QDeclarativeMessageModel::removeMessage(int index) +{ + if (index < 0 || index >= d->messageIds.count()) + return; + QMetaObject::invokeMethod(d->worker, "remove", Qt::QueuedConnection, Q_ARG(QMessageId,d->messageIds.at(index))); +} + +/*! + \qmlsignal MessageModel::messageAdded() + + This handler is called when a message that matches the filter criteria + is added to the store. The model will be updated shortly and will include + the new message. +*/ + +void QDeclarativeMessageModel::messageUpdated(const QMessageId &id) +{ + for (int i = 0; i < d->messageIds.count(); ++i) { + if (d->messageIds.at(i) == id) { + QModelIndex idx = index(i, 0); + emit dataChanged(idx, idx); + break; + } + } +} + +void QDeclarativeMessageModel::messageRemoved(const QMessageId &id) +{ + for (int i = 0; i < d->messageIds.count(); ++i) { + if (d->messageIds.at(i) == id) { + beginRemoveRows(QModelIndex(), i, i); + d->messageIds.removeAt(i); + endRemoveRows(); + break; + } + } +} + +void QDeclarativeMessageModel::updateFilter() +{ + d->updateFilter(); +} + +#include "qdeclarativemessagemodel.moc" diff --git a/plugins/declarative/messaging/qdeclarativemessagemodel.h b/plugins/declarative/messaging/qdeclarativemessagemodel.h new file mode 100644 index 0000000000..e7df4d0d01 --- /dev/null +++ b/plugins/declarative/messaging/qdeclarativemessagemodel.h @@ -0,0 +1,150 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, 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 qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qdeclarative.h> +#include <QDeclarativeExtensionPlugin> +#include <QAbstractListModel> +#include <qmessage.h> +#include <qmessagefilter.h> +#include <qmessageservice.h> + +QTM_USE_NAMESPACE + +class QDeclarativeMessageFilterBase; + +class QDeclarativeMessageModelPrivate; +class QDeclarativeMessageModel : public QAbstractListModel, public QDeclarativeParserStatus +{ + Q_OBJECT + + Q_PROPERTY(QDeclarativeMessageFilterBase *filter READ filter WRITE setFilter NOTIFY filterChanged) + Q_PROPERTY(SortKey sortBy READ sortBy WRITE setSortBy NOTIFY sortByChanged) + Q_PROPERTY(SortOrder sortOrder READ sortOrder WRITE setSortOrder NOTIFY sortOrderChanged) + Q_PROPERTY(int count READ count NOTIFY countChanged) + Q_PROPERTY(int limit READ limit WRITE setLimit NOTIFY limitChanged) + Q_INTERFACES(QDeclarativeParserStatus) + + Q_ENUMS(SortKey); + Q_ENUMS(SortOrder); + +public: + QDeclarativeMessageModel(QObject *parent=0); + ~QDeclarativeMessageModel(); + + QDeclarativeMessageFilterBase *filter() const; + void setFilter(QDeclarativeMessageFilterBase *filter); + + enum SortKey { + Priority, + Sender, + Size, + StatusRead, + StatusIncoming, + Subject, + Timestamp, + ReceptionTimestamp, + Recipients, + Type + }; + + SortKey sortBy() const; + void setSortBy(SortKey k); + + enum SortOrder { + AscendingOrder = Qt::AscendingOrder, + DescendingOrder = Qt::DescendingOrder + }; + + SortOrder sortOrder() const; + void setSortOrder(SortOrder o); + + enum Roles { + SubjectRole = Qt::DisplayRole, + TypeRole, + SizeRole, + SenderRole, + ToRole, + DateRole, + ReceivedDateRole, + BodyRole, + PriorityRole, + ReadyRole + }; + + Q_INVOKABLE void showMessage(int index) const; + Q_INVOKABLE void removeMessage(int index); + + int limit() const; + void setLimit(int l); + + int count() const { return rowCount(); } + + virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; + virtual QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const; + + virtual void classBegin() {} + virtual void componentComplete(); + +protected: + void scheduleUpdate(); + +signals: + void filterChanged(); + void sortByChanged(); + void sortOrderChanged(); + void limitChanged(); + void countChanged(); + void messageAdded(); + +private slots: + void messagesFound(const QMessageIdList &ids); + void serviceProgressChanged(uint value, uint total); + void messageUpdated(const QMessageId&); + void messageRemoved(const QMessageId&); + void updateFilter(); + +private: + friend class QDeclarativeMessageModelPrivate; + QDeclarativeMessageModelPrivate *d; +}; + +QML_DECLARE_TYPE(QDeclarativeMessageModel) + diff --git a/plugins/declarative/messaging/qmldir b/plugins/declarative/messaging/qmldir new file mode 100644 index 0000000000..3179b29a72 --- /dev/null +++ b/plugins/declarative/messaging/qmldir @@ -0,0 +1 @@ +plugin declarative_messaging |