19
19
#include "ucalarm.h"
20
20
#include "ucalarm_p.h"
21
21
#include "alarmmanager_p.h"
22
#include "alarmmanager_p_p.h"
23
22
#include "alarmrequest_p.h"
24
#include "alarmrequest_p_p.h"
26
#include <qorganizer.h>
27
#include <qorganizermanager.h>
29
// FIXME: remove once we have the Organizer backend ready
23
#include "alarmsadapter_p.h"
30
25
#include <QtCore/QFile>
31
26
#include <QtCore/QDir>
32
27
#include <QtCore/QStandardPaths>
34
#define ALARM_DATABASE "%1/alarms.database"
29
#define ALARM_DATABASE "%1/alarms.database"
31
* The main alarm manager engine used from Saucy onwards is EDS (Evolution Data
32
* Server) based. Any previous release uses the generic "memory" manager engine
33
* which does not store alarm data, does not schedule organizer events and does
34
* not give visual or audible reminding.
36
#define ALARM_MANAGER "eds"
37
#define ALARM_MANAGER_FALLBACK "memory"
38
#define ALARM_COLLECTION "Alarms"
36
40
QTORGANIZER_USE_NAMESPACE
38
42
/*-----------------------------------------------------------------------------
39
* Adaptation layer for Alarms. QOrganizer implementation may not require this,
40
* however in case we decide to go with some other approach, this layer is welcome.
43
class AlarmRequestAdapter : public AlarmRequestPrivate
46
AlarmRequestAdapter(AlarmRequest *parent, bool autoDelete);
49
bool save(AlarmData &alarm);
50
bool remove(AlarmData &alarm);
53
bool start(QOrganizerAbstractRequest *operation);
55
void _q_updateProgress();
58
QOrganizerAbstractRequest *m_request;
60
void completeUpdate();
61
void completeRemove();
65
class AlarmsAdapter : public AlarmManagerPrivate
69
DifferentTypeExpected = UCAlarm::AdaptationError + 1,
70
FetchedEventEmpty, // 102
71
UnhandledEventType, // 103
72
UnhandledRequest, // 104
73
OrganizerError // 105 onwards
76
AlarmsAdapter(AlarmManager *qq);
77
virtual ~AlarmsAdapter();
79
static AlarmsAdapter* get(AlarmManager *instance = 0) {
80
return static_cast<AlarmsAdapter*>(AlarmManagerPrivate::get(instance));
83
QOrganizerManager manager;
84
QOrganizerCollection collection;
86
virtual bool fetchAlarms();
87
void completeFetchAlarms(const QList<QOrganizerItem> &alarmList);
89
// FIXME: remove once we have the Organizer backend ready
93
void rawAlarm2Organizer(const AlarmData &alarm, QOrganizerTodo &event);
94
void updateOrganizerFromRaw(const AlarmData &alarm, QOrganizerTodo &event);
95
int organizer2RawAlarm(const QOrganizerItem &item, AlarmData &alarm);
96
QSet<Qt::DayOfWeek> daysToSet(const AlarmData &alarm) const;
97
void daysFromSet(AlarmData &alarm, QSet<Qt::DayOfWeek> set);
100
/*-----------------------------------------------------------------------------
101
* Adaptation layer for Alarms. QOrganizer implementation may not require this,
102
* however in case we decide to go with some other approach, this layer is welcome.
43
* Adaptation layer for Alarms.
104
45
AlarmManagerPrivate * createAlarmsAdapter(AlarmManager *alarms)
109
50
AlarmsAdapter::AlarmsAdapter(AlarmManager *qq)
110
: AlarmManagerPrivate(qq)
52
, AlarmManagerPrivate(qq)
113
bool alarmCollectionFound = false;
114
QList<QOrganizerCollection> collections = manager.collections();
57
QOrganizerManager local;
58
bool usingDefaultManager = local.availableManagers().contains(ALARM_MANAGER);
59
manager = (usingDefaultManager) ? new QOrganizerManager(ALARM_MANAGER) : new QOrganizerManager(ALARM_MANAGER_FALLBACK);
60
manager->setParent(q_ptr);
61
if (!usingDefaultManager) {
62
qWarning() << "WARNING: default alarm manager not installed, using" << manager->managerName() << "manager.";
63
qWarning() << "This manager may not provide all the needed features.";
66
QList<QOrganizerCollection> collections = manager->collections();
115
67
if (collections.count() > 0) {
116
68
Q_FOREACH(const QOrganizerCollection &c, collections) {
117
if (c.metaData(QOrganizerCollection::KeyName).toString() == "alarms") {
118
alarmCollectionFound = true;
69
if (c.metaData(QOrganizerCollection::KeyName).toString() == ALARM_COLLECTION) {
124
if (!alarmCollectionFound) {
75
if (collection.id().isNull()) {
125
76
// create alarm collection
126
collection.setMetaData(QOrganizerCollection::KeyName, "alarms");
127
manager.saveCollection(&collection);
77
collection.setMetaData(QOrganizerCollection::KeyName, ALARM_COLLECTION);
78
// EDS requires extra metadata to be set
79
collection. setExtendedMetaData("collection-type", "Task List");
80
if (!manager->saveCollection(&collection)) {
81
qWarning() << "WARNING: Creating dedicated collection for alarms was not possible, alarms will be saved into the default collection!";
82
collection = manager->defaultCollection();
87
// connect to manager to receive changes
88
QObject::connect(manager, SIGNAL(dataChanged()), this, SLOT(fetchAlarms()));
89
QObject::connect(manager, SIGNAL(itemsAdded(QList<QOrganizerItemId>)), this, SLOT(fetchAlarms()));
90
QObject::connect(manager, SIGNAL(itemsChanged(QList<QOrganizerItemId>)), this, SLOT(fetchAlarms()));
91
QObject::connect(manager, SIGNAL(itemsRemoved(QList<QOrganizerItemId>)), this, SLOT(fetchAlarms()));
132
94
AlarmsAdapter::~AlarmsAdapter()
152
117
alarm.days = static_cast<UCAlarm::DaysOfWeek>(days);
154
119
QOrganizerTodo event;
155
rawAlarm2Organizer(alarm, event);
156
manager.saveItem(&event);
120
organizerEventFromAlarmData(alarm, event);
121
manager->saveItem(&event);
161
// FIXME: remove once we have the Organizer backend ready
126
// save fallback manager data only
162
127
void AlarmsAdapter::saveAlarms()
129
if ((manager->managerName() != ALARM_MANAGER_FALLBACK) || !listDirty) {
164
132
QDir dir(QStandardPaths::writableLocation(QStandardPaths::DataLocation));
165
133
if (!dir.exists()) {
166
134
dir.mkpath(QStandardPaths::writableLocation(QStandardPaths::DataLocation));
242
212
event.removeDetail(&old);
245
rawAlarm2Organizer(alarm, event);
215
organizerEventFromAlarmData(alarm, event);
248
int AlarmsAdapter::organizer2RawAlarm(const QOrganizerItem &item, AlarmData &alarm)
218
int AlarmsAdapter::alarmDataFromOrganizerEvent(const QOrganizerTodo &event, AlarmData &alarm)
250
if ((item.type() != QOrganizerItemType::TypeTodo) &&
251
(item.type() != QOrganizerItemType::TypeTodoOccurrence)){
252
return DifferentTypeExpected;
255
QOrganizerTodo event;
256
if (item.type() == QOrganizerItemType::TypeTodoOccurrence) {
257
QOrganizerTodoOccurrence occurence = static_cast<QOrganizerTodoOccurrence>(item);
258
QOrganizerItemId eventId = occurence.parentId();
259
event = static_cast<QOrganizerTodo>(manager.item(eventId));
261
event = static_cast<QOrganizerTodo>(item);
263
220
if (event.isEmpty()) {
264
221
return FetchedEventEmpty;
267
224
alarm.cookie = QVariant::fromValue<QOrganizerItemId>(event.id());
268
225
alarm.message = event.displayLabel();
269
alarm.date = event.dueDateTime();
226
alarm.date = AlarmData::normalizeDate(event.dueDateTime());
270
227
alarm.sound = QUrl(event.description());
272
229
// check if the alarm is enabled or not
327
284
bool AlarmsAdapter::fetchAlarms()
287
// there is already a fetch request ongoing, exit
329
290
// create self deleting request
330
AlarmRequest *request = new AlarmRequest(true, q_ptr);
331
AlarmRequestAdapter *adapter = static_cast<AlarmRequestAdapter*>(AlarmRequestPrivate::get(request));
291
fetchRequest = new AlarmRequest(true, q_ptr);
292
AlarmRequestAdapter *adapter = static_cast<AlarmRequestAdapter*>(AlarmRequestPrivate::get(fetchRequest));
332
293
return adapter->fetch();
337
298
alarmList.clear();
339
300
QSet<QOrganizerItemId> parentId;
301
QOrganizerTodo event;
340
302
Q_FOREACH(const QOrganizerItem &item, alarms) {
341
303
// repeating alarms may be fetched as occurences, therefore check their parent event
342
304
if (item.type() == QOrganizerItemType::TypeTodoOccurrence) {
343
305
QOrganizerTodoOccurrence occurence = static_cast<QOrganizerTodoOccurrence>(item);
344
if (parentId.contains(occurence.parentId())) {
345
// skip this as we only consider parent items
306
QOrganizerItemId eventId = occurence.parentId();
307
if (parentId.contains(eventId)) {
348
parentId << occurence.parentId();
349
} else if (item.type() != QOrganizerItemType::TypeTodo) {
350
// skip any other type than Event
311
event = static_cast<QOrganizerTodo>(manager->item(eventId));
312
} else if (item.type() == QOrganizerItemType::TypeTodo){
313
event = static_cast<QOrganizerTodo>(item);
354
if (organizer2RawAlarm(item, alarm) == UCAlarm::NoError) {
318
if (alarmDataFromOrganizerEvent(event, alarm) == UCAlarm::NoError) {
355
319
alarmList << alarm;
361
Q_EMIT q_ptr->alarmsChanged();
324
Q_EMIT q_ptr->alarmsChanged();
363
325
completed = true;
366
329
/*-----------------------------------------------------------------------------
388
351
if (!alarm.cookie.isValid()) {
390
AlarmsAdapter::get()->rawAlarm2Organizer(alarm, event);
353
AlarmsAdapter::get()->organizerEventFromAlarmData(alarm, event);
392
355
// update existing event
393
356
QOrganizerItemId itemId = alarm.cookie.value<QOrganizerItemId>();
394
event = AlarmsAdapter::get()->manager.item(itemId);
357
event = AlarmsAdapter::get()->manager->item(itemId);
395
358
if (event.isEmpty()) {
396
setStatus(AlarmRequest::Fail, UCAlarm::AdaptationError);
359
setStatus(AlarmRequest::Saving, AlarmRequest::Fail, UCAlarm::AdaptationError);
399
AlarmsAdapter::get()->updateOrganizerFromRaw(alarm, event);
362
AlarmsAdapter::get()->updateOrganizerEventFromAlarmData(alarm, event);
402
365
QOrganizerItemSaveRequest *operation = new QOrganizerItemSaveRequest(q_ptr);
403
operation->setManager(&AlarmsAdapter::get()->manager);
366
operation->setManager(AlarmsAdapter::get()->manager);
404
367
operation->setItem(event);
368
AlarmsAdapter::get()->listDirty = true;
405
369
return start(operation);
411
375
bool AlarmRequestAdapter::remove(AlarmData &alarm)
413
377
if (!alarm.cookie.isValid()) {
414
setStatus(AlarmRequest::Fail, UCAlarm::InvalidEvent);
378
setStatus(AlarmRequest::Canceling, AlarmRequest::Fail, UCAlarm::InvalidEvent);
418
QOrganizerItemId itemId = alarm.cookie.value<QOrganizerItemId>();
419
QOrganizerItemRemoveByIdRequest *operation = new QOrganizerItemRemoveByIdRequest(q_ptr);
420
operation->setManager(&AlarmsAdapter::get()->manager);
421
operation->setItemId(itemId);
382
QOrganizerTodo event;
383
AlarmsAdapter::get()->organizerEventFromAlarmData(alarm, event);
384
event.setId(alarm.cookie.value<QOrganizerItemId>());
386
QOrganizerItemRemoveRequest *operation = new QOrganizerItemRemoveRequest(q_ptr);
387
operation->setManager(AlarmsAdapter::get()->manager);
388
operation->setItem(event);
389
AlarmsAdapter::get()->listDirty = true;
422
390
return start(operation);
394
* Waits for event completion. msec zero means wait forever.
396
bool AlarmRequestAdapter::wait(int msec)
398
return (m_request) ? m_request->waitForFinished(msec) : true;
426
402
* Initiates alarm fetching.
428
404
bool AlarmRequestAdapter::fetch()
460
436
completed = false;
461
437
// make sure we are in progress state
462
setStatus(AlarmRequest::InProgress);
438
setStatus(requestTypeToOperation(), AlarmRequest::InProgress);
439
QObject::connect(m_request, SIGNAL(resultsAvailable()), q_ptr, SLOT(_q_updateProgress()));
463
440
if (m_request->start()) {
464
441
// check if the request got completed without having the slot called (some engines may do that)
465
442
if (!completed && m_request->state() >= QOrganizerAbstractRequest::CanceledState) {
478
455
completed = true;
480
457
QOrganizerAbstractRequest::State state = m_request->state();
458
AlarmRequest::Operation opCode = requestTypeToOperation();
482
460
case QOrganizerAbstractRequest::InactiveState: {
483
setStatus(AlarmRequest::Ready);
461
setStatus(opCode, AlarmRequest::Ready);
486
464
case QOrganizerAbstractRequest::ActiveState: {
487
setStatus(AlarmRequest::InProgress);
465
setStatus(opCode, AlarmRequest::InProgress);
488
466
completed = false;
491
469
case QOrganizerAbstractRequest::CanceledState: {
492
setStatus(AlarmRequest::Fail, AlarmsAdapter::OrganizerError + m_request->error());
470
setStatus(opCode, AlarmRequest::Fail, AlarmsAdapter::OrganizerError + m_request->error());
495
473
case QOrganizerAbstractRequest::FinishedState: {
496
474
int code = m_request->error();
497
475
if (code != QOrganizerManager::NoError) {
498
setStatus(AlarmRequest::Fail, AlarmsAdapter::OrganizerError + code);
476
setStatus(opCode, AlarmRequest::Fail, AlarmsAdapter::OrganizerError + code);
500
switch (m_request->type()) {
501
case QOrganizerAbstractRequest::ItemSaveRequest: {
479
case AlarmRequest::Saving: {
502
480
completeUpdate();
505
case QOrganizerAbstractRequest::ItemRemoveByIdRequest: {
483
case AlarmRequest::Canceling: {
506
484
completeRemove();
509
case QOrganizerAbstractRequest::ItemFetchRequest: {
487
case AlarmRequest::Fetching: {
514
492
qWarning() << "Unhandled request:" << m_request->type();
515
setStatus(AlarmRequest::Fail, AlarmsAdapter::UnhandledRequest);
493
setStatus(opCode, AlarmRequest::Fail, AlarmsAdapter::UnhandledRequest);
519
setStatus(AlarmRequest::Ready);
497
setStatus(opCode, AlarmRequest::Ready);
524
502
qWarning() << "Invalid status" << state;
525
setStatus(AlarmRequest::Fail, UCAlarm::InvalidEvent);
503
setStatus(opCode, AlarmRequest::Fail, UCAlarm::InvalidEvent);
531
509
// cleanup request
510
m_request->deleteLater();
535
513
if (autoDelete) {
519
AlarmRequest::Operation AlarmRequestAdapter::requestTypeToOperation()
521
switch (m_request->type()) {
522
case QOrganizerAbstractRequest::ItemSaveRequest: {
523
return AlarmRequest::Saving;
525
case QOrganizerAbstractRequest::ItemRemoveRequest: {
526
return AlarmRequest::Canceling;
528
case QOrganizerAbstractRequest::ItemFetchRequest: {
529
return AlarmRequest::Fetching;
532
return AlarmRequest::NoOperation;
541
536
void AlarmRequestAdapter::completeUpdate()
543
538
UCAlarm *alarm = qobject_cast<UCAlarm*>(q_ptr->parent());