Merge lp:~zsombi/ubuntu-ui-toolkit/expose-alarm-id into lp:ubuntu-ui-toolkit/staging

Proposed by Zsombor Egri
Status: Work in progress
Proposed branch: lp:~zsombi/ubuntu-ui-toolkit/expose-alarm-id
Merge into: lp:ubuntu-ui-toolkit/staging
Diff against target: 639 lines (+268/-31)
14 files modified
components.api (+5/-3)
src/Ubuntu/Components/plugin/adapters/alarmsadapter_organizer.cpp (+149/-18)
src/Ubuntu/Components/plugin/adapters/alarmsadapter_p.h (+19/-0)
src/Ubuntu/Components/plugin/alarmmanager_p.cpp (+5/-0)
src/Ubuntu/Components/plugin/alarmmanager_p.h (+2/-0)
src/Ubuntu/Components/plugin/alarmmanager_p_p.h (+1/-0)
src/Ubuntu/Components/plugin/plugin.cpp (+2/-0)
src/Ubuntu/Components/plugin/ucalarm.cpp (+12/-1)
src/Ubuntu/Components/plugin/ucalarm.h (+3/-0)
src/Ubuntu/Components/plugin/ucalarm_p.h (+2/-0)
src/Ubuntu/Components/plugin/ucalarmmodel.cpp (+25/-9)
src/Ubuntu/Components/plugin/ucalarmmodel.h (+4/-0)
tests/resources/alarm/Alarms.qml (+2/-0)
tests/unit/tst_alarms/tst_alarms.cpp (+37/-0)
To merge this branch: bzr merge lp:~zsombi/ubuntu-ui-toolkit/expose-alarm-id
Reviewer Review Type Date Requested Status
Cris Dywan Needs Information
PS Jenkins bot continuous-integration Needs Fixing
Nekhelesh Ramananthan Pending
Review via email: mp+254084@code.launchpad.net

Commit message

Exposing Alarm.identifier and AlarmModel.find(identifier) API. Introduces alarm data versioning, introducing the version 1.1, all previous data being of version 1.0. Handles alarm data upgrades.

Description of the change

Exposing Alarm.identifier and AlarmModel.find(identifier) API. Introduces alarm data versioning, introducing the version 1.1, all previous data being of version 1.0. Handles alarm data upgrades.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Cris Dywan (kalikiana) wrote :

442 UCAlarm::~UCAlarm()
443 {
444 + if (!objectName().isEmpty()) {
445 + qDebug() << "DESTROYING" << objectName();
446 + }

Forgotten debug line? Or if this was intentional it should be a critical.

review: Approve
Revision history for this message
Zsombor Egri (zsombi) wrote :

> 442 UCAlarm::~UCAlarm()
> 443 {
> 444 + if (!objectName().isEmpty()) {
> 445 + qDebug() << "DESTROYING" << objectName();
> 446 + }
>
> Forgotten debug line? Or if this was intentional it should be a critical.

Fixed. Thanks!

Revision history for this message
Cris Dywan (kalikiana) wrote :

Thanks!

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1436. By Zsombor Egri

staging sync

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Cris Dywan (kalikiana) wrote :

What's up with this?

review: Needs Information

Unmerged revisions

1436. By Zsombor Egri

staging sync

1435. By Zsombor Egri

staging sync

1434. By Zsombor Egri

rogue debug removed

1433. By Zsombor Egri

staging merge

1432. By Zsombor Egri

alarms returned by get() and find() invokables are hashed to avoid OOM situation

1431. By Zsombor Egri

tests

1430. By Zsombor Egri

move JSON conversions into AlarmDataAdapter; data version handling added

1429. By Zsombor Egri

moving common code in separate functions

1428. By Zsombor Egri

store alarm ID as separate extended detail from activation URL; use private getter fro identifier, should be applied for the entire property set to simplify the code

1427. By Zsombor Egri

AlarmModel.find added

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'components.api'
2--- components.api 2015-07-24 13:31:03 +0000
3+++ components.api 2015-07-27 08:49:11 +0000
4@@ -81,11 +81,12 @@
5 Ubuntu.Components.ActivityIndicator 1.3: AnimatedItem
6 property bool onScreen
7 property bool running
8-Ubuntu.Components.Alarm 1.0 0.1: QtObject
9+Ubuntu.Components.Alarm 1.2 1.0 0.1: QtObject
10 property QDateTime date
11 property DaysOfWeek daysOfWeek
12 property bool enabled
13 readonly property int error
14+ readonly property string identifier 1.2
15 property string message
16 function save()
17 function cancel()
18@@ -134,10 +135,11 @@
19 Fail
20 InProgress
21 Ready
22-Ubuntu.Components.AlarmModel 1.0 0.1: QAbstractListModel
23+Ubuntu.Components.AlarmModel 1.2 1.0 0.1: QAbstractListModel
24 readonly property int count
25- function refresh() 1.0
26+ function refresh() 1.2
27 function UCAlarm* get(int index)
28+ function UCAlarm* find(string alarmId) 1.2
29 Ubuntu.Components.Argument 1.0 0.1: QtObject
30 property string help
31 function var at(int i)
32
33=== modified file 'src/Ubuntu/Components/plugin/adapters/alarmsadapter_organizer.cpp'
34--- src/Ubuntu/Components/plugin/adapters/alarmsadapter_organizer.cpp 2015-03-24 16:51:39 +0000
35+++ src/Ubuntu/Components/plugin/adapters/alarmsadapter_organizer.cpp 2015-07-27 08:49:11 +0000
36@@ -29,6 +29,8 @@
37 #include <QtCore/QJsonDocument>
38 #include <QtCore/QJsonObject>
39 #include <QtCore/QJsonArray>
40+#include <QtCore/QUuid>
41+#include <QtCore/QUrlQuery>
42 #include <QtCore/QDebug>
43
44 #define ALARM_DATABASE "%1/alarms.json"
45@@ -43,11 +45,46 @@
46 #define ALARM_COLLECTION "Alarms"
47
48 // special tags used as workaround for bug #1361702
49-const char *tagAlarmService = "x-canonical-alarm";
50-const char *tagDisabledAlarm = "x-canonical-disabled";
51+const char *tagAlarmService = "x-canonical-alarm";
52+const char *tagDisabledAlarm = "x-canonical-disabled";
53+const char *tagAlarmVersion = "x-canonical-alarm-version";
54+const char *tagAlarmId = "x-canonical-alarm-id";
55+const char *tagActivationUrl = "x-canonical-activation-url";
56+
57+const char *currentAlarmsVersion= "1.1";
58
59 QTORGANIZER_USE_NAMESPACE
60
61+QString getEventDetail(const QOrganizerItem &item, const char *detailTag)
62+{
63+ QList<QOrganizerItemDetail> details = item.details(QOrganizerItemDetail::TypeExtendedDetail);
64+ for (int i = 0; i < details.count(); i++) {
65+ QOrganizerItemDetail detail = details[i];
66+ if (detail.value(QOrganizerItemExtendedDetail::FieldName).toString() == QLatin1String(detailTag)) {
67+ return detail.value(QOrganizerItemExtendedDetail::FieldData).toString();
68+ }
69+ }
70+ return QString();
71+}
72+
73+void setEventDetail(QOrganizerItem &item, const char *detailTag, const QString &data)
74+{
75+ // remove all previous identifiers from event
76+ QList<QOrganizerItemDetail> details = item.details(QOrganizerItemDetail::TypeExtendedDetail);
77+ for (int i = 0; i < details.count(); i++) {
78+ QOrganizerItemDetail detail = details[i];
79+ if (detail.value(QOrganizerItemExtendedDetail::FieldName).toString() == QLatin1String(detailTag)) {
80+ item.removeDetail(&detail);
81+ break;
82+ }
83+ }
84+ // save the new detail
85+ QOrganizerItemExtendedDetail exData;
86+ exData.setName(detailTag);
87+ exData.setData(data);
88+ item.saveDetail(&exData);
89+}
90+
91 /*-----------------------------------------------------------------------------
92 * Adaptation layer for Alarm Data.
93 */
94@@ -171,6 +208,43 @@
95 return true;
96 }
97
98+// retrieve the identifier
99+QString AlarmDataAdapter::identifier()
100+{
101+ QString alarmId = getEventDetail(event, tagAlarmId);
102+ return alarmId;
103+}
104+
105+// creates a new identifier and sets it to the event
106+void AlarmDataAdapter::resetIdentifier(const QString &savedId)
107+{
108+ QString alarmId = savedId.isNull() ? QUuid::createUuid().toString() : savedId;
109+ setEventDetail(event, tagAlarmId, alarmId);
110+ changes |= AlarmManager::Identifier;
111+
112+ // update activation url as well
113+ QUrl url("alarm://open");
114+ QUrlQuery query;
115+ query.addQueryItem("alarmId", alarmId);
116+ url.setQuery(query);
117+ setEventDetail(event, tagActivationUrl, url.toString());
118+}
119+
120+// upgrade alarm data to the current version; returns true if upgare was needed
121+bool AlarmDataAdapter::upgradeAlarmData()
122+{
123+ QString version = getEventDetail(event, tagAlarmVersion);
124+ if (version.isEmpty() || version == QStringLiteral("1.0")) {
125+ // version 1.0, upgrade
126+ resetIdentifier();
127+ // finally upgare to the current version
128+ setEventDetail(event, tagAlarmVersion, currentAlarmsVersion);
129+ return true;
130+ }
131+ return false;
132+}
133+
134+
135 QVariant AlarmDataAdapter::cookie() const
136 {
137 return QVariant::fromValue(event.id());
138@@ -214,6 +288,12 @@
139 if (event.id().managerUri().isEmpty()) {
140 changes = AlarmManager::AllFields;
141 }
142+
143+ // make sure the alarm has an identifier set
144+ if (identifier().isEmpty()) {
145+ resetIdentifier();
146+ }
147+
148 QOrganizerItemSaveRequest *saveRequest = new QOrganizerItemSaveRequest(q_ptr);
149 saveRequest->setItem(event);
150 request = saveRequest;
151@@ -375,6 +455,37 @@
152 }
153 }
154
155+void AlarmDataAdapter::eventFromJson(const QJsonObject &object)
156+{
157+ q_ptr->setMessage(object["message"].toString());
158+ q_ptr->setDate(QDateTime::fromString(object["date"].toString()));
159+ q_ptr->setSound(object["sound"].toString());
160+ q_ptr->setType(static_cast<UCAlarm::AlarmType>(object["type"].toInt()));
161+ q_ptr->setDaysOfWeek(static_cast<UCAlarm::DaysOfWeek>(object["days"].toInt()));
162+ q_ptr->setEnabled(object["enabled"].toBool());
163+ setEventDetail(event, tagAlarmId, object[tagAlarmId].toString());
164+ setEventDetail(event, tagActivationUrl, object[tagActivationUrl].toString());
165+ setEventDetail(event, tagAlarmVersion, object[tagAlarmVersion].toString());
166+ // call checkAlarm to complete field checks (i.e. type vs daysOfWeek, kick date, etc)
167+ checkAlarm();
168+}
169+
170+QJsonObject AlarmDataAdapter::eventToJson()
171+{
172+ QJsonObject object;
173+ object[tagAlarmVersion] = QJsonValue(currentAlarmsVersion);
174+ object["message"] = message();
175+ object["date"] = date().toString();
176+ object["sound"] = sound().toString();
177+ object["type"] = QJsonValue(type());
178+ object["days"] = QJsonValue(daysOfWeek());
179+ object["enabled"] = QJsonValue(enabled());
180+ object[tagAlarmId] = QJsonValue(identifier());
181+ object[tagActivationUrl] = QJsonValue(getEventDetail(event, tagActivationUrl));
182+ return object;
183+}
184+
185+
186 /*-----------------------------------------------------------------------------
187 * Adaptation layer for Alarms.
188 */
189@@ -475,6 +586,9 @@
190 if (!file.open(QFile::ReadOnly)) {
191 return;
192 }
193+ // block the manager signals till we load the alarm data into memory
194+ manager->blockSignals(true);
195+
196 QByteArray data = file.readAll();
197 QJsonDocument document(QJsonDocument::fromJson(data));
198 QJsonArray array = document.array();
199@@ -483,20 +597,14 @@
200
201 // use UCAlarm to save store JSON data
202 UCAlarm alarm;
203- alarm.setMessage(object["message"].toString());
204- alarm.setDate(QDateTime::fromString(object["date"].toString()));
205- alarm.setSound(object["sound"].toString());
206- alarm.setType(static_cast<UCAlarm::AlarmType>(object["type"].toInt()));
207- alarm.setDaysOfWeek(static_cast<UCAlarm::DaysOfWeek>(object["days"].toInt()));
208- alarm.setEnabled(object["enabled"].toBool());
209-
210 AlarmDataAdapter *pAlarm = static_cast<AlarmDataAdapter*>(UCAlarmPrivate::get(&alarm));
211- // call checkAlarm to complete field checks (i.e. type vs daysOfWeek, kick date, etc)
212- pAlarm->checkAlarm();
213+ pAlarm->eventFromJson(object);
214 QOrganizerTodo event = pAlarm->data();
215 manager->saveItem(&event);
216 }
217 file.close();
218+ // unblock signals
219+ manager->blockSignals(false);
220 }
221
222 // save fallback manager data only
223@@ -517,13 +625,8 @@
224 for(int i = 0; i < alarmList.count(); i++) {
225 // create an UCAlarm and set its event to ease conversions
226 const UCAlarm *alarm = alarmList[i];
227- QJsonObject object;
228- object["message"] = alarm->message();
229- object["date"] = alarm->date().toString();
230- object["sound"] = alarm->sound().toString();
231- object["type"] = QJsonValue(alarm->type());
232- object["days"] = QJsonValue(alarm->daysOfWeek());
233- object["enabled"] = QJsonValue(alarm->enabled());
234+ AlarmDataAdapter *pAlarm = static_cast<AlarmDataAdapter*>(UCAlarmPrivate::get(alarm));
235+ QJsonObject object = pAlarm->eventToJson();
236 data.append(object);
237
238 }
239@@ -662,6 +765,12 @@
240 return false;
241 }
242
243+UCAlarm *AlarmsAdapter::findAlarm(const QString &alarmId) const
244+{
245+ Q_ASSERT(!alarmId.isEmpty());
246+ return const_cast<UCAlarm*>(alarmList.find(alarmId));
247+}
248+
249 // returns a todo event from an ID, which can be an occurence
250 QOrganizerTodo AlarmsAdapter::todoItem(const QOrganizerItemId &id)
251 {
252@@ -756,6 +865,12 @@
253
254 QSet<QOrganizerItemId> parentId;
255 QOrganizerTodo event;
256+ bool upgraded = false;
257+
258+ // disable manager signals till we fetch the alarms so in case we must upgrade
259+ // an alarm we won't get update signals
260+ manager->blockSignals(true);
261+
262 Q_FOREACH(const QOrganizerItem &item, fetchRequest->items()) {
263 // repeating alarms may be fetched as occurences, therefore check their parent event
264 if (item.type() == QOrganizerItemType::TypeTodoOccurrence) {
265@@ -776,10 +891,26 @@
266 UCAlarm alarm;
267 AlarmDataAdapter *pAlarm = static_cast<AlarmDataAdapter*>(UCAlarmPrivate::get(&alarm));
268 pAlarm->setData(event);
269+ // check if we need to upgrade the event to the current version
270+ if (pAlarm->upgradeAlarmData()) {
271+ // use synchronous save so we omit async signal replies
272+ event = pAlarm->data();
273+ manager->saveItem(&event);
274+ saveAlarms();
275+ upgraded = true;
276+ }
277 adjustAlarmOccurrence(*pAlarm);
278 alarmList.insert(alarm);
279 }
280
281+ // save upgrades
282+ if (upgraded) {
283+ saveAlarms();
284+ }
285+
286+ // re-enable manager signals
287+ manager->blockSignals(false);
288+
289 completed = true;
290 Q_EMIT q_ptr->alarmsRefreshed();
291 }
292
293=== modified file 'src/Ubuntu/Components/plugin/adapters/alarmsadapter_p.h'
294--- src/Ubuntu/Components/plugin/adapters/alarmsadapter_p.h 2015-03-24 16:51:39 +0000
295+++ src/Ubuntu/Components/plugin/adapters/alarmsadapter_p.h 2015-07-27 08:49:11 +0000
296@@ -49,6 +49,8 @@
297 bool setDaysOfWeek(UCAlarm::DaysOfWeek days);
298 QUrl sound() const;
299 bool setSound(const QUrl &sound);
300+ QString identifier();
301+ void resetIdentifier(const QString &savedId = QString());
302 QVariant cookie() const;
303 UCAlarm::Error checkAlarm();
304
305@@ -62,6 +64,7 @@
306
307 // adaptation specific data
308 void adjustDowSettings(UCAlarm::AlarmType type, UCAlarm::DaysOfWeek days);
309+ bool upgradeAlarmData();
310 static QSet<Qt::DayOfWeek> daysToSet(int days);
311 static UCAlarm::DaysOfWeek daysFromSet(const QSet<Qt::DayOfWeek> &set);
312
313@@ -71,6 +74,9 @@
314 }
315 void setData(const QOrganizerTodo &data);
316
317+ void eventFromJson(const QJsonObject &object);
318+ QJsonObject eventToJson();
319+
320 protected:
321 QOrganizerTodo event;
322 UCAlarm::AlarmType alarmType;
323@@ -140,6 +146,18 @@
324 UCAlarm *alarm = takeAt(index);
325 delete alarm;
326 }
327+ // find an alarm from its ID
328+ const UCAlarm *find(const QString &alarmId) const
329+ {
330+ QMapIterator< QPair<QDateTime, QOrganizerItemId>, UCAlarm* > i(data);
331+ while (i.hasNext()) {
332+ i.next();
333+ if (UCAlarmPrivate::get(i.value())->identifier() == alarmId) {
334+ return i.value();
335+ }
336+ }
337+ return NULL;
338+ }
339
340 protected:
341 // removes alarm data at index and returns the alarm pointer
342@@ -183,6 +201,7 @@
343 int alarmCount();
344 UCAlarm *getAlarmAt(int index) const;
345 bool findAlarm(const UCAlarm &alarm, const QVariant &cookie) const;
346+ UCAlarm *findAlarm(const QString &alarmId) const;
347 void adjustAlarmOccurrence(AlarmDataAdapter &alarm);
348
349 void loadAlarms();
350
351=== modified file 'src/Ubuntu/Components/plugin/alarmmanager_p.cpp'
352--- src/Ubuntu/Components/plugin/alarmmanager_p.cpp 2015-02-26 15:09:23 +0000
353+++ src/Ubuntu/Components/plugin/alarmmanager_p.cpp 2015-07-27 08:49:11 +0000
354@@ -78,6 +78,11 @@
355 return &alarm;
356 }
357
358+UCAlarm *AlarmManager::findAlarm(const QString &alarmId) const
359+{
360+ return d_ptr->findAlarm(alarmId);
361+}
362+
363 bool AlarmManager::verifyChange(UCAlarm *alarm, Change change, const QVariant &newData)
364 {
365 return d_ptr->verifyChange(alarm, change, newData);
366
367=== modified file 'src/Ubuntu/Components/plugin/alarmmanager_p.h'
368--- src/Ubuntu/Components/plugin/alarmmanager_p.h 2015-02-26 10:27:56 +0000
369+++ src/Ubuntu/Components/plugin/alarmmanager_p.h 2015-07-27 08:49:11 +0000
370@@ -89,6 +89,7 @@
371 Sound = 0x0008,
372 Type = 0x0010,
373 Days = 0x0020,
374+ Identifier = 0x0040,
375 AllFields = 0x00FF
376 };
377
378@@ -100,6 +101,7 @@
379 int alarmCount();
380 UCAlarm *alarmAt(int index);
381 UCAlarm *findAlarm(const QVariant &cookie) const;
382+ UCAlarm *findAlarm(const QString &alarmId) const;
383
384 bool verifyChange(UCAlarm *alarm, Change change, const QVariant &newData);
385 static UCAlarmPrivate *createAlarmData(UCAlarm *alarm);
386
387=== modified file 'src/Ubuntu/Components/plugin/alarmmanager_p_p.h'
388--- src/Ubuntu/Components/plugin/alarmmanager_p_p.h 2015-02-26 15:09:23 +0000
389+++ src/Ubuntu/Components/plugin/alarmmanager_p_p.h 2015-07-27 08:49:11 +0000
390@@ -47,6 +47,7 @@
391 virtual int alarmCount() = 0;
392 virtual UCAlarm *getAlarmAt(int index) const = 0;
393 virtual bool findAlarm(const UCAlarm &alarm, const QVariant &cookie) const = 0;
394+ virtual UCAlarm *findAlarm(const QString &alarmId) const = 0;
395
396 // function to verify whether the given alarm property has a given value set
397 // used for testing purposes
398
399=== modified file 'src/Ubuntu/Components/plugin/plugin.cpp'
400--- src/Ubuntu/Components/plugin/plugin.cpp 2015-07-19 17:44:46 +0000
401+++ src/Ubuntu/Components/plugin/plugin.cpp 2015-07-27 08:49:11 +0000
402@@ -197,6 +197,8 @@
403 qmlRegisterType<UCServiceProperties, 1>(uri, 1, 1, "ServiceProperties");
404
405 // register 1.2 only API
406+ qmlRegisterType<UCAlarm, 1>(uri, 1, 2, "Alarm");
407+ qmlRegisterType<UCAlarmModel, 1>(uri, 1, 2, "AlarmModel");
408 qmlRegisterType<UCListItem>(uri, 1, 2, "ListItem");
409 qmlRegisterType<UCListItemDivider>();
410 qmlRegisterUncreatableType<UCSwipeEvent>(uri, 1, 2, "SwipeEvent", "This is an event object.");
411
412=== modified file 'src/Ubuntu/Components/plugin/ucalarm.cpp'
413--- src/Ubuntu/Components/plugin/ucalarm.cpp 2015-03-03 13:47:48 +0000
414+++ src/Ubuntu/Components/plugin/ucalarm.cpp 2015-07-27 08:49:11 +0000
415@@ -41,6 +41,7 @@
416 setMessage(UbuntuI18n::instance().tr("Alarm"));
417 setType(UCAlarm::OneTime);
418 setDaysOfWeek(UCAlarm::AutoDetect);
419+ resetIdentifier();
420 }
421
422 void UCAlarmPrivate::_q_syncStatus(int operation, int status, int error) {
423@@ -64,6 +65,8 @@
424 Q_EMIT q->typeChanged();
425 if (changes & AlarmManager::Days)
426 Q_EMIT q->daysOfWeekChanged();
427+ if (changes & AlarmManager::Identifier)
428+ Q_EMIT q->identifierChanged();
429 changes = 0;
430 }
431
432@@ -482,7 +485,7 @@
433 * The property holds the alarm's sound to be played when the alarm is triggered.
434 * An empty url will mean to play the default sound.
435 *
436- * The defaul tvalue is an empty url.
437+ * The default value is an empty url.
438 */
439 QUrl UCAlarm::sound() const
440 {
441@@ -497,6 +500,14 @@
442 }
443
444 /*!
445+ * \qmlproperty string Alarm::identifier
446+ * \readonly
447+ * \since Ubuntu.Components 1.2
448+ * The property specifies the unique identifier of the alarm. The identifier is
449+ * set when created or when \l reset.
450+ */
451+
452+/*!
453 * \qmlproperty Error Alarm::error
454 * The property holds the error code occurred during the last performed operation.
455 *
456
457=== modified file 'src/Ubuntu/Components/plugin/ucalarm.h'
458--- src/Ubuntu/Components/plugin/ucalarm.h 2014-10-09 13:02:27 +0000
459+++ src/Ubuntu/Components/plugin/ucalarm.h 2015-07-27 08:49:11 +0000
460@@ -37,6 +37,7 @@
461
462 Q_PROPERTY(int error READ error NOTIFY errorChanged)
463 Q_PROPERTY(Status status READ status NOTIFY statusChanged)
464+ Q_PRIVATE_PROPERTY(d_ptr, QString identifier READ identifier NOTIFY identifierChanged REVISION 1)
465
466 Q_ENUMS(Status Operation Error AlarmType DayOfWeek)
467 Q_FLAGS(DaysOfWeek)
468@@ -121,6 +122,8 @@
469 void errorChanged();
470 void statusChanged(Operation operation);
471
472+ Q_REVISION(1) void identifierChanged();
473+
474 public Q_SLOTS:
475 void save();
476 void cancel();
477
478=== modified file 'src/Ubuntu/Components/plugin/ucalarm_p.h'
479--- src/Ubuntu/Components/plugin/ucalarm_p.h 2015-03-24 16:51:39 +0000
480+++ src/Ubuntu/Components/plugin/ucalarm_p.h 2015-07-27 08:49:11 +0000
481@@ -51,6 +51,8 @@
482 virtual bool setDaysOfWeek(UCAlarm::DaysOfWeek days) = 0;
483 virtual QUrl sound() const = 0;
484 virtual bool setSound(const QUrl &sound) = 0;
485+ virtual QString identifier() = 0;
486+ virtual void resetIdentifier(const QString &savedId = QString()) = 0;
487 virtual QVariant cookie() const = 0;
488 virtual UCAlarm::Error checkAlarm() = 0;
489
490
491=== modified file 'src/Ubuntu/Components/plugin/ucalarmmodel.cpp'
492--- src/Ubuntu/Components/plugin/ucalarmmodel.cpp 2015-06-16 13:15:41 +0000
493+++ src/Ubuntu/Components/plugin/ucalarmmodel.cpp 2015-07-27 08:49:11 +0000
494@@ -22,7 +22,6 @@
495 #include "alarmmanager_p.h"
496 #include <QtQml/QQmlPropertyMap>
497 #include <QtQml/QQmlInfo>
498-#include <QtQml/QQmlEngine>
499
500 /*!
501 * \qmltype AlarmModel
502@@ -156,6 +155,19 @@
503 refresh();
504 }
505
506+UCAlarm *UCAlarmModel::hashedAlarm(UCAlarm *alarm)
507+{
508+ UCAlarm *result = 0;
509+ const QString &id = UCAlarmPrivate::get(alarm)->identifier();
510+ result = alarmHash.value(id).data();
511+ if (!result) {
512+ result = new UCAlarm(this);
513+ UCAlarmPrivate::get(result)->copyAlarmData(*alarm);
514+ alarmHash.insert(id, QPointer<UCAlarm>(result));
515+ }
516+ return result;
517+}
518+
519 int UCAlarmModel::rowCount(const QModelIndex &parent) const
520 {
521 Q_UNUSED(parent);
522@@ -215,14 +227,18 @@
523 */
524 UCAlarm* UCAlarmModel::get(int index)
525 {
526- UCAlarm *alarm = AlarmManager::instance().alarmAt(index);
527- if (alarm) {
528- UCAlarm *tempAlarm = new UCAlarm(this);
529- UCAlarmPrivate::get(tempAlarm)->copyAlarmData(*alarm);
530- alarm = tempAlarm;
531- QQmlEngine::setObjectOwnership(tempAlarm, QQmlEngine::JavaScriptOwnership);
532- }
533- return alarm;
534+ return hashedAlarm(AlarmManager::instance().alarmAt(index));
535+}
536+
537+/*!
538+ * \qmlmethod Alarm AlarmModel::find(string alarmId)
539+ * \since Ubuntu.Components 1.2
540+ * The function returns the alarm identified by the \c alarmId. The \c alarmId
541+ * cannot be an empty string. Returns null on error.
542+ */
543+UCAlarm *UCAlarmModel::find(const QString &alarmId)
544+{
545+ return hashedAlarm(AlarmManager::instance().findAlarm(alarmId));
546 }
547
548 /*!
549
550=== modified file 'src/Ubuntu/Components/plugin/ucalarmmodel.h'
551--- src/Ubuntu/Components/plugin/ucalarmmodel.h 2015-06-16 11:34:02 +0000
552+++ src/Ubuntu/Components/plugin/ucalarmmodel.h 2015-07-27 08:49:11 +0000
553@@ -43,6 +43,7 @@
554
555 // invokables
556 Q_INVOKABLE UCAlarm *get(int index);
557+ Q_REVISION(1) Q_INVOKABLE UCAlarm *find(const QString &alarmId);
558
559 // property getters
560 int count() const;
561@@ -65,7 +66,10 @@
562 void moveFinished();
563
564 private:
565+ QHash<QString, QPointer<UCAlarm> > alarmHash;
566 bool m_moved:1;
567+
568+ UCAlarm *hashedAlarm(UCAlarm *alarm);
569 };
570
571 #endif // UCALARMSMODEL_H
572
573=== modified file 'tests/resources/alarm/Alarms.qml'
574--- tests/resources/alarm/Alarms.qml 2015-03-03 13:20:06 +0000
575+++ tests/resources/alarm/Alarms.qml 2015-07-27 08:49:11 +0000
576@@ -26,6 +26,8 @@
577 height: units.gu(71)
578 objectName: "mainView"
579
580+ applicationName: "com.canonical.alarmtest"
581+
582 AlarmModel{
583 id: alarmModel
584 }
585
586=== modified file 'tests/unit/tst_alarms/tst_alarms.cpp'
587--- tests/unit/tst_alarms/tst_alarms.cpp 2014-11-20 06:36:45 +0000
588+++ tests/unit/tst_alarms/tst_alarms.cpp 2015-07-27 08:49:11 +0000
589@@ -103,6 +103,15 @@
590 return false;
591 }
592
593+ QString createOneTime(const QString &message)
594+ {
595+ UCAlarm alarm(QDateTime::currentDateTime(), UCAlarm::AutoDetect, "test_" + message);
596+ alarm.setSound(QUrl("file:///usr/share/sounds/ubuntu/ringtones/Bliss.ogg"));
597+ alarm.save();
598+ waitForInsert();
599+ return UCAlarmPrivate::get(&alarm)->identifier();
600+ }
601+
602 private Q_SLOTS:
603
604 void initTestCase()
605@@ -583,6 +592,34 @@
606 // check the tags
607 QVERIFY(AlarmManager::instance().verifyChange(&alarm, AlarmManager::Enabled, enabled));
608 }
609+
610+ void test_alarm_identifier()
611+ {
612+ UCAlarm alarm;
613+ QVERIFY(!UCAlarmPrivate::get(&alarm)->identifier().isEmpty());
614+ }
615+
616+ void test_alarm_identifier_differs_on_reset()
617+ {
618+ UCAlarm alarm;
619+ QString id = UCAlarmPrivate::get(&alarm)->identifier();
620+ alarm.reset();
621+ QVERIFY(!UCAlarmPrivate::get(&alarm)->identifier().isEmpty());
622+ QVERIFY(UCAlarmPrivate::get(&alarm)->identifier() != id);
623+ }
624+
625+ void test_find_alarm_by_id()
626+ {
627+ QStringList ids;
628+ for (int i = 0; i < 5; i++) {
629+ ids << createOneTime(QString("find_alarm_by_id_%1").arg(i));
630+ }
631+
632+ UCAlarmModel model;
633+ for (int i = 0; i < ids.count(); i++) {
634+ QVERIFY(model.find(ids[i]));
635+ }
636+ }
637 };
638
639 QTEST_MAIN(tst_UCAlarms)

Subscribers

People subscribed via source and target branches