From 630f45719a527f8ee739b03bc62f886badea6df3 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Tue, 13 Dec 2016 16:24:31 +0100 Subject: Revamp of composercontroller to use actions more. Instead of setting all properties individually we directly assign all properties to a context that we assign to the actions. This way actions can automatically update themselves as new data becomes available, and we avoid the setter/getter boilerplate, at the cost of a less explicit interface (But that could be improved by allowing to define the required properties of a context in c++). By relying on prehandler/posthandler to execute certain actions we simplify the control flow and enable the future extension with handlers that i.e. do encryption etc. --- framework/domain/actions/sinkactions.cpp | 15 +- framework/domain/composercontroller.cpp | 229 ++++++++++---------------- framework/domain/composercontroller.h | 64 +++---- framework/domain/identitiesmodel.cpp | 25 +-- framework/domain/settings/accountsettings.cpp | 29 ++-- 5 files changed, 143 insertions(+), 219 deletions(-) (limited to 'framework/domain') diff --git a/framework/domain/actions/sinkactions.cpp b/framework/domain/actions/sinkactions.cpp index f996b91d..39b39a0a 100644 --- a/framework/domain/actions/sinkactions.cpp +++ b/framework/domain/actions/sinkactions.cpp @@ -98,10 +98,9 @@ static ActionHandlerHelper synchronizeHandler("org.kde.kube.actions.synchronize" static ActionHandlerHelper sendMailHandler("org.kde.kube.actions.sendmail", [](Context *context) -> bool { auto accountId = context->property("accountId").value(); - auto message = context->property("message").value(); - return !accountId.isEmpty() && message; + return !accountId.isEmpty(); }, - [](Context *context) { + ActionHandlerHelper::JobHandler{[](Context *context) -> KAsync::Job { auto accountId = context->property("accountId").value(); auto message = context->property("message").value(); SinkLog() << "Sending a mail: "; @@ -109,7 +108,7 @@ static ActionHandlerHelper sendMailHandler("org.kde.kube.actions.sendmail", Query query; query.containsFilter(ApplicationDomain::ResourceCapabilities::Mail::transport); query.filter(accountId); - Store::fetchAll(query) + return Store::fetchAll(query) .then>([=](const QList &resources) -> KAsync::Job { if (!resources.isEmpty()) { auto resourceId = resources[0]->identifier(); @@ -120,18 +119,18 @@ static ActionHandlerHelper sendMailHandler("org.kde.kube.actions.sendmail", } SinkWarning() << "Failed to find a mailtransport resource"; return KAsync::error(0, "Failed to find a MailTransport resource."); - }).exec(); - } + }); + }} ); static ActionHandlerHelper saveAsDraft("org.kde.kube.actions.save-as-draft", [](Context *context) -> bool { auto accountId = context->property("accountId").value(); - auto message = context->property("message").value(); - return !accountId.isEmpty() && message; + return !accountId.isEmpty(); }, ActionHandlerHelper::JobHandler([](Context *context) -> KAsync::Job { SinkLog() << "Executing the save-as-draft action"; + SinkLog() << *context; const auto accountId = context->property("accountId").value(); const auto message = context->property("message").value(); auto existingMail = context->property("existingMail").value(); diff --git a/framework/domain/composercontroller.cpp b/framework/domain/composercontroller.cpp index 7fd2593d..18ebc4c4 100644 --- a/framework/domain/composercontroller.cpp +++ b/framework/domain/composercontroller.cpp @@ -21,6 +21,7 @@ #include "composercontroller.h" #include #include +#include #include #include #include @@ -39,78 +40,25 @@ SINK_DEBUG_AREA("composercontroller"); -ComposerController::ComposerController(QObject *parent) : QObject(parent) -{ -} - -QString ComposerController::to() const -{ - return m_to; -} - -void ComposerController::setTo(const QString &to) -{ - if(m_to != to) { - m_to = to; - emit toChanged(); - } -} - -QString ComposerController::cc() const -{ - return m_cc; -} - -void ComposerController::setCc(const QString &cc) -{ - if(m_cc != cc) { - m_cc = cc; - emit ccChanged(); - } -} - -QString ComposerController::bcc() const -{ - return m_bcc; -} - -void ComposerController::setBcc(const QString &bcc) -{ - if(m_bcc != bcc) { - m_bcc = bcc; - emit bccChanged(); - } -} +Q_DECLARE_METATYPE(KMime::Types::Mailbox) -QString ComposerController::subject() const -{ - return m_subject; -} - -void ComposerController::setSubject(const QString &subject) +ComposerController::ComposerController(QObject *parent) : QObject(parent) { - if(m_subject != subject) { - m_subject = subject; - emit subjectChanged(); - } } -QString ComposerController::body() const +QString ComposerController::recepientSearchString() const { - return m_body; + return QString(); } -void ComposerController::setBody(const QString &body) +Kube::Context* ComposerController::mailContext() const { - if(m_body != body) { - m_body = body; - emit bodyChanged(); - } + return mContext; } -QString ComposerController::recepientSearchString() const +void ComposerController::setMailContext(Kube::Context *context) { - return QString(); + mContext = context; } void ComposerController::setRecepientSearchString(const QString &s) @@ -134,24 +82,13 @@ QAbstractItemModel *ComposerController::recepientAutocompletionModel() const return model; } -QStringList ComposerController::attachemts() const -{ - return m_attachments; -} - -void ComposerController::addAttachment(const QUrl &fileUrl) -{ - m_attachments.append(fileUrl.toString()); - emit attachmentsChanged(); -} - void ComposerController::setMessage(const KMime::Message::Ptr &msg) { - setTo(msg->to(true)->asUnicodeString()); - setCc(msg->cc(true)->asUnicodeString()); - setSubject(msg->subject(true)->asUnicodeString()); - setBody(msg->body()); - m_msg = QVariant::fromValue(msg); + mContext->setProperty("to", msg->to(true)->asUnicodeString()); + mContext->setProperty("cc", msg->cc(true)->asUnicodeString()); + mContext->setProperty("subject", msg->subject(true)->asUnicodeString()); + mContext->setProperty("body", msg->body()); + mContext->setProperty("existingMessage", QVariant::fromValue(msg)); } void ComposerController::loadMessage(const QVariant &message, bool loadAsDraft) @@ -159,7 +96,7 @@ void ComposerController::loadMessage(const QVariant &message, bool loadAsDraft) Sink::Query query(*message.value()); query.request(); Sink::Store::fetchOne(query).syncThen([this, loadAsDraft](const Sink::ApplicationDomain::Mail &mail) { - m_existingMail = mail; + mContext->setProperty("existingMail", QVariant::fromValue(mail)); const auto mailData = KMime::CRLFtoLF(mail.getMimeMessage()); if (!mailData.isEmpty()) { KMime::Message::Ptr mail(new KMime::Message); @@ -196,84 +133,88 @@ void applyAddresses(const QString &list, std::functionrowCount() > 0) && (m_currentAccountIndex >= 0); + mContext->setProperty("subject", QVariant()); + mContext->setProperty("body", QVariant()); + mContext->setProperty("to", QVariant()); + mContext->setProperty("cc", QVariant()); + mContext->setProperty("bcc", QVariant()); } -KMime::Message::Ptr ComposerController::assembleMessage() + +Kube::ActionHandler *ComposerController::messageHandler() { - auto mail = m_msg.value(); - if (!mail) { - mail = KMime::Message::Ptr::create(); - } - applyAddresses(m_to, [&](const QByteArray &addrSpec, const QByteArray &displayName) { - mail->to(true)->addAddress(addrSpec, displayName); - recordForAutocompletion(addrSpec, displayName); - }); - applyAddresses(m_cc, [&](const QByteArray &addrSpec, const QByteArray &displayName) { - mail->cc(true)->addAddress(addrSpec, displayName); - recordForAutocompletion(addrSpec, displayName); - }); - applyAddresses(m_bcc, [&](const QByteArray &addrSpec, const QByteArray &displayName) { - mail->bcc(true)->addAddress(addrSpec, displayName); - recordForAutocompletion(addrSpec, displayName); - }); - if (!identityIsSet()) { - SinkWarning() << "We don't have an identity to send the mail with."; - } else { - auto currentIndex = identityModel()->index(m_currentAccountIndex, 0); - KMime::Types::Mailbox mb; - mb.setName(currentIndex.data(IdentitiesModel::Username).toString()); - mb.setAddress(currentIndex.data(IdentitiesModel::Address).toString().toUtf8()); - mail->from(true)->addAddress(mb); - mail->subject(true)->fromUnicodeString(m_subject, "utf-8"); - mail->setBody(m_body.toUtf8()); - mail->assemble(); - return mail; - } - return KMime::Message::Ptr(); + return new Kube::ActionHandlerHelper( + [](Kube::Context *context) { + auto identity = context->property("identity"); + return identity.isValid(); + }, + [this](Kube::Context *context) { + auto mail = context->property("existingMessage").value(); + if (!mail) { + mail = KMime::Message::Ptr::create(); + } + applyAddresses(context->property("to").toString(), [&](const QByteArray &addrSpec, const QByteArray &displayName) { + mail->to(true)->addAddress(addrSpec, displayName); + recordForAutocompletion(addrSpec, displayName); + }); + applyAddresses(context->property("cc").toString(), [&](const QByteArray &addrSpec, const QByteArray &displayName) { + mail->cc(true)->addAddress(addrSpec, displayName); + recordForAutocompletion(addrSpec, displayName); + }); + applyAddresses(context->property("bcc").toString(), [&](const QByteArray &addrSpec, const QByteArray &displayName) { + mail->bcc(true)->addAddress(addrSpec, displayName); + recordForAutocompletion(addrSpec, displayName); + }); + + mail->from(true)->addAddress(context->property("identity").value()); + + mail->subject(true)->fromUnicodeString(context->property("subject").toString(), "utf-8"); + mail->setBody(context->property("body").toString().toUtf8()); + mail->assemble(); + + context->setProperty("message", QVariant::fromValue(mail)); + } + ); } -void ComposerController::send() +Kube::Action* ComposerController::saveAsDraftAction() { - auto mail = assembleMessage(); - - //TODO deactivate action if we don't have the identiy set - if (!identityIsSet()) { - SinkWarning() << "We don't have an identity to send the mail with."; - } else { - auto currentAccountId = identityModel()->index(m_currentAccountIndex, 0).data(IdentitiesModel::AccountId).toByteArray(); - - Kube::Context context; - context.setProperty("message", QVariant::fromValue(mail)); - context.setProperty("accountId", QVariant::fromValue(currentAccountId)); - - qDebug() << "Current account " << currentAccountId; - - Kube::Action("org.kde.kube.actions.sendmail", context).execute(); - clear(); - } + auto action = new Kube::Action("org.kde.kube.actions.save-as-draft", *mContext); + action->addPreHandler(messageHandler()); + return action; } -void ComposerController::saveAsDraft() +Kube::Action* ComposerController::sendAction() { - auto mail = assembleMessage(); - auto currentAccountId = identityModel()->index(m_currentAccountIndex, 0).data(IdentitiesModel::AccountId).toByteArray(); + qWarning() << "send action"; + auto action = new Kube::Action("org.kde.kube.actions.sendmail", *mContext); + // action->addPreHandler(identityHandler()); + action->addPreHandler(messageHandler()); + // action->addPreHandler(encryptionHandler()); + return action; +} - Kube::Context context; - context.setProperty("message", QVariant::fromValue(mail)); - context.setProperty("accountId", QVariant::fromValue(currentAccountId)); - context.setProperty("existingMail", QVariant::fromValue(m_existingMail)); - Kube::Action("org.kde.kube.actions.save-as-draft", context).execute(); - clear(); +void ComposerController::setCurrentIdentityIndex(int index) +{ + m_currentAccountIndex = index; + auto currentIndex = identityModel()->index(m_currentAccountIndex, 0); + if (currentIndex.isValid()) { + auto currentAccountId = currentIndex.data(IdentitiesModel::AccountId).toByteArray(); + SinkWarning() << "valid identity for index: " << index << " out of available in model: " << identityModel()->rowCount(); + KMime::Types::Mailbox mb; + mb.setName(currentIndex.data(IdentitiesModel::Username).toString()); + mb.setAddress(currentIndex.data(IdentitiesModel::Address).toString().toUtf8()); + SinkLog() << "Setting current identity: " << mb.prettyAddress() << "Account: " << currentAccountId; + mContext->setProperty("identity", QVariant::fromValue(mb)); + mContext->setProperty("accountId", QVariant::fromValue(currentAccountId)); + } else { + SinkWarning() << "No valid identity for index: " << index << " out of available in model: " << identityModel()->rowCount(); + } } -void ComposerController::clear() +int ComposerController::currentIdentityIndex() const { - setSubject(""); - setBody(""); - setTo(""); - setCc(""); - setBcc(""); + return m_currentAccountIndex; } diff --git a/framework/domain/composercontroller.h b/framework/domain/composercontroller.h index aa2ae0d7..6fad0685 100644 --- a/framework/domain/composercontroller.h +++ b/framework/domain/composercontroller.h @@ -26,6 +26,9 @@ #include #include +#include +#include + namespace KMime { class Message; } @@ -33,34 +36,21 @@ class Message; class ComposerController : public QObject { Q_OBJECT - Q_PROPERTY (QString to READ to WRITE setTo NOTIFY toChanged) - Q_PROPERTY (QString cc READ cc WRITE setCc NOTIFY ccChanged) - Q_PROPERTY (QString bcc READ bcc WRITE setBcc NOTIFY bccChanged) - Q_PROPERTY (QString subject READ subject WRITE setSubject NOTIFY subjectChanged) - Q_PROPERTY (QString body READ body WRITE setBody NOTIFY bodyChanged) + Q_PROPERTY (Kube::Context* mailContext READ mailContext WRITE setMailContext) + Q_PROPERTY (int currentIdentityIndex READ currentIdentityIndex WRITE setCurrentIdentityIndex) + Q_PROPERTY (QString recepientSearchString READ recepientSearchString WRITE setRecepientSearchString) Q_PROPERTY (QAbstractItemModel* recepientAutocompletionModel READ recepientAutocompletionModel CONSTANT) Q_PROPERTY (QAbstractItemModel* identityModel READ identityModel CONSTANT) - Q_PROPERTY (int currentIdentityIndex MEMBER m_currentAccountIndex) - Q_PROPERTY (QStringList attachments READ attachemts NOTIFY attachmentsChanged) + + Q_PROPERTY (Kube::Action* sendAction READ sendAction) + Q_PROPERTY (Kube::Action* saveAsDraftAction READ saveAsDraftAction) public: explicit ComposerController(QObject *parent = Q_NULLPTR); - QString to() const; - void setTo(const QString &to); - - QString cc() const; - void setCc(const QString &cc); - - QString bcc() const; - void setBcc(const QString &bcc); - - QString subject() const; - void setSubject(const QString &subject); - - QString body() const; - void setBody(const QString &body); + Kube::Context* mailContext() const; + void setMailContext(Kube::Context *context); QString recepientSearchString() const; void setRecepientSearchString(const QString &body); @@ -68,36 +58,22 @@ public: QAbstractItemModel *identityModel() const; QAbstractItemModel *recepientAutocompletionModel() const; - QStringList attachemts() const; Q_INVOKABLE void loadMessage(const QVariant &draft, bool loadAsDraft); -signals: - void subjectChanged(); - void bodyChanged(); - void toChanged(); - void ccChanged(); - void bccChanged(); - void fromIndexChanged(); - void attachmentsChanged(); + Kube::Action* sendAction(); + Kube::Action* saveAsDraftAction(); + + void setCurrentIdentityIndex(int index); + int currentIdentityIndex() const; public slots: - void send(); - void saveAsDraft(); void clear(); - void addAttachment(const QUrl &fileUrl); private: - bool identityIsSet() const; + Kube::ActionHandler *messageHandler(); void recordForAutocompletion(const QByteArray &addrSpec, const QByteArray &displayName); void setMessage(const QSharedPointer &msg); - QSharedPointer assembleMessage(); - QString m_to; - QString m_cc; - QString m_bcc; - QString m_subject; - QString m_body; - QStringList m_attachments; - Sink::ApplicationDomain::Mail m_existingMail; - QVariant m_msg; - int m_currentAccountIndex; + + int m_currentAccountIndex = -1; + Kube::Context *mContext; }; diff --git a/framework/domain/identitiesmodel.cpp b/framework/domain/identitiesmodel.cpp index 8f5c4963..33cc191c 100644 --- a/framework/domain/identitiesmodel.cpp +++ b/framework/domain/identitiesmodel.cpp @@ -18,12 +18,17 @@ */ #include "identitiesmodel.h" #include +#include + +using namespace Sink; IdentitiesModel::IdentitiesModel(QObject *parent) : QIdentityProxyModel() { Sink::Query query; query.setFlags(Sink::Query::LiveQuery); - query.requestedProperties << "name" << "username" << "address" << "account"; + query.request() + .request() + .request(); runQuery(query); } @@ -53,21 +58,21 @@ QVariant IdentitiesModel::data(const QModelIndex &idx, int role) const auto srcIdx = mapToSource(idx); switch (role) { case Name: - return srcIdx.sibling(srcIdx.row(), 0).data(Qt::DisplayRole).toString(); + return srcIdx.data(Sink::Store::DomainObjectRole).value()->getName(); case Username: - return srcIdx.sibling(srcIdx.row(), 1).data(Qt::DisplayRole).toString(); + return srcIdx.data(Sink::Store::DomainObjectRole).value()->getName(); case Address: - return srcIdx.sibling(srcIdx.row(), 2).data(Qt::DisplayRole).toString(); + return srcIdx.data(Sink::Store::DomainObjectRole).value()->getAddress(); case IdentityId: - return srcIdx.data(Sink::Store::DomainObjectBaseRole).value()->identifier(); + return srcIdx.data(Sink::Store::DomainObjectRole).value()->identifier(); case AccountId: - return srcIdx.data(Sink::Store::DomainObjectBaseRole).value()->getProperty("account").toByteArray(); + return srcIdx.data(Sink::Store::DomainObjectRole).value()->getAccount(); case AccountName: { - const auto accountId = srcIdx.sibling(srcIdx.row(), 3).data(Qt::DisplayRole).toByteArray(); + const auto accountId = srcIdx.data(Sink::Store::DomainObjectRole).value()->getAccount(); return mAccountNames.value(accountId); } case AccountIcon: { - const auto accountId = srcIdx.sibling(srcIdx.row(), 3).data(Qt::DisplayRole).toByteArray(); + const auto accountId = srcIdx.data(Sink::Store::DomainObjectRole).value()->getAccount(); return mAccountIcons.value(accountId); } case DisplayName: { @@ -85,8 +90,8 @@ void IdentitiesModel::runQuery(const Sink::Query &query) Sink::Store::fetchAll(Sink::Query()) .syncThen >([this](const QList &accounts) { for (const auto &account : accounts) { - mAccountNames.insert(account->identifier(), account->getProperty("name").toString()); - mAccountIcons.insert(account->identifier(), account->getProperty("icon").toString()); + mAccountNames.insert(account->identifier(), account->getName()); + mAccountIcons.insert(account->identifier(), account->getIcon()); } emit layoutChanged(); }).exec(); diff --git a/framework/domain/settings/accountsettings.cpp b/framework/domain/settings/accountsettings.cpp index f2c5a66f..067d1d79 100644 --- a/framework/domain/settings/accountsettings.cpp +++ b/framework/domain/settings/accountsettings.cpp @@ -19,6 +19,7 @@ #include "accountsettings.h" #include +#include #include #include #include @@ -26,6 +27,8 @@ using namespace Sink; using namespace Sink::ApplicationDomain; +SINK_DEBUG_AREA("accountsettings") + AccountSettings::AccountSettings(QObject *parent) : QObject(parent) { @@ -181,7 +184,7 @@ void AccountSettings::loadMaildirResource() emit pathChanged(); } }).onError([](const KAsync::Error &error) { - qWarning() << "Failed to find the maildir resource: " << error.errorMessage; + SinkWarning() << "Failed to find the maildir resource: " << error.errorMessage; }).exec(); } @@ -195,7 +198,7 @@ void AccountSettings::loadMailtransportResource() mSmtpPassword = resource.getProperty("password").toString(); emit smtpResourceChanged(); }).onError([](const KAsync::Error &error) { - qWarning() << "Failed to find the smtp resource: " << error.errorMessage; + SinkWarning() << "Failed to find the smtp resource: " << error.errorMessage; }).exec(); } @@ -209,7 +212,7 @@ void AccountSettings::loadIdentity() mEmailAddress = identity.getAddress(); emit identityChanged(); }).onError([](const KAsync::Error &error) { - qWarning() << "Failed to find the identity resource: " << error.errorMessage; + SinkWarning() << "Failed to find the identity resource: " << error.errorMessage; }).exec(); } @@ -225,7 +228,7 @@ static QByteArray saveResource(const QByteArray &accountIdentifier, const QByteA } Store::modify(resource) .onError([](const KAsync::Error &error) { - qWarning() << "Error while modifying resource: " << error.errorMessage; + SinkWarning() << "Error while modifying resource: " << error.errorMessage; }) .exec(); } else { @@ -236,7 +239,7 @@ static QByteArray saveResource(const QByteArray &accountIdentifier, const QByteA } Store::create(resource) .onError([](const KAsync::Error &error) { - qWarning() << "Error while creating resource: " << error.errorMessage; + SinkWarning() << "Error while creating resource: " << error.errorMessage; }) .exec(); return newIdentifier; @@ -277,7 +280,7 @@ void AccountSettings::saveIdentity() identity.setAddress(mEmailAddress); Store::modify(identity) .onError([](const KAsync::Error &error) { - qWarning() << "Error while modifying identity: " << error.errorMessage; + SinkWarning() << "Error while modifying identity: " << error.errorMessage; }) .exec(); } else { @@ -288,7 +291,7 @@ void AccountSettings::saveIdentity() identity.setAddress(mEmailAddress); Store::create(identity) .onError([](const KAsync::Error &error) { - qWarning() << "Error while creating identity: " << error.errorMessage; + SinkWarning() << "Error while creating identity: " << error.errorMessage; }) .exec(); } @@ -297,12 +300,12 @@ void AccountSettings::saveIdentity() void AccountSettings::removeResource(const QByteArray &identifier) { if (identifier.isEmpty()) { - qWarning() << "We're missing an identifier"; + SinkWarning() << "We're missing an identifier"; } else { SinkResource resource(identifier); Store::remove(resource) .onError([](const KAsync::Error &error) { - qWarning() << "Error while removing resource: " << error.errorMessage; + SinkWarning() << "Error while removing resource: " << error.errorMessage; }) .exec(); } @@ -311,12 +314,12 @@ void AccountSettings::removeResource(const QByteArray &identifier) void AccountSettings::removeAccount() { if (mAccountIdentifier.isEmpty()) { - qWarning() << "We're missing an identifier"; + SinkWarning() << "We're missing an identifier"; } else { SinkAccount account(mAccountIdentifier); Store::remove(account) .onError([](const KAsync::Error &error) { - qWarning() << "Error while removing account: " << error.errorMessage; + SinkWarning() << "Error while removing account: " << error.errorMessage; }) .exec(); } @@ -325,12 +328,12 @@ void AccountSettings::removeAccount() void AccountSettings::removeIdentity() { if (mIdentityIdentifier.isEmpty()) { - qWarning() << "We're missing an identifier"; + SinkWarning() << "We're missing an identifier"; } else { Identity identity(mIdentityIdentifier); Store::remove(identity) .onError([](const KAsync::Error &error) { - qWarning() << "Error while removing identity: " << error.errorMessage; + SinkWarning() << "Error while removing identity: " << error.errorMessage; }) .exec(); } -- cgit v1.2.3