summaryrefslogtreecommitdiffstats
path: root/framework/domain
diff options
context:
space:
mode:
authorChristian Mollekopf <chrigi_1@fastmail.fm>2016-11-17 12:04:41 +0100
committerChristian Mollekopf <chrigi_1@fastmail.fm>2016-11-17 17:57:36 +0100
commit56d0411b0a8bce305220adbf12f6b859abf9f431 (patch)
treeec1e6aeb0bd1b73b6c59d48eb3fa9d623a69a0b4 /framework/domain
parentc633f7c5fce50db60035792526b6c7e84b51149f (diff)
downloadkube-56d0411b0a8bce305220adbf12f6b859abf9f431.tar.gz
kube-56d0411b0a8bce305220adbf12f6b859abf9f431.zip
AutocompleteLineEdit
Diffstat (limited to 'framework/domain')
-rw-r--r--framework/domain/CMakeLists.txt1
-rw-r--r--framework/domain/composercontroller.cpp106
-rw-r--r--framework/domain/composercontroller.h8
-rw-r--r--framework/domain/recepientautocompletionmodel.cpp110
-rw-r--r--framework/domain/recepientautocompletionmodel.h55
5 files changed, 259 insertions, 21 deletions
diff --git a/framework/domain/CMakeLists.txt b/framework/domain/CMakeLists.txt
index 094eac04..24fdb49f 100644
--- a/framework/domain/CMakeLists.txt
+++ b/framework/domain/CMakeLists.txt
@@ -18,6 +18,7 @@ set(mailplugin_SRCS
18 accountsmodel.cpp 18 accountsmodel.cpp
19 outboxmodel.cpp 19 outboxmodel.cpp
20 identitiesmodel.cpp 20 identitiesmodel.cpp
21 recepientautocompletionmodel.cpp
21 settings/accountsettings.cpp 22 settings/accountsettings.cpp
22) 23)
23find_package(KF5 REQUIRED COMPONENTS Package) 24find_package(KF5 REQUIRED COMPONENTS Package)
diff --git a/framework/domain/composercontroller.cpp b/framework/domain/composercontroller.cpp
index b2ad7ecc..7fd2593d 100644
--- a/framework/domain/composercontroller.cpp
+++ b/framework/domain/composercontroller.cpp
@@ -25,14 +25,20 @@
25#include <KMime/Message> 25#include <KMime/Message>
26#include <KCodecs/KEmailAddress> 26#include <KCodecs/KEmailAddress>
27#include <QVariant> 27#include <QVariant>
28#include <QSortFilterProxyModel>
29#include <QList>
28#include <QDebug> 30#include <QDebug>
29#include <QQmlEngine> 31#include <QQmlEngine>
30#include <sink/store.h> 32#include <sink/store.h>
33#include <sink/log.h>
31 34
32#include "accountsmodel.h" 35#include "accountsmodel.h"
33#include "identitiesmodel.h" 36#include "identitiesmodel.h"
37#include "recepientautocompletionmodel.h"
34#include "mailtemplates.h" 38#include "mailtemplates.h"
35 39
40SINK_DEBUG_AREA("composercontroller");
41
36ComposerController::ComposerController(QObject *parent) : QObject(parent) 42ComposerController::ComposerController(QObject *parent) : QObject(parent)
37{ 43{
38} 44}
@@ -102,6 +108,18 @@ void ComposerController::setBody(const QString &body)
102 } 108 }
103} 109}
104 110
111QString ComposerController::recepientSearchString() const
112{
113 return QString();
114}
115
116void ComposerController::setRecepientSearchString(const QString &s)
117{
118 if (auto model = static_cast<RecipientAutocompletionModel*>(recepientAutocompletionModel())) {
119 model->setFilter(s);
120 }
121}
122
105QAbstractItemModel *ComposerController::identityModel() const 123QAbstractItemModel *ComposerController::identityModel() const
106{ 124{
107 static auto model = new IdentitiesModel(); 125 static auto model = new IdentitiesModel();
@@ -109,6 +127,13 @@ QAbstractItemModel *ComposerController::identityModel() const
109 return model; 127 return model;
110} 128}
111 129
130QAbstractItemModel *ComposerController::recepientAutocompletionModel() const
131{
132 static auto model = new RecipientAutocompletionModel();
133 QQmlEngine::setObjectOwnership(model, QQmlEngine::CppOwnership);
134 return model;
135}
136
112QStringList ComposerController::attachemts() const 137QStringList ComposerController::attachemts() const
113{ 138{
114 return m_attachments; 139 return m_attachments;
@@ -153,43 +178,82 @@ void ComposerController::loadMessage(const QVariant &message, bool loadAsDraft)
153 }).exec(); 178 }).exec();
154} 179}
155 180
156KMime::Message::Ptr ComposerController::assembleMessage() 181void ComposerController::recordForAutocompletion(const QByteArray &addrSpec, const QByteArray &displayName)
157{ 182{
158 auto mail = m_msg.value<KMime::Message::Ptr>(); 183 if (auto model = static_cast<RecipientAutocompletionModel*>(recepientAutocompletionModel())) {
159 if (!mail) { 184 model->addEntry(addrSpec, displayName);
160 mail = KMime::Message::Ptr::create();
161 } 185 }
162 for (const auto &to : KEmailAddress::splitAddressList(m_to)) { 186}
187
188void applyAddresses(const QString &list, std::function<void(const QByteArray &, const QByteArray &)> callback)
189{
190 for (const auto &to : KEmailAddress::splitAddressList(list)) {
163 QByteArray displayName; 191 QByteArray displayName;
164 QByteArray addrSpec; 192 QByteArray addrSpec;
165 QByteArray comment; 193 QByteArray comment;
166 KEmailAddress::splitAddress(to.toUtf8(), displayName, addrSpec, comment); 194 KEmailAddress::splitAddress(to.toUtf8(), displayName, addrSpec, comment);
195 callback(addrSpec, displayName);
196 }
197}
198
199bool ComposerController::identityIsSet() const
200{
201 return (identityModel()->rowCount() > 0) && (m_currentAccountIndex >= 0);
202}
203
204KMime::Message::Ptr ComposerController::assembleMessage()
205{
206 auto mail = m_msg.value<KMime::Message::Ptr>();
207 if (!mail) {
208 mail = KMime::Message::Ptr::create();
209 }
210 applyAddresses(m_to, [&](const QByteArray &addrSpec, const QByteArray &displayName) {
167 mail->to(true)->addAddress(addrSpec, displayName); 211 mail->to(true)->addAddress(addrSpec, displayName);
212 recordForAutocompletion(addrSpec, displayName);
213 });
214 applyAddresses(m_cc, [&](const QByteArray &addrSpec, const QByteArray &displayName) {
215 mail->cc(true)->addAddress(addrSpec, displayName);
216 recordForAutocompletion(addrSpec, displayName);
217 });
218 applyAddresses(m_bcc, [&](const QByteArray &addrSpec, const QByteArray &displayName) {
219 mail->bcc(true)->addAddress(addrSpec, displayName);
220 recordForAutocompletion(addrSpec, displayName);
221 });
222 if (!identityIsSet()) {
223 SinkWarning() << "We don't have an identity to send the mail with.";
224 } else {
225 auto currentIndex = identityModel()->index(m_currentAccountIndex, 0);
226 KMime::Types::Mailbox mb;
227 mb.setName(currentIndex.data(IdentitiesModel::Username).toString());
228 mb.setAddress(currentIndex.data(IdentitiesModel::Address).toString().toUtf8());
229 mail->from(true)->addAddress(mb);
230 mail->subject(true)->fromUnicodeString(m_subject, "utf-8");
231 mail->setBody(m_body.toUtf8());
232 mail->assemble();
233 return mail;
168 } 234 }
169 auto currentIndex = identityModel()->index(m_currentAccountIndex, 0); 235 return KMime::Message::Ptr();
170 KMime::Types::Mailbox mb;
171 mb.setName(currentIndex.data(IdentitiesModel::Username).toString());
172 mb.setAddress(currentIndex.data(IdentitiesModel::Address).toString().toUtf8());
173 mail->from(true)->addAddress(mb);
174 mail->subject(true)->fromUnicodeString(m_subject, "utf-8");
175 mail->setBody(m_body.toUtf8());
176 mail->assemble();
177 return mail;
178} 236}
179 237
180void ComposerController::send() 238void ComposerController::send()
181{ 239{
182 auto mail = assembleMessage(); 240 auto mail = assembleMessage();
183 auto currentAccountId = identityModel()->index(m_currentAccountIndex, 0).data(IdentitiesModel::AccountId).toByteArray();
184 241
185 Kube::Context context; 242 //TODO deactivate action if we don't have the identiy set
186 context.setProperty("message", QVariant::fromValue(mail)); 243 if (!identityIsSet()) {
187 context.setProperty("accountId", QVariant::fromValue(currentAccountId)); 244 SinkWarning() << "We don't have an identity to send the mail with.";
245 } else {
246 auto currentAccountId = identityModel()->index(m_currentAccountIndex, 0).data(IdentitiesModel::AccountId).toByteArray();
188 247
189 qDebug() << "Current account " << currentAccountId; 248 Kube::Context context;
249 context.setProperty("message", QVariant::fromValue(mail));
250 context.setProperty("accountId", QVariant::fromValue(currentAccountId));
190 251
191 Kube::Action("org.kde.kube.actions.sendmail", context).execute(); 252 qDebug() << "Current account " << currentAccountId;
192 clear(); 253
254 Kube::Action("org.kde.kube.actions.sendmail", context).execute();
255 clear();
256 }
193} 257}
194 258
195void ComposerController::saveAsDraft() 259void ComposerController::saveAsDraft()
diff --git a/framework/domain/composercontroller.h b/framework/domain/composercontroller.h
index 8390c639..aa2ae0d7 100644
--- a/framework/domain/composercontroller.h
+++ b/framework/domain/composercontroller.h
@@ -38,6 +38,8 @@ class ComposerController : public QObject
38 Q_PROPERTY (QString bcc READ bcc WRITE setBcc NOTIFY bccChanged) 38 Q_PROPERTY (QString bcc READ bcc WRITE setBcc NOTIFY bccChanged)
39 Q_PROPERTY (QString subject READ subject WRITE setSubject NOTIFY subjectChanged) 39 Q_PROPERTY (QString subject READ subject WRITE setSubject NOTIFY subjectChanged)
40 Q_PROPERTY (QString body READ body WRITE setBody NOTIFY bodyChanged) 40 Q_PROPERTY (QString body READ body WRITE setBody NOTIFY bodyChanged)
41 Q_PROPERTY (QString recepientSearchString READ recepientSearchString WRITE setRecepientSearchString)
42 Q_PROPERTY (QAbstractItemModel* recepientAutocompletionModel READ recepientAutocompletionModel CONSTANT)
41 Q_PROPERTY (QAbstractItemModel* identityModel READ identityModel CONSTANT) 43 Q_PROPERTY (QAbstractItemModel* identityModel READ identityModel CONSTANT)
42 Q_PROPERTY (int currentIdentityIndex MEMBER m_currentAccountIndex) 44 Q_PROPERTY (int currentIdentityIndex MEMBER m_currentAccountIndex)
43 Q_PROPERTY (QStringList attachments READ attachemts NOTIFY attachmentsChanged) 45 Q_PROPERTY (QStringList attachments READ attachemts NOTIFY attachmentsChanged)
@@ -60,7 +62,11 @@ public:
60 QString body() const; 62 QString body() const;
61 void setBody(const QString &body); 63 void setBody(const QString &body);
62 64
65 QString recepientSearchString() const;
66 void setRecepientSearchString(const QString &body);
67
63 QAbstractItemModel *identityModel() const; 68 QAbstractItemModel *identityModel() const;
69 QAbstractItemModel *recepientAutocompletionModel() const;
64 70
65 QStringList attachemts() const; 71 QStringList attachemts() const;
66 Q_INVOKABLE void loadMessage(const QVariant &draft, bool loadAsDraft); 72 Q_INVOKABLE void loadMessage(const QVariant &draft, bool loadAsDraft);
@@ -81,6 +87,8 @@ public slots:
81 void addAttachment(const QUrl &fileUrl); 87 void addAttachment(const QUrl &fileUrl);
82 88
83private: 89private:
90 bool identityIsSet() const;
91 void recordForAutocompletion(const QByteArray &addrSpec, const QByteArray &displayName);
84 void setMessage(const QSharedPointer<KMime::Message> &msg); 92 void setMessage(const QSharedPointer<KMime::Message> &msg);
85 QSharedPointer<KMime::Message> assembleMessage(); 93 QSharedPointer<KMime::Message> assembleMessage();
86 QString m_to; 94 QString m_to;
diff --git a/framework/domain/recepientautocompletionmodel.cpp b/framework/domain/recepientautocompletionmodel.cpp
new file mode 100644
index 00000000..4e5fed95
--- /dev/null
+++ b/framework/domain/recepientautocompletionmodel.cpp
@@ -0,0 +1,110 @@
1/*
2 Copyright (c) 2016 Christian Mollekopf <mollekopf@kolabsys.com>
3
4 This library is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Library General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or (at your
7 option) any later version.
8
9 This library is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12 License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to the
16 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 02110-1301, USA.
18*/
19#include "recepientautocompletionmodel.h"
20
21#include <QStandardItemModel>
22#include <QSettings>
23#include <QStandardPaths>
24#include <QSet>
25#include <QDebug>
26#include <QTimer>
27
28RecipientAutocompletionModel::RecipientAutocompletionModel(QObject *parent)
29 : QSortFilterProxyModel(),
30 mSourceModel(new QStandardItemModel),
31 mTimer(new QTimer)
32{
33 setSourceModel(mSourceModel.data());
34 setDynamicSortFilter(true);
35 setFilterCaseSensitivity(Qt::CaseInsensitive);
36 mTimer->setSingleShot(true);
37 QObject::connect(mTimer.data(), &QTimer::timeout, this, &RecipientAutocompletionModel::save);
38
39 load();
40}
41
42RecipientAutocompletionModel::~RecipientAutocompletionModel()
43{
44 save();
45}
46
47static QString getPath()
48{
49 return QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/kube/recepientautocompletion.ini";
50}
51
52void RecipientAutocompletionModel::save()
53{
54 QSet<QString> list;
55 for (int row = 0; row < mSourceModel->rowCount(); row++) {
56 list << mSourceModel->item(row)->data(Text).toString();
57 }
58
59 qWarning() << "Path " << getPath();
60 QSettings settings(getPath(), QSettings::IniFormat);
61 settings.setValue("list", QStringList{list.toList()});
62}
63
64void RecipientAutocompletionModel::load()
65{
66 qWarning() << "Path " << getPath();
67 QSettings settings(getPath(), QSettings::IniFormat);
68 auto list = settings.value("list").toStringList();
69 auto add = [] (const QString &n) {
70 auto item = new QStandardItem{n};
71 item->setData(n, Text);
72 return item;
73 };
74 for (const auto &entry : list) {
75 mSourceModel->appendRow(add(entry));
76 }
77}
78
79QHash< int, QByteArray > RecipientAutocompletionModel::roleNames() const
80{
81 QHash<int, QByteArray> roles;
82 roles[Text] = "text";
83 roles[Color] = "color";
84 return roles;
85}
86
87void RecipientAutocompletionModel::addEntry(const QByteArray &address, const QByteArray &name)
88{
89 auto add = [] (const QString &n) {
90 auto item = new QStandardItem{n};
91 item->setData(n, Text);
92 return item;
93 };
94 auto formattedName = [&] () {
95 if (name.isEmpty()) {
96 return QString(address);
97 }
98 return QString("%1 <%2>").arg(QString(address), QString(name));
99 }();
100 auto matches = mSourceModel->findItems(formattedName);
101 if (matches.isEmpty()) {
102 mSourceModel->appendRow(add(formattedName));
103 mTimer->start(100);
104 }
105}
106
107void RecipientAutocompletionModel::setFilter(const QString &filter)
108{
109 setFilterWildcard("*" + filter +"*");
110}
diff --git a/framework/domain/recepientautocompletionmodel.h b/framework/domain/recepientautocompletionmodel.h
new file mode 100644
index 00000000..7e89e513
--- /dev/null
+++ b/framework/domain/recepientautocompletionmodel.h
@@ -0,0 +1,55 @@
1/*
2 Copyright (c) 2016 Christian Mollekopf <mollekopf@kolabsys.com>
3
4 This library is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Library General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or (at your
7 option) any later version.
8
9 This library is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12 License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to the
16 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 02110-1301, USA.
18*/
19
20#pragma once
21
22#include <QSortFilterProxyModel>
23#include <QScopedPointer>
24
25class QStandardItemModel;
26class QTimer;
27
28class RecipientAutocompletionModel : public QSortFilterProxyModel
29{
30 Q_OBJECT
31
32public:
33 RecipientAutocompletionModel(QObject *parent = Q_NULLPTR);
34 ~RecipientAutocompletionModel();
35
36 enum Roles {
37 Text = Qt::UserRole + 1,
38 Color
39 };
40 Q_ENUMS(Roles)
41
42 QHash<int, QByteArray> roleNames() const Q_DECL_OVERRIDE;
43
44 void addEntry(const QByteArray &address, const QByteArray &name);
45 void setFilter(const QString &);
46
47private slots:
48 void save();
49
50private:
51 void load();
52
53 QScopedPointer<QStandardItemModel> mSourceModel;
54 QScopedPointer<QTimer> mTimer;
55};