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
=== modified file 'Ubuntu/History/CMakeLists.txt'
--- Ubuntu/History/CMakeLists.txt 2015-09-28 14:26:09 +0000
+++ Ubuntu/History/CMakeLists.txt 2017-01-26 18:33:44 +0000
@@ -26,7 +26,7 @@
26 historyqmltexteventattachment.h26 historyqmltexteventattachment.h
27 historyqmlunionfilter.h27 historyqmlunionfilter.h
28 historythreadmodel.h28 historythreadmodel.h
29)29 )
3030
31include_directories(31include_directories(
32 ${CMAKE_SOURCE_DIR}/src32 ${CMAKE_SOURCE_DIR}/src
3333
=== modified file 'Ubuntu/History/historygroupedthreadsmodel.cpp'
--- Ubuntu/History/historygroupedthreadsmodel.cpp 2015-10-08 19:35:40 +0000
+++ Ubuntu/History/historygroupedthreadsmodel.cpp 2017-01-26 18:33:44 +0000
@@ -247,25 +247,42 @@
247 removeThreadFromGroup(thread);247 removeThreadFromGroup(thread);
248 return;248 return;
249 }249 }
250
251 // now filter the threads according to the search term
252 History::Threads filtered = filterThreads(groupedThread.groupedThreads());
253 if (filtered.isEmpty()) {
254 return;
255 }
256
257 bool needsUpdating = false;
258 if (!filtered.contains(groupedThread)) {
259 groupedThread = filtered.first();
260 needsUpdating = true;
261 } else {
262 // call matchThread just to get the event updated
263 matchThread(groupedThread);
264 }
265
250 int pos = existingPositionForEntry(groupedThread);266 int pos = existingPositionForEntry(groupedThread);
251267
252 // if the group is empty, we need to insert it into the map268 // if the group is empty, we need to insert it into the map
253 if (pos < 0) {269 if (pos < 0) {
254 HistoryThreadGroup group;270 HistoryThreadGroup group;
255 int newPos = positionForItem(groupedThread.properties());271 int newPos = positionForItem(groupedThread.properties());
256 group.threads = groupedThread.groupedThreads();272 group.threads = filtered;
257 group.displayedThread = groupedThread;273 group.displayedThread = groupedThread;
258 beginInsertRows(QModelIndex(), newPos, newPos);274 beginInsertRows(QModelIndex(), newPos, newPos);
259 mGroups.insert(newPos, group);275 mGroups.insert(newPos, group);
260 endInsertRows();276 endInsertRows();
261 return;277 if (needsUpdating) {
278 updateDisplayedThread(mGroups[newPos]);
279 }
280 } else {
281 HistoryThreadGroup &group = mGroups[pos];
282 group.threads = filtered;
283 updateDisplayedThread(group);
284 markGroupAsChanged(group);
262 }285 }
263
264 HistoryThreadGroup &group = mGroups[pos];
265 group.threads = groupedThread.groupedThreads();
266
267 updateDisplayedThread(group);
268 markGroupAsChanged(group);
269}286}
270287
271void HistoryGroupedThreadsModel::removeThreadFromGroup(const History::Thread &thread)288void HistoryGroupedThreadsModel::removeThreadFromGroup(const History::Thread &thread)
272289
=== modified file 'Ubuntu/History/historythreadmodel.cpp'
--- Ubuntu/History/historythreadmodel.cpp 2016-06-17 01:49:46 +0000
+++ Ubuntu/History/historythreadmodel.cpp 2017-01-26 18:33:44 +0000
@@ -19,10 +19,13 @@
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */20 */
2121
22#include "eventview.h"
22#include "historythreadmodel.h"23#include "historythreadmodel.h"
23#include "historyqmltexteventattachment.h"24#include "historyqmltexteventattachment.h"
25#include "intersectionfilter.h"
24#include "manager.h"26#include "manager.h"
25#include "threadview.h"27#include "threadview.h"
28#include "utils_p.h"
26#include "voiceevent.h"29#include "voiceevent.h"
27#include <QDBusMetaType>30#include <QDBusMetaType>
2831
@@ -38,6 +41,7 @@
38 mRoles = HistoryModel::roleNames();41 mRoles = HistoryModel::roleNames();
39 mRoles[CountRole] = "count";42 mRoles[CountRole] = "count";
40 mRoles[UnreadCountRole] = "unreadCount";43 mRoles[UnreadCountRole] = "unreadCount";
44 mRoles[ThreadsRole] = "threads";
41 mRoles[ChatType] = "chatType";45 mRoles[ChatType] = "chatType";
42 mRoles[ChatRoomInfo] = "chatRoomInfo";46 mRoles[ChatRoomInfo] = "chatRoomInfo";
4347
@@ -100,12 +104,38 @@
100104
101 QVariant result;105 QVariant result;
102 switch (role) {106 switch (role) {
103 case CountRole:107 case CountRole: {
104 result = thread.count();108 if (thread.groupedThreads().isEmpty()) {
105 break;109 result = thread.count();
106 case UnreadCountRole:110 } else {
107 result = thread.unreadCount();111 int count = 0;
108 break;112 Q_FOREACH(const History::Thread &groupedThread, thread.groupedThreads()) {
113 count += groupedThread.count();
114 }
115 result = count;
116 }
117 break;
118 }
119 case UnreadCountRole: {
120 if (thread.groupedThreads().isEmpty()) {
121 result = thread.unreadCount();
122 } else {
123 int count = 0;
124 Q_FOREACH(const History::Thread &groupedThread, thread.groupedThreads()) {
125 count += groupedThread.unreadCount();
126 }
127 result = count;
128 }
129 break;
130 }
131 case ThreadsRole: {
132 QVariantList threads;
133 Q_FOREACH(const History::Thread &groupedThread, thread.groupedThreads()) {
134 threads << groupedThread.properties();
135 }
136 result = threads;
137 break;
138 }
109 case ChatType:139 case ChatType:
110 result = thread.chatType();140 result = thread.chatType();
111 break;141 break;
@@ -251,6 +281,32 @@
251 return History::Manager::instance()->removeThreads(threads);281 return History::Manager::instance()->removeThreads(threads);
252}282}
253283
284QString HistoryThreadModel::searchTerm() const
285{
286 return mSearchTerm;
287}
288
289void HistoryThreadModel::setSearchTerm(const QString &term)
290{
291 mSearchTerm = term.toLower().trimmed();
292 Q_EMIT searchTermChanged();
293 updateQuery();
294}
295
296QString HistoryThreadModel::groupingProperty() const
297{
298 return mGroupingProperty;
299}
300
301void HistoryThreadModel::setGroupingProperty(const QString &value)
302{
303 mGroupingProperty = value;
304 mGroupThreads = !mGroupingProperty.isEmpty();
305 Q_EMIT groupingPropertyChanged();
306
307 triggerQueryUpdate();
308}
309
254void HistoryThreadModel::updateQuery()310void HistoryThreadModel::updateQuery()
255{311{
256 // remove all events from the model312 // remove all events from the model
@@ -280,19 +336,25 @@
280336
281 QVariantMap properties;337 QVariantMap properties;
282 if (mGroupThreads) {338 if (mGroupThreads) {
283 properties[History::FieldGroupingProperty] = History::FieldParticipants;339 properties[History::FieldGroupingProperty] = mGroupingProperty;
284 }340 }
285341
286 mThreadView = History::Manager::instance()->queryThreads((History::EventType)mType, querySort, queryFilter, properties);342 mThreadView = History::Manager::instance()->queryThreads((History::EventType)mType, querySort, queryFilter, properties);
287 connect(mThreadView.data(),343 connect(mThreadView.data(),
288 SIGNAL(threadsAdded(History::Threads)),344 &History::ThreadView::threadsAdded,
289 SLOT(onThreadsAdded(History::Threads)));345 [&](History::Threads threads){
290 connect(mThreadView.data(),346 onThreadsAdded(filterThreads(threads));
291 SIGNAL(threadsModified(History::Threads)),347 });
292 SLOT(onThreadsModified(History::Threads)));348 connect(mThreadView.data(),
293 connect(mThreadView.data(),349 &History::ThreadView::threadsModified,
294 SIGNAL(threadsRemoved(History::Threads)),350 [&](History::Threads threads){
295 SLOT(onThreadsRemoved(History::Threads)));351 onThreadsModified(filterThreads(threads));
352 });
353 connect(mThreadView.data(),
354 &History::ThreadView::threadsRemoved,
355 [&](History::Threads threads){
356 onThreadsRemoved(filterThreads(threads));
357 });
296 connect(mThreadView.data(),358 connect(mThreadView.data(),
297 SIGNAL(invalidated()),359 SIGNAL(invalidated()),
298 SLOT(triggerQueryUpdate()));360 SLOT(triggerQueryUpdate()));
@@ -369,5 +431,99 @@
369431
370History::Threads HistoryThreadModel::fetchNextPage()432History::Threads HistoryThreadModel::fetchNextPage()
371{433{
372 return mThreadView->nextPage();434 History::Threads filtered;
435 while (filtered.isEmpty()) {
436 History::Threads threads = mThreadView->nextPage();
437 if (threads.isEmpty()) {
438 return threads;
439 }
440 filtered = filterThreads(threads);
441 }
442 return filtered;
443}
444
445bool HistoryThreadModel::matchThread(History::Thread &thread)
446{
447 if (mSearchTerm.isEmpty()) {
448 return true;
449 }
450
451 // first try to match the contact alias or the identifier
452 Q_FOREACH(const History::Participant &participant, thread.participants()) {
453 if (participant.alias().toLower().contains(mSearchTerm)) {
454 return true;
455 }
456
457 if (History::Utils::compareIds(thread.accountId(), participant.identifier(), mSearchTerm)) {
458 return true;
459 } else if (participant.identifier().contains(mSearchTerm)) {
460 return true;
461 }
462 }
463
464 // now the more expensive search: query the events to see if any match
465 History::Sort sort;
466 sort.setSortField(History::FieldTimestamp);
467 sort.setSortOrder(Qt::DescendingOrder);
468
469 History::IntersectionFilter topLevelFilter;
470
471 // we need to match accountId, threadId and the text
472 History::Filter filter;
473 filter.setFilterProperty(History::FieldAccountId);
474 filter.setFilterValue(thread.accountId());
475 topLevelFilter.append(filter);
476
477 filter.setFilterProperty(History::FieldThreadId);
478 filter.setFilterValue(thread.threadId());
479 topLevelFilter.append(filter);
480
481 filter.setFilterProperty(History::FieldMessage);
482 filter.setFilterValue(mSearchTerm);
483 filter.setMatchFlags(History::MatchContains);
484 topLevelFilter.append(filter);
485
486 History::EventViewPtr eventView = History::Manager::instance()->queryEvents(History::EventTypeText,
487 sort,
488 topLevelFilter);
489 if (eventView.isNull()) {
490 return false;
491 }
492
493 if (!eventView->isValid()) {
494 eventView->deleteLater();
495 return false;
496 }
497
498 // now check if we have events
499 History::Events events = eventView->nextPage();
500 if (events.isEmpty()) {
501 eventView->deleteLater();
502 return false;
503 }
504
505 QVariantMap threadProperties = thread.properties();
506 History::TextEvent event = events.first();
507 QVariantMap eventProperties = event.properties();
508 Q_FOREACH(const QString &key, eventProperties.keys()) {
509 threadProperties[key] = eventProperties[key];
510 }
511
512 // overwrite the thread with the one matching the search
513 thread = History::Thread::fromProperties(threadProperties);
514 eventView->deleteLater();
515
516 // if we got here, the thread already contains the matching event and matches the filters
517 return true;
518}
519
520History::Threads HistoryThreadModel::filterThreads(const History::Threads &threads)
521{
522 History::Threads filtered;
523 Q_FOREACH(History::Thread thread, threads) {
524 if (matchThread(thread)) {
525 filtered << thread;
526 }
527 }
528 return filtered;
373}529}
374530
=== modified file 'Ubuntu/History/historythreadmodel.h'
--- Ubuntu/History/historythreadmodel.h 2016-06-17 01:49:46 +0000
+++ Ubuntu/History/historythreadmodel.h 2017-01-26 18:33:44 +0000
@@ -34,11 +34,21 @@
34{34{
35 Q_OBJECT35 Q_OBJECT
36 Q_ENUMS(ThreadRole)36 Q_ENUMS(ThreadRole)
37 Q_PROPERTY(QString searchTerm
38 READ searchTerm
39 WRITE setSearchTerm
40 NOTIFY searchTermChanged)
41 Q_PROPERTY(QString groupingProperty
42 READ groupingProperty
43 WRITE setGroupingProperty
44 NOTIFY groupingPropertyChanged)
45
3746
38public:47public:
3948
40 enum ThreadRole {49 enum ThreadRole {
41 CountRole = HistoryModel::LastRole,50 CountRole = HistoryModel::LastRole,
51 ThreadsRole,
42 UnreadCountRole,52 UnreadCountRole,
43 ChatType,53 ChatType,
44 ChatRoomInfo,54 ChatRoomInfo,
@@ -71,6 +81,16 @@
7181
72 Q_INVOKABLE bool removeThreads(const QVariantList &threadsProperties);82 Q_INVOKABLE bool removeThreads(const QVariantList &threadsProperties);
7383
84 QString searchTerm() const;
85 void setSearchTerm(const QString &term);
86
87 QString groupingProperty() const;
88 void setGroupingProperty(const QString &value);
89
90Q_SIGNALS:
91 void searchTermChanged();
92 void groupingPropertyChanged();
93
74protected Q_SLOTS:94protected Q_SLOTS:
75 virtual void updateQuery();95 virtual void updateQuery();
76 virtual void onThreadsAdded(const History::Threads &threads);96 virtual void onThreadsAdded(const History::Threads &threads);
@@ -79,12 +99,16 @@
7999
80protected:100protected:
81 History::Threads fetchNextPage();101 History::Threads fetchNextPage();
102 virtual bool matchThread(History::Thread &thread);
103 virtual History::Threads filterThreads(const History::Threads &threads);
82 bool mCanFetchMore;104 bool mCanFetchMore;
83 bool mGroupThreads;105 bool mGroupThreads;
106 QString mSearchTerm;
84107
85private:108private:
86 History::ThreadViewPtr mThreadView;109 History::ThreadViewPtr mThreadView;
87 History::Threads mThreads;110 History::Threads mThreads;
111 QString mGroupingProperty;
88 QHash<int, QByteArray> mRoles;112 QHash<int, QByteArray> mRoles;
89 mutable QMap<History::TextEvent, QList<QVariant> > mAttachmentCache;113 mutable QMap<History::TextEvent, QList<QVariant> > mAttachmentCache;
90};114};
91115
=== modified file 'daemon/historydaemon.cpp'
--- daemon/historydaemon.cpp 2016-11-24 02:02:32 +0000
+++ daemon/historydaemon.cpp 2017-01-26 18:33:44 +0000
@@ -146,6 +146,20 @@
146 SIGNAL(channelAvailable(Tp::TextChannelPtr)),146 SIGNAL(channelAvailable(Tp::TextChannelPtr)),
147 SLOT(onTextChannelAvailable(Tp::TextChannelPtr)));147 SLOT(onTextChannelAvailable(Tp::TextChannelPtr)));
148148
149 // connect the signals that need to be relayed into DBus
150 connect(this, SIGNAL(threadsAdded(QList<QVariantMap>)),
151 &mDBus, SIGNAL(ThreadsAdded(QList<QVariantMap>)));
152 connect(this, SIGNAL(threadsModified(QList<QVariantMap>)),
153 &mDBus, SIGNAL(ThreadsModified(QList<QVariantMap>)));
154 connect(this, SIGNAL(threadsRemoved(QList<QVariantMap>)),
155 &mDBus, SIGNAL(ThreadsRemoved(QList<QVariantMap>)));
156 connect(this, SIGNAL(eventsAdded(QList<QVariantMap>)),
157 &mDBus, SIGNAL(EventsAdded(QList<QVariantMap>)));
158 connect(this, SIGNAL(eventsModified(QList<QVariantMap>)),
159 &mDBus, SIGNAL(EventsModified(QList<QVariantMap>)));
160 connect(this, SIGNAL(eventsRemoved(QList<QVariantMap>)),
161 &mDBus, SIGNAL(EventsRemoved(QList<QVariantMap>)));
162
149 // FIXME: we need to do this in a better way, but for now this should do163 // FIXME: we need to do this in a better way, but for now this should do
150 mProtocolFlags["ofono"] = History::MatchPhoneNumber;164 mProtocolFlags["ofono"] = History::MatchPhoneNumber;
151 mProtocolFlags["multimedia"] = History::MatchPhoneNumber;165 mProtocolFlags["multimedia"] = History::MatchPhoneNumber;
@@ -308,7 +322,7 @@
308 map["Requested"] = properties["Requested"];322 map["Requested"] = properties["Requested"];
309 thread[History::FieldChatRoomInfo] = map;323 thread[History::FieldChatRoomInfo] = map;
310 }324 }
311 mDBus.notifyThreadsAdded(QList<QVariantMap>() << thread);325 Q_EMIT threadsAdded(QList<QVariantMap>() << thread);
312 }326 }
313 }327 }
314 return thread;328 return thread;
@@ -328,6 +342,8 @@
328 return QString::null;342 return QString::null;
329 }343 }
330344
345 setupThreadView(view);
346
331 // FIXME: maybe we should keep a list of views to manually remove them at some point?347 // FIXME: maybe we should keep a list of views to manually remove them at some point?
332 view->setParent(this);348 view->setParent(this);
333 return view->objectPath();349 return view->objectPath();
@@ -428,13 +444,13 @@
428444
429 // and last but not least, notify the results445 // and last but not least, notify the results
430 if (!newEvents.isEmpty()) {446 if (!newEvents.isEmpty()) {
431 mDBus.notifyEventsAdded(newEvents);447 Q_EMIT eventsAdded(newEvents);
432 }448 }
433 if (!modifiedEvents.isEmpty()) {449 if (!modifiedEvents.isEmpty()) {
434 mDBus.notifyEventsModified(modifiedEvents);450 Q_EMIT eventsModified(modifiedEvents);
435 }451 }
436 if (!threads.isEmpty()) {452 if (!threads.isEmpty()) {
437 mDBus.notifyThreadsModified(threads.values());453 Q_EMIT threadsModified(threads.values());
438 }454 }
439 return true;455 return true;
440}456}
@@ -502,12 +518,12 @@
502518
503 mBackend->endBatchOperation();519 mBackend->endBatchOperation();
504520
505 mDBus.notifyEventsRemoved(events);521 Q_EMIT eventsRemoved(events);
506 if (!removedThreads.isEmpty()) {522 if (!removedThreads.isEmpty()) {
507 mDBus.notifyThreadsRemoved(removedThreads.values());523 Q_EMIT threadsRemoved(removedThreads.values());
508 }524 }
509 if (!modifiedThreads.isEmpty()) {525 if (!modifiedThreads.isEmpty()) {
510 mDBus.notifyThreadsModified(modifiedThreads.values());526 Q_EMIT threadsModified(modifiedThreads.values());
511 }527 }
512 return true;528 return true;
513}529}
@@ -540,7 +556,7 @@
540 }556 }
541557
542 if (!removedEmptyThreads.isEmpty()) {558 if (!removedEmptyThreads.isEmpty()) {
543 mDBus.notifyThreadsRemoved(removedEmptyThreads.values());559 Q_EMIT threadsRemoved(removedEmptyThreads.values());
544 }560 }
545561
546 if (events.size() > 0) {562 if (events.size() > 0) {
@@ -812,7 +828,7 @@
812 QString threadId = channel->targetId();828 QString threadId = channel->targetId();
813 if (mBackend->updateRoomParticipants(accountId, threadId, History::EventTypeText, participants)) {829 if (mBackend->updateRoomParticipants(accountId, threadId, History::EventTypeText, participants)) {
814 QVariantMap updatedThread = getSingleThread(History::EventTypeText, accountId, threadId, QVariantMap());830 QVariantMap updatedThread = getSingleThread(History::EventTypeText, accountId, threadId, QVariantMap());
815 mDBus.notifyThreadsModified(QList<QVariantMap>() << updatedThread);831 Q_EMIT threadsModified(QList<QVariantMap>() << updatedThread);
816 }832 }
817}833}
818834
@@ -842,7 +858,7 @@
842 QString threadId = channel->targetId();858 QString threadId = channel->targetId();
843 if (mBackend->updateRoomParticipantsRoles(accountId, threadId, History::EventTypeText, participantsRoles)) {859 if (mBackend->updateRoomParticipantsRoles(accountId, threadId, History::EventTypeText, participantsRoles)) {
844 QVariantMap updatedThread = getSingleThread(History::EventTypeText, accountId, threadId, QVariantMap());860 QVariantMap updatedThread = getSingleThread(History::EventTypeText, accountId, threadId, QVariantMap());
845 mDBus.notifyThreadsModified(QList<QVariantMap>() << updatedThread);861 Q_EMIT threadsModified(QList<QVariantMap>() << updatedThread);
846 }862 }
847863
848 // update self roles in room properties864 // update self roles in room properties
@@ -877,7 +893,7 @@
877{893{
878 if (mBackend->updateRoomInfo(accountId, threadId, type, properties, invalidated)) {894 if (mBackend->updateRoomInfo(accountId, threadId, type, properties, invalidated)) {
879 QVariantMap thread = getSingleThread(type, accountId, threadId, QVariantMap());895 QVariantMap thread = getSingleThread(type, accountId, threadId, QVariantMap());
880 mDBus.notifyThreadsModified(QList<QVariantMap>() << thread);896 Q_EMIT threadsModified(QList<QVariantMap>() << thread);
881 }897 }
882}898}
883899
@@ -1181,6 +1197,16 @@
1181 return hash;1197 return hash;
1182}1198}
11831199
1200void HistoryDaemon::setupThreadView(History::PluginThreadView *view)
1201{
1202 connect(this, SIGNAL(threadsAdded(QList<QVariantMap>)),
1203 view, SLOT(onThreadsAdded(QList<QVariantMap>)));
1204 connect(this, SIGNAL(threadsModified(QList<QVariantMap>)),
1205 view, SLOT(onThreadsModified(QList<QVariantMap>)));
1206 connect(this, SIGNAL(threadsRemoved(QList<QVariantMap>)),
1207 view, SLOT(onThreadsRemoved(QList<QVariantMap>)));
1208}
1209
1184QVariantMap HistoryDaemon::getInterfaceProperties(const Tp::AbstractInterface *interface)1210QVariantMap HistoryDaemon::getInterfaceProperties(const Tp::AbstractInterface *interface)
1185{1211{
1186 QDBusInterface propsInterface(interface->service(), interface->path(), "org.freedesktop.DBus.Properties");1212 QDBusInterface propsInterface(interface->service(), interface->path(), "org.freedesktop.DBus.Properties");
11871213
=== modified file 'daemon/historydaemon.h'
--- daemon/historydaemon.h 2016-10-20 13:56:10 +0000
+++ daemon/historydaemon.h 2017-01-26 18:33:44 +0000
@@ -58,6 +58,15 @@
58 bool removeEvents(const QList<QVariantMap> &events);58 bool removeEvents(const QList<QVariantMap> &events);
59 bool removeThreads(const QList<QVariantMap> &threads);59 bool removeThreads(const QList<QVariantMap> &threads);
6060
61Q_SIGNALS:
62 void threadsAdded(const QList<QVariantMap> &threads);
63 void threadsModified(const QList<QVariantMap> &threads);
64 void threadsRemoved(const QList<QVariantMap> &threads);
65
66 void eventsAdded(const QList<QVariantMap> &events);
67 void eventsModified(const QList<QVariantMap> &events);
68 void eventsRemoved(const QList<QVariantMap> &events);
69
61private Q_SLOTS:70private Q_SLOTS:
62 void onObserverCreated();71 void onObserverCreated();
63 void onCallEnded(const Tp::CallChannelPtr &channel);72 void onCallEnded(const Tp::CallChannelPtr &channel);
@@ -76,6 +85,8 @@
76 void updateRoomParticipants(const Tp::TextChannelPtr channel);85 void updateRoomParticipants(const Tp::TextChannelPtr channel);
77 void updateRoomRoles(const Tp::TextChannelPtr &channel, const RolesMap &rolesMap);86 void updateRoomRoles(const Tp::TextChannelPtr &channel, const RolesMap &rolesMap);
78 QString hashThread(const QVariantMap &thread);87 QString hashThread(const QVariantMap &thread);
88 void setupThreadView(History::PluginThreadView *view);
89
79 static QVariantMap getInterfaceProperties(const Tp::AbstractInterface *interface);90 static QVariantMap getInterfaceProperties(const Tp::AbstractInterface *interface);
80 void updateRoomProperties(const Tp::TextChannelPtr &channel, const QVariantMap &properties);91 void updateRoomProperties(const Tp::TextChannelPtr &channel, const QVariantMap &properties);
81 void updateRoomProperties(const QString &accountId, const QString &threadId, History::EventType type, const QVariantMap &properties, const QStringList &invalidated);92 void updateRoomProperties(const QString &accountId, const QString &threadId, History::EventType type, const QVariantMap &properties, const QStringList &invalidated);
8293
=== modified file 'daemon/historyservicedbus.cpp'
--- daemon/historyservicedbus.cpp 2016-11-24 01:56:01 +0000
+++ daemon/historyservicedbus.cpp 2017-01-26 18:33:44 +0000
@@ -45,36 +45,6 @@
45 return QDBusConnection::sessionBus().registerService(History::DBusService);45 return QDBusConnection::sessionBus().registerService(History::DBusService);
46}46}
4747
48void HistoryServiceDBus::notifyThreadsAdded(const QList<QVariantMap> &threads)
49{
50 Q_EMIT ThreadsAdded(threads);
51}
52
53void HistoryServiceDBus::notifyThreadsModified(const QList<QVariantMap> &threads)
54{
55 Q_EMIT ThreadsModified(threads);
56}
57
58void HistoryServiceDBus::notifyThreadsRemoved(const QList<QVariantMap> &threads)
59{
60 Q_EMIT ThreadsRemoved(threads);
61}
62
63void HistoryServiceDBus::notifyEventsAdded(const QList<QVariantMap> &events)
64{
65 Q_EMIT EventsAdded(events);
66}
67
68void HistoryServiceDBus::notifyEventsModified(const QList<QVariantMap> &events)
69{
70 Q_EMIT EventsModified(events);
71}
72
73void HistoryServiceDBus::notifyEventsRemoved(const QList<QVariantMap> &events)
74{
75 Q_EMIT EventsRemoved(events);
76}
77
78QVariantMap HistoryServiceDBus::ThreadForProperties(const QString &accountId,48QVariantMap HistoryServiceDBus::ThreadForProperties(const QString &accountId,
79 int type,49 int type,
80 const QVariantMap &properties,50 const QVariantMap &properties,
8151
=== modified file 'daemon/historyservicedbus.h'
--- daemon/historyservicedbus.h 2016-06-17 01:49:46 +0000
+++ daemon/historyservicedbus.h 2017-01-26 18:33:44 +0000
@@ -36,14 +36,6 @@
3636
37 bool connectToBus();37 bool connectToBus();
3838
39 void notifyThreadsAdded(const QList<QVariantMap> &threads);
40 void notifyThreadsModified(const QList<QVariantMap> &threads);
41 void notifyThreadsRemoved(const QList<QVariantMap> &threads);
42
43 void notifyEventsAdded(const QList<QVariantMap> &events);
44 void notifyEventsModified(const QList<QVariantMap> &events);
45 void notifyEventsRemoved(const QList<QVariantMap> &events);
46
47 // functions exposed on DBUS39 // functions exposed on DBUS
48 QVariantMap ThreadForParticipants(const QString &accountId,40 QVariantMap ThreadForParticipants(const QString &accountId,
49 int type,41 int type,
5042
=== modified file 'plugins/sqlite/sqlitehistoryplugin.cpp'
--- plugins/sqlite/sqlitehistoryplugin.cpp 2016-11-24 01:50:48 +0000
+++ plugins/sqlite/sqlitehistoryplugin.cpp 2017-01-26 18:33:44 +0000
@@ -479,10 +479,10 @@
479 return result;479 return result;
480 }480 }
481481
482 QList<QVariantMap> results = parseThreadResults(type, query, properties);482 History::Threads results = parseThreadResults(type, query, properties);
483 query.clear();483 query.clear();
484 if (!results.isEmpty()) {484 if (!results.isEmpty()) {
485 result = results.first();485 result = results.first().properties();
486 }486 }
487487
488 return result;488 return result;
@@ -1133,9 +1133,9 @@
1133 return queryText;1133 return queryText;
1134}1134}
11351135
1136QList<QVariantMap> SQLiteHistoryPlugin::parseThreadResults(History::EventType type, QSqlQuery &query, const QVariantMap &properties)1136History::Threads SQLiteHistoryPlugin::parseThreadResults(History::EventType type, QSqlQuery &query, const QVariantMap &properties)
1137{1137{
1138 QList<QVariantMap> threads;1138 History::Threads threads;
1139 QSqlQuery attachmentsQuery(SQLiteDatabase::instance()->database());1139 QSqlQuery attachmentsQuery(SQLiteDatabase::instance()->database());
1140 QList<QVariantMap> attachments;1140 QList<QVariantMap> attachments;
1141 bool grouped = false;1141 bool grouped = false;
@@ -1298,7 +1298,7 @@
1298 thread[History::FieldRemoteParticipant] = History::ContactMatcher::instance()->contactInfo(accountId, query.value(13).toString(), true);1298 thread[History::FieldRemoteParticipant] = History::ContactMatcher::instance()->contactInfo(accountId, query.value(13).toString(), true);
1299 break;1299 break;
1300 }1300 }
1301 threads << thread;1301 threads << History::Thread::fromProperties(thread);
1302 }1302 }
1303 return threads;1303 return threads;
1304}1304}
13051305
=== modified file 'plugins/sqlite/sqlitehistoryplugin.h'
--- plugins/sqlite/sqlitehistoryplugin.h 2016-09-21 17:44:39 +0000
+++ plugins/sqlite/sqlitehistoryplugin.h 2017-01-26 18:33:44 +0000
@@ -86,7 +86,7 @@
8686
87 // functions to be used internally87 // functions to be used internally
88 QString sqlQueryForThreads(History::EventType type, const QString &condition, const QString &order);88 QString sqlQueryForThreads(History::EventType type, const QString &condition, const QString &order);
89 QList<QVariantMap> parseThreadResults(History::EventType type, QSqlQuery &query, const QVariantMap &properties = QVariantMap());89 History::Threads parseThreadResults(History::EventType type, QSqlQuery &query, const QVariantMap &properties = QVariantMap());
9090
91 QString sqlQueryForEvents(History::EventType type, const QString &condition, const QString &order);91 QString sqlQueryForEvents(History::EventType type, const QString &condition, const QString &order);
92 QList<QVariantMap> parseEventResults(History::EventType type, QSqlQuery &query);92 QList<QVariantMap> parseEventResults(History::EventType type, QSqlQuery &query);
9393
=== modified file 'plugins/sqlite/sqlitehistorythreadview.cpp'
--- plugins/sqlite/sqlitehistorythreadview.cpp 2016-11-24 01:56:01 +0000
+++ plugins/sqlite/sqlitehistorythreadview.cpp 2017-01-26 18:33:44 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright (C) 2013 Canonical, Ltd.2 * Copyright (C) 2013-2016 Canonical, Ltd.
3 *3 *
4 * Authors:4 * Authors:
5 * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com>5 * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com>
@@ -35,6 +35,10 @@
35 : History::PluginThreadView(), mPlugin(plugin), mType(type), mSort(sort),35 : History::PluginThreadView(), mPlugin(plugin), mType(type), mSort(sort),
36 mFilter(filter), mPageSize(15), mQuery(SQLiteDatabase::instance()->database()), mOffset(0), mValid(true), mQueryProperties(properties)36 mFilter(filter), mPageSize(15), mQuery(SQLiteDatabase::instance()->database()), mOffset(0), mValid(true), mQueryProperties(properties)
37{37{
38 qDebug() << __PRETTY_FUNCTION__;
39
40 // connect to the thread signals in the daemon to filter the threads
41
38 mTemporaryTable = QString("threadview%1%2").arg(QString::number((qulonglong)this), QDateTime::currentDateTimeUtc().toString("yyyyMMddhhmmsszzz"));42 mTemporaryTable = QString("threadview%1%2").arg(QString::number((qulonglong)this), QDateTime::currentDateTimeUtc().toString("yyyyMMddhhmmsszzz"));
39 mQuery.setForwardOnly(true);43 mQuery.setForwardOnly(true);
4044
@@ -80,7 +84,9 @@
8084
81QList<QVariantMap> SQLiteHistoryThreadView::NextPage()85QList<QVariantMap> SQLiteHistoryThreadView::NextPage()
82{86{
83 QList<QVariantMap> threads;87 qDebug() << __PRETTY_FUNCTION__;
88 History::Threads threads;
89 QList<QVariantMap> props;
8490
85 // now prepare for selecting from it91 // now prepare for selecting from it
86 mQuery.prepare(QString("SELECT * FROM %1 LIMIT %2 OFFSET %3").arg(mTemporaryTable,92 mQuery.prepare(QString("SELECT * FROM %1 LIMIT %2 OFFSET %3").arg(mTemporaryTable,
@@ -89,17 +95,233 @@
89 qCritical() << "Error:" << mQuery.lastError() << mQuery.lastQuery();95 qCritical() << "Error:" << mQuery.lastError() << mQuery.lastQuery();
90 mValid = false;96 mValid = false;
91 Q_EMIT Invalidated();97 Q_EMIT Invalidated();
92 return threads;98 return props;
93 }99 }
94100
95 threads = mPlugin->parseThreadResults(mType, mQuery, mQueryProperties);101 threads = mPlugin->parseThreadResults(mType, mQuery, mQueryProperties);
96 mOffset += mPageSize;102 mOffset += mPageSize;
97 mQuery.clear();103 mQuery.clear();
98104
99 return threads;105 Q_FOREACH(const History::Thread &thread, threads) {
106 if (threadIsInGroup(thread)) {
107 continue;
108 }
109 createThreadGroup(thread);
110 props << thread.properties();
111 }
112 return props;
100}113}
101114
102bool SQLiteHistoryThreadView::IsValid() const115bool SQLiteHistoryThreadView::IsValid() const
103{116{
104 return mValid;117 return mValid;
105}118}
119
120bool SQLiteHistoryThreadView::threadIsInGroup(const History::Thread &thread)
121{
122 Q_FOREACH(const HistoryThreadGroup &group, mGroups) {
123 if (group.threads.contains(thread)) {
124 return true;
125 }
126 }
127 return false;
128}
129
130void SQLiteHistoryThreadView::createThreadGroup(const History::Thread &thread)
131{
132 HistoryThreadGroup group;
133 group.displayedThread = thread;
134 group.threads = thread.groupedThreads();
135 mGroups << group;
136}
137
138History::Threads SQLiteHistoryThreadView::fromList(const QList<QVariantMap> &threads)
139{
140 History::Threads result;
141 Q_FOREACH(const QVariantMap &map, threads) {
142 result << History::Thread::fromProperties(map);
143 }
144 return result;
145}
146
147QList<QVariantMap> SQLiteHistoryThreadView::getGroupedThreads(const QList<QVariantMap> &originalThreads)
148{
149 bool needsGrouping = mQueryProperties.contains(History::FieldGroupingProperty);
150 QList<QVariantMap> grouped;
151 Q_FOREACH(const QVariantMap &originalThread, originalThreads) {
152 if (needsGrouping) {
153 QVariantMap groupedThread = mPlugin->getSingleThread((History::EventType)originalThread[History::FieldType].toInt(),
154 originalThread[History::FieldAccountId].toString(),
155 originalThread[History::FieldThreadId].toString(),
156 mQueryProperties);
157 grouped << groupedThread;
158 } else {
159 grouped << originalThread;
160 }
161 }
162 return grouped;
163}
164
165HistoryThreadGroup SQLiteHistoryThreadView::updateDisplayedThread(HistoryThreadGroup group)
166{
167 if (group.threads.isEmpty()) {
168 return group;
169 }
170
171 History::Thread displayedThread = group.threads.first();
172 Q_FOREACH(const History::Thread &thread, group.threads) {
173 if (thread.lastEvent().timestamp() > displayedThread.lastEvent().timestamp()) {
174 displayedThread = thread;
175 }
176 }
177 group.displayedThread = displayedThread;
178 return group;
179}
180
181void SQLiteHistoryThreadView::notifyChanges(const QList<QVariantMap> added, const QList<QVariantMap> removed, const QList<QVariantMap> modified)
182{
183 qDebug() << "Added:" << added.count() << "Removed:" << removed.count() << "Modified:" << modified.count();
184
185 if (!removed.isEmpty()) {
186 Q_EMIT ThreadsRemoved(removed);
187 }
188
189 if (!added.isEmpty()) {
190 Q_EMIT ThreadsAdded(added);
191 }
192
193 if (!modified.isEmpty()) {
194 Q_EMIT ThreadsModified(modified);
195 }
196}
197
198void SQLiteHistoryThreadView::onThreadsAdded(const QList<QVariantMap> &threads)
199{
200 qDebug() << __PRETTY_FUNCTION__;
201
202 History::Threads groupedThreads = fromList(getGroupedThreads(threads));
203
204 QList<QVariantMap> addedThreads;
205 QList<QVariantMap> modifiedThreads;
206 QList<QVariantMap> removedThreads;
207
208 // now we need to iterate over the existing groups to see if this new thread belongs to any existing group
209 Q_FOREACH(const History::Thread &groupedThread, groupedThreads) {
210 bool found = false;
211 for (int i = 0; i < mGroups.count(); ++i) {
212 HistoryThreadGroup &group = mGroups[i];
213 if (groupedThread.groupedThreads().contains(group.displayedThread)) {
214 // append the new thread to the group.
215 group.threads.append(groupedThread);
216 HistoryThreadGroup updatedGroup = updateDisplayedThread(group);
217 if (updatedGroup.displayedThread != group.displayedThread) {
218 // as the displayed thread changed, we need to remove the old thread
219 // and add the new one
220 removedThreads << group.displayedThread.properties();
221 addedThreads << updatedGroup.displayedThread.properties();
222 } else {
223 // the thread was just updated, notify as such
224 modifiedThreads << updatedGroup.displayedThread.properties();
225 }
226 group = updatedGroup;
227 found = true;
228 break;
229 }
230 }
231
232 // in case it is not found, we need to create a group for the thread
233 if (!found) {
234 HistoryThreadGroup group;
235 group.displayedThread = groupedThread;
236 group.threads = groupedThread.groupedThreads();
237 mGroups << group;
238 addedThreads << groupedThread.properties();
239 }
240 }
241
242 // the modified threads here are threads that are currently displayed but they need updating
243 // since the group itself got one extra thread, so get the latest version of them.
244 notifyChanges(addedThreads, removedThreads, getGroupedThreads(modifiedThreads));
245}
246
247void SQLiteHistoryThreadView::onThreadsModified(const QList<QVariantMap> &threads)
248{
249 qDebug() << __PRETTY_FUNCTION__;
250 History::Threads groupedThreads = fromList(getGroupedThreads(threads));
251
252 QList<QVariantMap> addedThreads;
253 QList<QVariantMap> modifiedThreads;
254 QList<QVariantMap> removedThreads;
255
256 // now we need to check if the thread is already displayed and if so,
257 // check if the displayed thread changed.
258 Q_FOREACH(const History::Thread &groupedThread, groupedThreads) {
259 bool found = false;
260 for (int i = 0; i < mGroups.count(); ++i) {
261 HistoryThreadGroup &group = mGroups[i];
262 if (group.threads.contains(groupedThread)) {
263 // remove the old instance and append the new one
264 group.threads.removeOne(groupedThread);
265 group.threads.append(groupedThread);
266 HistoryThreadGroup updatedGroup = updateDisplayedThread(group);
267 if (updatedGroup.displayedThread != group.displayedThread) {
268 // as the displayed thread changed, we need to remove the old thread
269 // and add the new one
270 removedThreads << group.displayedThread.properties();
271 addedThreads << updatedGroup.displayedThread.properties();
272 } else {
273 // the thread was just updated, notify as such
274 modifiedThreads << updatedGroup.displayedThread.properties();
275 }
276 group = updatedGroup;
277 found = true;
278 break;
279 }
280 }
281
282 // in case it is not found, we need to create a group for the thread
283 if (!found) {
284 HistoryThreadGroup group;
285 group.displayedThread = groupedThread;
286 group.threads = groupedThread.groupedThreads();
287 mGroups << group;
288 addedThreads << groupedThread.properties();
289 }
290 }
291
292 // the threads marked as "added" are existing threads that were not displayed before
293 // and that are displayed now. So in order to make sure they are up-to-date, get the latest
294 // version of the grouping for each of them.
295 notifyChanges(getGroupedThreads(addedThreads), removedThreads, modifiedThreads);
296}
297
298void SQLiteHistoryThreadView::onThreadsRemoved(const QList<QVariantMap> &threads)
299{
300 qDebug() << __PRETTY_FUNCTION__;
301 QList<QVariantMap> addedThreads;
302 QList<QVariantMap> modifiedThreads;
303 QList<QVariantMap> removedThreads;
304
305 // try to find the thread in the groups to notify its removal
306 Q_FOREACH(const History::Thread &thread, fromList(threads)) {
307 for (int i = 0; i < mGroups.count(); ++i) {
308 HistoryThreadGroup &group = mGroups[i];
309 if (group.threads.contains(thread)) {
310 group.threads.removeOne(thread);
311 if (group.displayedThread == thread) {
312 removedThreads << thread.properties();
313 if (!group.threads.isEmpty()) {
314 group = updateDisplayedThread(group);
315 addedThreads << group.displayedThread.properties();
316 }
317 } else {
318 modifiedThreads << group.displayedThread.properties();
319 }
320 break;
321 }
322 }
323 }
324
325 // we need to update the added and modified threads to get the correct group buddies
326 notifyChanges(getGroupedThreads(addedThreads), removedThreads, getGroupedThreads(modifiedThreads));
327}
106328
=== modified file 'plugins/sqlite/sqlitehistorythreadview.h'
--- plugins/sqlite/sqlitehistorythreadview.h 2015-09-21 20:05:06 +0000
+++ plugins/sqlite/sqlitehistorythreadview.h 2017-01-26 18:33:44 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright (C) 2013 Canonical, Ltd.2 * Copyright (C) 2013-2016 Canonical, Ltd.
3 *3 *
4 * Authors:4 * Authors:
5 * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com>5 * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com>
@@ -30,6 +30,16 @@
3030
31class SQLiteHistoryPlugin;31class SQLiteHistoryPlugin;
3232
33class HistoryThreadGroup {
34public:
35 History::Thread displayedThread;
36 History::Threads threads;
37
38 bool operator==(const HistoryThreadGroup &other) const;
39};
40
41typedef QList<HistoryThreadGroup> HistoryThreadGroupList;
42
33class SQLiteHistoryThreadView : public History::PluginThreadView43class SQLiteHistoryThreadView : public History::PluginThreadView
34{44{
35 Q_OBJECT45 Q_OBJECT
@@ -44,6 +54,22 @@
44 QList<QVariantMap> NextPage();54 QList<QVariantMap> NextPage();
45 bool IsValid() const;55 bool IsValid() const;
4656
57public Q_SLOTS:
58 virtual void onThreadsAdded(const QList<QVariantMap> &threads);
59 virtual void onThreadsModified(const QList<QVariantMap> &threads);
60 virtual void onThreadsRemoved(const QList<QVariantMap> &threads);
61
62protected:
63 bool threadIsInGroup(const History::Thread &thread);
64 void createThreadGroup(const History::Thread &thread);
65 History::Threads fromList(const QList<QVariantMap> &threads);
66 QList<QVariantMap> getGroupedThreads(const QList<QVariantMap> &originalThreads);
67 HistoryThreadGroup updateDisplayedThread(HistoryThreadGroup group);
68
69 void notifyChanges(const QList<QVariantMap> added,
70 const QList<QVariantMap> removed,
71 const QList<QVariantMap> modified);
72
47private:73private:
48 History::EventType mType;74 History::EventType mType;
49 History::Sort mSort;75 History::Sort mSort;
@@ -55,6 +81,7 @@
55 int mOffset;81 int mOffset;
56 bool mValid;82 bool mValid;
57 QVariantMap mQueryProperties;83 QVariantMap mQueryProperties;
84 HistoryThreadGroupList mGroups;
58};85};
5986
60#endif // SQLITEHISTORYTHREADVIEW_H87#endif // SQLITEHISTORYTHREADVIEW_H
6188
=== modified file 'src/PluginThreadView.xml'
--- src/PluginThreadView.xml 2013-09-13 19:24:03 +0000
+++ src/PluginThreadView.xml 2017-01-26 18:33:44 +0000
@@ -33,5 +33,33 @@
33 Notifies that this view is no longer valid.33 Notifies that this view is no longer valid.
34 ]]></dox:d>34 ]]></dox:d>
35 </signal>35 </signal>
36 <signal name="ThreadsAdded">
37 <dox:d><![CDATA[
38 Notifies that new threads were added.
39 ]]></dox:d>
40 <arg type="a(a{sv})" direction="in"/>
41 <arg type="a(a{sv})" direction="out"/>
42 <annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QList &lt; QVariantMap &gt;"/>
43 <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QList &lt; QVariantMap &gt;"/>
44 </signal>
45 <signal name="ThreadsModified">
46 <dox:d><![CDATA[
47 Notifies that threads were modified.
48 ]]></dox:d>
49 <arg type="a(a{sv})" direction="in"/>
50 <arg type="a(a{sv})" direction="out"/>
51 <annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QList &lt; QVariantMap &gt;"/>
52 <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QList &lt; QVariantMap &gt;"/>
53 </signal>
54 <signal name="ThreadsRemoved">
55 <dox:d><![CDATA[
56 Notifies that threads were removed.
57 ]]></dox:d>
58 <arg type="a(a{sv})" direction="in"/>
59 <arg type="a(a{sv})" direction="out"/>
60 <annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QList &lt; QVariantMap &gt;"/>
61 <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QList &lt; QVariantMap &gt;"/>
62 </signal>
63
36 </interface>64 </interface>
37</node>65</node>
3866
=== modified file 'src/contactmatcher.cpp'
--- src/contactmatcher.cpp 2016-06-17 01:49:46 +0000
+++ src/contactmatcher.cpp 2017-01-26 18:33:44 +0000
@@ -112,6 +112,10 @@
112 } else if (!synchronous) {112 } else if (!synchronous) {
113 RequestInfo info{accountId, identifier};113 RequestInfo info{accountId, identifier};
114 mPendingRequests.append(info);114 mPendingRequests.append(info);
115 map[History::FieldAlias] = "";
116 map[History::FieldAvatar] = "";
117 map[History::FieldContactId] = "";
118 map[History::FieldDetailProperties] = QVariantMap();
115 }119 }
116 map[History::FieldIdentifier] = identifier;120 map[History::FieldIdentifier] = identifier;
117 map[History::FieldAccountId] = accountId;121 map[History::FieldAccountId] = accountId;
@@ -196,7 +200,7 @@
196 QString identifier = it2.key();200 QString identifier = it2.key();
197201
198 Q_FOREACH(const QContact &contact, contacts) {202 Q_FOREACH(const QContact &contact, contacts) {
199 bool previousMatch = (contactInfo.contains(History::FieldContactId) &&203 bool previousMatch = (hasMatch(contactInfo) &&
200 contactInfo[History::FieldContactId].toString() == contact.id().toString());204 contactInfo[History::FieldContactId].toString() == contact.id().toString());
201 QVariantMap map = matchAndUpdate(accountId, identifier, contact);205 QVariantMap map = matchAndUpdate(accountId, identifier, contact);
202 if (hasMatch(map)){206 if (hasMatch(map)){
@@ -406,6 +410,10 @@
406 QVariantMap contactInfo;410 QVariantMap contactInfo;
407 contactInfo[History::FieldIdentifier] = identifier;411 contactInfo[History::FieldIdentifier] = identifier;
408 contactInfo[History::FieldAccountId] = accountId;412 contactInfo[History::FieldAccountId] = accountId;
413 contactInfo[History::FieldAlias] = "";
414 contactInfo[History::FieldAvatar] = "";
415 contactInfo[History::FieldContactId] = "";
416 contactInfo[History::FieldDetailProperties] = QVariantMap();
409417
410 if (contact.isEmpty()) {418 if (contact.isEmpty()) {
411 return contactInfo;419 return contactInfo;
412420
=== modified file 'src/pluginthreadview.cpp'
--- src/pluginthreadview.cpp 2016-11-24 01:56:01 +0000
+++ src/pluginthreadview.cpp 2017-01-26 18:33:44 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright (C) 2013 Canonical, Ltd.2 * Copyright (C) 2013-2016 Canonical, Ltd.
3 *3 *
4 * Authors:4 * Authors:
5 * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com>5 * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com>
@@ -71,4 +71,22 @@
71 return d->objectPath;71 return d->objectPath;
72}72}
7373
74void PluginThreadView::onThreadsAdded(const QList<QVariantMap> &threads)
75{
76 // the default implementation just relay the signal
77 Q_EMIT ThreadsAdded(threads);
78}
79
80void PluginThreadView::onThreadsModified(const QList<QVariantMap> &threads)
81{
82 // the default implementation just relay the signal
83 Q_EMIT ThreadsModified(threads);
84}
85
86void PluginThreadView::onThreadsRemoved(const QList<QVariantMap> &threads)
87{
88 // the default implementation just relay the signal
89 Q_EMIT ThreadsRemoved(threads);
90}
91
74}92}
7593
=== modified file 'src/pluginthreadview.h'
--- src/pluginthreadview.h 2013-11-19 17:52:53 +0000
+++ src/pluginthreadview.h 2017-01-26 18:33:44 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright (C) 2013 Canonical, Ltd.2 * Copyright (C) 2013-2016 Canonical, Ltd.
3 *3 *
4 * Authors:4 * Authors:
5 * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com>5 * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com>
@@ -26,6 +26,7 @@
26#include <QDBusContext>26#include <QDBusContext>
27#include <QScopedPointer>27#include <QScopedPointer>
28#include <QVariantMap>28#include <QVariantMap>
29#include <Thread>
2930
30namespace History {31namespace History {
3132
@@ -41,14 +42,22 @@
4142
42 // DBus exposed methods43 // DBus exposed methods
43 Q_NOREPLY void Destroy();44 Q_NOREPLY void Destroy();
45 virtual bool IsValid() const;
44 virtual QList<QVariantMap> NextPage() = 0;46 virtual QList<QVariantMap> NextPage() = 0;
45 virtual bool IsValid() const;
4647
47 // other methods48 // other methods
48 QString objectPath() const;49 QString objectPath() const;
4950
50Q_SIGNALS:51Q_SIGNALS:
51 void Invalidated();52 void Invalidated();
53 void ThreadsAdded(const QList<QVariantMap> &threads);
54 void ThreadsModified(const QList<QVariantMap> &threads);
55 void ThreadsRemoved(const QList<QVariantMap> &threads);
56
57public Q_SLOTS:
58 virtual void onThreadsAdded(const QList<QVariantMap> &threads);
59 virtual void onThreadsModified(const QList<QVariantMap> &threads);
60 virtual void onThreadsRemoved(const QList<QVariantMap> &threads);
5261
53private:62private:
54 QScopedPointer<PluginThreadViewPrivate> d_ptr;63 QScopedPointer<PluginThreadViewPrivate> d_ptr;
5564
=== modified file 'src/thread.cpp'
--- src/thread.cpp 2016-07-12 02:08:11 +0000
+++ src/thread.cpp 2017-01-26 18:33:44 +0000
@@ -185,6 +185,11 @@
185 return true;185 return true;
186}186}
187187
188bool Thread::operator!=(const Thread &other) const
189{
190 return !(*this == other);
191}
192
188bool Thread::operator<(const Thread &other) const193bool Thread::operator<(const Thread &other) const
189{194{
190 QString selfData = QString::number(type()) + accountId() + threadId();195 QString selfData = QString::number(type()) + accountId() + threadId();
@@ -280,10 +285,14 @@
280 while (!argument.atEnd()) {285 while (!argument.atEnd()) {
281 QVariantMap props;286 QVariantMap props;
282 QVariant variant;287 QVariant variant;
283 argument >> variant;288 if (argument.currentType() == QDBusArgument::MapType) {
284 QDBusArgument innerArgument = variant.value<QDBusArgument>();289 argument >> props;
285 if (!innerArgument.atEnd()) {290 } else {
286 innerArgument >> props;291 argument >> variant;
292 QDBusArgument innerArgument = variant.value<QDBusArgument>();
293 if (!innerArgument.atEnd()) {
294 innerArgument >> props;
295 }
287 }296 }
288 threads << Thread::fromProperties(props);297 threads << Thread::fromProperties(props);
289 }298 }
290299
=== modified file 'src/thread.h'
--- src/thread.h 2016-07-12 01:59:06 +0000
+++ src/thread.h 2017-01-26 18:33:44 +0000
@@ -76,6 +76,7 @@
7676
77 bool isNull() const;77 bool isNull() const;
78 bool operator==(const Thread &other) const;78 bool operator==(const Thread &other) const;
79 bool operator!=(const Thread &other) const;
79 bool operator<(const Thread &other) const;80 bool operator<(const Thread &other) const;
8081
81 virtual QVariantMap properties() const;82 virtual QVariantMap properties() const;
8283
=== modified file 'src/threadview.cpp'
--- src/threadview.cpp 2015-10-01 19:44:45 +0000
+++ src/threadview.cpp 2017-01-26 18:33:44 +0000
@@ -59,36 +59,48 @@
59 return filtered;59 return filtered;
60}60}
6161
62void ThreadViewPrivate::_d_threadsAdded(const History::Threads &threads)62void ThreadViewPrivate::_d_threadsAdded(const QList<QVariantMap> &threads)
63{63{
64 qDebug() << __PRETTY_FUNCTION__ << threads.count();
64 Q_Q(ThreadView);65 Q_Q(ThreadView);
6566
66 Threads filtered = filteredThreads(threads);67 Threads filtered = filteredThreads(parseThreads(threads));
67 if (!filtered.isEmpty()) {68 if (!filtered.isEmpty()) {
68 Q_EMIT q->threadsAdded(filtered);69 Q_EMIT q->threadsAdded(filtered);
69 }70 }
70}71}
7172
72void ThreadViewPrivate::_d_threadsModified(const Threads &threads)73void ThreadViewPrivate::_d_threadsModified(const QList<QVariantMap> &threads)
73{74{
75 qDebug() << __PRETTY_FUNCTION__ << threads.count();
74 Q_Q(ThreadView);76 Q_Q(ThreadView);
7577
76 Threads filtered = filteredThreads(threads);78 Threads filtered = filteredThreads(parseThreads(threads));
77 if (!filtered.isEmpty()) {79 if (!filtered.isEmpty()) {
78 Q_EMIT q->threadsModified(filtered);80 Q_EMIT q->threadsModified(filtered);
79 }81 }
80}82}
8183
82void ThreadViewPrivate::_d_threadsRemoved(const Threads &threads)84void ThreadViewPrivate::_d_threadsRemoved(const QList<QVariantMap> &threads)
83{85{
86 qDebug() << __PRETTY_FUNCTION__ << threads.count();
84 Q_Q(ThreadView);87 Q_Q(ThreadView);
8588
86 Threads filtered = filteredThreads(threads);89 Threads filtered = filteredThreads(parseThreads(threads));
87 if (!filtered.isEmpty()) {90 if (!filtered.isEmpty()) {
88 Q_EMIT q->threadsRemoved(filtered);91 Q_EMIT q->threadsRemoved(filtered);
89 }92 }
90}93}
9194
95Threads ThreadViewPrivate::parseThreads(const QList<QVariantMap> &threads)
96{
97 Threads result;
98 Q_FOREACH(const QVariantMap &thread, threads) {
99 result << Thread::fromProperties(thread);
100 }
101 return result;
102}
103
92// ------------- ThreadView -------------------------------------------------------104// ------------- ThreadView -------------------------------------------------------
93105
94ThreadView::ThreadView(History::EventType type,106ThreadView::ThreadView(History::EventType type,
@@ -123,15 +135,13 @@
123 d_ptr->dbus = new QDBusInterface(History::DBusService, d_ptr->objectPath, History::ThreadViewInterface,135 d_ptr->dbus = new QDBusInterface(History::DBusService, d_ptr->objectPath, History::ThreadViewInterface,
124 QDBusConnection::sessionBus(), this);136 QDBusConnection::sessionBus(), this);
125137
126 connect(Manager::instance(),138 QDBusConnection connection = QDBusConnection::sessionBus();
127 SIGNAL(threadsAdded(History::Threads)),139 connection.connect(d_ptr->dbus->service(), d_ptr->dbus->path(), d_ptr->dbus->interface(), "ThreadsAdded",
128 SLOT(_d_threadsAdded(History::Threads)));140 this, SLOT(_d_threadsAdded(QList<QVariantMap>)));
129 connect(Manager::instance(),141 connection.connect(d_ptr->dbus->service(), d_ptr->dbus->path(), d_ptr->dbus->interface(), "ThreadsModified",
130 SIGNAL(threadsModified(History::Threads)),142 this, SLOT(_d_threadsModified(QList<QVariantMap>)));
131 SLOT(_d_threadsModified(History::Threads)));143 connection.connect(d_ptr->dbus->service(), d_ptr->dbus->path(), d_ptr->dbus->interface(), "ThreadsRemoved",
132 connect(Manager::instance(),144 this, SLOT(_d_threadsRemoved(QList<QVariantMap>)));
133 SIGNAL(threadsRemoved(History::Threads)),
134 SLOT(_d_threadsRemoved(History::Threads)));
135}145}
136146
137ThreadView::~ThreadView()147ThreadView::~ThreadView()
138148
=== modified file 'src/threadview.h'
--- src/threadview.h 2015-09-21 20:05:06 +0000
+++ src/threadview.h 2017-01-26 18:33:44 +0000
@@ -55,9 +55,9 @@
55 void invalidated();55 void invalidated();
5656
57private:57private:
58 Q_PRIVATE_SLOT(d_func(), void _d_threadsAdded(const History::Threads &threads))58 Q_PRIVATE_SLOT(d_func(), void _d_threadsAdded(const QList<QVariantMap> &threads))
59 Q_PRIVATE_SLOT(d_func(), void _d_threadsModified(const History::Threads &threads))59 Q_PRIVATE_SLOT(d_func(), void _d_threadsModified(const QList<QVariantMap> &threads))
60 Q_PRIVATE_SLOT(d_func(), void _d_threadsRemoved(const History::Threads &threads))60 Q_PRIVATE_SLOT(d_func(), void _d_threadsRemoved(const QList<QVariantMap> &threads))
61 QScopedPointer<ThreadViewPrivate> d_ptr;61 QScopedPointer<ThreadViewPrivate> d_ptr;
6262
63};63};
6464
=== modified file 'src/threadview_p.h'
--- src/threadview_p.h 2013-09-17 21:33:34 +0000
+++ src/threadview_p.h 2017-01-26 18:33:44 +0000
@@ -47,9 +47,12 @@
47 Threads filteredThreads(const Threads &threads);47 Threads filteredThreads(const Threads &threads);
4848
49 // private slots49 // private slots
50 void _d_threadsAdded(const History::Threads &threads);50 void _d_threadsAdded(const QList<QVariantMap> &threads);
51 void _d_threadsModified(const History::Threads &threads);51 void _d_threadsModified(const QList<QVariantMap> &threads);
52 void _d_threadsRemoved(const History::Threads &threads);52 void _d_threadsRemoved(const QList<QVariantMap> &threads);
53
54 protected:
55 Threads parseThreads(const QList<QVariantMap> &threads);
5356
54 ThreadView *q_ptr;57 ThreadView *q_ptr;
55 };58 };

Subscribers

People subscribed via source and target branches

to all changes: