Merge lp:~bfiller/history-service/rtm-14.09-sim-presence into lp:history-service/rtm-14.09

Proposed by Bill Filler
Status: Merged
Approved by: Bill Filler
Approved revision: 164
Merged at revision: 164
Proposed branch: lp:~bfiller/history-service/rtm-14.09-sim-presence
Merge into: lp:history-service/rtm-14.09
Diff against target: 884 lines (+517/-56)
11 files modified
Ubuntu/History/CMakeLists.txt (+2/-0)
Ubuntu/History/historyeventmodel.cpp (+34/-20)
Ubuntu/History/historyeventmodel.h (+18/-14)
Ubuntu/History/historygroupedeventsmodel.cpp (+346/-0)
Ubuntu/History/historygroupedeventsmodel.h (+82/-0)
Ubuntu/History/historyqmlplugin.cpp (+2/-0)
Ubuntu/History/historythreadmodel.cpp (+23/-21)
Ubuntu/History/historythreadmodel.h (+2/-1)
src/event.cpp (+6/-0)
src/event.h (+1/-0)
src/types.h (+1/-0)
To merge this branch: bzr merge lp:~bfiller/history-service/rtm-14.09-sim-presence
Reviewer Review Type Date Requested Status
Ubuntu Phablet Team Pending
Review via email: mp+231916@code.launchpad.net

Commit message

sim presence and call grouping merge from trunk

Description of the change

sim presence and call grouping merge from trunk

To post a comment you must log in.

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 2014-07-14 23:05:23 +0000
3+++ Ubuntu/History/CMakeLists.txt 2014-08-22 15:31:10 +0000
4@@ -2,6 +2,7 @@
5
6 set(plugin_SRCS
7 historyeventmodel.cpp
8+ historygroupedeventsmodel.cpp
9 historythreadgroupingproxymodel.cpp
10 historyqmltexteventattachment.cpp
11 historyqmlfilter.cpp
12@@ -15,6 +16,7 @@
13
14 set(plugin_HDRS
15 historyeventmodel.h
16+ historygroupedeventsmodel.h
17 historythreadgroupingproxymodel.h
18 historyqmltexteventattachment.h
19 historyqmlfilter.h
20
21=== modified file 'Ubuntu/History/historyeventmodel.cpp'
22--- Ubuntu/History/historyeventmodel.cpp 2014-08-07 19:22:31 +0000
23+++ Ubuntu/History/historyeventmodel.cpp 2014-08-22 15:31:10 +0000
24@@ -37,7 +37,8 @@
25
26 HistoryEventModel::HistoryEventModel(QObject *parent) :
27 QAbstractListModel(parent), mCanFetchMore(true), mFilter(0),
28- mSort(0), mType(HistoryThreadModel::EventTypeText), mEventWritingTimer(0), mFetchTimer(0)
29+ mSort(new HistoryQmlSort(this)), mType(HistoryThreadModel::EventTypeText),
30+ mEventWritingTimer(0), mUpdateTimer(0)
31 {
32 connect(this, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SIGNAL(countChanged()));
33 connect(this, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SIGNAL(countChanged()));
34@@ -63,7 +64,7 @@
35 mRoles[CallDurationRole] = "callDuration";
36
37 // create the view and get some objects
38- updateQuery();
39+ triggerQueryUpdate();
40 }
41
42 int HistoryEventModel::rowCount(const QModelIndex &parent) const
43@@ -81,7 +82,11 @@
44 return QVariant();
45 }
46
47- History::Event event = mEvents[index.row()];
48+ return eventData(mEvents[index.row()], role);
49+}
50+
51+QVariant HistoryEventModel::eventData(const History::Event &event, int role) const
52+{
53 History::TextEvent textEvent;
54 History::VoiceEvent voiceEvent;
55 History::Thread thread;
56@@ -194,7 +199,7 @@
57 return;
58 }
59
60- History::Events events = mView->nextPage();
61+ History::Events events = fetchNextPage();
62
63 qDebug() << "Got events:" << events.count();
64 if (events.isEmpty()) {
65@@ -227,11 +232,11 @@
66 if (mFilter) {
67 connect(mFilter,
68 SIGNAL(filterChanged()),
69- SLOT(updateQuery()));
70+ SLOT(triggerQueryUpdate()));
71 }
72
73 Q_EMIT filterChanged();
74- updateQuery();
75+ triggerQueryUpdate();
76 }
77
78 HistoryQmlSort *HistoryEventModel::sort() const
79@@ -250,11 +255,11 @@
80 if (mSort) {
81 connect(mSort,
82 SIGNAL(sortChanged()),
83- SLOT(updateQuery()));
84+ SLOT(triggerQueryUpdate()));
85 }
86
87 Q_EMIT sortChanged();
88- updateQuery();
89+ triggerQueryUpdate();
90 }
91
92 HistoryThreadModel::EventType HistoryEventModel::type() const
93@@ -266,7 +271,7 @@
94 {
95 mType = value;
96 Q_EMIT typeChanged();
97- updateQuery();
98+ triggerQueryUpdate();
99 }
100
101 QString HistoryEventModel::threadIdForParticipants(const QString &accountId, int eventType, const QStringList &participants, int matchFlags, bool create)
102@@ -378,7 +383,7 @@
103 SLOT(onEventsRemoved(History::Events)));
104 connect(mView.data(),
105 SIGNAL(invalidated()),
106- SLOT(updateQuery()));
107+ SLOT(triggerQueryUpdate()));
108
109 mCanFetchMore = true;
110 Q_EMIT canFetchMoreChanged();
111@@ -391,12 +396,7 @@
112 }
113 mAttachmentCache.clear();
114
115- if (mFetchTimer) {
116- killTimer(mFetchTimer);
117- }
118-
119- // delay the loading of the model data until the settings settle down
120- mFetchTimer = startTimer(100);
121+ fetchMore(QModelIndex());
122 }
123
124 void HistoryEventModel::onEventsAdded(const History::Events &events)
125@@ -474,13 +474,18 @@
126 qDebug() << "... succeeded!";
127 mEventWritingQueue.clear();
128 }
129- } else if (event->timerId() == mFetchTimer) {
130- killTimer(mFetchTimer);
131- mFetchTimer = 0;
132- fetchMore(QModelIndex());
133+ } else if (event->timerId() == mUpdateTimer) {
134+ killTimer(mUpdateTimer);
135+ mUpdateTimer = 0;
136+ updateQuery();
137 }
138 }
139
140+History::Events HistoryEventModel::fetchNextPage()
141+{
142+ return mView->nextPage();
143+}
144+
145 QVariant HistoryEventModel::get(int row) const
146 {
147 if (row >= this->rowCount() || row < 0) {
148@@ -489,3 +494,12 @@
149
150 return QVariant(mEvents[row].properties());
151 }
152+
153+void HistoryEventModel::triggerQueryUpdate()
154+{
155+ if (mUpdateTimer) {
156+ killTimer(mUpdateTimer);
157+ }
158+ // delay the loading of the model data until the settings settle down
159+ mUpdateTimer = startTimer(100);
160+}
161
162=== modified file 'Ubuntu/History/historyeventmodel.h'
163--- Ubuntu/History/historyeventmodel.h 2014-08-07 19:22:31 +0000
164+++ Ubuntu/History/historyeventmodel.h 2014-08-22 15:31:10 +0000
165@@ -53,18 +53,20 @@
166 TextReadSubjectRole,
167 TextMessageAttachmentsRole,
168 CallMissedRole,
169- CallDurationRole
170+ CallDurationRole,
171+ LastRole
172 };
173
174 explicit HistoryEventModel(QObject *parent = 0);
175
176- int rowCount(const QModelIndex &parent = QModelIndex()) const;
177- QVariant data(const QModelIndex &index, int role) const;
178-
179- Q_INVOKABLE bool canFetchMore(const QModelIndex &parent = QModelIndex()) const;
180- Q_INVOKABLE void fetchMore(const QModelIndex &parent = QModelIndex());
181-
182- QHash<int, QByteArray> roleNames() const;
183+ virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
184+ virtual QVariant data(const QModelIndex &index, int role) const;
185+ QVariant eventData(const History::Event &event, int role) const;
186+
187+ Q_INVOKABLE virtual bool canFetchMore(const QModelIndex &parent = QModelIndex()) const;
188+ Q_INVOKABLE virtual void fetchMore(const QModelIndex &parent = QModelIndex());
189+
190+ virtual QHash<int, QByteArray> roleNames() const;
191
192 HistoryQmlFilter *filter() const;
193 void setFilter(HistoryQmlFilter *value);
194@@ -85,7 +87,7 @@
195 Q_INVOKABLE bool markEventAsRead(const QString &accountId, const QString &threadId, const QString &eventId, int eventType);
196
197 Q_INVOKABLE bool removeEventAttachment(const QString &accountId, const QString &threadId, const QString &eventId, int eventType, const QString &attachmentId);
198- Q_INVOKABLE QVariant get(int row) const;
199+ Q_INVOKABLE virtual QVariant get(int row) const;
200
201 Q_SIGNALS:
202 void countChanged();
203@@ -95,13 +97,15 @@
204 void canFetchMoreChanged();
205
206 protected Q_SLOTS:
207- void updateQuery();
208- void onEventsAdded(const History::Events &events);
209- void onEventsModified(const History::Events &events);
210- void onEventsRemoved(const History::Events &events);
211+ void triggerQueryUpdate();
212+ virtual void updateQuery();
213+ virtual void onEventsAdded(const History::Events &events);
214+ virtual void onEventsModified(const History::Events &events);
215+ virtual void onEventsRemoved(const History::Events &events);
216
217 protected:
218 void timerEvent(QTimerEvent *event);
219+ History::Events fetchNextPage();
220
221 private:
222 History::EventViewPtr mView;
223@@ -114,7 +118,7 @@
224 mutable QMap<History::TextEvent, QList<QVariant> > mAttachmentCache;
225 History::Events mEventWritingQueue;
226 int mEventWritingTimer;
227- int mFetchTimer;
228+ int mUpdateTimer;
229 };
230
231 #endif // HISTORYEVENTMODEL_H
232
233=== added file 'Ubuntu/History/historygroupedeventsmodel.cpp'
234--- Ubuntu/History/historygroupedeventsmodel.cpp 1970-01-01 00:00:00 +0000
235+++ Ubuntu/History/historygroupedeventsmodel.cpp 2014-08-22 15:31:10 +0000
236@@ -0,0 +1,346 @@
237+/*
238+ * Copyright (C) 2014 Canonical, Ltd.
239+ *
240+ * Authors:
241+ * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com>
242+ *
243+ * This file is part of history-service.
244+ *
245+ * history-service is free software; you can redistribute it and/or modify
246+ * it under the terms of the GNU General Public License as published by
247+ * the Free Software Foundation; version 3.
248+ *
249+ * history-service is distributed in the hope that it will be useful,
250+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
251+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
252+ * GNU General Public License for more details.
253+ *
254+ * You should have received a copy of the GNU General Public License
255+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
256+ */
257+
258+#include "historygroupedeventsmodel.h"
259+#include "phoneutils_p.h"
260+#include "sort.h"
261+#include "historyqmlsort.h"
262+
263+HistoryGroupedEventsModel::HistoryGroupedEventsModel(QObject *parent) :
264+ HistoryEventModel(parent)
265+{
266+}
267+
268+int HistoryGroupedEventsModel::rowCount(const QModelIndex &parent) const
269+{
270+ if (parent.isValid()) {
271+ return 0;
272+ }
273+
274+ return mEventGroups.count();
275+}
276+
277+QVariant HistoryGroupedEventsModel::data(const QModelIndex &index, int role) const
278+{
279+ if (!index.isValid() || index.row() < 0 || index.row() >= mEventGroups.count()) {
280+ return QVariant();
281+ }
282+
283+ HistoryEventGroup group = mEventGroups[index.row()];
284+ QVariant result;
285+ QVariantList events;
286+
287+ switch (role) {
288+ case EventsRole:
289+ Q_FOREACH(const History::Event &event, group.events) {
290+ events << event.properties();
291+ }
292+ result = events;
293+ break;
294+ case EventCountRole:
295+ result = group.events.count();
296+ break;
297+ default:
298+ result = eventData(group.displayedEvent, role);
299+ break;
300+ }
301+
302+ return result;
303+}
304+
305+void HistoryGroupedEventsModel::fetchMore(const QModelIndex &parent)
306+{
307+ if (!canFetchMore(parent)) {
308+ return;
309+ }
310+
311+ History::Events events = fetchNextPage();
312+
313+ // History already deliver us the events in the right order
314+ // but we might have added new entries in the added, removed, modified events.
315+ // still, it is less expensive to do a sequential search starting from the bottom
316+ // than to do a binary search for each event, as it is very likely that the entries
317+ // belong to the bottom part of the model.
318+ Q_FOREACH(const History::Event event, events) {
319+ bool found = false;
320+ int pos = mEventGroups.count() -1;
321+ for (; pos >= 0; pos--) {
322+ HistoryEventGroup &group = mEventGroups[pos];
323+ if (areOfSameGroup(event, group.displayedEvent)) {
324+ found = true;
325+ addEventToGroup(event, group, pos);
326+ break;
327+ } else if (isAscending() ? lessThan(group.displayedEvent, event) : lessThan(event, group.displayedEvent)) {
328+ break;
329+ }
330+ }
331+
332+ if (!found) {
333+ // the item goes into a new group right after the position found above
334+ pos++;
335+ HistoryEventGroup group;
336+ group.displayedEvent = event;
337+ group.events << event;
338+ beginInsertRows(QModelIndex(), pos, pos);
339+ mEventGroups.insert(pos, group);
340+ endInsertRows();
341+ }
342+ }
343+}
344+
345+QHash<int, QByteArray> HistoryGroupedEventsModel::roleNames() const
346+{
347+ QHash<int, QByteArray> roles = HistoryEventModel::roleNames();
348+ roles[EventsRole] = "events";
349+ roles[EventCountRole] = "eventCount";
350+ return roles;
351+}
352+
353+void HistoryGroupedEventsModel::updateQuery()
354+{
355+ // remove all event groups from the model
356+ if (!mEventGroups.isEmpty()) {
357+ beginRemoveRows(QModelIndex(), 0, mEventGroups.count() - 1);
358+ mEventGroups.clear();
359+ endRemoveRows();
360+ }
361+
362+ // and ask HistoryEventModel to update the query and fetch items again
363+ HistoryEventModel::updateQuery();
364+}
365+
366+void HistoryGroupedEventsModel::onEventsAdded(const History::Events &events)
367+{
368+ if (!events.count()) {
369+ return;
370+ }
371+
372+ Q_FOREACH(const History::Event &event, events) {
373+ int pos = positionForEvent(event);
374+
375+ // check if the event belongs to the group at the position
376+ if (pos >= 0 && pos < mEventGroups.count()) {
377+ HistoryEventGroup &group = mEventGroups[pos];
378+ if (areOfSameGroup(event, group.displayedEvent)) {
379+ addEventToGroup(event, group, pos);
380+ continue;
381+ }
382+ }
383+
384+ // else, we just create a new group
385+ beginInsertRows(QModelIndex(), pos, pos);
386+ HistoryEventGroup group;
387+ group.displayedEvent = event;
388+ group.events << event;
389+ mEventGroups.insert(pos, group);
390+ endInsertRows();
391+
392+ }
393+}
394+
395+void HistoryGroupedEventsModel::onEventsModified(const History::Events &events)
396+{
397+ // FIXME: we are not yet handling events changing the property used for sorting
398+ // so for now the behavior is to find the item and check if it needs inserting or
399+ // updating in the group, which is exactly what onEventsAdded() does, so:
400+ onEventsAdded(events);
401+}
402+
403+void HistoryGroupedEventsModel::onEventsRemoved(const History::Events &events)
404+{
405+ Q_FOREACH(const History::Event &event, events) {
406+ int pos = positionForEvent(event);
407+ if (pos < 0 || pos >= rowCount()) {
408+ continue;
409+ }
410+ HistoryEventGroup &group = mEventGroups[pos];
411+ if (!group.events.contains(event)) {
412+ continue;
413+ }
414+ removeEventFromGroup(event, group, pos);
415+ }
416+}
417+
418+bool HistoryGroupedEventsModel::compareParticipants(const QStringList &list1, const QStringList &list2)
419+{
420+ if (list1.count() != list2.count()) {
421+ return false;
422+ }
423+
424+ int found = 0;
425+ Q_FOREACH(const QString &participant, list1) {
426+ Q_FOREACH(const QString &item, list2) {
427+ if (PhoneUtils::comparePhoneNumbers(participant, item)) {
428+ found++;
429+ break;
430+ }
431+ }
432+ }
433+
434+ return found == list1.count();
435+}
436+
437+bool HistoryGroupedEventsModel::areOfSameGroup(const History::Event &event1, const History::Event &event2)
438+{
439+ QVariantMap props1 = event1.properties();
440+ QVariantMap props2 = event2.properties();
441+
442+ Q_FOREACH(const QString &property, mGroupingProperties) {
443+ // first check if the property exists in the maps
444+ if (!props1.contains(property) || !props2.contains(property)) {
445+ return false;
446+ }
447+
448+ // now check if the values are the same
449+ if (property == History::FieldParticipants) {
450+ if (!compareParticipants(props1[property].toStringList(),
451+ props2[property].toStringList())) {
452+ return false;
453+ }
454+ } else if (props1[property] != props2[property]) {
455+ return false;
456+ }
457+ }
458+
459+ // if it didn't fail before, the events are indeed of the same group
460+ return true;
461+}
462+
463+void HistoryGroupedEventsModel::addEventToGroup(const History::Event &event, HistoryEventGroup &group, int row)
464+{
465+ if (!group.events.contains(event)) {
466+ // insert the event in the correct position according to the sort criteria
467+ bool append = true;
468+ for (int i = 0; i < group.events.count(); ++i) {
469+ History::Event &otherEvent = group.events[i];
470+ if (isAscending() ? lessThan(event, otherEvent) : lessThan(otherEvent, event)) {
471+ group.events.insert(i, event);
472+ append = false;
473+ break;
474+ }
475+ }
476+
477+ // if it is not above any item, just append it
478+ if (append) {
479+ group.events.append(event);
480+ }
481+ }
482+
483+ // now check if the displayed event should be updated
484+ History::Event &firstEvent = group.events.first();
485+ if (group.displayedEvent != firstEvent) {
486+ group.displayedEvent = firstEvent;
487+ QModelIndex idx(index(row));
488+ Q_EMIT dataChanged(idx, idx);
489+ }
490+}
491+
492+void HistoryGroupedEventsModel::removeEventFromGroup(const History::Event &event, HistoryEventGroup &group, int row)
493+{
494+ if (group.events.contains(event)) {
495+ group.events.removeOne(event);
496+ }
497+
498+ if (group.events.isEmpty()) {
499+ beginRemoveRows(QModelIndex(), row, row);
500+ mEventGroups.removeAt(row);
501+ endRemoveRows();
502+ return;
503+ }
504+
505+ if (group.displayedEvent == event) {
506+ // check what is the event that should be displayed
507+ group.displayedEvent = group.events.first();
508+ Q_FOREACH(const History::Event &other, group.events) {
509+ if (isAscending() ? lessThan(other, group.displayedEvent) : lessThan(group.displayedEvent, other)) {
510+ group.displayedEvent = other;
511+ }
512+ }
513+ }
514+ QModelIndex idx = index(row);
515+ Q_EMIT dataChanged(idx, idx);
516+}
517+
518+bool HistoryGroupedEventsModel::lessThan(const History::Event &left, const History::Event &right) const
519+{
520+
521+ QVariant leftValue = left.properties()[sort()->sortField()];
522+ QVariant rightValue = right.properties()[sort()->sortField()];
523+ return leftValue < rightValue;
524+}
525+
526+int HistoryGroupedEventsModel::positionForEvent(const History::Event &event) const
527+{
528+ // do a binary search for the item position on the list
529+ int lowerBound = 0;
530+ int upperBound = mEventGroups.count() - 1;
531+ if (upperBound < 0) {
532+ return 0;
533+ }
534+
535+ while (true) {
536+ int pos = (upperBound + lowerBound) / 2;
537+ const History::Event &posEvent = mEventGroups[pos].displayedEvent;
538+ if (lowerBound == pos) {
539+ if (isAscending() ? lessThan(event, posEvent) : lessThan(posEvent, event)) {
540+ return pos;
541+ }
542+ }
543+ if (isAscending() ? lessThan(posEvent, event) : lessThan(event, posEvent)) {
544+ lowerBound = pos + 1; // its in the upper
545+ if (lowerBound > upperBound) {
546+ return pos += 1;
547+ }
548+ } else if (lowerBound > upperBound) {
549+ return pos;
550+ } else {
551+ upperBound = pos - 1; // its in the lower
552+ }
553+ }
554+
555+}
556+
557+QVariant HistoryGroupedEventsModel::get(int row) const
558+{
559+ if (row >= rowCount() || row < 0) {
560+ return QVariant();
561+ }
562+
563+ return data(index(row), EventsRole);
564+}
565+
566+
567+QStringList HistoryGroupedEventsModel::groupingProperties() const
568+{
569+ return mGroupingProperties;
570+}
571+
572+void HistoryGroupedEventsModel::setGroupingProperties(const QStringList &properties)
573+{
574+ mGroupingProperties = properties;
575+ Q_EMIT groupingPropertiesChanged();
576+ triggerQueryUpdate();
577+}
578+
579+bool HistoryGroupedEventsModel::isAscending() const
580+{
581+ return sort() && sort()->sort().sortOrder() == Qt::AscendingOrder;
582+}
583
584=== added file 'Ubuntu/History/historygroupedeventsmodel.h'
585--- Ubuntu/History/historygroupedeventsmodel.h 1970-01-01 00:00:00 +0000
586+++ Ubuntu/History/historygroupedeventsmodel.h 2014-08-22 15:31:10 +0000
587@@ -0,0 +1,82 @@
588+/*
589+ * Copyright (C) 2014 Canonical, Ltd.
590+ *
591+ * Authors:
592+ * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com>
593+ *
594+ * This file is part of history-service.
595+ *
596+ * history-service is free software; you can redistribute it and/or modify
597+ * it under the terms of the GNU General Public License as published by
598+ * the Free Software Foundation; version 3.
599+ *
600+ * history-service is distributed in the hope that it will be useful,
601+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
602+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
603+ * GNU General Public License for more details.
604+ *
605+ * You should have received a copy of the GNU General Public License
606+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
607+ */
608+
609+#ifndef HISTORYGROUPEDEVENTSMODEL_H
610+#define HISTORYGROUPEDEVENTSMODEL_H
611+
612+#include "historyeventmodel.h"
613+
614+typedef struct {
615+ History::Events events;
616+ History::Event displayedEvent;
617+} HistoryEventGroup;
618+
619+class HistoryGroupedEventsModel : public HistoryEventModel
620+{
621+ Q_OBJECT
622+ Q_PROPERTY(QStringList groupingProperties
623+ READ groupingProperties
624+ WRITE setGroupingProperties
625+ NOTIFY groupingPropertiesChanged)
626+ Q_ENUMS(GroupedRole)
627+public:
628+ enum GroupedRole {
629+ EventsRole = HistoryEventModel::LastRole,
630+ EventCountRole
631+ };
632+
633+ explicit HistoryGroupedEventsModel(QObject *parent = 0);
634+
635+ // reimplemented from HistoryEventModel
636+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
637+ QVariant data(const QModelIndex &index, int role) const;
638+ Q_INVOKABLE void fetchMore(const QModelIndex &parent = QModelIndex());
639+ QHash<int, QByteArray> roleNames() const;
640+ Q_INVOKABLE QVariant get(int row) const;
641+
642+ QStringList groupingProperties() const;
643+ void setGroupingProperties(const QStringList &properties);
644+
645+ bool isAscending() const;
646+
647+Q_SIGNALS:
648+ void groupingPropertiesChanged();
649+
650+protected Q_SLOTS:
651+ void updateQuery();
652+ void onEventsAdded(const History::Events &events);
653+ void onEventsModified(const History::Events &events);
654+ void onEventsRemoved(const History::Events &events);
655+
656+protected:
657+ bool compareParticipants(const QStringList &list1, const QStringList &list2);
658+ bool areOfSameGroup(const History::Event &event1, const History::Event &event2);
659+ void addEventToGroup(const History::Event &event, HistoryEventGroup &group, int row);
660+ void removeEventFromGroup(const History::Event &event, HistoryEventGroup &group, int row);
661+ bool lessThan(const History::Event &left, const History::Event &right) const;
662+ int positionForEvent(const History::Event &event) const;
663+
664+private:
665+ QStringList mGroupingProperties;
666+ QList<HistoryEventGroup> mEventGroups;
667+};
668+
669+#endif // HISTORYGROUPEDEVENTSMODEL_H
670
671=== modified file 'Ubuntu/History/historyqmlplugin.cpp'
672--- Ubuntu/History/historyqmlplugin.cpp 2014-07-14 23:05:23 +0000
673+++ Ubuntu/History/historyqmlplugin.cpp 2014-08-22 15:31:10 +0000
674@@ -27,6 +27,7 @@
675 #include "historythreadmodel.h"
676 #include "historythreadgroupingproxymodel.h"
677 #include "historyeventmodel.h"
678+#include "historygroupedeventsmodel.h"
679 #include "historyqmltexteventattachment.h"
680 #include "sortproxymodel.h"
681 #include <QQmlEngine>
682@@ -43,6 +44,7 @@
683 {
684 // @uri History
685 qmlRegisterType<HistoryEventModel>(uri, 0, 1, "HistoryEventModel");
686+ qmlRegisterType<HistoryGroupedEventsModel>(uri, 0, 1, "HistoryGroupedEventsModel");
687 qmlRegisterType<HistoryThreadModel>(uri, 0, 1, "HistoryThreadModel");
688 qmlRegisterType<HistoryQmlFilter>(uri, 0, 1, "HistoryFilter");
689 qmlRegisterType<HistoryQmlIntersectionFilter>(uri, 0, 1, "HistoryIntersectionFilter");
690
691=== modified file 'Ubuntu/History/historythreadmodel.cpp'
692--- Ubuntu/History/historythreadmodel.cpp 2014-08-07 19:22:31 +0000
693+++ Ubuntu/History/historythreadmodel.cpp 2014-08-22 15:31:10 +0000
694@@ -35,7 +35,8 @@
695 Q_DECLARE_METATYPE(History::TextEventAttachments)
696
697 HistoryThreadModel::HistoryThreadModel(QObject *parent) :
698- QAbstractListModel(parent), mCanFetchMore(true), mFilter(0), mSort(0), mType(EventTypeText), mFetchTimer(0)
699+ QAbstractListModel(parent), mCanFetchMore(true), mFilter(0), mSort(0),
700+ mType(EventTypeText), mUpdateTimer(0)
701 {
702 // configure the roles
703 mRoles[AccountIdRole] = "accountId";
704@@ -66,7 +67,7 @@
705 connect(this, SIGNAL(modelReset()), SIGNAL(countChanged()));
706
707 // create the results view
708- updateQuery();
709+ triggerQueryUpdate();
710 }
711
712 int HistoryThreadModel::rowCount(const QModelIndex &parent) const
713@@ -213,7 +214,7 @@
714
715 void HistoryThreadModel::fetchMore(const QModelIndex &parent)
716 {
717- if (parent.isValid()) {
718+ if (parent.isValid() || mThreadView.isNull()) {
719 return;
720 }
721
722@@ -249,11 +250,11 @@
723 if (mFilter) {
724 connect(mFilter,
725 SIGNAL(filterChanged()),
726- SLOT(updateQuery()));
727+ SLOT(triggerQueryUpdate()));
728 }
729
730 Q_EMIT filterChanged();
731- updateQuery();
732+ triggerQueryUpdate();
733 }
734
735 HistoryQmlSort *HistoryThreadModel::sort() const
736@@ -272,11 +273,11 @@
737 if (mSort) {
738 connect(mSort,
739 SIGNAL(sortChanged()),
740- SLOT(updateQuery()));
741+ SLOT(triggerQueryUpdate()));
742 }
743
744 Q_EMIT sortChanged();
745- updateQuery();
746+ triggerQueryUpdate();
747 }
748
749 HistoryThreadModel::EventType HistoryThreadModel::type() const
750@@ -288,7 +289,7 @@
751 {
752 mType = value;
753 Q_EMIT typeChanged();
754- updateQuery();
755+ triggerQueryUpdate();
756 }
757
758 QString HistoryThreadModel::threadIdForParticipants(const QString &accountId, int eventType, const QStringList &participants, int matchFlags, bool create)
759@@ -324,6 +325,14 @@
760 return mThreads[row].properties();
761 }
762
763+void HistoryThreadModel::triggerQueryUpdate()
764+{
765+ if (mUpdateTimer) {
766+ killTimer(mUpdateTimer);
767+ }
768+ mUpdateTimer = startTimer(100);
769+}
770+
771 void HistoryThreadModel::updateQuery()
772 {
773 // remove all events from the model
774@@ -363,7 +372,7 @@
775 SLOT(onThreadsRemoved(History::Threads)));
776 connect(mThreadView.data(),
777 SIGNAL(invalidated()),
778- SLOT(updateQuery()));
779+ SLOT(triggerQueryUpdate()));
780
781 Q_FOREACH(const QVariant &attachment, mAttachmentCache) {
782 HistoryQmlTextEventAttachment *qmlAttachment = attachment.value<HistoryQmlTextEventAttachment *>();
783@@ -373,16 +382,10 @@
784 }
785 mAttachmentCache.clear();
786
787- if (mFetchTimer) {
788- killTimer(mFetchTimer);
789- }
790-
791 // and fetch again
792 mCanFetchMore = true;
793 Q_EMIT canFetchMoreChanged();
794-
795- // delay the loading just to give the settings some time to settle down
796- mFetchTimer = startTimer(100);
797+ fetchMore(QModelIndex());
798 }
799
800 void HistoryThreadModel::onThreadsAdded(const History::Threads &threads)
801@@ -430,10 +433,9 @@
802
803 void HistoryThreadModel::timerEvent(QTimerEvent *event)
804 {
805- if (event->timerId() == mFetchTimer) {
806- killTimer(mFetchTimer);
807- mFetchTimer = 0;
808-
809- fetchMore(QModelIndex());
810+ if (event->timerId() == mUpdateTimer) {
811+ killTimer(mUpdateTimer);
812+ mUpdateTimer = 0;
813+ updateQuery();
814 }
815 }
816
817=== modified file 'Ubuntu/History/historythreadmodel.h'
818--- Ubuntu/History/historythreadmodel.h 2014-08-07 19:22:31 +0000
819+++ Ubuntu/History/historythreadmodel.h 2014-08-22 15:31:10 +0000
820@@ -125,6 +125,7 @@
821 void canFetchMoreChanged();
822
823 protected Q_SLOTS:
824+ void triggerQueryUpdate();
825 void updateQuery();
826 void onThreadsAdded(const History::Threads &threads);
827 void onThreadsModified(const History::Threads &threads);
828@@ -142,7 +143,7 @@
829 EventType mType;
830 QHash<int, QByteArray> mRoles;
831 mutable QMap<History::TextEvent, QList<QVariant> > mAttachmentCache;
832- int mFetchTimer;
833+ int mUpdateTimer;
834 };
835
836 #endif // HISTORYTHREADMODEL_H
837
838=== modified file 'src/event.cpp'
839--- src/event.cpp 2013-09-26 21:06:50 +0000
840+++ src/event.cpp 2014-08-22 15:31:10 +0000
841@@ -55,6 +55,7 @@
842 map[FieldEventId] = eventId;
843 map[FieldSenderId] = senderId;
844 map[FieldTimestamp] = timestamp.toString(Qt::ISODate);
845+ map[FieldDate] = timestamp.date().toString(Qt::ISODate);
846 map[FieldNewEvent] = newEvent;
847 map[FieldType] = type();
848 map[FieldParticipants] = participants;
849@@ -243,6 +244,11 @@
850 return true;
851 }
852
853+bool Event::operator!=(const Event &other) const
854+{
855+ return !(*this == other);
856+}
857+
858 bool Event::operator<(const Event &other) const
859 {
860 QString selfData = accountId() + threadId() + eventId();
861
862=== modified file 'src/event.h'
863--- src/event.h 2013-09-26 21:06:50 +0000
864+++ src/event.h 2014-08-22 15:31:10 +0000
865@@ -56,6 +56,7 @@
866 QVariantMap properties() const;
867 bool isNull() const;
868 bool operator==(const Event &other) const;
869+ bool operator!=(const Event &other) const;
870 bool operator<(const Event &other) const;
871
872 protected:
873
874=== modified file 'src/types.h'
875--- src/types.h 2014-06-25 11:45:09 +0000
876+++ src/types.h 2014-08-22 15:31:10 +0000
877@@ -106,6 +106,7 @@
878 static const char* FieldUnreadCount = "unreadCount";
879 static const char* FieldSenderId = "senderId";
880 static const char* FieldTimestamp = "timestamp";
881+static const char* FieldDate = "date";
882 static const char* FieldNewEvent = "newEvent";
883
884 // text event fields

Subscribers

People subscribed via source and target branches