Merge lp:~renatofilho/qtorganizer5-eds/fix-1426519 into lp:qtorganizer5-eds

Proposed by Renato Araujo Oliveira Filho on 2015-03-24
Status: Merged
Approved by: Charles Kerr on 2015-03-26
Approved revision: 76
Merged at revision: 80
Proposed branch: lp:~renatofilho/qtorganizer5-eds/fix-1426519
Merge into: lp:qtorganizer5-eds
Diff against target: 331 lines (+124/-16)
8 files modified
CMakeLists.txt (+1/-0)
organizer/qorganizer-eds-engine.cpp (+43/-7)
organizer/qorganizer-eds-engine.h (+3/-1)
organizer/qorganizer-eds-requestdata.cpp (+16/-4)
organizer/qorganizer-eds-requestdata.h (+1/-1)
tests/unittest/CMakeLists.txt (+0/-1)
tests/unittest/event-test.cpp (+59/-1)
tests/unittest/run-eds-test.sh (+1/-1)
To merge this branch: bzr merge lp:~renatofilho/qtorganizer5-eds/fix-1426519
Reviewer Review Type Date Requested Status
Charles Kerr (community) 2015-03-24 Approve on 2015-03-24
PS Jenkins bot continuous-integration Needs Fixing on 2015-03-24
Review via email: mp+253985@code.launchpad.net

Commit message

Implemented support for extended details.

Now you can set extended details (X-*, properties) for calendar items.

To post a comment you must log in.
Charles Kerr (charlesk) wrote :

Looks good to me. Thanks for the fast work, Renato!

Charles Kerr (charlesk) :
review: Approve
77. By Renato Araujo Oliveira Filho on 2015-03-30

Fixed wait function to not block glib.
Fixed source creation process to avoid return unready sources.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2014-09-22 13:18:51 +0000
3+++ CMakeLists.txt 2015-03-30 17:59:30 +0000
4@@ -9,6 +9,7 @@
5
6 find_package(Qt5Core REQUIRED)
7 add_definitions(-DQT_NO_KEYWORDS)
8+add_definitions(-std=c++11)
9
10 pkg_check_modules(GLIB REQUIRED glib-2.0>=2.32)
11 pkg_check_modules(GIO REQUIRED gio-2.0>=2.32)
12
13=== modified file 'organizer/qorganizer-eds-engine.cpp'
14--- organizer/qorganizer-eds-engine.cpp 2015-03-24 17:56:44 +0000
15+++ organizer/qorganizer-eds-engine.cpp 2015-03-30 17:59:30 +0000
16@@ -61,6 +61,7 @@
17 #include <QtOrganizer/QOrganizerEventOccurrence>
18 #include <QtOrganizer/QOrganizerTodoOccurrence>
19 #include <QtOrganizer/QOrganizerItemParent>
20+#include <QtOrganizer/QOrganizerItemExtendedDetail>
21
22 #include <glib.h>
23 #include <libecal/libecal.h>
24@@ -863,7 +864,7 @@
25 requestData);
26 } else {
27 requestData->prepareToUpdate();
28- saveCollectionUpdateAsyncStart(requestData);
29+ g_idle_add((GSourceFunc) saveCollectionUpdateAsyncStart, requestData);
30 }
31 }
32
33@@ -884,16 +885,16 @@
34 } else if (data->isLive()) {
35 data->commitSourceCreated();
36 data->prepareToUpdate();
37- saveCollectionUpdateAsyncStart(data);
38+ g_idle_add((GSourceFunc) saveCollectionUpdateAsyncStart, data);
39 }
40 }
41
42-void QOrganizerEDSEngine::saveCollectionUpdateAsyncStart(SaveCollectionRequestData *data)
43+gboolean QOrganizerEDSEngine::saveCollectionUpdateAsyncStart(SaveCollectionRequestData *data)
44 {
45 // check if request was destroyed by the caller
46 if (!data->isLive()) {
47 releaseRequestData(data);
48- return;
49+ return FALSE;
50 }
51
52 ESource *source = data->nextSourceToUpdate();
53@@ -906,6 +907,7 @@
54 data->finish();
55 releaseRequestData(data);
56 }
57+ return FALSE;
58 }
59
60 void QOrganizerEDSEngine::saveCollectionUpdateAsynCommited(ESource *source,
61@@ -926,7 +928,7 @@
62 }
63
64 if (data->isLive()) {
65- saveCollectionUpdateAsyncStart(data);
66+ g_idle_add((GSourceFunc) saveCollectionUpdateAsyncStart, data);
67 } else {
68 releaseRequestData(data);
69 }
70@@ -1081,11 +1083,10 @@
71 bool QOrganizerEDSEngine::waitForRequestFinished(QOrganizerAbstractRequest* req, int msecs)
72 {
73 Q_ASSERT(req);
74- Q_UNUSED(msecs);
75
76 RequestData *data = m_runningRequests.value(req);
77 if (data) {
78- data->wait();
79+ data->wait(msecs);
80 // We can delete the operation already finished
81 data->deleteLater();
82 }
83@@ -1619,6 +1620,20 @@
84 e_cal_component_free_attendee_list(attendeeList);
85 }
86
87+void QOrganizerEDSEngine::parseExtendedDetails(ECalComponent *comp, QOrganizerItem *item)
88+{
89+ icalcomponent *icalcomp = e_cal_component_get_icalcomponent(comp);
90+ for (icalproperty *prop = icalcomponent_get_first_property(icalcomp, ICAL_X_PROPERTY);
91+ prop != NULL;
92+ prop = icalcomponent_get_next_property (icalcomp, ICAL_X_PROPERTY)) {
93+
94+ QOrganizerItemExtendedDetail ex;
95+ ex.setName(QString::fromUtf8(icalproperty_get_x_name(prop)));
96+ ex.setData(QByteArray(icalproperty_get_x(prop)));
97+ item->saveDetail(&ex);
98+ }
99+}
100+
101 QOrganizerItem *QOrganizerEDSEngine::parseEvent(ECalComponent *comp)
102 {
103 QOrganizerItem *event;
104@@ -1841,6 +1856,7 @@
105 parseTags(comp, item);
106 parseReminders(comp, item);
107 parseAttendeeList(comp, item);
108+ parseExtendedDetails(comp, item);
109
110 items << *item;
111 delete item;
112@@ -2160,6 +2176,25 @@
113 e_cal_component_free_attendee_list(attendeeList);
114 }
115
116+void QOrganizerEDSEngine::parseExtendedDetails(const QOrganizerItem &item, ECalComponent *comp)
117+{
118+ icalcomponent *icalcomp = e_cal_component_get_icalcomponent(comp);
119+ Q_FOREACH(const QOrganizerItemExtendedDetail &ex, item.details(QOrganizerItemDetail::TypeExtendedDetail)) {
120+ // We only support QByteArray.
121+ // We could use QStream serialization but it will make it impossible to read it from glib side, for example indicators.
122+ QByteArray data = ex.data().toByteArray();
123+ if (data.isEmpty()) {
124+ qWarning() << "Invalid value for property" << ex.name()
125+ <<". EDS only supports QByteArray values for extended properties";
126+ continue;
127+ }
128+
129+ icalproperty *xProp = icalproperty_new_x(data.constData());
130+ icalproperty_set_x_name(xProp, ex.name().toUtf8().constData());
131+ icalcomponent_add_property(icalcomp, xProp);
132+ }
133+}
134+
135 bool QOrganizerEDSEngine::hasRecurrence(ECalComponent *comp)
136 {
137 char *rid = e_cal_component_get_recurid_as_string(comp);
138@@ -2433,6 +2468,7 @@
139 parseTags(item, comp);
140 parseReminders(item, comp);
141 parseAttendeeList(item, comp);
142+ parseExtendedDetails(item, comp);
143
144 if (!item.id().isNull()) {
145 e_cal_component_commit_sequence(comp);
146
147=== modified file 'organizer/qorganizer-eds-engine.h'
148--- organizer/qorganizer-eds-engine.h 2015-03-24 17:56:44 +0000
149+++ organizer/qorganizer-eds-engine.h 2015-03-30 17:59:30 +0000
150@@ -168,6 +168,7 @@
151 static void parseProgress(const QtOrganizer::QOrganizerItem &item, ECalComponent *comp);
152 static void parseStatus(const QtOrganizer::QOrganizerItem &item, ECalComponent *comp);
153 static void parseAttendeeList(const QtOrganizer::QOrganizerItem &item, ECalComponent *comp);
154+ static void parseExtendedDetails(const QtOrganizer::QOrganizerItem &item, ECalComponent *comp);
155
156 // ECalComponent -> QOrganizerItem
157 static bool hasRecurrence(ECalComponent *comp);
158@@ -193,6 +194,7 @@
159 static void parseProgress(ECalComponent *comp, QtOrganizer::QOrganizerItem *item);
160 static void parseStatus(ECalComponent *comp, QtOrganizer::QOrganizerItem *item);
161 static void parseAttendeeList(ECalComponent *comp, QtOrganizer::QOrganizerItem *item);
162+ static void parseExtendedDetails(ECalComponent *comp, QtOrganizer::QOrganizerItem *item);
163
164 static QDateTime fromIcalTime(struct icaltimetype value, const char *tzId);
165 static icaltimetype fromQDateTime(const QDateTime &dateTime, bool allDay, QByteArray *tzId);
166@@ -234,7 +236,7 @@
167 static void removeItemsAsyncStart(RemoveRequestData *data);
168
169 void saveCollectionAsync(QtOrganizer::QOrganizerCollectionSaveRequest *req);
170- static void saveCollectionUpdateAsyncStart(SaveCollectionRequestData *data);
171+ static gboolean saveCollectionUpdateAsyncStart(SaveCollectionRequestData *data);
172 static void saveCollectionAsyncCommited(ESourceRegistry *registry, GAsyncResult *res, SaveCollectionRequestData *data);
173 static void saveCollectionUpdateAsynCommited(ESource *source, GAsyncResult *res, SaveCollectionRequestData *data);
174
175
176=== modified file 'organizer/qorganizer-eds-requestdata.cpp'
177--- organizer/qorganizer-eds-requestdata.cpp 2015-03-06 22:47:19 +0000
178+++ organizer/qorganizer-eds-requestdata.cpp 2015-03-30 17:59:30 +0000
179@@ -19,7 +19,7 @@
180 #include "qorganizer-eds-requestdata.h"
181
182 #include <QtCore/QDebug>
183-#include <QtCore/QCoreApplication>
184+#include <QtCore/QTimer>
185
186 #include <QtOrganizer/QOrganizerAbstractRequest>
187 #include <QtOrganizer/QOrganizerManagerEngine>
188@@ -81,12 +81,24 @@
189 }
190 }
191
192-void RequestData::wait()
193+void RequestData::wait(int msec)
194 {
195 QMutexLocker locker(&m_waiting);
196- while(!m_finished) {
197- QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
198+ QEventLoop *loop = new QEventLoop;
199+ QOrganizerAbstractRequest *req = m_req.data();
200+ QObject::connect(req, &QOrganizerAbstractRequest::stateChanged, [req, loop](QOrganizerAbstractRequest::State newState) {
201+ if (newState != QOrganizerAbstractRequest::ActiveState) {
202+ loop->quit();
203+ }
204+ });
205+ QTimer timeout;
206+ if (msec > 0) {
207+ timeout.setInterval(msec);
208+ timeout.setSingleShot(true);
209+ timeout.start();
210 }
211+ loop->exec(QEventLoop::AllEvents|QEventLoop::WaitForMoreEvents);
212+ delete loop;
213 }
214
215 bool RequestData::isWaiting()
216
217=== modified file 'organizer/qorganizer-eds-requestdata.h'
218--- organizer/qorganizer-eds-requestdata.h 2015-03-06 22:47:19 +0000
219+++ organizer/qorganizer-eds-requestdata.h 2015-03-30 17:59:30 +0000
220@@ -42,7 +42,7 @@
221 virtual void cancel();
222 void deleteLater();
223 virtual void finish(QtOrganizer::QOrganizerManager::Error error, QtOrganizer::QOrganizerAbstractRequest::State state) = 0;
224- void wait();
225+ void wait(int msec = 0);
226 bool isWaiting();
227
228 template<class T>
229
230=== modified file 'tests/unittest/CMakeLists.txt'
231--- tests/unittest/CMakeLists.txt 2015-03-24 17:56:44 +0000
232+++ tests/unittest/CMakeLists.txt 2015-03-30 17:59:30 +0000
233@@ -38,7 +38,6 @@
234 )
235
236 add_definitions(-DTEST_SUITE)
237-add_definitions(-std=c++11)
238
239 declare_test(itemid-test)
240 declare_test(parseecal-test)
241
242=== modified file 'tests/unittest/event-test.cpp'
243--- tests/unittest/event-test.cpp 2014-10-29 14:19:47 +0000
244+++ tests/unittest/event-test.cpp 2015-03-30 17:59:30 +0000
245@@ -806,7 +806,6 @@
246 QList<QOrganizerItemId> ids;
247 QOrganizerItemFetchHint hint;
248 ids << items[0].id();
249- qDebug() << "Find for id" << ids;
250 QList<QOrganizerItem> newItems = m_engine->items(ids, hint, &errorMap, &error);
251 QCOMPARE(newItems.size(), 1);
252
253@@ -819,6 +818,65 @@
254 QCOMPARE(newAttendee.participationRole(), attendee.participationRole());
255 QCOMPARE(newAttendee.participationStatus(), attendee.participationStatus());
256 }
257+
258+ void testExtendedProperties()
259+ {
260+ static QString displayLabelValue = QStringLiteral("event with collection attendee");
261+ static QString descriptionValue = QStringLiteral("event without collection");
262+ QOrganizerItemId itemId;
263+ QDateTime currentTime = QDateTime::currentDateTime();
264+
265+ {
266+ // create a item with X-URL
267+ QOrganizerEvent event;
268+ event.setStartDateTime(currentTime);
269+ event.setEndDateTime(currentTime.addSecs(60 * 30));
270+ event.setDisplayLabel(displayLabelValue);
271+ event.setDescription(descriptionValue);
272+
273+ QOrganizerItemExtendedDetail ex;
274+ ex.setName(QStringLiteral("X-URL"));
275+ ex.setData(QByteArray("http://canonical.com"));
276+ event.saveDetail(&ex);
277+
278+ // save the new item
279+ QtOrganizer::QOrganizerManager::Error error;
280+ QMap<int, QtOrganizer::QOrganizerManager::Error> errorMap;
281+ QList<QOrganizerItem> items;
282+ QSignalSpy createdItem(m_engine, SIGNAL(itemsAdded(QList<QOrganizerItemId>)));
283+ items << event;
284+ bool saveResult = m_engine->saveItems(&items,
285+ QList<QtOrganizer::QOrganizerItemDetail::DetailType>(),
286+ &errorMap,
287+ &error);
288+ QTRY_COMPARE(createdItem.count(), 1);
289+ QVERIFY(saveResult);
290+ QCOMPARE(error, QOrganizerManager::NoError);
291+ QCOMPARE(items.size(), 1);
292+ QVERIFY(errorMap.isEmpty());
293+ QVERIFY(!items[0].id().isNull());
294+ QCOMPARE(items[0].details(QOrganizerItemDetail::TypeExtendedDetail).size(), 1);
295+ itemId = items[0].id();
296+ }
297+
298+ // fetch for the item
299+ {
300+ QtOrganizer::QOrganizerManager::Error error;
301+ QMap<int, QtOrganizer::QOrganizerManager::Error> errorMap;
302+ QList<QOrganizerItemId> ids;
303+ QOrganizerItemFetchHint hint;
304+ ids << itemId;
305+ QList<QOrganizerItem> items = m_engine->items(ids, hint, &errorMap, &error);
306+ QCOMPARE(items.size(), 1);
307+
308+ QList<QOrganizerItemDetail> exs = items[0].details(QOrganizerItemDetail::TypeExtendedDetail);
309+ QCOMPARE(exs.size(), 1);
310+ QCOMPARE(exs[0].value(QOrganizerItemExtendedDetail::FieldName).toString(),
311+ QStringLiteral("X-URL"));
312+ QCOMPARE(exs[0].value(QOrganizerItemExtendedDetail::FieldData).toByteArray(),
313+ QByteArray("http://canonical.com"));
314+ }
315+ }
316 };
317
318 const QString EventTest::collectionTypePropertyName = QStringLiteral("collection-type");
319
320=== modified file 'tests/unittest/run-eds-test.sh'
321--- tests/unittest/run-eds-test.sh 2014-10-28 20:54:11 +0000
322+++ tests/unittest/run-eds-test.sh 2015-03-30 17:59:30 +0000
323@@ -12,7 +12,7 @@
324 export QT_QPA_PLATFORM=minimal
325 export HOME=$TEST_TMP_DIR
326 export XDG_RUNTIME_DIR=$TEST_TMP_DIR
327-export XDG_CACHE_HOME=$TEST_TMP_DIR}/.cache
328+export XDG_CACHE_HOME=$TEST_TMP_DIR/.cache
329 export XDG_CONFIG_HOME=$TEST_TMP_DIR/.config
330 export XDG_DATA_HOME=$TEST_TMP_DIR/.local/share
331 export XDG_DESKTOP_DIR=$TEST_TMP_DIR

Subscribers

People subscribed via source and target branches