Changeset View
Changeset View
Standalone View
Standalone View
src/akonadi/akonadiserializer.cpp
Show All 34 Lines | |||||
35 | 35 | | |||
36 | #include "utils/mem_fn.h" | 36 | #include "utils/mem_fn.h" | ||
37 | 37 | | |||
38 | #include "akonadi/akonadiapplicationselectedattribute.h" | 38 | #include "akonadi/akonadiapplicationselectedattribute.h" | ||
39 | #include "akonadi/akonaditimestampattribute.h" | 39 | #include "akonadi/akonaditimestampattribute.h" | ||
40 | 40 | | |||
41 | using namespace Akonadi; | 41 | using namespace Akonadi; | ||
42 | 42 | | |||
43 | static const char s_contextListProperty[] = "ContextList"; | | |||
44 | static const char s_appName[] = "Zanshin"; | | |||
45 | | ||||
46 | Serializer::Serializer() | 43 | Serializer::Serializer() | ||
47 | { | 44 | { | ||
48 | } | 45 | } | ||
49 | 46 | | |||
50 | Serializer::~Serializer() | 47 | Serializer::~Serializer() | ||
51 | { | 48 | { | ||
52 | } | 49 | } | ||
53 | 50 | | |||
▲ Show 20 Lines • Show All 124 Lines • ▼ Show 20 Line(s) | 167 | { | |||
178 | task->setDone(todo->isCompleted()); | 175 | task->setDone(todo->isCompleted()); | ||
179 | task->setDoneDate(todo->completed().toLocalTime().date()); | 176 | task->setDoneDate(todo->completed().toLocalTime().date()); | ||
180 | task->setStartDate(todo->dtStart().toLocalTime().date()); | 177 | task->setStartDate(todo->dtStart().toLocalTime().date()); | ||
181 | task->setDueDate(todo->dtDue().toLocalTime().date()); | 178 | task->setDueDate(todo->dtDue().toLocalTime().date()); | ||
182 | task->setProperty("itemId", item.id()); | 179 | task->setProperty("itemId", item.id()); | ||
183 | task->setProperty("parentCollectionId", item.parentCollection().id()); | 180 | task->setProperty("parentCollectionId", item.parentCollection().id()); | ||
184 | task->setProperty("todoUid", todo->uid()); | 181 | task->setProperty("todoUid", todo->uid()); | ||
185 | task->setProperty("relatedUid", todo->relatedTo()); | 182 | task->setProperty("relatedUid", todo->relatedTo()); | ||
186 | task->setRunning(todo->customProperty("Zanshin", "Running") == QLatin1String("1")); | 183 | task->setRunning(todo->customProperty(Serializer::customPropertyAppName(), Serializer::customPropertyIsRunning()) == QLatin1String("1")); | ||
187 | 184 | | |||
188 | switch (todo->recurrence()->recurrenceType()) { | 185 | switch (todo->recurrence()->recurrenceType()) { | ||
189 | case KCalCore::Recurrence::rDaily: | 186 | case KCalCore::Recurrence::rDaily: | ||
190 | task->setRecurrence(Domain::Task::RecursDaily); | 187 | task->setRecurrence(Domain::Task::RecursDaily); | ||
191 | break; | 188 | break; | ||
192 | case KCalCore::Recurrence::rWeekly: | 189 | case KCalCore::Recurrence::rWeekly: | ||
193 | task->setRecurrence(Domain::Task::RecursWeekly); | 190 | task->setRecurrence(Domain::Task::RecursWeekly); | ||
194 | break; | 191 | break; | ||
▲ Show 20 Lines • Show All 81 Lines • ▼ Show 20 Line(s) | 269 | for (const auto &attachment : task->attachments()) { | |||
276 | else | 273 | else | ||
277 | attach->setDecodedData(attachment.data()); | 274 | attach->setDecodedData(attachment.data()); | ||
278 | attach->setMimeType(attachment.mimeType()); | 275 | attach->setMimeType(attachment.mimeType()); | ||
279 | attach->setLabel(attachment.label()); | 276 | attach->setLabel(attachment.label()); | ||
280 | todo->addAttachment(attach); | 277 | todo->addAttachment(attach); | ||
281 | } | 278 | } | ||
282 | 279 | | |||
283 | if (task->isRunning()) { | 280 | if (task->isRunning()) { | ||
284 | todo->setCustomProperty("Zanshin", "Running", "1"); | 281 | todo->setCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyIsRunning(), "1"); | ||
285 | } else { | 282 | } else { | ||
286 | todo->removeCustomProperty("Zanshin", "Running"); | 283 | todo->removeCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyIsRunning()); | ||
287 | } | 284 | } | ||
288 | 285 | | |||
289 | // Needs to be done after all other dates are positioned | 286 | // Needs to be done after all other dates are positioned | ||
290 | // since this applies the recurrence logic | 287 | // since this applies the recurrence logic | ||
291 | if (task->isDone()) | 288 | if (task->isDone()) | ||
292 | todo->setCompleted(QDateTime(task->doneDate(), QTime(), Qt::UTC)); | 289 | todo->setCompleted(QDateTime(task->doneDate(), QTime(), Qt::UTC)); | ||
293 | else | 290 | else | ||
294 | todo->setCompleted(false); | 291 | todo->setCompleted(false); | ||
▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Line(s) | |||||
344 | 341 | | |||
345 | void Serializer::promoteItemToProject(Akonadi::Item item) | 342 | void Serializer::promoteItemToProject(Akonadi::Item item) | ||
346 | { | 343 | { | ||
347 | if (!isTaskItem(item)) | 344 | if (!isTaskItem(item)) | ||
348 | return; | 345 | return; | ||
349 | 346 | | |||
350 | auto todo = item.payload<KCalCore::Todo::Ptr>(); | 347 | auto todo = item.payload<KCalCore::Todo::Ptr>(); | ||
351 | todo->setRelatedTo(QString()); | 348 | todo->setRelatedTo(QString()); | ||
352 | todo->setCustomProperty("Zanshin", "Project", QStringLiteral("1")); | 349 | todo->setCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyIsProject(), QStringLiteral("1")); | ||
353 | } | 350 | } | ||
354 | 351 | | |||
355 | void Serializer::clearItem(Akonadi::Item *item) | 352 | void Serializer::clearItem(Akonadi::Item *item) | ||
356 | { | 353 | { | ||
357 | Q_ASSERT(item); | 354 | Q_ASSERT(item); | ||
358 | if (!isTaskItem(*item)) | 355 | if (!isTaskItem(*item)) | ||
359 | return; | 356 | return; | ||
360 | 357 | | |||
361 | auto todo = item->payload<KCalCore::Todo::Ptr>(); | 358 | auto todo = item->payload<KCalCore::Todo::Ptr>(); | ||
362 | todo->removeCustomProperty(s_appName, s_contextListProperty); | 359 | todo->removeCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyContextList()); | ||
363 | } | 360 | } | ||
364 | 361 | | |||
365 | Akonadi::Item::List Serializer::filterDescendantItems(const Akonadi::Item::List &potentialChildren, const Akonadi::Item &ancestorItem) | 362 | Akonadi::Item::List Serializer::filterDescendantItems(const Akonadi::Item::List &potentialChildren, const Akonadi::Item &ancestorItem) | ||
366 | { | 363 | { | ||
367 | if (potentialChildren.isEmpty()) | 364 | if (potentialChildren.isEmpty()) | ||
368 | return Akonadi::Item::List(); | 365 | return Akonadi::Item::List(); | ||
369 | 366 | | |||
370 | Akonadi::Item::List itemsToProcess = potentialChildren; | 367 | Akonadi::Item::List itemsToProcess = potentialChildren; | ||
Show All 22 Lines | |||||
393 | } | 390 | } | ||
394 | 391 | | |||
395 | bool Serializer::isProjectItem(Item item) | 392 | bool Serializer::isProjectItem(Item item) | ||
396 | { | 393 | { | ||
397 | if (!item.hasPayload<KCalCore::Todo::Ptr>()) | 394 | if (!item.hasPayload<KCalCore::Todo::Ptr>()) | ||
398 | return false; | 395 | return false; | ||
399 | 396 | | |||
400 | auto todo = item.payload<KCalCore::Todo::Ptr>(); | 397 | auto todo = item.payload<KCalCore::Todo::Ptr>(); | ||
401 | return !todo->customProperty(s_appName, "Project").isEmpty(); | 398 | return !todo->customProperty(Serializer::customPropertyAppName(), Serializer::customPropertyIsProject()).isEmpty(); | ||
402 | } | 399 | } | ||
403 | 400 | | |||
404 | Domain::Project::Ptr Serializer::createProjectFromItem(Item item) | 401 | Domain::Project::Ptr Serializer::createProjectFromItem(Item item) | ||
405 | { | 402 | { | ||
406 | if (!isProjectItem(item)) | 403 | if (!isProjectItem(item)) | ||
407 | return Domain::Project::Ptr(); | 404 | return Domain::Project::Ptr(); | ||
408 | 405 | | |||
409 | auto project = Domain::Project::Ptr::create(); | 406 | auto project = Domain::Project::Ptr::create(); | ||
Show All 14 Lines | 412 | { | |||
424 | project->setProperty("todoUid", todo->uid()); | 421 | project->setProperty("todoUid", todo->uid()); | ||
425 | } | 422 | } | ||
426 | 423 | | |||
427 | Item Serializer::createItemFromProject(Domain::Project::Ptr project) | 424 | Item Serializer::createItemFromProject(Domain::Project::Ptr project) | ||
428 | { | 425 | { | ||
429 | auto todo = KCalCore::Todo::Ptr::create(); | 426 | auto todo = KCalCore::Todo::Ptr::create(); | ||
430 | 427 | | |||
431 | todo->setSummary(project->name()); | 428 | todo->setSummary(project->name()); | ||
432 | todo->setCustomProperty("Zanshin", "Project", QStringLiteral("1")); | 429 | todo->setCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyIsProject(), QStringLiteral("1")); | ||
433 | 430 | | |||
434 | if (project->property("todoUid").isValid()) { | 431 | if (project->property("todoUid").isValid()) { | ||
435 | todo->setUid(project->property("todoUid").toString()); | 432 | todo->setUid(project->property("todoUid").toString()); | ||
436 | } | 433 | } | ||
437 | 434 | | |||
438 | Akonadi::Item item; | 435 | Akonadi::Item item; | ||
439 | if (project->property("itemId").isValid()) { | 436 | if (project->property("itemId").isValid()) { | ||
440 | item.setId(project->property("itemId").value<Akonadi::Item::Id>()); | 437 | item.setId(project->property("itemId").value<Akonadi::Item::Id>()); | ||
Show All 14 Lines | 449 | { | |||
455 | 452 | | |||
456 | return !todoUid.isEmpty() | 453 | return !todoUid.isEmpty() | ||
457 | && !relatedUid.isEmpty() | 454 | && !relatedUid.isEmpty() | ||
458 | && todoUid == relatedUid; | 455 | && todoUid == relatedUid; | ||
459 | } | 456 | } | ||
460 | 457 | | |||
461 | static QStringList extractContexts(KCalCore::Todo::Ptr todo) | 458 | static QStringList extractContexts(KCalCore::Todo::Ptr todo) | ||
462 | { | 459 | { | ||
463 | const auto contexts = todo->customProperty(s_appName, s_contextListProperty); | 460 | const QString contexts = todo->customProperty(Serializer::customPropertyAppName(), Serializer::customPropertyContextList()); | ||
464 | return contexts.split(',', QString::SkipEmptyParts); | 461 | return contexts.split(',', QString::SkipEmptyParts); | ||
465 | } | 462 | } | ||
466 | 463 | | |||
467 | bool Serializer::isContextChild(Domain::Context::Ptr context, Item item) const | 464 | bool Serializer::isContextChild(Domain::Context::Ptr context, Item item) const | ||
468 | { | 465 | { | ||
469 | if (!context->property("todoUid").isValid()) | 466 | if (!context->property("todoUid").isValid()) | ||
470 | return false; | 467 | return false; | ||
471 | 468 | | |||
472 | if (!item.hasPayload<KCalCore::Todo::Ptr>()) | 469 | if (!item.hasPayload<KCalCore::Todo::Ptr>()) | ||
473 | return false; | 470 | return false; | ||
474 | 471 | | |||
475 | auto contextUid = context->property("todoUid").toString(); | 472 | auto contextUid = context->property("todoUid").toString(); | ||
476 | auto todo = item.payload<KCalCore::Todo::Ptr>(); | 473 | auto todo = item.payload<KCalCore::Todo::Ptr>(); | ||
477 | const auto contextList = extractContexts(todo); | 474 | const auto contextList = extractContexts(todo); | ||
478 | return contextList.contains(contextUid); | 475 | return contextList.contains(contextUid); | ||
479 | } | 476 | } | ||
480 | 477 | | |||
481 | bool Serializer::isContext(Item item) | 478 | bool Serializer::isContext(Item item) | ||
482 | { | 479 | { | ||
483 | if (!item.hasPayload<KCalCore::Todo::Ptr>()) | 480 | if (!item.hasPayload<KCalCore::Todo::Ptr>()) | ||
484 | return false; | 481 | return false; | ||
485 | 482 | | |||
486 | auto todo = item.payload<KCalCore::Todo::Ptr>(); | 483 | auto todo = item.payload<KCalCore::Todo::Ptr>(); | ||
487 | return !todo->customProperty(s_appName, "Context").isEmpty(); | 484 | return !todo->customProperty(Serializer::customPropertyAppName(), Serializer::customPropertyIsContext()).isEmpty(); | ||
488 | } | 485 | } | ||
489 | 486 | | |||
490 | Domain::Context::Ptr Serializer::createContextFromItem(Item item) | 487 | Domain::Context::Ptr Serializer::createContextFromItem(Item item) | ||
491 | { | 488 | { | ||
492 | if (!isContext(item)) | 489 | if (!isContext(item)) | ||
493 | return {}; | 490 | return {}; | ||
494 | 491 | | |||
495 | auto context = Domain::Context::Ptr::create(); | 492 | auto context = Domain::Context::Ptr::create(); | ||
496 | updateContextFromItem(context, item); | 493 | updateContextFromItem(context, item); | ||
497 | return context; | 494 | return context; | ||
498 | } | 495 | } | ||
499 | 496 | | |||
500 | Akonadi::Item Serializer::createItemFromContext(Domain::Context::Ptr context) | 497 | Akonadi::Item Serializer::createItemFromContext(Domain::Context::Ptr context) | ||
501 | { | 498 | { | ||
502 | auto todo = KCalCore::Todo::Ptr::create(); | 499 | auto todo = KCalCore::Todo::Ptr::create(); | ||
503 | 500 | | |||
504 | todo->setSummary(context->name()); | 501 | todo->setSummary(context->name()); | ||
505 | todo->setCustomProperty(s_appName, "Context", QStringLiteral("1")); | 502 | todo->setCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyIsContext(), QStringLiteral("1")); | ||
506 | 503 | | |||
507 | if (context->property("todoUid").isValid()) { | 504 | if (context->property("todoUid").isValid()) { | ||
508 | todo->setUid(context->property("todoUid").toString()); | 505 | todo->setUid(context->property("todoUid").toString()); | ||
509 | } | 506 | } | ||
510 | 507 | | |||
511 | auto item = Akonadi::Item(); | 508 | auto item = Akonadi::Item(); | ||
512 | if (context->property("itemId").isValid()) { | 509 | if (context->property("itemId").isValid()) { | ||
513 | item.setId(context->property("itemId").value<Akonadi::Item::Id>()); | 510 | item.setId(context->property("itemId").value<Akonadi::Item::Id>()); | ||
Show All 31 Lines | 535 | { | |||
545 | 542 | | |||
546 | if (!context->property("todoUid").isValid()) | 543 | if (!context->property("todoUid").isValid()) | ||
547 | return; | 544 | return; | ||
548 | 545 | | |||
549 | auto contextUid = context->property("todoUid").toString(); | 546 | auto contextUid = context->property("todoUid").toString(); | ||
550 | auto contextList = extractContexts(todo); | 547 | auto contextList = extractContexts(todo); | ||
551 | if (!contextList.contains(contextUid)) | 548 | if (!contextList.contains(contextUid)) | ||
552 | contextList.append(contextUid); | 549 | contextList.append(contextUid); | ||
553 | todo->setCustomProperty(s_appName, s_contextListProperty, contextList.join(',')); | 550 | todo->setCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyContextList(), contextList.join(',')); | ||
554 | 551 | | |||
555 | item.setPayload<KCalCore::Todo::Ptr>(todo); | 552 | item.setPayload<KCalCore::Todo::Ptr>(todo); | ||
556 | } | 553 | } | ||
557 | 554 | | |||
558 | void Serializer::removeContextFromTask(Domain::Context::Ptr context, Item item) | 555 | void Serializer::removeContextFromTask(Domain::Context::Ptr context, Item item) | ||
559 | { | 556 | { | ||
560 | if (!isTaskItem(item)) { | 557 | if (!isTaskItem(item)) { | ||
561 | qWarning() << "Cannot remove context from a non-task" << item.id(); | 558 | qWarning() << "Cannot remove context from a non-task" << item.id(); | ||
562 | return; | 559 | return; | ||
563 | } | 560 | } | ||
564 | 561 | | |||
565 | auto todo = item.payload<KCalCore::Todo::Ptr>(); | 562 | auto todo = item.payload<KCalCore::Todo::Ptr>(); | ||
566 | 563 | | |||
567 | if (!context->property("todoUid").isValid()) | 564 | if (!context->property("todoUid").isValid()) | ||
568 | return; | 565 | return; | ||
569 | 566 | | |||
570 | auto contextUid = context->property("todoUid").toString(); | 567 | auto contextUid = context->property("todoUid").toString(); | ||
571 | QStringList contextList = extractContexts(todo); | 568 | QStringList contextList = extractContexts(todo); | ||
572 | contextList.removeAll(contextUid); | 569 | contextList.removeAll(contextUid); | ||
573 | if (contextList.isEmpty()) | 570 | if (contextList.isEmpty()) | ||
574 | todo->removeCustomProperty(s_appName, s_contextListProperty); | 571 | todo->removeCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyContextList()); | ||
575 | else | 572 | else | ||
576 | todo->setCustomProperty(s_appName, s_contextListProperty, contextList.join(',')); | 573 | todo->setCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyContextList(), contextList.join(',')); | ||
577 | 574 | | |||
578 | item.setPayload<KCalCore::Todo::Ptr>(todo); | 575 | item.setPayload<KCalCore::Todo::Ptr>(todo); | ||
579 | } | 576 | } | ||
580 | 577 | | |||
581 | QString Serializer::contextUid(Item item) | 578 | QString Serializer::contextUid(Item item) | ||
582 | { | 579 | { | ||
583 | if (!isContext(item)) | 580 | if (!isContext(item)) | ||
584 | return {}; | 581 | return {}; | ||
585 | 582 | | |||
586 | auto todo = item.payload<KCalCore::Todo::Ptr>(); | 583 | auto todo = item.payload<KCalCore::Todo::Ptr>(); | ||
587 | return todo->uid(); | 584 | return todo->uid(); | ||
588 | } | 585 | } | ||
586 | | ||||
587 | // KCalCore's CustomProperties doesn't implement case insensitivity | ||||
588 | // and some CALDAV servers make everything uppercase. So do like most of kdepim | ||||
589 | // and use uppercase property names. | ||||
590 | | ||||
591 | QByteArray Serializer::customPropertyAppName() | ||||
592 | { | ||||
593 | return QByteArrayLiteral("ZANSHIN"); | ||||
594 | } | ||||
595 | | ||||
596 | QByteArray Serializer::customPropertyIsProject() | ||||
597 | { | ||||
598 | return QByteArrayLiteral("ISPROJECT"); | ||||
599 | } | ||||
600 | | ||||
601 | QByteArray Serializer::customPropertyIsContext() | ||||
602 | { | ||||
603 | return QByteArrayLiteral("ISCONTEXT"); | ||||
604 | } | ||||
605 | | ||||
606 | QByteArray Serializer::customPropertyIsRunning() | ||||
607 | { | ||||
608 | return QByteArrayLiteral("ISRUNNING"); | ||||
609 | } | ||||
610 | | ||||
611 | QByteArray Serializer::customPropertyContextList() | ||||
612 | { | ||||
613 | return QByteArrayLiteral("CONTEXTLIST"); | ||||
614 | } |