Merge lp:~renatofilho/qtorganizer5-eds/fix-query-with-detached-events into lp:qtorganizer5-eds
- fix-query-with-detached-events
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Bill Filler |
Approved revision: | 90 |
Merged at revision: | 93 |
Proposed branch: | lp:~renatofilho/qtorganizer5-eds/fix-query-with-detached-events |
Merge into: | lp:qtorganizer5-eds |
Prerequisite: | lp:~renatofilho/qtorganizer5-eds/optimize-query |
Diff against target: |
421 lines (+221/-50) 5 files modified
organizer/qorganizer-eds-engine.cpp (+77/-20) organizer/qorganizer-eds-engine.h (+3/-1) organizer/qorganizer-eds-fetchrequestdata.cpp (+63/-29) organizer/qorganizer-eds-fetchrequestdata.h (+5/-0) tests/unittest/recurrence-test.cpp (+73/-0) |
To merge this branch: | bzr merge lp:~renatofilho/qtorganizer5-eds/fix-query-with-detached-events |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot | continuous-integration | Approve | |
Ubuntu Phablet Team | Pending | ||
Review via email: mp+282767@code.launchpad.net |
Commit message
Populate event list with detached events.
Make sure that detached events appear on the list while fetching events.
Description of the change
PS Jenkins bot (ps-jenkins) wrote : | # |
- 88. By Renato Araujo Oliveira Filho
-
Check if request still valid bofere parse items on thread.
- 89. By Renato Araujo Oliveira Filho
-
Fixed event recurrence cb signature.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:89
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 90. By Renato Araujo Oliveira Filho
-
Avoid crash when searching with invalid filter.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:90
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Preview Diff
1 | === modified file 'organizer/qorganizer-eds-engine.cpp' |
2 | --- organizer/qorganizer-eds-engine.cpp 2016-01-25 14:17:34 +0000 |
3 | +++ organizer/qorganizer-eds-engine.cpp 2016-01-25 14:17:34 +0000 |
4 | @@ -133,7 +133,6 @@ |
5 | itemsAsyncStart(data); |
6 | } else { |
7 | data->finish(); |
8 | - releaseRequestData(data); |
9 | } |
10 | } |
11 | |
12 | @@ -175,16 +174,63 @@ |
13 | void QOrganizerEDSEngine::itemsAsyncDone(FetchRequestData *data) |
14 | { |
15 | if (data->isLive()) { |
16 | + data->compileCurrentIds(); |
17 | + itemsAsyncFetchDeatachedItems(data); |
18 | + } else { |
19 | + releaseRequestData(data); |
20 | + } |
21 | +} |
22 | + |
23 | +void QOrganizerEDSEngine::itemsAsyncFetchDeatachedItems(FetchRequestData *data) |
24 | +{ |
25 | + QString parentId = data->nextParentId(); |
26 | + if (!parentId.isEmpty()) { |
27 | + e_cal_client_get_objects_for_uid(E_CAL_CLIENT(data->client()), |
28 | + parentId.toUtf8().data(), |
29 | + data->cancellable(), |
30 | + (GAsyncReadyCallback) QOrganizerEDSEngine::itemsAsyncListByIdListed, |
31 | + data); |
32 | + } else { |
33 | itemsAsyncStart(data); |
34 | - } else { |
35 | - releaseRequestData(data); |
36 | - } |
37 | -} |
38 | - |
39 | -void QOrganizerEDSEngine::itemsAsyncListed(ECalComponent *comp, |
40 | - time_t instanceStart, |
41 | - time_t instanceEnd, |
42 | - FetchRequestData *data) |
43 | + } |
44 | +} |
45 | + |
46 | +void QOrganizerEDSEngine::itemsAsyncListByIdListed(GObject *source, |
47 | + GAsyncResult *res, |
48 | + FetchRequestData *data) |
49 | +{ |
50 | + Q_UNUSED(source); |
51 | + GError *gError = 0; |
52 | + GSList *events = 0; |
53 | + e_cal_client_get_objects_for_uid_finish(E_CAL_CLIENT(data->client()), |
54 | + res, |
55 | + &events, |
56 | + &gError); |
57 | + if (gError) { |
58 | + qWarning() << "Fail to list deatached events in calendar" << gError->message; |
59 | + g_error_free(gError); |
60 | + gError = 0; |
61 | + if (data->isLive()) { |
62 | + data->finish(QOrganizerManager::InvalidCollectionError); |
63 | + } else { |
64 | + releaseRequestData(data); |
65 | + } |
66 | + return; |
67 | + } |
68 | + |
69 | + for(GSList *e = events; e != NULL; e = e->next) { |
70 | + icalcomponent * ical = e_cal_component_get_icalcomponent(static_cast<ECalComponent*>(e->data)); |
71 | + data->appendDeatachedResult(ical); |
72 | + } |
73 | + |
74 | + itemsAsyncFetchDeatachedItems(data); |
75 | +} |
76 | + |
77 | + |
78 | +gboolean QOrganizerEDSEngine::itemsAsyncListed(ECalComponent *comp, |
79 | + time_t instanceStart, |
80 | + time_t instanceEnd, |
81 | + FetchRequestData *data) |
82 | { |
83 | Q_UNUSED(instanceStart); |
84 | Q_UNUSED(instanceEnd); |
85 | @@ -194,7 +240,9 @@ |
86 | if (icalComp) { |
87 | data->appendResult(icalComp); |
88 | } |
89 | + return TRUE; |
90 | } |
91 | + return FALSE; |
92 | } |
93 | |
94 | void QOrganizerEDSEngine::itemsAsyncListedAsComps(GObject *source, |
95 | @@ -662,7 +710,9 @@ |
96 | QOrganizerEDSEngineId *eid = new QOrganizerEDSEngineId(currentCollectionId, |
97 | QString::fromUtf8(uid)); |
98 | item.setId(QOrganizerItemId(eid)); |
99 | - item.setGuid(QString::fromUtf8(uid)); |
100 | + item.setGuid(QString("%1/%2") |
101 | + .arg(eid->m_collectionId) |
102 | + .arg(eid->m_itemId)); |
103 | |
104 | QOrganizerEDSCollectionEngineId *edsCollectionId = new QOrganizerEDSCollectionEngineId(currentCollectionId); |
105 | item.setCollectionId(QOrganizerCollectionId(edsCollectionId)); |
106 | @@ -2349,12 +2399,21 @@ |
107 | QOrganizerItem *item, |
108 | QOrganizerEDSCollectionEngineId *edsCollectionId) |
109 | { |
110 | + |
111 | ECalComponentId *id = e_cal_component_get_id(comp); |
112 | QOrganizerEDSEngineId *edsParentId = 0; |
113 | - QOrganizerEDSEngineId *edsId = QOrganizerEDSEngineId::fromComponentId(edsCollectionId->m_collectionId, id, &edsParentId); |
114 | - |
115 | + QOrganizerEDSEngineId *edsId; |
116 | + |
117 | + if (!edsCollectionId) { |
118 | + qWarning() << "Parse Id with null collection"; |
119 | + return; |
120 | + } |
121 | + |
122 | + edsId = QOrganizerEDSEngineId::fromComponentId(edsCollectionId->m_collectionId, id, &edsParentId); |
123 | item->setId(QOrganizerItemId(edsId)); |
124 | - item->setGuid(QString::fromUtf8(id->uid)); |
125 | + item->setGuid(QString("%1/%2") |
126 | + .arg(edsCollectionId->m_collectionId) |
127 | + .arg(edsId->m_itemId)); |
128 | |
129 | if (edsParentId) { |
130 | QOrganizerItemParent itemParent = item->detail(QOrganizerItemDetail::TypeParent); |
131 | @@ -2633,14 +2692,12 @@ |
132 | e_cal_component_set_uid(comp, cId.toUtf8().data()); |
133 | |
134 | if (!rId.isEmpty()) { |
135 | - ECalComponentRange *recur_id; |
136 | + ECalComponentRange recur_id; |
137 | struct icaltimetype tt = icaltime_from_string(rId.toUtf8().data()); |
138 | |
139 | - recur_id = g_new0 (ECalComponentRange, 1); |
140 | - recur_id->type = E_CAL_COMPONENT_RANGE_SINGLE; |
141 | - recur_id->datetime.value = &tt; |
142 | - e_cal_component_set_recurid(comp, recur_id); |
143 | - g_free (recur_id); |
144 | + recur_id.type = E_CAL_COMPONENT_RANGE_SINGLE; |
145 | + recur_id.datetime.value = &tt; |
146 | + e_cal_component_set_recurid(comp, &recur_id); |
147 | } |
148 | } |
149 | } |
150 | |
151 | === modified file 'organizer/qorganizer-eds-engine.h' |
152 | --- organizer/qorganizer-eds-engine.h 2016-01-25 14:17:34 +0000 |
153 | +++ organizer/qorganizer-eds-engine.h 2016-01-25 14:17:34 +0000 |
154 | @@ -217,9 +217,11 @@ |
155 | // glib callback |
156 | void itemsAsync(QtOrganizer::QOrganizerItemFetchRequest *req); |
157 | static void itemsAsyncStart(FetchRequestData *data); |
158 | - static void itemsAsyncListed(ECalComponent *comp, time_t instanceStart, time_t instanceEnd, FetchRequestData *data); |
159 | + static gboolean itemsAsyncListed(ECalComponent *comp, time_t instanceStart, time_t instanceEnd, FetchRequestData *data); |
160 | static void itemsAsyncDone(FetchRequestData *data); |
161 | static void itemsAsyncListedAsComps(GObject *source, GAsyncResult *res, FetchRequestData *data); |
162 | + static void itemsAsyncFetchDeatachedItems(FetchRequestData *data); |
163 | + static void itemsAsyncListByIdListed(GObject *source, GAsyncResult *res, FetchRequestData *data); |
164 | |
165 | void itemsByIdAsync(QtOrganizer::QOrganizerItemFetchByIdRequest *req); |
166 | static void itemsByIdAsyncStart(FetchByIdRequestData *data); |
167 | |
168 | === modified file 'organizer/qorganizer-eds-fetchrequestdata.cpp' |
169 | --- organizer/qorganizer-eds-fetchrequestdata.cpp 2016-01-25 14:17:34 +0000 |
170 | +++ organizer/qorganizer-eds-fetchrequestdata.cpp 2016-01-25 14:17:34 +0000 |
171 | @@ -17,6 +17,7 @@ |
172 | */ |
173 | |
174 | #include "qorganizer-eds-fetchrequestdata.h" |
175 | +#include "qorganizer-eds-engineid.h" |
176 | |
177 | #include <QtCore/QDebug> |
178 | |
179 | @@ -64,6 +65,16 @@ |
180 | } |
181 | } |
182 | |
183 | +QString FetchRequestData::nextParentId() |
184 | +{ |
185 | + QString nextId; |
186 | + if (!m_currentParentIds.isEmpty()) { |
187 | + nextId = m_currentParentIds.values().first(); |
188 | + m_currentParentIds.remove(nextId); |
189 | + } |
190 | + return nextId; |
191 | +} |
192 | + |
193 | QString FetchRequestData::collection() const |
194 | { |
195 | return m_current; |
196 | @@ -119,6 +130,16 @@ |
197 | RequestData::cancel(); |
198 | } |
199 | |
200 | +void FetchRequestData::compileCurrentIds() |
201 | +{ |
202 | + for(GSList *e = m_currentComponents; e != NULL; e = e->next) { |
203 | + icalcomponent *icalComp = static_cast<icalcomponent *>(e->data); |
204 | + if (e_cal_util_component_has_recurrences (icalComp)) { |
205 | + m_currentParentIds.insert(QString::fromUtf8(icalcomponent_get_uid(icalComp))); |
206 | + } |
207 | + } |
208 | +} |
209 | + |
210 | void FetchRequestData::finish(QOrganizerManager::Error error, |
211 | QOrganizerAbstractRequest::State state) |
212 | { |
213 | @@ -126,21 +147,18 @@ |
214 | m_parseListener = new FetchRequestDataParseListener(this, |
215 | error, |
216 | state); |
217 | -#if 1 |
218 | - parent()->parseEventsAsync(m_components, |
219 | - true, |
220 | - request<QOrganizerItemFetchRequest>()->fetchHint().detailTypesHint(), |
221 | - m_parseListener, |
222 | - SLOT(onParseDone(QList<QtOrganizer::QOrganizerItem>))); |
223 | -#else |
224 | - Q_FOREACH(const QString &id, m_components.keys()) { |
225 | - appendResults(parent()->parseEvents(id, m_components[id], true, request<QOrganizerItemFetchRequest>()->fetchHint().detailTypesHint())); |
226 | + QOrganizerItemFetchRequest *req = request<QOrganizerItemFetchRequest>(); |
227 | + if (req) { |
228 | + parent()->parseEventsAsync(m_components, |
229 | + true, |
230 | + req->fetchHint().detailTypesHint(), |
231 | + m_parseListener, |
232 | + SLOT(onParseDone(QList<QtOrganizer::QOrganizerItem>))); |
233 | + |
234 | + return; |
235 | } |
236 | - finishContinue(error, state); |
237 | -#endif |
238 | - } else { |
239 | - finishContinue(error, state); |
240 | } |
241 | + finishContinue(error, state); |
242 | } |
243 | |
244 | void FetchRequestData::finishContinue(QOrganizerManager::Error error, |
245 | @@ -169,27 +187,43 @@ |
246 | m_currentComponents = g_slist_append(m_currentComponents, comp); |
247 | } |
248 | |
249 | +void FetchRequestData::appendDeatachedResult(icalcomponent *comp) |
250 | +{ |
251 | + const gchar *uid; |
252 | + struct icaltimetype rid; |
253 | + |
254 | + uid = icalcomponent_get_uid(comp); |
255 | + rid = icalcomponent_get_recurrenceid(comp); |
256 | + |
257 | + for(GSList *e=m_currentComponents; e != NULL; e = e->next) { |
258 | + icalcomponent *ical = static_cast<icalcomponent *>(e->data); |
259 | + if ((g_strcmp0(uid, icalcomponent_get_uid(ical)) == 0) && |
260 | + (icaltime_compare(rid, icalcomponent_get_recurrenceid(ical)) == 0)) { |
261 | + |
262 | + // replace instance event |
263 | + icalcomponent_free (ical); |
264 | + e->data = icalcomponent_new_clone(comp); |
265 | + QString itemId = QString("%1/%2#%3") |
266 | + .arg(QString(m_current).replace(QOrganizerEDSEngineId::managerUriStatic() + ":", "")) |
267 | + .arg(QString::fromUtf8(uid)) |
268 | + .arg(QString::fromUtf8(icaltime_as_ical_string(rid))); |
269 | + m_deatachedIds.append(itemId); |
270 | + break; |
271 | + } |
272 | + } |
273 | +} |
274 | + |
275 | int FetchRequestData::appendResults(QList<QOrganizerItem> results) |
276 | { |
277 | int count = 0; |
278 | - // check if we really need filter or sort the result |
279 | QOrganizerItemFetchRequest *req = request<QOrganizerItemFetchRequest>(); |
280 | QOrganizerItemFilter filter = req->filter(); |
281 | - if ((filter.type() == QOrganizerItemFilter::DefaultFilter) && |
282 | - req->sorting().isEmpty()) { |
283 | - m_results += results; |
284 | - count = results.size(); |
285 | - } else { |
286 | - Q_FOREACH(const QOrganizerItem &item, results) { |
287 | - if ((req->filter().type() == QOrganizerItemFilter::DefaultFilter) || |
288 | - QOrganizerManagerEngine::testFilter(req->filter(), item)) { |
289 | - if (!req->sorting().isEmpty()) { |
290 | - QOrganizerManagerEngine::addSorted(&m_results, item, req->sorting()); |
291 | - } else { |
292 | - m_results << item; |
293 | - } |
294 | - count++; |
295 | - } |
296 | + QList<QOrganizerItemSortOrder> sorting = req->sorting(); |
297 | + |
298 | + Q_FOREACH(QOrganizerItem item, results) { |
299 | + if (QOrganizerManagerEngine::testFilter(filter, item)) { |
300 | + QOrganizerManagerEngine::addSorted(&m_results, item, sorting); |
301 | + count++; |
302 | } |
303 | } |
304 | return count; |
305 | |
306 | === modified file 'organizer/qorganizer-eds-fetchrequestdata.h' |
307 | --- organizer/qorganizer-eds-fetchrequestdata.h 2016-01-25 14:17:34 +0000 |
308 | +++ organizer/qorganizer-eds-fetchrequestdata.h 2016-01-25 14:17:34 +0000 |
309 | @@ -33,16 +33,19 @@ |
310 | ~FetchRequestData(); |
311 | |
312 | QString nextCollection(); |
313 | + QString nextParentId(); |
314 | QString collection() const; |
315 | time_t startDate() const; |
316 | time_t endDate() const; |
317 | bool hasDateInterval() const; |
318 | bool filterIsValid() const; |
319 | void cancel(); |
320 | + void compileCurrentIds(); |
321 | |
322 | void finish(QtOrganizer::QOrganizerManager::Error error = QtOrganizer::QOrganizerManager::NoError, |
323 | QtOrganizer::QOrganizerAbstractRequest::State state = QtOrganizer::QOrganizerAbstractRequest::FinishedState); |
324 | void appendResult(icalcomponent *comp); |
325 | + void appendDeatachedResult(icalcomponent *comp); |
326 | int appendResults(QList<QtOrganizer::QOrganizerItem> results); |
327 | QString dateFilter(); |
328 | |
329 | @@ -50,6 +53,8 @@ |
330 | FetchRequestDataParseListener *m_parseListener; |
331 | QMap<QString, GSList*> m_components; |
332 | QStringList m_collections; |
333 | + QSet<QString> m_currentParentIds; |
334 | + QStringList m_deatachedIds; |
335 | QString m_current; |
336 | GSList* m_currentComponents; |
337 | QList<QtOrganizer::QOrganizerItem> m_results; |
338 | |
339 | === modified file 'tests/unittest/recurrence-test.cpp' |
340 | --- tests/unittest/recurrence-test.cpp 2015-02-26 17:30:35 +0000 |
341 | +++ tests/unittest/recurrence-test.cpp 2016-01-25 14:17:34 +0000 |
342 | @@ -632,6 +632,79 @@ |
343 | QCOMPARE(savedRule.limitDate().isValid(), false); |
344 | QCOMPARE(savedRule.limitCount(), -1); |
345 | } |
346 | + |
347 | + void testModifiedRecurrenceDescription() |
348 | + { |
349 | + static QString displayLabelValue = QStringLiteral("testModifiedRecurrenceDescription test"); |
350 | + static QString descriptionValue = QStringLiteral("testModifiedRecurrenceDescription description"); |
351 | + |
352 | + // create a recurrence event |
353 | + QOrganizerEvent ev; |
354 | + ev.setCollectionId(m_collection.id()); |
355 | + ev.setStartDateTime(QDateTime(QDate(2013, 12, 2), QTime(0,0,0))); |
356 | + ev.setEndDateTime(QDateTime(QDate(2013, 12, 2), QTime(0,30,0))); |
357 | + ev.setDisplayLabel(displayLabelValue); |
358 | + ev.setDescription(descriptionValue); |
359 | + |
360 | + QOrganizerRecurrenceRule rule; |
361 | + rule.setFrequency(QOrganizerRecurrenceRule::Daily); |
362 | + rule.setLimit(QDate(2013, 12, 31)); |
363 | + ev.setRecurrenceRule(rule); |
364 | + |
365 | + QSignalSpy itemsAdded(m_engine, SIGNAL(itemsAdded(QList<QOrganizerItemId>))); |
366 | + QtOrganizer::QOrganizerManager::Error error; |
367 | + QMap<int, QtOrganizer::QOrganizerManager::Error> errorMap; |
368 | + QList<QOrganizerItem> items; |
369 | + items << ev; |
370 | + bool saveResult = m_engine->saveItems(&items, |
371 | + QList<QtOrganizer::QOrganizerItemDetail::DetailType>(), |
372 | + &errorMap, |
373 | + &error); |
374 | + QVERIFY(saveResult); |
375 | + QCOMPARE(error, QtOrganizer::QOrganizerManager::NoError); |
376 | + QTRY_COMPARE_WITH_TIMEOUT(itemsAdded.count(), 1, 10000); |
377 | + |
378 | + // modify the second ocurrence |
379 | + QOrganizerItemSortOrder sort; |
380 | + QOrganizerItemFetchHint hint; |
381 | + QOrganizerItemCollectionFilter filter; |
382 | + filter.setCollectionId(m_collection.id()); |
383 | + |
384 | + items = m_engine->items(filter, |
385 | + QDateTime(QDate(2013, 12, 1), QTime(0,0,0)), |
386 | + QDateTime(QDate(2013, 12, 31), QTime(0,0,0)), |
387 | + 100, |
388 | + sort, |
389 | + hint, |
390 | + &error); |
391 | + |
392 | + QOrganizerItem ocurr = items.at(1); |
393 | + ocurr.setDescription(QString("%1 modified").arg(descriptionValue)); |
394 | + items.clear(); |
395 | + items << ocurr; |
396 | + saveResult = m_engine->saveItems(&items, |
397 | + QList<QtOrganizer::QOrganizerItemDetail::DetailType>(), |
398 | + &errorMap, |
399 | + &error); |
400 | + QVERIFY(saveResult); |
401 | + QCOMPARE(error, QtOrganizer::QOrganizerManager::NoError); |
402 | + QVERIFY(errorMap.isEmpty()); |
403 | + QTRY_COMPARE_WITH_TIMEOUT(itemsAdded.count(), 2, 10000); |
404 | + |
405 | + // Fetch items by date and check if the modified recurrence has his own id |
406 | + items = m_engine->items(filter, |
407 | + QDateTime(QDate(2013, 12, 1), QTime(0,0,0)), |
408 | + QDateTime(QDate(2013, 12, 31), QTime(0,0,0)), |
409 | + 100, |
410 | + sort, |
411 | + hint, |
412 | + &error); |
413 | + |
414 | + // Check if the modified item appear on the list |
415 | + QOrganizerItem ocurr1 = items.at(1); |
416 | + QCOMPARE(ocurr1.description(), QString("%1 modified").arg(descriptionValue)); |
417 | + QVERIFY(!ocurr1.id().isNull()); |
418 | + } |
419 | }; |
420 | |
421 | QTEST_MAIN(RecurrenceTest) |
PASSED: Continuous integration, rev:87 jenkins. qa.ubuntu. com/job/ qtorganizer5- eds-ci/ 243/ jenkins. qa.ubuntu. com/job/ qtorganizer5- eds-vivid- amd64-ci/ 50 jenkins. qa.ubuntu. com/job/ qtorganizer5- eds-vivid- armhf-ci/ 50 jenkins. qa.ubuntu. com/job/ qtorganizer5- eds-vivid- armhf-ci/ 50/artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ qtorganizer5- eds-vivid- i386-ci/ 50
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/qtorganizer 5-eds-ci/ 243/rebuild
http://