diff --git a/framework/domain/maillistmodel.cpp b/framework/domain/maillistmodel.cpp index 58a6b384..c6897990 100644 --- a/framework/domain/maillistmodel.cpp +++ b/framework/domain/maillistmodel.cpp @@ -1,221 +1,240 @@ /* Copyright (c) 2016 Michael Bohlender Copyright (c) 2016 Christian Mollekopf This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "maillistmodel.h" #include MailListModel::MailListModel(QObject *parent) : QSortFilterProxyModel() { setDynamicSortFilter(true); sort(0, Qt::DescendingOrder); + connect(&mFetchTimer, &QTimer::timeout, this, &MailListModel::fetch); + mFetchTimer.setSingleShot(true); } MailListModel::~MailListModel() { } QHash< int, QByteArray > MailListModel::roleNames() const { QHash roles; roles[Subject] = "subject"; roles[Sender] = "sender"; roles[SenderName] = "senderName"; roles[To] = "to"; roles[Cc] = "cc"; roles[Bcc] = "bcc"; roles[Date] = "date"; roles[Unread] = "unread"; roles[Important] = "important"; roles[Draft] = "draft"; roles[Trash] = "trash"; roles[Id] = "id"; roles[MimeMessage] = "mimeMessage"; roles[DomainObject] = "domainObject"; roles[ThreadSize] = "threadSize"; roles[Mail] = "mail"; return roles; } static QString join(const QList &contacts) { QStringList list; for (const auto &contact : contacts) { if (!contact.name.isEmpty()) { list << QString("%1 <%2>").arg(contact.name).arg(contact.emailAddress); } else { list << contact.emailAddress; } } return list.join(", "); } -void MailListModel::fetchMail(Sink::ApplicationDomain::Mail::Ptr mail) const +void MailListModel::fetchMail(Sink::ApplicationDomain::Mail::Ptr mail) { if (mail && !mail->getFullPayloadAvailable() && !mFetchedMails.contains(mail->identifier())) { qDebug() << "Fetching mail: " << mail->identifier() << mail->getSubject(); mFetchedMails.insert(mail->identifier()); - Sink::Store::synchronize(Sink::SyncScope{*mail}).exec(); + mMailsToFetch << *mail; + //TODO it would be nicer if Sink could just transparently merge synchronization requeusts. + if (!mFetchTimer.isActive()) { + mFetchTimer.start(50); + } + } +} + +void MailListModel::fetch() +{ + if (!mMailsToFetch.isEmpty()) { + auto first = mMailsToFetch.first(); + auto scope = Sink::SyncScope{first}; + for (const auto &m : mMailsToFetch) { + scope.filter(m.identifier()); + } + Sink::Store::synchronize(scope).exec(); + mMailsToFetch.clear(); } } QVariant MailListModel::data(const QModelIndex &idx, int role) const { auto srcIdx = mapToSource(idx); auto mail = srcIdx.data(Sink::Store::DomainObjectRole).value(); switch (role) { case Subject: return mail->getSubject(); case Sender: return mail->getSender().emailAddress; case SenderName: return mail->getSender().name; case To: return join(mail->getTo()); case Cc: return join(mail->getCc()); case Bcc: return join(mail->getBcc()); case Date: return mail->getDate(); case Unread: return mail->getProperty("unreadCollected").toList().contains(true); case Important: return mail->getProperty("importantCollected").toList().contains(true); case Draft: return mail->getDraft(); case Trash: return mail->getTrash(); case Id: return mail->identifier(); case DomainObject: return QVariant::fromValue(mail); case MimeMessage: if (mFetchMails) { - fetchMail(mail); + const_cast(this)->fetchMail(mail); } return mail->getMimeMessage(); case ThreadSize: return mail->getProperty("count").toInt(); case Mail: return QVariant::fromValue(mail); } return QSortFilterProxyModel::data(idx, role); } bool MailListModel::lessThan(const QModelIndex &left, const QModelIndex &right) const { const auto leftDate = left.data(Sink::Store::DomainObjectRole).value()->getDate(); const auto rightDate = right.data(Sink::Store::DomainObjectRole).value()->getDate(); return leftDate < rightDate; } void MailListModel::runQuery(const Sink::Query &query) { m_model = Sink::Store::loadModel(query); setSourceModel(m_model.data()); } void MailListModel::setParentFolder(const QVariant &parentFolder) { using namespace Sink::ApplicationDomain; auto folder = parentFolder.value(); if (!folder) { qWarning() << "No folder: " << parentFolder; mCurrentQueryItem.clear(); setSourceModel(nullptr); return; } if (mCurrentQueryItem == folder->identifier()) { return; } mCurrentQueryItem = folder->identifier(); Sink::Query query = Sink::StandardQueries::threadLeaders(*folder); query.setFlags(Sink::Query::LiveQuery); query.limit(100); query.request(); query.request(); query.request(); query.request(); query.request(); query.request(); query.request(); query.request(); query.request(); query.request(); query.request(); mFetchMails = false; qDebug() << "Running folder query: " << folder->resourceInstanceIdentifier() << folder->identifier(); //Latest mail on top sort(0, Qt::DescendingOrder); runQuery(query); } QVariant MailListModel::parentFolder() const { return QVariant(); } void MailListModel::setMail(const QVariant &variant) { using namespace Sink::ApplicationDomain; auto mail = variant.value(); if (!mail) { qWarning() << "No mail: " << mail; mCurrentQueryItem.clear(); setSourceModel(nullptr); return; } if (mCurrentQueryItem == mail->identifier()) { return; } mCurrentQueryItem = mail->identifier(); Sink::Query query = Sink::StandardQueries::completeThread(*mail); query.setFlags(Sink::Query::LiveQuery); query.request(); query.request(); query.request(); query.request(); query.request(); query.request(); query.request(); query.request(); query.request(); query.request(); query.request(); query.request(); mFetchMails = true; mFetchedMails.clear(); qDebug() << "Running mail query: " << mail->resourceInstanceIdentifier() << mail->identifier(); //Latest mail at the bottom sort(0, Qt::AscendingOrder); runQuery(query); } QVariant MailListModel::mail() const { return QVariant(); } diff --git a/framework/domain/maillistmodel.h b/framework/domain/maillistmodel.h index af079a1b..1fd0ef5e 100644 --- a/framework/domain/maillistmodel.h +++ b/framework/domain/maillistmodel.h @@ -1,79 +1,85 @@ /* Copyright (c) 2016 Michael Bohlender Copyright (c) 2016 Christian Mollekopf This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include #include #include #include +#include class MailListModel : public QSortFilterProxyModel { Q_OBJECT Q_PROPERTY (QVariant parentFolder READ parentFolder WRITE setParentFolder) Q_PROPERTY (QVariant mail READ mail WRITE setMail) public: MailListModel(QObject *parent = Q_NULLPTR); ~MailListModel(); QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; bool lessThan(const QModelIndex &left, const QModelIndex &right) const Q_DECL_OVERRIDE; enum Roles { Subject = Qt::UserRole + 1, Sender, SenderName, To, Cc, Bcc, Date, Unread, Important, Draft, Trash, Id, MimeMessage, DomainObject, ThreadSize, Mail }; QHash roleNames() const Q_DECL_OVERRIDE; void runQuery(const Sink::Query &query); void setParentFolder(const QVariant &parentFolder); QVariant parentFolder() const; void setMail(const QVariant &mail); QVariant mail() const; +private slots: + void fetch(); + private: - void fetchMail(Sink::ApplicationDomain::Mail::Ptr mail) const; + void fetchMail(Sink::ApplicationDomain::Mail::Ptr mail); QSharedPointer m_model; bool mFetchMails = false; - mutable QSet mFetchedMails; + QSet mFetchedMails; + QList mMailsToFetch; QByteArray mCurrentQueryItem; + QTimer mFetchTimer; };