diff options
author | Christian Mollekopf <chrigi_1@fastmail.fm> | 2017-04-16 17:47:48 +0200 |
---|---|---|
committer | Christian Mollekopf <chrigi_1@fastmail.fm> | 2017-04-16 17:47:48 +0200 |
commit | ef8a9f2f1d9f91358541b83fab63603aa3001bff (patch) | |
tree | 205a945c83a5029c7f700c0cb9c682a99fba30b2 | |
parent | 899ca952964a09bf2c2304b42d2ce0d859c99c39 (diff) | |
download | kube-ef8a9f2f1d9f91358541b83fab63603aa3001bff.tar.gz kube-ef8a9f2f1d9f91358541b83fab63603aa3001bff.zip |
Don't thread drafts and sent
To do this we:
* Expose from the model wether or not the model is threaded
* Set the relevant properties from the model on the controller (so we
can switch between aggregate and non-aggregate versions)
* Keep the controller in the view it belongs to.
While this works it highlights a couple of issues:
* Controllers are view specific and should be kept within the view.
* The actions we execute in the controller are closely related to the
model. The model is essentially what the user sees, and therefore what
he operatees on.
* Sink should perhaps expose aggregates better. We have to pass around
the values from the model because the model dispatches between
aggregate and non-aggregate property depending on the threaded state.
Similary the controller operates on the thread or not depending on the
threaded state. Perhaps it would be more useful if sink actually
returned the aggregate somehow, with the regular properties. That way
the controller could use the regular properties from the entity it
gets (which would simply either be the aggregate or non-aggregate
depending on the executed query). If the aggregate already contains
all matched ids, then we would also not have to execute an additional
query to get the thread again, the modification would simply be
applied to all ids originally returned.
-rw-r--r-- | components/kube/contents/ui/Kube.qml | 22 | ||||
-rw-r--r-- | framework/qml/ConversationView.qml | 1 | ||||
-rw-r--r-- | framework/qml/MailListView.qml | 35 | ||||
-rw-r--r-- | framework/src/domain/mailcontroller.cpp | 32 | ||||
-rw-r--r-- | framework/src/domain/mailcontroller.h | 8 | ||||
-rw-r--r-- | framework/src/domain/maillistmodel.cpp | 47 | ||||
-rw-r--r-- | framework/src/domain/maillistmodel.h | 7 |
7 files changed, 109 insertions, 43 deletions
diff --git a/components/kube/contents/ui/Kube.qml b/components/kube/contents/ui/Kube.qml index 41e970c6..979f7bd5 100644 --- a/components/kube/contents/ui/Kube.qml +++ b/components/kube/contents/ui/Kube.qml | |||
@@ -89,15 +89,6 @@ Controls2.ApplicationWindow { | |||
89 | //END ActionHandler | 89 | //END ActionHandler |
90 | 90 | ||
91 | //Controller | 91 | //Controller |
92 | Kube.MailController { | ||
93 | id: mailController | ||
94 | Binding on threadLeader { | ||
95 | //!! checks for the availability of the type | ||
96 | when: !!mailListView.currentMail | ||
97 | value: mailListView.currentMail | ||
98 | } | ||
99 | } | ||
100 | |||
101 | Kube.FolderController { | 92 | Kube.FolderController { |
102 | id: folderController | 93 | id: folderController |
103 | Binding on folder { | 94 | Binding on folder { |
@@ -119,19 +110,6 @@ Controls2.ApplicationWindow { | |||
119 | onActivated: folderController.synchronizeAction.execute() | 110 | onActivated: folderController.synchronizeAction.execute() |
120 | enabled: folderController.synchronizeAction.enabled | 111 | enabled: folderController.synchronizeAction.enabled |
121 | } | 112 | } |
122 | Shortcut { | ||
123 | sequence: StandardKey.Delete | ||
124 | onActivated: mailController.moveToTrashAction.execute() | ||
125 | enabled: mailController.moveToTrashAction.enabled | ||
126 | } | ||
127 | Shortcut { | ||
128 | sequence: StandardKey.MoveToNextLine | ||
129 | onActivated: mailListView.currentIndex++ | ||
130 | } | ||
131 | Shortcut { | ||
132 | sequence: StandardKey.MoveToPreviousLine | ||
133 | onActivated: mailListView.currentIndex-- | ||
134 | } | ||
135 | //END Shortcuts | 113 | //END Shortcuts |
136 | 114 | ||
137 | //BEGIN background | 115 | //BEGIN background |
diff --git a/framework/qml/ConversationView.qml b/framework/qml/ConversationView.qml index 8c6e2d38..83771925 100644 --- a/framework/qml/ConversationView.qml +++ b/framework/qml/ConversationView.qml | |||
@@ -149,6 +149,7 @@ Rectangle { | |||
149 | when: !!root.currentMail | 149 | when: !!root.currentMail |
150 | value: root.currentMail | 150 | value: root.currentMail |
151 | } | 151 | } |
152 | operateOnThreads: false | ||
152 | } | 153 | } |
153 | 154 | ||
154 | Timer { | 155 | Timer { |
diff --git a/framework/qml/MailListView.qml b/framework/qml/MailListView.qml index 1e0123cc..27fae7c2 100644 --- a/framework/qml/MailListView.qml +++ b/framework/qml/MailListView.qml | |||
@@ -28,6 +28,9 @@ Item { | |||
28 | property variant parentFolder | 28 | property variant parentFolder |
29 | property variant currentMail: null | 29 | property variant currentMail: null |
30 | property bool isDraft : false | 30 | property bool isDraft : false |
31 | property bool isImportant : false | ||
32 | property bool isTrash : false | ||
33 | property bool isUnread : false | ||
31 | property int currentIndex | 34 | property int currentIndex |
32 | property string filterString: searchBar.text; | 35 | property string filterString: searchBar.text; |
33 | 36 | ||
@@ -35,6 +38,34 @@ Item { | |||
35 | currentMail = null | 38 | currentMail = null |
36 | } | 39 | } |
37 | 40 | ||
41 | Kube.MailController { | ||
42 | id: mailController | ||
43 | Binding on mail { | ||
44 | //!! checks for the availability of the type | ||
45 | when: !!root.currentMail | ||
46 | value: root.currentMail | ||
47 | } | ||
48 | unread: root.isUnread | ||
49 | trash: root.isUnread | ||
50 | important: root.isUnread | ||
51 | draft: root.isUnread | ||
52 | operateOnThreads: mailListModel.isThreaded | ||
53 | } | ||
54 | |||
55 | Shortcut { | ||
56 | sequence: StandardKey.Delete | ||
57 | onActivated: mailController.moveToTrashAction.execute() | ||
58 | enabled: mailController.moveToTrashAction.enabled | ||
59 | } | ||
60 | Shortcut { | ||
61 | sequence: StandardKey.MoveToNextLine | ||
62 | onActivated: root.currentIndex++ | ||
63 | } | ||
64 | Shortcut { | ||
65 | sequence: StandardKey.MoveToPreviousLine | ||
66 | onActivated: root.currentIndex-- | ||
67 | } | ||
68 | |||
38 | ToolBar { | 69 | ToolBar { |
39 | id: toolbar | 70 | id: toolbar |
40 | 71 | ||
@@ -142,9 +173,13 @@ Item { | |||
142 | onCurrentItemChanged: { | 173 | onCurrentItemChanged: { |
143 | root.currentMail = currentItem.currentData.domainObject; | 174 | root.currentMail = currentItem.currentData.domainObject; |
144 | root.isDraft = currentItem.currentData.draft; | 175 | root.isDraft = currentItem.currentData.draft; |
176 | root.isTrash = currentItem.currentData.trash; | ||
177 | root.isImportant = currentItem.currentData.important; | ||
178 | root.isUnread = currentItem.currentData.unread; | ||
145 | } | 179 | } |
146 | 180 | ||
147 | model: Kube.MailListModel { | 181 | model: Kube.MailListModel { |
182 | id: mailListModel | ||
148 | parentFolder: root.parentFolder | 183 | parentFolder: root.parentFolder |
149 | filter: root.filterString | 184 | filter: root.filterString |
150 | } | 185 | } |
diff --git a/framework/src/domain/mailcontroller.cpp b/framework/src/domain/mailcontroller.cpp index fe02afc3..a6c5c555 100644 --- a/framework/src/domain/mailcontroller.cpp +++ b/framework/src/domain/mailcontroller.cpp | |||
@@ -39,7 +39,10 @@ MailController::MailController() | |||
39 | action_moveToFolder{new Kube::ControllerAction{this, &MailController::moveToFolder}} | 39 | action_moveToFolder{new Kube::ControllerAction{this, &MailController::moveToFolder}} |
40 | { | 40 | { |
41 | QObject::connect(this, &MailController::mailChanged, &MailController::updateActions); | 41 | QObject::connect(this, &MailController::mailChanged, &MailController::updateActions); |
42 | QObject::connect(this, &MailController::threadLeaderChanged, &MailController::updateActions); | 42 | QObject::connect(this, &MailController::importantChanged, &MailController::updateActions); |
43 | QObject::connect(this, &MailController::draftChanged, &MailController::updateActions); | ||
44 | QObject::connect(this, &MailController::trashChanged, &MailController::updateActions); | ||
45 | QObject::connect(this, &MailController::unreadChanged, &MailController::updateActions); | ||
43 | updateActions(); | 46 | updateActions(); |
44 | } | 47 | } |
45 | 48 | ||
@@ -47,24 +50,21 @@ void MailController::runModification(const std::function<void(ApplicationDomain: | |||
47 | { | 50 | { |
48 | if (auto mail = getMail()) { | 51 | if (auto mail = getMail()) { |
49 | f(*mail); | 52 | f(*mail); |
50 | run(Store::modify(*mail)); | 53 | if (getOperateOnThreads()) { |
51 | } else if (auto mail = getThreadLeader()) { | 54 | run(Store::modify(Sink::StandardQueries::completeThread(*mail), *mail)); |
52 | f(*mail); | 55 | } else { |
53 | run(Store::modify(Sink::StandardQueries::completeThread(*mail), *mail)); | 56 | run(Store::modify(*mail)); |
57 | } | ||
54 | } | 58 | } |
55 | } | 59 | } |
56 | 60 | ||
57 | void MailController::updateActions() | 61 | void MailController::updateActions() |
58 | { | 62 | { |
59 | auto mail = getMail(); | 63 | if (auto mail = getMail()) { |
60 | if (!mail) { | 64 | action_moveToTrash->setEnabled(!getTrash()); |
61 | mail= getThreadLeader(); | 65 | action_restoreFromTrash->setEnabled(getTrash()); |
62 | } | 66 | action_markAsRead->setEnabled(getUnread()); |
63 | if (mail) { | 67 | action_markAsUnread->setEnabled(getUnread()); |
64 | action_moveToTrash->setEnabled(!mail->getTrash()); | ||
65 | action_restoreFromTrash->setEnabled(mail->getTrash()); | ||
66 | action_markAsRead->setEnabled(mail->getUnread()); | ||
67 | action_markAsUnread->setEnabled(!mail->getUnread()); | ||
68 | } else { | 68 | } else { |
69 | action_moveToTrash->setEnabled(false); | 69 | action_moveToTrash->setEnabled(false); |
70 | action_restoreFromTrash->setEnabled(false); | 70 | action_restoreFromTrash->setEnabled(false); |
@@ -99,8 +99,8 @@ void MailController::markAsImportant() | |||
99 | 99 | ||
100 | void MailController::toggleImportant() | 100 | void MailController::toggleImportant() |
101 | { | 101 | { |
102 | runModification([] (ApplicationDomain::Mail &mail) { | 102 | runModification([this] (ApplicationDomain::Mail &mail) { |
103 | mail.setImportant(!mail.getImportant()); | 103 | mail.setImportant(!getImportant()); |
104 | SinkLog() << "Toggle important " << mail.identifier() << mail.getImportant(); | 104 | SinkLog() << "Toggle important " << mail.identifier() << mail.getImportant(); |
105 | }); | 105 | }); |
106 | } | 106 | } |
diff --git a/framework/src/domain/mailcontroller.h b/framework/src/domain/mailcontroller.h index f6613558..0bc000f1 100644 --- a/framework/src/domain/mailcontroller.h +++ b/framework/src/domain/mailcontroller.h | |||
@@ -25,9 +25,15 @@ | |||
25 | class MailController : public Kube::Controller | 25 | class MailController : public Kube::Controller |
26 | { | 26 | { |
27 | Q_OBJECT | 27 | Q_OBJECT |
28 | //Use this instead of mail property to get overall status of thread. | ||
29 | KUBE_CONTROLLER_PROPERTY(bool, Unread, unread) | ||
30 | KUBE_CONTROLLER_PROPERTY(bool, Important, important) | ||
31 | KUBE_CONTROLLER_PROPERTY(bool, Trash, trash) | ||
32 | KUBE_CONTROLLER_PROPERTY(bool, Draft, draft) | ||
33 | |||
28 | KUBE_CONTROLLER_PROPERTY(Sink::ApplicationDomain::Mail::Ptr, Mail, mail) | 34 | KUBE_CONTROLLER_PROPERTY(Sink::ApplicationDomain::Mail::Ptr, Mail, mail) |
29 | KUBE_CONTROLLER_PROPERTY(Sink::ApplicationDomain::Mail::Ptr, ThreadLeader, threadLeader) | ||
30 | KUBE_CONTROLLER_PROPERTY(Sink::ApplicationDomain::Folder::Ptr, TargetFolder, targetFolder) | 35 | KUBE_CONTROLLER_PROPERTY(Sink::ApplicationDomain::Folder::Ptr, TargetFolder, targetFolder) |
36 | KUBE_CONTROLLER_PROPERTY(bool, OperateOnThreads, operateOnThreads) | ||
31 | KUBE_CONTROLLER_ACTION(markAsRead) | 37 | KUBE_CONTROLLER_ACTION(markAsRead) |
32 | KUBE_CONTROLLER_ACTION(markAsUnread) | 38 | KUBE_CONTROLLER_ACTION(markAsUnread) |
33 | KUBE_CONTROLLER_ACTION(markAsImportant) | 39 | KUBE_CONTROLLER_ACTION(markAsImportant) |
diff --git a/framework/src/domain/maillistmodel.cpp b/framework/src/domain/maillistmodel.cpp index 83340f69..0f477624 100644 --- a/framework/src/domain/maillistmodel.cpp +++ b/framework/src/domain/maillistmodel.cpp | |||
@@ -114,9 +114,17 @@ QVariant MailListModel::data(const QModelIndex &idx, int role) const | |||
114 | case Date: | 114 | case Date: |
115 | return mail->getDate(); | 115 | return mail->getDate(); |
116 | case Unread: | 116 | case Unread: |
117 | return mail->getProperty("unreadCollected").toList().contains(true); | 117 | if (mIsThreaded) { |
118 | return mail->getProperty("unreadCollected").toList().contains(true); | ||
119 | } else { | ||
120 | return mail->getUnread(); | ||
121 | } | ||
118 | case Important: | 122 | case Important: |
119 | return mail->getProperty("importantCollected").toList().contains(true); | 123 | if (mIsThreaded) { |
124 | return mail->getProperty("importantCollected").toList().contains(true); | ||
125 | } else { | ||
126 | return mail->getImportant(); | ||
127 | } | ||
120 | case Draft: | 128 | case Draft: |
121 | return mail->getDraft(); | 129 | return mail->getDraft(); |
122 | case Sent: | 130 | case Sent: |
@@ -133,7 +141,11 @@ QVariant MailListModel::data(const QModelIndex &idx, int role) const | |||
133 | } | 141 | } |
134 | return mail->getMimeMessage(); | 142 | return mail->getMimeMessage(); |
135 | case ThreadSize: | 143 | case ThreadSize: |
136 | return mail->getProperty("count").toInt(); | 144 | if (mIsThreaded) { |
145 | return mail->getProperty("count").toInt(); | ||
146 | } else { | ||
147 | return 1; | ||
148 | } | ||
137 | case Mail: | 149 | case Mail: |
138 | return QVariant::fromValue(mail); | 150 | return QVariant::fromValue(mail); |
139 | case Incomplete: | 151 | case Incomplete: |
@@ -176,6 +188,11 @@ void MailListModel::runQuery(const Sink::Query &query) | |||
176 | setSourceModel(m_model.data()); | 188 | setSourceModel(m_model.data()); |
177 | } | 189 | } |
178 | 190 | ||
191 | bool MailListModel::isThreaded() const | ||
192 | { | ||
193 | return mIsThreaded; | ||
194 | } | ||
195 | |||
179 | void MailListModel::setParentFolder(const QVariant &parentFolder) | 196 | void MailListModel::setParentFolder(const QVariant &parentFolder) |
180 | { | 197 | { |
181 | using namespace Sink::ApplicationDomain; | 198 | using namespace Sink::ApplicationDomain; |
@@ -189,11 +206,33 @@ void MailListModel::setParentFolder(const QVariant &parentFolder) | |||
189 | return; | 206 | return; |
190 | } | 207 | } |
191 | mCurrentQueryItem = folder->identifier(); | 208 | mCurrentQueryItem = folder->identifier(); |
192 | Sink::Query query = Sink::StandardQueries::threadLeaders(*folder); | 209 | if (folder->getSpecialPurpose().contains(Sink::ApplicationDomain::SpecialPurpose::Mail::drafts) || |
210 | folder->getSpecialPurpose().contains(Sink::ApplicationDomain::SpecialPurpose::Mail::sent)) { | ||
211 | mIsThreaded = false; | ||
212 | } else { | ||
213 | mIsThreaded = true; | ||
214 | } | ||
215 | emit isThreadedChanged(); | ||
216 | |||
217 | Sink::Query query = [&] { | ||
218 | if (mIsThreaded) { | ||
219 | return Sink::StandardQueries::threadLeaders(*folder); | ||
220 | } else { | ||
221 | Sink::Query query; | ||
222 | query.setId("threadleaders-unthreaded"); | ||
223 | if (!folder->resourceInstanceIdentifier().isEmpty()) { | ||
224 | query.resourceFilter(folder->resourceInstanceIdentifier()); | ||
225 | } | ||
226 | query.filter<Sink::ApplicationDomain::Mail::Folder>(*folder); | ||
227 | query.sort<Sink::ApplicationDomain::Mail::Date>(); | ||
228 | return query; | ||
229 | } | ||
230 | }(); | ||
193 | if (!folder->getSpecialPurpose().contains(Sink::ApplicationDomain::SpecialPurpose::Mail::trash)) { | 231 | if (!folder->getSpecialPurpose().contains(Sink::ApplicationDomain::SpecialPurpose::Mail::trash)) { |
194 | //Filter trash if this is not a trash folder | 232 | //Filter trash if this is not a trash folder |
195 | query.filter<Sink::ApplicationDomain::Mail::Trash>(false); | 233 | query.filter<Sink::ApplicationDomain::Mail::Trash>(false); |
196 | } | 234 | } |
235 | |||
197 | query.setFlags(Sink::Query::LiveQuery); | 236 | query.setFlags(Sink::Query::LiveQuery); |
198 | query.limit(100); | 237 | query.limit(100); |
199 | query.request<Mail::Subject>(); | 238 | query.request<Mail::Subject>(); |
diff --git a/framework/src/domain/maillistmodel.h b/framework/src/domain/maillistmodel.h index 44347661..5ed081f4 100644 --- a/framework/src/domain/maillistmodel.h +++ b/framework/src/domain/maillistmodel.h | |||
@@ -32,6 +32,7 @@ class MailListModel : public QSortFilterProxyModel | |||
32 | Q_PROPERTY (QVariant parentFolder READ parentFolder WRITE setParentFolder) | 32 | Q_PROPERTY (QVariant parentFolder READ parentFolder WRITE setParentFolder) |
33 | Q_PROPERTY (QVariant mail READ mail WRITE setMail) | 33 | Q_PROPERTY (QVariant mail READ mail WRITE setMail) |
34 | Q_PROPERTY (QString filter READ filter WRITE setFilter) | 34 | Q_PROPERTY (QString filter READ filter WRITE setFilter) |
35 | Q_PROPERTY (bool isThreaded READ isThreaded NOTIFY isThreadedChanged) | ||
35 | 36 | ||
36 | public: | 37 | public: |
37 | enum Status { | 38 | enum Status { |
@@ -49,6 +50,8 @@ public: | |||
49 | bool lessThan(const QModelIndex &left, const QModelIndex &right) const Q_DECL_OVERRIDE; | 50 | bool lessThan(const QModelIndex &left, const QModelIndex &right) const Q_DECL_OVERRIDE; |
50 | bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const Q_DECL_OVERRIDE; | 51 | bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const Q_DECL_OVERRIDE; |
51 | 52 | ||
53 | bool isThreaded() const; | ||
54 | |||
52 | enum Roles { | 55 | enum Roles { |
53 | Subject = Qt::UserRole + 1, | 56 | Subject = Qt::UserRole + 1, |
54 | Sender, | 57 | Sender, |
@@ -84,6 +87,9 @@ public: | |||
84 | void setFilter(const QString &mail); | 87 | void setFilter(const QString &mail); |
85 | QString filter() const; | 88 | QString filter() const; |
86 | 89 | ||
90 | signals: | ||
91 | void isThreadedChanged(); | ||
92 | |||
87 | private: | 93 | private: |
88 | void fetchMail(Sink::ApplicationDomain::Mail::Ptr mail); | 94 | void fetchMail(Sink::ApplicationDomain::Mail::Ptr mail); |
89 | 95 | ||
@@ -91,4 +97,5 @@ private: | |||
91 | bool mFetchMails = false; | 97 | bool mFetchMails = false; |
92 | QSet<QByteArray> mFetchedMails; | 98 | QSet<QByteArray> mFetchedMails; |
93 | QByteArray mCurrentQueryItem; | 99 | QByteArray mCurrentQueryItem; |
100 | bool mIsThreaded = true; | ||
94 | }; | 101 | }; |