Merge lp:~phablet-team/history-service/thread_search_model into lp:history-service

Proposed by Gustavo Pichorim Boiko
Status: Work in progress
Proposed branch: lp:~phablet-team/history-service/thread_search_model
Merge into: lp:history-service
Diff against target: 1280 lines (+645/-114)
21 files modified
Ubuntu/History/CMakeLists.txt (+1/-1)
Ubuntu/History/historygroupedthreadsmodel.cpp (+25/-8)
Ubuntu/History/historythreadmodel.cpp (+172/-16)
Ubuntu/History/historythreadmodel.h (+24/-0)
daemon/historydaemon.cpp (+37/-11)
daemon/historydaemon.h (+11/-0)
daemon/historyservicedbus.cpp (+0/-30)
daemon/historyservicedbus.h (+0/-8)
plugins/sqlite/sqlitehistoryplugin.cpp (+5/-5)
plugins/sqlite/sqlitehistoryplugin.h (+1/-1)
plugins/sqlite/sqlitehistorythreadview.cpp (+226/-4)
plugins/sqlite/sqlitehistorythreadview.h (+28/-1)
src/PluginThreadView.xml (+28/-0)
src/contactmatcher.cpp (+9/-1)
src/pluginthreadview.cpp (+19/-1)
src/pluginthreadview.h (+11/-2)
src/thread.cpp (+13/-4)
src/thread.h (+1/-0)
src/threadview.cpp (+25/-15)
src/threadview.h (+3/-3)
src/threadview_p.h (+6/-3)
To merge this branch: bzr merge lp:~phablet-team/history-service/thread_search_model
Reviewer Review Type Date Requested Status
system-apps-ci-bot continuous-integration Needs Fixing
PS Jenkins bot continuous-integration Needs Fixing
Ubuntu Phablet Team Pending
Review via email: mp+286656@code.launchpad.net

Commit message

Add search capabilities to the thread models.

Description of the change

Add search capabilities to the thread models.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
231. By Gustavo Pichorim Boiko

Fix the interaction with the cached thread grouping.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
232. By Gustavo Pichorim Boiko

Instead of having NextPage() as virtual directly, add a fetchNextPage() virtual
function so that we can use NextPage to preprocess the results.

233. By Gustavo Pichorim Boiko

Revert the approach: the grouping will have to be implemented in the plugin itself.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
234. By Gustavo Pichorim Boiko

Start implementing the grouping all in server side.

235. By Gustavo Pichorim Boiko

Emit the signals in the manager itself so that they can be used in the views.

236. By Gustavo Pichorim Boiko

Make it possible to handle thread changes in the server side view.

237. By Gustavo Pichorim Boiko

Get the signals from the thread view itself and not from the manager as
it will have the threads already filtered.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
238. By Gustavo Pichorim Boiko

Start to add code to handle thread changes in the server side of the thread view.
Also fix the SqlitePluginTest.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
239. By Gustavo Pichorim Boiko

Fix ContactMatcher.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
240. By Gustavo Pichorim Boiko

Fix parsing grouped threads.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
241. By Gustavo Pichorim Boiko

Implement the group updating.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
242. By Gustavo Pichorim Boiko

Fix the dbus connection of signals.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
243. By Gustavo Pichorim Boiko

Handle thread removing and adding.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
system-apps-ci-bot (system-apps-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
244. By Gustavo Pichorim Boiko

Merge trunk

Revision history for this message
system-apps-ci-bot (system-apps-ci-bot) wrote :
review: Needs Fixing (continuous-integration)

Unmerged revisions

244. By Gustavo Pichorim Boiko

Merge trunk

243. By Gustavo Pichorim Boiko

Handle thread removing and adding.

242. By Gustavo Pichorim Boiko

Fix the dbus connection of signals.

241. By Gustavo Pichorim Boiko

Implement the group updating.

240. By Gustavo Pichorim Boiko

Fix parsing grouped threads.

239. By Gustavo Pichorim Boiko

Fix ContactMatcher.

238. By Gustavo Pichorim Boiko

Start to add code to handle thread changes in the server side of the thread view.
Also fix the SqlitePluginTest.

237. By Gustavo Pichorim Boiko

Get the signals from the thread view itself and not from the manager as
it will have the threads already filtered.

236. By Gustavo Pichorim Boiko

Make it possible to handle thread changes in the server side view.

235. By Gustavo Pichorim Boiko

Emit the signals in the manager itself so that they can be used in the views.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'Ubuntu/History/CMakeLists.txt'
2--- Ubuntu/History/CMakeLists.txt 2015-09-28 14:26:09 +0000
3+++ Ubuntu/History/CMakeLists.txt 2017-01-26 18:33:44 +0000
4@@ -26,7 +26,7 @@
5 historyqmltexteventattachment.h
6 historyqmlunionfilter.h
7 historythreadmodel.h
8-)
9+ )
10
11 include_directories(
12 ${CMAKE_SOURCE_DIR}/src
13
14=== modified file 'Ubuntu/History/historygroupedthreadsmodel.cpp'
15--- Ubuntu/History/historygroupedthreadsmodel.cpp 2015-10-08 19:35:40 +0000
16+++ Ubuntu/History/historygroupedthreadsmodel.cpp 2017-01-26 18:33:44 +0000
17@@ -247,25 +247,42 @@
18 removeThreadFromGroup(thread);
19 return;
20 }
21+
22+ // now filter the threads according to the search term
23+ History::Threads filtered = filterThreads(groupedThread.groupedThreads());
24+ if (filtered.isEmpty()) {
25+ return;
26+ }
27+
28+ bool needsUpdating = false;
29+ if (!filtered.contains(groupedThread)) {
30+ groupedThread = filtered.first();
31+ needsUpdating = true;
32+ } else {
33+ // call matchThread just to get the event updated
34+ matchThread(groupedThread);
35+ }
36+
37 int pos = existingPositionForEntry(groupedThread);
38
39 // if the group is empty, we need to insert it into the map
40 if (pos < 0) {
41 HistoryThreadGroup group;
42 int newPos = positionForItem(groupedThread.properties());
43- group.threads = groupedThread.groupedThreads();
44+ group.threads = filtered;
45 group.displayedThread = groupedThread;
46 beginInsertRows(QModelIndex(), newPos, newPos);
47 mGroups.insert(newPos, group);
48 endInsertRows();
49- return;
50+ if (needsUpdating) {
51+ updateDisplayedThread(mGroups[newPos]);
52+ }
53+ } else {
54+ HistoryThreadGroup &group = mGroups[pos];
55+ group.threads = filtered;
56+ updateDisplayedThread(group);
57+ markGroupAsChanged(group);
58 }
59-
60- HistoryThreadGroup &group = mGroups[pos];
61- group.threads = groupedThread.groupedThreads();
62-
63- updateDisplayedThread(group);
64- markGroupAsChanged(group);
65 }
66
67 void HistoryGroupedThreadsModel::removeThreadFromGroup(const History::Thread &thread)
68
69=== modified file 'Ubuntu/History/historythreadmodel.cpp'
70--- Ubuntu/History/historythreadmodel.cpp 2016-06-17 01:49:46 +0000
71+++ Ubuntu/History/historythreadmodel.cpp 2017-01-26 18:33:44 +0000
72@@ -19,10 +19,13 @@
73 * along with this program. If not, see <http://www.gnu.org/licenses/>.
74 */
75
76+#include "eventview.h"
77 #include "historythreadmodel.h"
78 #include "historyqmltexteventattachment.h"
79+#include "intersectionfilter.h"
80 #include "manager.h"
81 #include "threadview.h"
82+#include "utils_p.h"
83 #include "voiceevent.h"
84 #include <QDBusMetaType>
85
86@@ -38,6 +41,7 @@
87 mRoles = HistoryModel::roleNames();
88 mRoles[CountRole] = "count";
89 mRoles[UnreadCountRole] = "unreadCount";
90+ mRoles[ThreadsRole] = "threads";
91 mRoles[ChatType] = "chatType";
92 mRoles[ChatRoomInfo] = "chatRoomInfo";
93
94@@ -100,12 +104,38 @@
95
96 QVariant result;
97 switch (role) {
98- case CountRole:
99- result = thread.count();
100- break;
101- case UnreadCountRole:
102- result = thread.unreadCount();
103- break;
104+ case CountRole: {
105+ if (thread.groupedThreads().isEmpty()) {
106+ result = thread.count();
107+ } else {
108+ int count = 0;
109+ Q_FOREACH(const History::Thread &groupedThread, thread.groupedThreads()) {
110+ count += groupedThread.count();
111+ }
112+ result = count;
113+ }
114+ break;
115+ }
116+ case UnreadCountRole: {
117+ if (thread.groupedThreads().isEmpty()) {
118+ result = thread.unreadCount();
119+ } else {
120+ int count = 0;
121+ Q_FOREACH(const History::Thread &groupedThread, thread.groupedThreads()) {
122+ count += groupedThread.unreadCount();
123+ }
124+ result = count;
125+ }
126+ break;
127+ }
128+ case ThreadsRole: {
129+ QVariantList threads;
130+ Q_FOREACH(const History::Thread &groupedThread, thread.groupedThreads()) {
131+ threads << groupedThread.properties();
132+ }
133+ result = threads;
134+ break;
135+ }
136 case ChatType:
137 result = thread.chatType();
138 break;
139@@ -251,6 +281,32 @@
140 return History::Manager::instance()->removeThreads(threads);
141 }
142
143+QString HistoryThreadModel::searchTerm() const
144+{
145+ return mSearchTerm;
146+}
147+
148+void HistoryThreadModel::setSearchTerm(const QString &term)
149+{
150+ mSearchTerm = term.toLower().trimmed();
151+ Q_EMIT searchTermChanged();
152+ updateQuery();
153+}
154+
155+QString HistoryThreadModel::groupingProperty() const
156+{
157+ return mGroupingProperty;
158+}
159+
160+void HistoryThreadModel::setGroupingProperty(const QString &value)
161+{
162+ mGroupingProperty = value;
163+ mGroupThreads = !mGroupingProperty.isEmpty();
164+ Q_EMIT groupingPropertyChanged();
165+
166+ triggerQueryUpdate();
167+}
168+
169 void HistoryThreadModel::updateQuery()
170 {
171 // remove all events from the model
172@@ -280,19 +336,25 @@
173
174 QVariantMap properties;
175 if (mGroupThreads) {
176- properties[History::FieldGroupingProperty] = History::FieldParticipants;
177+ properties[History::FieldGroupingProperty] = mGroupingProperty;
178 }
179
180 mThreadView = History::Manager::instance()->queryThreads((History::EventType)mType, querySort, queryFilter, properties);
181 connect(mThreadView.data(),
182- SIGNAL(threadsAdded(History::Threads)),
183- SLOT(onThreadsAdded(History::Threads)));
184- connect(mThreadView.data(),
185- SIGNAL(threadsModified(History::Threads)),
186- SLOT(onThreadsModified(History::Threads)));
187- connect(mThreadView.data(),
188- SIGNAL(threadsRemoved(History::Threads)),
189- SLOT(onThreadsRemoved(History::Threads)));
190+ &History::ThreadView::threadsAdded,
191+ [&](History::Threads threads){
192+ onThreadsAdded(filterThreads(threads));
193+ });
194+ connect(mThreadView.data(),
195+ &History::ThreadView::threadsModified,
196+ [&](History::Threads threads){
197+ onThreadsModified(filterThreads(threads));
198+ });
199+ connect(mThreadView.data(),
200+ &History::ThreadView::threadsRemoved,
201+ [&](History::Threads threads){
202+ onThreadsRemoved(filterThreads(threads));
203+ });
204 connect(mThreadView.data(),
205 SIGNAL(invalidated()),
206 SLOT(triggerQueryUpdate()));
207@@ -369,5 +431,99 @@
208
209 History::Threads HistoryThreadModel::fetchNextPage()
210 {
211- return mThreadView->nextPage();
212+ History::Threads filtered;
213+ while (filtered.isEmpty()) {
214+ History::Threads threads = mThreadView->nextPage();
215+ if (threads.isEmpty()) {
216+ return threads;
217+ }
218+ filtered = filterThreads(threads);
219+ }
220+ return filtered;
221+}
222+
223+bool HistoryThreadModel::matchThread(History::Thread &thread)
224+{
225+ if (mSearchTerm.isEmpty()) {
226+ return true;
227+ }
228+
229+ // first try to match the contact alias or the identifier
230+ Q_FOREACH(const History::Participant &participant, thread.participants()) {
231+ if (participant.alias().toLower().contains(mSearchTerm)) {
232+ return true;
233+ }
234+
235+ if (History::Utils::compareIds(thread.accountId(), participant.identifier(), mSearchTerm)) {
236+ return true;
237+ } else if (participant.identifier().contains(mSearchTerm)) {
238+ return true;
239+ }
240+ }
241+
242+ // now the more expensive search: query the events to see if any match
243+ History::Sort sort;
244+ sort.setSortField(History::FieldTimestamp);
245+ sort.setSortOrder(Qt::DescendingOrder);
246+
247+ History::IntersectionFilter topLevelFilter;
248+
249+ // we need to match accountId, threadId and the text
250+ History::Filter filter;
251+ filter.setFilterProperty(History::FieldAccountId);
252+ filter.setFilterValue(thread.accountId());
253+ topLevelFilter.append(filter);
254+
255+ filter.setFilterProperty(History::FieldThreadId);
256+ filter.setFilterValue(thread.threadId());
257+ topLevelFilter.append(filter);
258+
259+ filter.setFilterProperty(History::FieldMessage);
260+ filter.setFilterValue(mSearchTerm);
261+ filter.setMatchFlags(History::MatchContains);
262+ topLevelFilter.append(filter);
263+
264+ History::EventViewPtr eventView = History::Manager::instance()->queryEvents(History::EventTypeText,
265+ sort,
266+ topLevelFilter);
267+ if (eventView.isNull()) {
268+ return false;
269+ }
270+
271+ if (!eventView->isValid()) {
272+ eventView->deleteLater();
273+ return false;
274+ }
275+
276+ // now check if we have events
277+ History::Events events = eventView->nextPage();
278+ if (events.isEmpty()) {
279+ eventView->deleteLater();
280+ return false;
281+ }
282+
283+ QVariantMap threadProperties = thread.properties();
284+ History::TextEvent event = events.first();
285+ QVariantMap eventProperties = event.properties();
286+ Q_FOREACH(const QString &key, eventProperties.keys()) {
287+ threadProperties[key] = eventProperties[key];
288+ }
289+
290+ // overwrite the thread with the one matching the search
291+ thread = History::Thread::fromProperties(threadProperties);
292+ eventView->deleteLater();
293+
294+ // if we got here, the thread already contains the matching event and matches the filters
295+ return true;
296+}
297+
298+History::Threads HistoryThreadModel::filterThreads(const History::Threads &threads)
299+{
300+ History::Threads filtered;
301+ Q_FOREACH(History::Thread thread, threads) {
302+ if (matchThread(thread)) {
303+ filtered << thread;
304+ }
305+ }
306+ return filtered;
307 }
308
309=== modified file 'Ubuntu/History/historythreadmodel.h'
310--- Ubuntu/History/historythreadmodel.h 2016-06-17 01:49:46 +0000
311+++ Ubuntu/History/historythreadmodel.h 2017-01-26 18:33:44 +0000
312@@ -34,11 +34,21 @@
313 {
314 Q_OBJECT
315 Q_ENUMS(ThreadRole)
316+ Q_PROPERTY(QString searchTerm
317+ READ searchTerm
318+ WRITE setSearchTerm
319+ NOTIFY searchTermChanged)
320+ Q_PROPERTY(QString groupingProperty
321+ READ groupingProperty
322+ WRITE setGroupingProperty
323+ NOTIFY groupingPropertyChanged)
324+
325
326 public:
327
328 enum ThreadRole {
329 CountRole = HistoryModel::LastRole,
330+ ThreadsRole,
331 UnreadCountRole,
332 ChatType,
333 ChatRoomInfo,
334@@ -71,6 +81,16 @@
335
336 Q_INVOKABLE bool removeThreads(const QVariantList &threadsProperties);
337
338+ QString searchTerm() const;
339+ void setSearchTerm(const QString &term);
340+
341+ QString groupingProperty() const;
342+ void setGroupingProperty(const QString &value);
343+
344+Q_SIGNALS:
345+ void searchTermChanged();
346+ void groupingPropertyChanged();
347+
348 protected Q_SLOTS:
349 virtual void updateQuery();
350 virtual void onThreadsAdded(const History::Threads &threads);
351@@ -79,12 +99,16 @@
352
353 protected:
354 History::Threads fetchNextPage();
355+ virtual bool matchThread(History::Thread &thread);
356+ virtual History::Threads filterThreads(const History::Threads &threads);
357 bool mCanFetchMore;
358 bool mGroupThreads;
359+ QString mSearchTerm;
360
361 private:
362 History::ThreadViewPtr mThreadView;
363 History::Threads mThreads;
364+ QString mGroupingProperty;
365 QHash<int, QByteArray> mRoles;
366 mutable QMap<History::TextEvent, QList<QVariant> > mAttachmentCache;
367 };
368
369=== modified file 'daemon/historydaemon.cpp'
370--- daemon/historydaemon.cpp 2016-11-24 02:02:32 +0000
371+++ daemon/historydaemon.cpp 2017-01-26 18:33:44 +0000
372@@ -146,6 +146,20 @@
373 SIGNAL(channelAvailable(Tp::TextChannelPtr)),
374 SLOT(onTextChannelAvailable(Tp::TextChannelPtr)));
375
376+ // connect the signals that need to be relayed into DBus
377+ connect(this, SIGNAL(threadsAdded(QList<QVariantMap>)),
378+ &mDBus, SIGNAL(ThreadsAdded(QList<QVariantMap>)));
379+ connect(this, SIGNAL(threadsModified(QList<QVariantMap>)),
380+ &mDBus, SIGNAL(ThreadsModified(QList<QVariantMap>)));
381+ connect(this, SIGNAL(threadsRemoved(QList<QVariantMap>)),
382+ &mDBus, SIGNAL(ThreadsRemoved(QList<QVariantMap>)));
383+ connect(this, SIGNAL(eventsAdded(QList<QVariantMap>)),
384+ &mDBus, SIGNAL(EventsAdded(QList<QVariantMap>)));
385+ connect(this, SIGNAL(eventsModified(QList<QVariantMap>)),
386+ &mDBus, SIGNAL(EventsModified(QList<QVariantMap>)));
387+ connect(this, SIGNAL(eventsRemoved(QList<QVariantMap>)),
388+ &mDBus, SIGNAL(EventsRemoved(QList<QVariantMap>)));
389+
390 // FIXME: we need to do this in a better way, but for now this should do
391 mProtocolFlags["ofono"] = History::MatchPhoneNumber;
392 mProtocolFlags["multimedia"] = History::MatchPhoneNumber;
393@@ -308,7 +322,7 @@
394 map["Requested"] = properties["Requested"];
395 thread[History::FieldChatRoomInfo] = map;
396 }
397- mDBus.notifyThreadsAdded(QList<QVariantMap>() << thread);
398+ Q_EMIT threadsAdded(QList<QVariantMap>() << thread);
399 }
400 }
401 return thread;
402@@ -328,6 +342,8 @@
403 return QString::null;
404 }
405
406+ setupThreadView(view);
407+
408 // FIXME: maybe we should keep a list of views to manually remove them at some point?
409 view->setParent(this);
410 return view->objectPath();
411@@ -428,13 +444,13 @@
412
413 // and last but not least, notify the results
414 if (!newEvents.isEmpty()) {
415- mDBus.notifyEventsAdded(newEvents);
416+ Q_EMIT eventsAdded(newEvents);
417 }
418 if (!modifiedEvents.isEmpty()) {
419- mDBus.notifyEventsModified(modifiedEvents);
420+ Q_EMIT eventsModified(modifiedEvents);
421 }
422 if (!threads.isEmpty()) {
423- mDBus.notifyThreadsModified(threads.values());
424+ Q_EMIT threadsModified(threads.values());
425 }
426 return true;
427 }
428@@ -502,12 +518,12 @@
429
430 mBackend->endBatchOperation();
431
432- mDBus.notifyEventsRemoved(events);
433+ Q_EMIT eventsRemoved(events);
434 if (!removedThreads.isEmpty()) {
435- mDBus.notifyThreadsRemoved(removedThreads.values());
436+ Q_EMIT threadsRemoved(removedThreads.values());
437 }
438 if (!modifiedThreads.isEmpty()) {
439- mDBus.notifyThreadsModified(modifiedThreads.values());
440+ Q_EMIT threadsModified(modifiedThreads.values());
441 }
442 return true;
443 }
444@@ -540,7 +556,7 @@
445 }
446
447 if (!removedEmptyThreads.isEmpty()) {
448- mDBus.notifyThreadsRemoved(removedEmptyThreads.values());
449+ Q_EMIT threadsRemoved(removedEmptyThreads.values());
450 }
451
452 if (events.size() > 0) {
453@@ -812,7 +828,7 @@
454 QString threadId = channel->targetId();
455 if (mBackend->updateRoomParticipants(accountId, threadId, History::EventTypeText, participants)) {
456 QVariantMap updatedThread = getSingleThread(History::EventTypeText, accountId, threadId, QVariantMap());
457- mDBus.notifyThreadsModified(QList<QVariantMap>() << updatedThread);
458+ Q_EMIT threadsModified(QList<QVariantMap>() << updatedThread);
459 }
460 }
461
462@@ -842,7 +858,7 @@
463 QString threadId = channel->targetId();
464 if (mBackend->updateRoomParticipantsRoles(accountId, threadId, History::EventTypeText, participantsRoles)) {
465 QVariantMap updatedThread = getSingleThread(History::EventTypeText, accountId, threadId, QVariantMap());
466- mDBus.notifyThreadsModified(QList<QVariantMap>() << updatedThread);
467+ Q_EMIT threadsModified(QList<QVariantMap>() << updatedThread);
468 }
469
470 // update self roles in room properties
471@@ -877,7 +893,7 @@
472 {
473 if (mBackend->updateRoomInfo(accountId, threadId, type, properties, invalidated)) {
474 QVariantMap thread = getSingleThread(type, accountId, threadId, QVariantMap());
475- mDBus.notifyThreadsModified(QList<QVariantMap>() << thread);
476+ Q_EMIT threadsModified(QList<QVariantMap>() << thread);
477 }
478 }
479
480@@ -1181,6 +1197,16 @@
481 return hash;
482 }
483
484+void HistoryDaemon::setupThreadView(History::PluginThreadView *view)
485+{
486+ connect(this, SIGNAL(threadsAdded(QList<QVariantMap>)),
487+ view, SLOT(onThreadsAdded(QList<QVariantMap>)));
488+ connect(this, SIGNAL(threadsModified(QList<QVariantMap>)),
489+ view, SLOT(onThreadsModified(QList<QVariantMap>)));
490+ connect(this, SIGNAL(threadsRemoved(QList<QVariantMap>)),
491+ view, SLOT(onThreadsRemoved(QList<QVariantMap>)));
492+}
493+
494 QVariantMap HistoryDaemon::getInterfaceProperties(const Tp::AbstractInterface *interface)
495 {
496 QDBusInterface propsInterface(interface->service(), interface->path(), "org.freedesktop.DBus.Properties");
497
498=== modified file 'daemon/historydaemon.h'
499--- daemon/historydaemon.h 2016-10-20 13:56:10 +0000
500+++ daemon/historydaemon.h 2017-01-26 18:33:44 +0000
501@@ -58,6 +58,15 @@
502 bool removeEvents(const QList<QVariantMap> &events);
503 bool removeThreads(const QList<QVariantMap> &threads);
504
505+Q_SIGNALS:
506+ void threadsAdded(const QList<QVariantMap> &threads);
507+ void threadsModified(const QList<QVariantMap> &threads);
508+ void threadsRemoved(const QList<QVariantMap> &threads);
509+
510+ void eventsAdded(const QList<QVariantMap> &events);
511+ void eventsModified(const QList<QVariantMap> &events);
512+ void eventsRemoved(const QList<QVariantMap> &events);
513+
514 private Q_SLOTS:
515 void onObserverCreated();
516 void onCallEnded(const Tp::CallChannelPtr &channel);
517@@ -76,6 +85,8 @@
518 void updateRoomParticipants(const Tp::TextChannelPtr channel);
519 void updateRoomRoles(const Tp::TextChannelPtr &channel, const RolesMap &rolesMap);
520 QString hashThread(const QVariantMap &thread);
521+ void setupThreadView(History::PluginThreadView *view);
522+
523 static QVariantMap getInterfaceProperties(const Tp::AbstractInterface *interface);
524 void updateRoomProperties(const Tp::TextChannelPtr &channel, const QVariantMap &properties);
525 void updateRoomProperties(const QString &accountId, const QString &threadId, History::EventType type, const QVariantMap &properties, const QStringList &invalidated);
526
527=== modified file 'daemon/historyservicedbus.cpp'
528--- daemon/historyservicedbus.cpp 2016-11-24 01:56:01 +0000
529+++ daemon/historyservicedbus.cpp 2017-01-26 18:33:44 +0000
530@@ -45,36 +45,6 @@
531 return QDBusConnection::sessionBus().registerService(History::DBusService);
532 }
533
534-void HistoryServiceDBus::notifyThreadsAdded(const QList<QVariantMap> &threads)
535-{
536- Q_EMIT ThreadsAdded(threads);
537-}
538-
539-void HistoryServiceDBus::notifyThreadsModified(const QList<QVariantMap> &threads)
540-{
541- Q_EMIT ThreadsModified(threads);
542-}
543-
544-void HistoryServiceDBus::notifyThreadsRemoved(const QList<QVariantMap> &threads)
545-{
546- Q_EMIT ThreadsRemoved(threads);
547-}
548-
549-void HistoryServiceDBus::notifyEventsAdded(const QList<QVariantMap> &events)
550-{
551- Q_EMIT EventsAdded(events);
552-}
553-
554-void HistoryServiceDBus::notifyEventsModified(const QList<QVariantMap> &events)
555-{
556- Q_EMIT EventsModified(events);
557-}
558-
559-void HistoryServiceDBus::notifyEventsRemoved(const QList<QVariantMap> &events)
560-{
561- Q_EMIT EventsRemoved(events);
562-}
563-
564 QVariantMap HistoryServiceDBus::ThreadForProperties(const QString &accountId,
565 int type,
566 const QVariantMap &properties,
567
568=== modified file 'daemon/historyservicedbus.h'
569--- daemon/historyservicedbus.h 2016-06-17 01:49:46 +0000
570+++ daemon/historyservicedbus.h 2017-01-26 18:33:44 +0000
571@@ -36,14 +36,6 @@
572
573 bool connectToBus();
574
575- void notifyThreadsAdded(const QList<QVariantMap> &threads);
576- void notifyThreadsModified(const QList<QVariantMap> &threads);
577- void notifyThreadsRemoved(const QList<QVariantMap> &threads);
578-
579- void notifyEventsAdded(const QList<QVariantMap> &events);
580- void notifyEventsModified(const QList<QVariantMap> &events);
581- void notifyEventsRemoved(const QList<QVariantMap> &events);
582-
583 // functions exposed on DBUS
584 QVariantMap ThreadForParticipants(const QString &accountId,
585 int type,
586
587=== modified file 'plugins/sqlite/sqlitehistoryplugin.cpp'
588--- plugins/sqlite/sqlitehistoryplugin.cpp 2016-11-24 01:50:48 +0000
589+++ plugins/sqlite/sqlitehistoryplugin.cpp 2017-01-26 18:33:44 +0000
590@@ -479,10 +479,10 @@
591 return result;
592 }
593
594- QList<QVariantMap> results = parseThreadResults(type, query, properties);
595+ History::Threads results = parseThreadResults(type, query, properties);
596 query.clear();
597 if (!results.isEmpty()) {
598- result = results.first();
599+ result = results.first().properties();
600 }
601
602 return result;
603@@ -1133,9 +1133,9 @@
604 return queryText;
605 }
606
607-QList<QVariantMap> SQLiteHistoryPlugin::parseThreadResults(History::EventType type, QSqlQuery &query, const QVariantMap &properties)
608+History::Threads SQLiteHistoryPlugin::parseThreadResults(History::EventType type, QSqlQuery &query, const QVariantMap &properties)
609 {
610- QList<QVariantMap> threads;
611+ History::Threads threads;
612 QSqlQuery attachmentsQuery(SQLiteDatabase::instance()->database());
613 QList<QVariantMap> attachments;
614 bool grouped = false;
615@@ -1298,7 +1298,7 @@
616 thread[History::FieldRemoteParticipant] = History::ContactMatcher::instance()->contactInfo(accountId, query.value(13).toString(), true);
617 break;
618 }
619- threads << thread;
620+ threads << History::Thread::fromProperties(thread);
621 }
622 return threads;
623 }
624
625=== modified file 'plugins/sqlite/sqlitehistoryplugin.h'
626--- plugins/sqlite/sqlitehistoryplugin.h 2016-09-21 17:44:39 +0000
627+++ plugins/sqlite/sqlitehistoryplugin.h 2017-01-26 18:33:44 +0000
628@@ -86,7 +86,7 @@
629
630 // functions to be used internally
631 QString sqlQueryForThreads(History::EventType type, const QString &condition, const QString &order);
632- QList<QVariantMap> parseThreadResults(History::EventType type, QSqlQuery &query, const QVariantMap &properties = QVariantMap());
633+ History::Threads parseThreadResults(History::EventType type, QSqlQuery &query, const QVariantMap &properties = QVariantMap());
634
635 QString sqlQueryForEvents(History::EventType type, const QString &condition, const QString &order);
636 QList<QVariantMap> parseEventResults(History::EventType type, QSqlQuery &query);
637
638=== modified file 'plugins/sqlite/sqlitehistorythreadview.cpp'
639--- plugins/sqlite/sqlitehistorythreadview.cpp 2016-11-24 01:56:01 +0000
640+++ plugins/sqlite/sqlitehistorythreadview.cpp 2017-01-26 18:33:44 +0000
641@@ -1,5 +1,5 @@
642 /*
643- * Copyright (C) 2013 Canonical, Ltd.
644+ * Copyright (C) 2013-2016 Canonical, Ltd.
645 *
646 * Authors:
647 * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com>
648@@ -35,6 +35,10 @@
649 : History::PluginThreadView(), mPlugin(plugin), mType(type), mSort(sort),
650 mFilter(filter), mPageSize(15), mQuery(SQLiteDatabase::instance()->database()), mOffset(0), mValid(true), mQueryProperties(properties)
651 {
652+ qDebug() << __PRETTY_FUNCTION__;
653+
654+ // connect to the thread signals in the daemon to filter the threads
655+
656 mTemporaryTable = QString("threadview%1%2").arg(QString::number((qulonglong)this), QDateTime::currentDateTimeUtc().toString("yyyyMMddhhmmsszzz"));
657 mQuery.setForwardOnly(true);
658
659@@ -80,7 +84,9 @@
660
661 QList<QVariantMap> SQLiteHistoryThreadView::NextPage()
662 {
663- QList<QVariantMap> threads;
664+ qDebug() << __PRETTY_FUNCTION__;
665+ History::Threads threads;
666+ QList<QVariantMap> props;
667
668 // now prepare for selecting from it
669 mQuery.prepare(QString("SELECT * FROM %1 LIMIT %2 OFFSET %3").arg(mTemporaryTable,
670@@ -89,17 +95,233 @@
671 qCritical() << "Error:" << mQuery.lastError() << mQuery.lastQuery();
672 mValid = false;
673 Q_EMIT Invalidated();
674- return threads;
675+ return props;
676 }
677
678 threads = mPlugin->parseThreadResults(mType, mQuery, mQueryProperties);
679 mOffset += mPageSize;
680 mQuery.clear();
681
682- return threads;
683+ Q_FOREACH(const History::Thread &thread, threads) {
684+ if (threadIsInGroup(thread)) {
685+ continue;
686+ }
687+ createThreadGroup(thread);
688+ props << thread.properties();
689+ }
690+ return props;
691 }
692
693 bool SQLiteHistoryThreadView::IsValid() const
694 {
695 return mValid;
696 }
697+
698+bool SQLiteHistoryThreadView::threadIsInGroup(const History::Thread &thread)
699+{
700+ Q_FOREACH(const HistoryThreadGroup &group, mGroups) {
701+ if (group.threads.contains(thread)) {
702+ return true;
703+ }
704+ }
705+ return false;
706+}
707+
708+void SQLiteHistoryThreadView::createThreadGroup(const History::Thread &thread)
709+{
710+ HistoryThreadGroup group;
711+ group.displayedThread = thread;
712+ group.threads = thread.groupedThreads();
713+ mGroups << group;
714+}
715+
716+History::Threads SQLiteHistoryThreadView::fromList(const QList<QVariantMap> &threads)
717+{
718+ History::Threads result;
719+ Q_FOREACH(const QVariantMap &map, threads) {
720+ result << History::Thread::fromProperties(map);
721+ }
722+ return result;
723+}
724+
725+QList<QVariantMap> SQLiteHistoryThreadView::getGroupedThreads(const QList<QVariantMap> &originalThreads)
726+{
727+ bool needsGrouping = mQueryProperties.contains(History::FieldGroupingProperty);
728+ QList<QVariantMap> grouped;
729+ Q_FOREACH(const QVariantMap &originalThread, originalThreads) {
730+ if (needsGrouping) {
731+ QVariantMap groupedThread = mPlugin->getSingleThread((History::EventType)originalThread[History::FieldType].toInt(),
732+ originalThread[History::FieldAccountId].toString(),
733+ originalThread[History::FieldThreadId].toString(),
734+ mQueryProperties);
735+ grouped << groupedThread;
736+ } else {
737+ grouped << originalThread;
738+ }
739+ }
740+ return grouped;
741+}
742+
743+HistoryThreadGroup SQLiteHistoryThreadView::updateDisplayedThread(HistoryThreadGroup group)
744+{
745+ if (group.threads.isEmpty()) {
746+ return group;
747+ }
748+
749+ History::Thread displayedThread = group.threads.first();
750+ Q_FOREACH(const History::Thread &thread, group.threads) {
751+ if (thread.lastEvent().timestamp() > displayedThread.lastEvent().timestamp()) {
752+ displayedThread = thread;
753+ }
754+ }
755+ group.displayedThread = displayedThread;
756+ return group;
757+}
758+
759+void SQLiteHistoryThreadView::notifyChanges(const QList<QVariantMap> added, const QList<QVariantMap> removed, const QList<QVariantMap> modified)
760+{
761+ qDebug() << "Added:" << added.count() << "Removed:" << removed.count() << "Modified:" << modified.count();
762+
763+ if (!removed.isEmpty()) {
764+ Q_EMIT ThreadsRemoved(removed);
765+ }
766+
767+ if (!added.isEmpty()) {
768+ Q_EMIT ThreadsAdded(added);
769+ }
770+
771+ if (!modified.isEmpty()) {
772+ Q_EMIT ThreadsModified(modified);
773+ }
774+}
775+
776+void SQLiteHistoryThreadView::onThreadsAdded(const QList<QVariantMap> &threads)
777+{
778+ qDebug() << __PRETTY_FUNCTION__;
779+
780+ History::Threads groupedThreads = fromList(getGroupedThreads(threads));
781+
782+ QList<QVariantMap> addedThreads;
783+ QList<QVariantMap> modifiedThreads;
784+ QList<QVariantMap> removedThreads;
785+
786+ // now we need to iterate over the existing groups to see if this new thread belongs to any existing group
787+ Q_FOREACH(const History::Thread &groupedThread, groupedThreads) {
788+ bool found = false;
789+ for (int i = 0; i < mGroups.count(); ++i) {
790+ HistoryThreadGroup &group = mGroups[i];
791+ if (groupedThread.groupedThreads().contains(group.displayedThread)) {
792+ // append the new thread to the group.
793+ group.threads.append(groupedThread);
794+ HistoryThreadGroup updatedGroup = updateDisplayedThread(group);
795+ if (updatedGroup.displayedThread != group.displayedThread) {
796+ // as the displayed thread changed, we need to remove the old thread
797+ // and add the new one
798+ removedThreads << group.displayedThread.properties();
799+ addedThreads << updatedGroup.displayedThread.properties();
800+ } else {
801+ // the thread was just updated, notify as such
802+ modifiedThreads << updatedGroup.displayedThread.properties();
803+ }
804+ group = updatedGroup;
805+ found = true;
806+ break;
807+ }
808+ }
809+
810+ // in case it is not found, we need to create a group for the thread
811+ if (!found) {
812+ HistoryThreadGroup group;
813+ group.displayedThread = groupedThread;
814+ group.threads = groupedThread.groupedThreads();
815+ mGroups << group;
816+ addedThreads << groupedThread.properties();
817+ }
818+ }
819+
820+ // the modified threads here are threads that are currently displayed but they need updating
821+ // since the group itself got one extra thread, so get the latest version of them.
822+ notifyChanges(addedThreads, removedThreads, getGroupedThreads(modifiedThreads));
823+}
824+
825+void SQLiteHistoryThreadView::onThreadsModified(const QList<QVariantMap> &threads)
826+{
827+ qDebug() << __PRETTY_FUNCTION__;
828+ History::Threads groupedThreads = fromList(getGroupedThreads(threads));
829+
830+ QList<QVariantMap> addedThreads;
831+ QList<QVariantMap> modifiedThreads;
832+ QList<QVariantMap> removedThreads;
833+
834+ // now we need to check if the thread is already displayed and if so,
835+ // check if the displayed thread changed.
836+ Q_FOREACH(const History::Thread &groupedThread, groupedThreads) {
837+ bool found = false;
838+ for (int i = 0; i < mGroups.count(); ++i) {
839+ HistoryThreadGroup &group = mGroups[i];
840+ if (group.threads.contains(groupedThread)) {
841+ // remove the old instance and append the new one
842+ group.threads.removeOne(groupedThread);
843+ group.threads.append(groupedThread);
844+ HistoryThreadGroup updatedGroup = updateDisplayedThread(group);
845+ if (updatedGroup.displayedThread != group.displayedThread) {
846+ // as the displayed thread changed, we need to remove the old thread
847+ // and add the new one
848+ removedThreads << group.displayedThread.properties();
849+ addedThreads << updatedGroup.displayedThread.properties();
850+ } else {
851+ // the thread was just updated, notify as such
852+ modifiedThreads << updatedGroup.displayedThread.properties();
853+ }
854+ group = updatedGroup;
855+ found = true;
856+ break;
857+ }
858+ }
859+
860+ // in case it is not found, we need to create a group for the thread
861+ if (!found) {
862+ HistoryThreadGroup group;
863+ group.displayedThread = groupedThread;
864+ group.threads = groupedThread.groupedThreads();
865+ mGroups << group;
866+ addedThreads << groupedThread.properties();
867+ }
868+ }
869+
870+ // the threads marked as "added" are existing threads that were not displayed before
871+ // and that are displayed now. So in order to make sure they are up-to-date, get the latest
872+ // version of the grouping for each of them.
873+ notifyChanges(getGroupedThreads(addedThreads), removedThreads, modifiedThreads);
874+}
875+
876+void SQLiteHistoryThreadView::onThreadsRemoved(const QList<QVariantMap> &threads)
877+{
878+ qDebug() << __PRETTY_FUNCTION__;
879+ QList<QVariantMap> addedThreads;
880+ QList<QVariantMap> modifiedThreads;
881+ QList<QVariantMap> removedThreads;
882+
883+ // try to find the thread in the groups to notify its removal
884+ Q_FOREACH(const History::Thread &thread, fromList(threads)) {
885+ for (int i = 0; i < mGroups.count(); ++i) {
886+ HistoryThreadGroup &group = mGroups[i];
887+ if (group.threads.contains(thread)) {
888+ group.threads.removeOne(thread);
889+ if (group.displayedThread == thread) {
890+ removedThreads << thread.properties();
891+ if (!group.threads.isEmpty()) {
892+ group = updateDisplayedThread(group);
893+ addedThreads << group.displayedThread.properties();
894+ }
895+ } else {
896+ modifiedThreads << group.displayedThread.properties();
897+ }
898+ break;
899+ }
900+ }
901+ }
902+
903+ // we need to update the added and modified threads to get the correct group buddies
904+ notifyChanges(getGroupedThreads(addedThreads), removedThreads, getGroupedThreads(modifiedThreads));
905+}
906
907=== modified file 'plugins/sqlite/sqlitehistorythreadview.h'
908--- plugins/sqlite/sqlitehistorythreadview.h 2015-09-21 20:05:06 +0000
909+++ plugins/sqlite/sqlitehistorythreadview.h 2017-01-26 18:33:44 +0000
910@@ -1,5 +1,5 @@
911 /*
912- * Copyright (C) 2013 Canonical, Ltd.
913+ * Copyright (C) 2013-2016 Canonical, Ltd.
914 *
915 * Authors:
916 * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com>
917@@ -30,6 +30,16 @@
918
919 class SQLiteHistoryPlugin;
920
921+class HistoryThreadGroup {
922+public:
923+ History::Thread displayedThread;
924+ History::Threads threads;
925+
926+ bool operator==(const HistoryThreadGroup &other) const;
927+};
928+
929+typedef QList<HistoryThreadGroup> HistoryThreadGroupList;
930+
931 class SQLiteHistoryThreadView : public History::PluginThreadView
932 {
933 Q_OBJECT
934@@ -44,6 +54,22 @@
935 QList<QVariantMap> NextPage();
936 bool IsValid() const;
937
938+public Q_SLOTS:
939+ virtual void onThreadsAdded(const QList<QVariantMap> &threads);
940+ virtual void onThreadsModified(const QList<QVariantMap> &threads);
941+ virtual void onThreadsRemoved(const QList<QVariantMap> &threads);
942+
943+protected:
944+ bool threadIsInGroup(const History::Thread &thread);
945+ void createThreadGroup(const History::Thread &thread);
946+ History::Threads fromList(const QList<QVariantMap> &threads);
947+ QList<QVariantMap> getGroupedThreads(const QList<QVariantMap> &originalThreads);
948+ HistoryThreadGroup updateDisplayedThread(HistoryThreadGroup group);
949+
950+ void notifyChanges(const QList<QVariantMap> added,
951+ const QList<QVariantMap> removed,
952+ const QList<QVariantMap> modified);
953+
954 private:
955 History::EventType mType;
956 History::Sort mSort;
957@@ -55,6 +81,7 @@
958 int mOffset;
959 bool mValid;
960 QVariantMap mQueryProperties;
961+ HistoryThreadGroupList mGroups;
962 };
963
964 #endif // SQLITEHISTORYTHREADVIEW_H
965
966=== modified file 'src/PluginThreadView.xml'
967--- src/PluginThreadView.xml 2013-09-13 19:24:03 +0000
968+++ src/PluginThreadView.xml 2017-01-26 18:33:44 +0000
969@@ -33,5 +33,33 @@
970 Notifies that this view is no longer valid.
971 ]]></dox:d>
972 </signal>
973+ <signal name="ThreadsAdded">
974+ <dox:d><![CDATA[
975+ Notifies that new threads were added.
976+ ]]></dox:d>
977+ <arg type="a(a{sv})" direction="in"/>
978+ <arg type="a(a{sv})" direction="out"/>
979+ <annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QList &lt; QVariantMap &gt;"/>
980+ <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QList &lt; QVariantMap &gt;"/>
981+ </signal>
982+ <signal name="ThreadsModified">
983+ <dox:d><![CDATA[
984+ Notifies that threads were modified.
985+ ]]></dox:d>
986+ <arg type="a(a{sv})" direction="in"/>
987+ <arg type="a(a{sv})" direction="out"/>
988+ <annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QList &lt; QVariantMap &gt;"/>
989+ <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QList &lt; QVariantMap &gt;"/>
990+ </signal>
991+ <signal name="ThreadsRemoved">
992+ <dox:d><![CDATA[
993+ Notifies that threads were removed.
994+ ]]></dox:d>
995+ <arg type="a(a{sv})" direction="in"/>
996+ <arg type="a(a{sv})" direction="out"/>
997+ <annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QList &lt; QVariantMap &gt;"/>
998+ <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QList &lt; QVariantMap &gt;"/>
999+ </signal>
1000+
1001 </interface>
1002 </node>
1003
1004=== modified file 'src/contactmatcher.cpp'
1005--- src/contactmatcher.cpp 2016-06-17 01:49:46 +0000
1006+++ src/contactmatcher.cpp 2017-01-26 18:33:44 +0000
1007@@ -112,6 +112,10 @@
1008 } else if (!synchronous) {
1009 RequestInfo info{accountId, identifier};
1010 mPendingRequests.append(info);
1011+ map[History::FieldAlias] = "";
1012+ map[History::FieldAvatar] = "";
1013+ map[History::FieldContactId] = "";
1014+ map[History::FieldDetailProperties] = QVariantMap();
1015 }
1016 map[History::FieldIdentifier] = identifier;
1017 map[History::FieldAccountId] = accountId;
1018@@ -196,7 +200,7 @@
1019 QString identifier = it2.key();
1020
1021 Q_FOREACH(const QContact &contact, contacts) {
1022- bool previousMatch = (contactInfo.contains(History::FieldContactId) &&
1023+ bool previousMatch = (hasMatch(contactInfo) &&
1024 contactInfo[History::FieldContactId].toString() == contact.id().toString());
1025 QVariantMap map = matchAndUpdate(accountId, identifier, contact);
1026 if (hasMatch(map)){
1027@@ -406,6 +410,10 @@
1028 QVariantMap contactInfo;
1029 contactInfo[History::FieldIdentifier] = identifier;
1030 contactInfo[History::FieldAccountId] = accountId;
1031+ contactInfo[History::FieldAlias] = "";
1032+ contactInfo[History::FieldAvatar] = "";
1033+ contactInfo[History::FieldContactId] = "";
1034+ contactInfo[History::FieldDetailProperties] = QVariantMap();
1035
1036 if (contact.isEmpty()) {
1037 return contactInfo;
1038
1039=== modified file 'src/pluginthreadview.cpp'
1040--- src/pluginthreadview.cpp 2016-11-24 01:56:01 +0000
1041+++ src/pluginthreadview.cpp 2017-01-26 18:33:44 +0000
1042@@ -1,5 +1,5 @@
1043 /*
1044- * Copyright (C) 2013 Canonical, Ltd.
1045+ * Copyright (C) 2013-2016 Canonical, Ltd.
1046 *
1047 * Authors:
1048 * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com>
1049@@ -71,4 +71,22 @@
1050 return d->objectPath;
1051 }
1052
1053+void PluginThreadView::onThreadsAdded(const QList<QVariantMap> &threads)
1054+{
1055+ // the default implementation just relay the signal
1056+ Q_EMIT ThreadsAdded(threads);
1057+}
1058+
1059+void PluginThreadView::onThreadsModified(const QList<QVariantMap> &threads)
1060+{
1061+ // the default implementation just relay the signal
1062+ Q_EMIT ThreadsModified(threads);
1063+}
1064+
1065+void PluginThreadView::onThreadsRemoved(const QList<QVariantMap> &threads)
1066+{
1067+ // the default implementation just relay the signal
1068+ Q_EMIT ThreadsRemoved(threads);
1069+}
1070+
1071 }
1072
1073=== modified file 'src/pluginthreadview.h'
1074--- src/pluginthreadview.h 2013-11-19 17:52:53 +0000
1075+++ src/pluginthreadview.h 2017-01-26 18:33:44 +0000
1076@@ -1,5 +1,5 @@
1077 /*
1078- * Copyright (C) 2013 Canonical, Ltd.
1079+ * Copyright (C) 2013-2016 Canonical, Ltd.
1080 *
1081 * Authors:
1082 * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com>
1083@@ -26,6 +26,7 @@
1084 #include <QDBusContext>
1085 #include <QScopedPointer>
1086 #include <QVariantMap>
1087+#include <Thread>
1088
1089 namespace History {
1090
1091@@ -41,14 +42,22 @@
1092
1093 // DBus exposed methods
1094 Q_NOREPLY void Destroy();
1095+ virtual bool IsValid() const;
1096 virtual QList<QVariantMap> NextPage() = 0;
1097- virtual bool IsValid() const;
1098
1099 // other methods
1100 QString objectPath() const;
1101
1102 Q_SIGNALS:
1103 void Invalidated();
1104+ void ThreadsAdded(const QList<QVariantMap> &threads);
1105+ void ThreadsModified(const QList<QVariantMap> &threads);
1106+ void ThreadsRemoved(const QList<QVariantMap> &threads);
1107+
1108+public Q_SLOTS:
1109+ virtual void onThreadsAdded(const QList<QVariantMap> &threads);
1110+ virtual void onThreadsModified(const QList<QVariantMap> &threads);
1111+ virtual void onThreadsRemoved(const QList<QVariantMap> &threads);
1112
1113 private:
1114 QScopedPointer<PluginThreadViewPrivate> d_ptr;
1115
1116=== modified file 'src/thread.cpp'
1117--- src/thread.cpp 2016-07-12 02:08:11 +0000
1118+++ src/thread.cpp 2017-01-26 18:33:44 +0000
1119@@ -185,6 +185,11 @@
1120 return true;
1121 }
1122
1123+bool Thread::operator!=(const Thread &other) const
1124+{
1125+ return !(*this == other);
1126+}
1127+
1128 bool Thread::operator<(const Thread &other) const
1129 {
1130 QString selfData = QString::number(type()) + accountId() + threadId();
1131@@ -280,10 +285,14 @@
1132 while (!argument.atEnd()) {
1133 QVariantMap props;
1134 QVariant variant;
1135- argument >> variant;
1136- QDBusArgument innerArgument = variant.value<QDBusArgument>();
1137- if (!innerArgument.atEnd()) {
1138- innerArgument >> props;
1139+ if (argument.currentType() == QDBusArgument::MapType) {
1140+ argument >> props;
1141+ } else {
1142+ argument >> variant;
1143+ QDBusArgument innerArgument = variant.value<QDBusArgument>();
1144+ if (!innerArgument.atEnd()) {
1145+ innerArgument >> props;
1146+ }
1147 }
1148 threads << Thread::fromProperties(props);
1149 }
1150
1151=== modified file 'src/thread.h'
1152--- src/thread.h 2016-07-12 01:59:06 +0000
1153+++ src/thread.h 2017-01-26 18:33:44 +0000
1154@@ -76,6 +76,7 @@
1155
1156 bool isNull() const;
1157 bool operator==(const Thread &other) const;
1158+ bool operator!=(const Thread &other) const;
1159 bool operator<(const Thread &other) const;
1160
1161 virtual QVariantMap properties() const;
1162
1163=== modified file 'src/threadview.cpp'
1164--- src/threadview.cpp 2015-10-01 19:44:45 +0000
1165+++ src/threadview.cpp 2017-01-26 18:33:44 +0000
1166@@ -59,36 +59,48 @@
1167 return filtered;
1168 }
1169
1170-void ThreadViewPrivate::_d_threadsAdded(const History::Threads &threads)
1171+void ThreadViewPrivate::_d_threadsAdded(const QList<QVariantMap> &threads)
1172 {
1173+ qDebug() << __PRETTY_FUNCTION__ << threads.count();
1174 Q_Q(ThreadView);
1175
1176- Threads filtered = filteredThreads(threads);
1177+ Threads filtered = filteredThreads(parseThreads(threads));
1178 if (!filtered.isEmpty()) {
1179 Q_EMIT q->threadsAdded(filtered);
1180 }
1181 }
1182
1183-void ThreadViewPrivate::_d_threadsModified(const Threads &threads)
1184+void ThreadViewPrivate::_d_threadsModified(const QList<QVariantMap> &threads)
1185 {
1186+ qDebug() << __PRETTY_FUNCTION__ << threads.count();
1187 Q_Q(ThreadView);
1188
1189- Threads filtered = filteredThreads(threads);
1190+ Threads filtered = filteredThreads(parseThreads(threads));
1191 if (!filtered.isEmpty()) {
1192 Q_EMIT q->threadsModified(filtered);
1193 }
1194 }
1195
1196-void ThreadViewPrivate::_d_threadsRemoved(const Threads &threads)
1197+void ThreadViewPrivate::_d_threadsRemoved(const QList<QVariantMap> &threads)
1198 {
1199+ qDebug() << __PRETTY_FUNCTION__ << threads.count();
1200 Q_Q(ThreadView);
1201
1202- Threads filtered = filteredThreads(threads);
1203+ Threads filtered = filteredThreads(parseThreads(threads));
1204 if (!filtered.isEmpty()) {
1205 Q_EMIT q->threadsRemoved(filtered);
1206 }
1207 }
1208
1209+Threads ThreadViewPrivate::parseThreads(const QList<QVariantMap> &threads)
1210+{
1211+ Threads result;
1212+ Q_FOREACH(const QVariantMap &thread, threads) {
1213+ result << Thread::fromProperties(thread);
1214+ }
1215+ return result;
1216+}
1217+
1218 // ------------- ThreadView -------------------------------------------------------
1219
1220 ThreadView::ThreadView(History::EventType type,
1221@@ -123,15 +135,13 @@
1222 d_ptr->dbus = new QDBusInterface(History::DBusService, d_ptr->objectPath, History::ThreadViewInterface,
1223 QDBusConnection::sessionBus(), this);
1224
1225- connect(Manager::instance(),
1226- SIGNAL(threadsAdded(History::Threads)),
1227- SLOT(_d_threadsAdded(History::Threads)));
1228- connect(Manager::instance(),
1229- SIGNAL(threadsModified(History::Threads)),
1230- SLOT(_d_threadsModified(History::Threads)));
1231- connect(Manager::instance(),
1232- SIGNAL(threadsRemoved(History::Threads)),
1233- SLOT(_d_threadsRemoved(History::Threads)));
1234+ QDBusConnection connection = QDBusConnection::sessionBus();
1235+ connection.connect(d_ptr->dbus->service(), d_ptr->dbus->path(), d_ptr->dbus->interface(), "ThreadsAdded",
1236+ this, SLOT(_d_threadsAdded(QList<QVariantMap>)));
1237+ connection.connect(d_ptr->dbus->service(), d_ptr->dbus->path(), d_ptr->dbus->interface(), "ThreadsModified",
1238+ this, SLOT(_d_threadsModified(QList<QVariantMap>)));
1239+ connection.connect(d_ptr->dbus->service(), d_ptr->dbus->path(), d_ptr->dbus->interface(), "ThreadsRemoved",
1240+ this, SLOT(_d_threadsRemoved(QList<QVariantMap>)));
1241 }
1242
1243 ThreadView::~ThreadView()
1244
1245=== modified file 'src/threadview.h'
1246--- src/threadview.h 2015-09-21 20:05:06 +0000
1247+++ src/threadview.h 2017-01-26 18:33:44 +0000
1248@@ -55,9 +55,9 @@
1249 void invalidated();
1250
1251 private:
1252- Q_PRIVATE_SLOT(d_func(), void _d_threadsAdded(const History::Threads &threads))
1253- Q_PRIVATE_SLOT(d_func(), void _d_threadsModified(const History::Threads &threads))
1254- Q_PRIVATE_SLOT(d_func(), void _d_threadsRemoved(const History::Threads &threads))
1255+ Q_PRIVATE_SLOT(d_func(), void _d_threadsAdded(const QList<QVariantMap> &threads))
1256+ Q_PRIVATE_SLOT(d_func(), void _d_threadsModified(const QList<QVariantMap> &threads))
1257+ Q_PRIVATE_SLOT(d_func(), void _d_threadsRemoved(const QList<QVariantMap> &threads))
1258 QScopedPointer<ThreadViewPrivate> d_ptr;
1259
1260 };
1261
1262=== modified file 'src/threadview_p.h'
1263--- src/threadview_p.h 2013-09-17 21:33:34 +0000
1264+++ src/threadview_p.h 2017-01-26 18:33:44 +0000
1265@@ -47,9 +47,12 @@
1266 Threads filteredThreads(const Threads &threads);
1267
1268 // private slots
1269- void _d_threadsAdded(const History::Threads &threads);
1270- void _d_threadsModified(const History::Threads &threads);
1271- void _d_threadsRemoved(const History::Threads &threads);
1272+ void _d_threadsAdded(const QList<QVariantMap> &threads);
1273+ void _d_threadsModified(const QList<QVariantMap> &threads);
1274+ void _d_threadsRemoved(const QList<QVariantMap> &threads);
1275+
1276+ protected:
1277+ Threads parseThreads(const QList<QVariantMap> &threads);
1278
1279 ThreadView *q_ptr;
1280 };

Subscribers

People subscribed via source and target branches

to all changes: