summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Jones <martin.jones@nokia.com>2010-06-30 09:30:00 +1000
committerMartin Jones <martin.jones@nokia.com>2010-08-17 10:35:31 +1000
commit58ccc3c10f0ebc1951270be621cb113351980e1e (patch)
tree62ad1cf741f361d3dd223ea8b8940ce7d0488651
parent26abb974c6617ecb2256b699a9e0f50ceff4a280 (diff)
Messaging QML model/filter implementation.
-rw-r--r--doc/src/messaging.qdoc9
-rw-r--r--doc/src/qtmobility.qdocconf1
-rw-r--r--examples/declarative-messages/messaging.qml96
-rw-r--r--plugins/declarative/declarative.pro1
-rw-r--r--plugins/declarative/messaging/messaging.pro44
-rw-r--r--plugins/declarative/messaging/plugin.cpp27
-rw-r--r--plugins/declarative/messaging/qdeclarativemessagefilter.cpp560
-rw-r--r--plugins/declarative/messaging/qdeclarativemessagefilter.h206
-rw-r--r--plugins/declarative/messaging/qdeclarativemessagemodel.cpp777
-rw-r--r--plugins/declarative/messaging/qdeclarativemessagemodel.h150
-rw-r--r--plugins/declarative/messaging/qmldir1
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