45 #include <kcalcore/visitor.h>
46 using namespace KCalCore;
48 #include <kpimidentities/identitymanager.h>
50 #include <kpimutils/email.h>
51 #include <kpimutils/linklocator.h>
53 #include <KCalendarSystem>
55 #include <KIconLoader>
56 #include <KLocalizedString>
59 #include <KSystemTimeZone>
61 #include <QtCore/QBitArray>
62 #include <QApplication>
64 #include <QTextDocument>
66 using namespace KCalUtils;
67 using namespace IncidenceFormatter;
74 static QString string2HTML(
const QString &str)
78 return KPIMUtils::LinkLocator::convertToHtml(str);
81 static bool thatIsMe(
const QString &email)
83 return KPIMIdentities::IdentityManager(
true).thatIsMe(email);
89 return thatIsMe(attendee->email());
92 static bool iamPerson(
const Person &person)
95 return thatIsMe(person.
email());
98 static QString htmlAddLink(
const QString &ref,
const QString &text,
101 QString tmpStr(QLatin1String(
"<a href=\"") + ref + QLatin1String(
"\">") + text + QLatin1String(
"</a>"));
103 tmpStr += QLatin1Char(
'\n');
108 static QString htmlAddMailtoLink(
const QString &email,
const QString &name)
112 if (!email.isEmpty()) {
113 Person person(name, email);
114 if (!iamPerson(person)) {
115 QString path = person.
fullName().simplified();
116 if (path.isEmpty() || path.startsWith(QLatin1Char(
'"'))) {
120 mailto.setProtocol(QLatin1String(
"mailto"));
121 mailto.setPath(path);
122 const QString iconPath =
123 KIconLoader::global()->iconPath(QLatin1String(
"mail-message-new"), KIconLoader::Small);
124 str = htmlAddLink(mailto.url(), QLatin1String(
"<img valign=\"top\" src=\"") + iconPath + QLatin1String(
"\">"));
130 static QString htmlAddUidLink(
const QString &email,
const QString &name,
const QString &uid)
134 if (!uid.isEmpty()) {
136 if (name.isEmpty()) {
138 str += htmlAddLink(QLatin1String(
"uid:") + uid, email);
140 str += htmlAddLink(QLatin1String(
"uid:") + uid, name);
146 static QString htmlAddTag(
const QString &tag,
const QString &text)
148 int numLineBreaks = text.count(QLatin1String(
"\n"));
149 QString str = QLatin1Char(
'<') + tag + QLatin1Char(
'>');
150 QString tmpText = text;
151 QString tmpStr = str;
152 if (numLineBreaks >= 0) {
153 if (numLineBreaks > 0) {
156 for (
int i = 0; i <= numLineBreaks; ++i) {
157 pos = tmpText.indexOf(QLatin1String(
"\n"));
158 tmp = tmpText.left(pos);
159 tmpText = tmpText.right(tmpText.length() - pos - 1);
160 tmpStr += tmp + QLatin1String(
"<br>");
166 tmpStr += QLatin1String(
"</") + tag + QLatin1Char(
'>');
170 static QPair<QString, QString> searchNameAndUid(
const QString &email,
const QString &name,
176 QPair<QString, QString>s;
179 if (!email.isEmpty() && (name.isEmpty() || uid.isEmpty())) {
185 static QString searchName(
const QString &email,
const QString &name)
187 const QString printName = name.isEmpty() ? email : name;
191 static bool iamOrganizer(Incidence::Ptr incidence)
199 return thatIsMe(incidence->organizer()->email());
202 static bool senderIsOrganizer(Incidence::Ptr incidence,
const QString &sender)
206 if (!incidence || sender.isEmpty()) {
211 QString senderName, senderEmail;
212 if (KPIMUtils::extractEmailAddressAndName(sender, senderEmail, senderName)) {
214 if (incidence->organizer()->email() != senderEmail &&
215 incidence->organizer()->name() != senderName) {
222 static bool attendeeIsOrganizer(
const Incidence::Ptr &incidence,
const Attendee::Ptr &attendee)
224 if (incidence && attendee &&
225 (incidence->organizer()->email() == attendee->email())) {
232 static QString organizerName(
const Incidence::Ptr incidence,
const QString &defName)
235 if (!defName.isEmpty()) {
238 tName = i18n(
"Organizer Unknown");
243 name = incidence->organizer()->name();
244 if (name.isEmpty()) {
245 name = incidence->organizer()->email();
248 if (name.isEmpty()) {
254 static QString firstAttendeeName(
const Incidence::Ptr &incidence,
const QString &defName)
257 if (!defName.isEmpty()) {
260 tName = i18n(
"Sender");
266 if (attendees.count() > 0) {
268 name = attendee->name();
269 if (name.isEmpty()) {
270 name = attendee->email();
274 if (name.isEmpty()) {
285 iconPath = KIconLoader::global()->iconPath(QLatin1String(
"dialog-ok-apply"), KIconLoader::Small);
288 iconPath = KIconLoader::global()->iconPath(QLatin1String(
"dialog-cancel"), KIconLoader::Small);
291 iconPath = KIconLoader::global()->iconPath(QLatin1String(
"help-about"), KIconLoader::Small);
294 iconPath = KIconLoader::global()->iconPath(QLatin1String(
"help-about"), KIconLoader::Small);
297 iconPath = KIconLoader::global()->iconPath(QLatin1String(
"dialog-ok"), KIconLoader::Small);
300 iconPath = KIconLoader::global()->iconPath(QLatin1String(
"mail-forward"), KIconLoader::Small);
303 iconPath = KIconLoader::global()->iconPath(QLatin1String(
"mail-mark-read"), KIconLoader::Small);
317 static QString displayViewFormatPerson(
const QString &email,
const QString &name,
318 const QString &uid,
const QString &iconPath)
321 QPair<QString, QString> s = searchNameAndUid(email, name, uid);
322 const QString printName = s.first;
323 const QString printUid = s.second;
325 QString personString;
326 if (!iconPath.isEmpty()) {
327 personString += QLatin1String(
"<img valign=\"top\" src=\"") + iconPath + QLatin1String(
"\">") + QLatin1String(
" ");
331 if (!printUid.isEmpty()) {
332 personString += htmlAddUidLink(email, printName, printUid);
335 personString += (printName.isEmpty() ? email : printName);
338 #ifndef KDEPIM_MOBILE_UI
340 if (!email.isEmpty()) {
341 personString += QLatin1String(
" ") + htmlAddMailtoLink(email, printName);
348 static QString displayViewFormatPerson(
const QString &email,
const QString &name,
351 return displayViewFormatPerson(email, name, uid, rsvpStatusIconPath(status));
354 static bool incOrganizerOwnsCalendar(
const Calendar::Ptr &calendar,
355 const Incidence::Ptr &incidence)
361 return iamOrganizer(incidence);
364 static QString displayViewFormatAttendeeRoleList(Incidence::Ptr incidence,
Attendee::Role role,
368 Attendee::List::ConstIterator it;
371 for (it = attendees.constBegin(); it != attendees.constEnd(); ++it) {
373 if (a->role() != role) {
377 if (attendeeIsOrganizer(incidence, a)) {
381 tmpStr += displayViewFormatPerson(a->email(), a->name(), a->uid(),
382 showStatus ? a->status() : Attendee::None);
383 if (!a->delegator().isEmpty()) {
384 tmpStr += i18n(
" (delegated by %1)", a->delegator());
386 if (!a->delegate().isEmpty()) {
387 tmpStr += i18n(
" (delegated to %1)", a->delegate());
389 tmpStr += QLatin1String(
"<br>");
391 if (tmpStr.endsWith(QLatin1String(
"<br>"))) {
397 static QString displayViewFormatAttendees(
Calendar::Ptr calendar, Incidence::Ptr incidence)
402 int attendeeCount = incidence->attendees().count();
403 if (attendeeCount > 1 ||
404 (attendeeCount == 1 &&
405 !attendeeIsOrganizer(incidence, incidence->attendees().first()))) {
407 QPair<QString, QString> s = searchNameAndUid(incidence->organizer()->email(),
408 incidence->organizer()->name(),
410 tmpStr += QLatin1String(
"<tr>");
411 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Organizer:") + QLatin1String(
"</b></td>");
412 const QString iconPath =
413 KIconLoader::global()->iconPath(QLatin1String(
"meeting-organizer"), KIconLoader::Small);
414 tmpStr += QLatin1String(
"<td>") + displayViewFormatPerson(incidence->organizer()->email(),
415 s.first, s.second, iconPath) +
416 QLatin1String(
"</td>");
417 tmpStr += QLatin1String(
"</tr>");
422 bool showStatus = incOrganizerOwnsCalendar(calendar, incidence);
425 str = displayViewFormatAttendeeRoleList(incidence,
Attendee::Chair, showStatus);
426 if (!str.isEmpty()) {
427 tmpStr += QLatin1String(
"<tr>");
428 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Chair:") + QLatin1String(
"</b></td>");
429 tmpStr += QLatin1String(
"<td>") + str + QLatin1String(
"</td>");
430 tmpStr += QLatin1String(
"</tr>");
435 if (!str.isEmpty()) {
436 tmpStr += QLatin1String(
"<tr>");
437 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Required Participants:") + QLatin1String(
"</b></td>");
438 tmpStr += QLatin1String(
"<td>") + str + QLatin1String(
"</td>");
439 tmpStr += QLatin1String(
"</tr>");
444 if (!str.isEmpty()) {
445 tmpStr += QLatin1String(
"<tr>");
446 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Optional Participants:") + QLatin1String(
"</b></td>");
447 tmpStr += QLatin1String(
"<td>") + str + QLatin1String(
"</td>");
448 tmpStr += QLatin1String(
"</tr>");
453 if (!str.isEmpty()) {
454 tmpStr += QLatin1String(
"<tr>");
455 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Observers:") + QLatin1String(
"</b></td>");
456 tmpStr += QLatin1String(
"<td>") + str + QLatin1String(
"</td>");
457 tmpStr += QLatin1String(
"</tr>");
463 static QString displayViewFormatAttachments(Incidence::Ptr incidence)
467 Attachment::List::ConstIterator it;
469 for (it = as.constBegin(); it != as.constEnd(); ++it) {
471 if ((*it)->isUri()) {
473 if ((*it)->uri().startsWith(QLatin1String(
"kmail:"))) {
474 name = i18n(
"Show mail");
476 if ((*it)->label().isEmpty()) {
479 name = (*it)->label();
482 tmpStr += htmlAddLink((*it)->uri(), name);
484 tmpStr += htmlAddLink(QString::fromLatin1(
"ATTACH:%1").
485 arg(QString::fromUtf8((*it)->label().toUtf8().toBase64())),
488 if (count < as.count()) {
489 tmpStr += QLatin1String(
"<br>");
495 static QString displayViewFormatCategories(Incidence::Ptr incidence)
498 return incidence->categories().join(QLatin1String(
", "));
501 static QString displayViewFormatCreationDate(Incidence::Ptr incidence, KDateTime::Spec spec)
503 KDateTime kdt = incidence->created().toTimeSpec(spec);
504 return i18n(
"Creation date: %1",
dateTimeToString(incidence->created(),
false,
true, spec));
507 static QString displayViewFormatBirthday(
Event::Ptr event)
512 if (event->customProperty(
"KABC",
"BIRTHDAY") != QLatin1String(
"YES") &&
513 event->customProperty(
"KABC",
"ANNIVERSARY") != QLatin1String(
"YES")) {
517 QString uid_1 =
event->customProperty(
"KABC",
"UID-1");
518 QString name_1 =
event->customProperty(
"KABC",
"NAME-1");
519 QString email_1=
event->customProperty(
"KABC",
"EMAIL-1");
521 QString tmpStr = displayViewFormatPerson(email_1, name_1, uid_1, QString());
525 static QString displayViewFormatHeader(Incidence::Ptr incidence)
527 QString tmpStr = QLatin1String(
"<table><tr>");
530 KIconLoader *iconLoader = KIconLoader::global();
531 tmpStr += QLatin1String(
"<td>");
534 if (incidence->customProperty(
"KABC",
"BIRTHDAY") == QLatin1String(
"YES")) {
535 iconPath = iconLoader->iconPath(QLatin1String(
"view-calendar-birthday"), KIconLoader::Small);
536 }
else if (incidence->customProperty(
"KABC",
"ANNIVERSARY") == QLatin1String(
"YES")) {
537 iconPath = iconLoader->iconPath(QLatin1String(
"view-calendar-wedding-anniversary"), KIconLoader::Small);
539 iconPath = iconLoader->iconPath(incidence->iconName(), KIconLoader::Small);
541 tmpStr += QLatin1String(
"<img valign=\"top\" src=\"") + iconPath + QLatin1String(
"\">");
543 if (incidence->hasEnabledAlarms()) {
544 tmpStr += QLatin1String(
"<img valign=\"top\" src=\"") +
545 iconLoader->iconPath(QLatin1String(
"preferences-desktop-notification-bell"), KIconLoader::Small) +
546 QLatin1String(
"\">");
548 if (incidence->recurs()) {
549 tmpStr += QLatin1String(
"<img valign=\"top\" src=\"") +
550 iconLoader->iconPath(QLatin1String(
"edit-redo"), KIconLoader::Small) +
551 QLatin1String(
"\">");
553 if (incidence->isReadOnly()) {
554 tmpStr += QLatin1String(
"<img valign=\"top\" src=\"") +
555 iconLoader->iconPath(QLatin1String(
"object-locked"), KIconLoader::Small) +
556 QLatin1String(
"\">");
558 tmpStr += QLatin1String(
"</td>");
560 tmpStr += QLatin1String(
"<td>");
561 tmpStr += QLatin1String(
"<b><u>") + incidence->richSummary() + QLatin1String(
"</u></b>");
562 tmpStr += QLatin1String(
"</td>");
564 tmpStr += QLatin1String(
"</tr></table>");
569 static QString displayViewFormatEvent(
const Calendar::Ptr calendar,
const QString &sourceName,
571 const QDate &date, KDateTime::Spec spec)
577 QString tmpStr = displayViewFormatHeader(event);
579 tmpStr += QLatin1String(
"<table>");
580 tmpStr += QLatin1String(
"<col width=\"25%\"/>");
581 tmpStr += QLatin1String(
"<col width=\"75%\"/>");
583 const QString calStr = calendar ?
resourceString(calendar, event) : sourceName;
584 if (!calStr.isEmpty()) {
585 tmpStr += QLatin1String(
"<tr>");
586 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Calendar:") + QLatin1String(
"</b></td>");
587 tmpStr += QLatin1String(
"<td>") + calStr + QLatin1String(
"</td>");
588 tmpStr += QLatin1String(
"</tr>");
591 if (!event->location().isEmpty()) {
592 tmpStr += QLatin1String(
"<tr>");
593 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Location:") + QLatin1String(
"</b></td>");
594 tmpStr += QLatin1String(
"<td>") +
event->richLocation() + QLatin1String(
"</td>");
595 tmpStr +=QLatin1String(
"</tr>");
598 KDateTime startDt =
event->dtStart();
599 KDateTime endDt =
event->dtEnd();
600 if (event->recurs()) {
601 if (date.isValid()) {
602 KDateTime kdt(date, QTime(0, 0, 0), KSystemTimeZones::local());
603 int diffDays = startDt.daysTo(kdt);
604 kdt = kdt.addSecs(-1);
605 startDt.setDate(event->recurrence()->getNextDateTime(kdt).date());
606 if (event->hasEndDate()) {
607 endDt = endDt.addDays(diffDays);
608 if (startDt > endDt) {
609 startDt.setDate(event->recurrence()->getPreviousDateTime(kdt).date());
610 endDt = startDt.addDays(event->dtStart().daysTo(event->dtEnd()));
616 tmpStr += QLatin1String(
"<tr>");
617 if (event->allDay()) {
618 if (event->isMultiDay()) {
619 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Date:") + QLatin1String(
"</b></td>");
620 tmpStr += QLatin1String(
"<td>") +
621 i18nc(
"<beginTime> - <endTime>",
"%1 - %2",
624 QLatin1String(
"</td>");
626 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Date:") + QLatin1String(
"</b></td>");
627 tmpStr += QLatin1String(
"<td>") +
628 i18nc(
"date as string",
"%1",
630 QLatin1String(
"</td>");
633 if (event->isMultiDay()) {
634 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Date:") + QLatin1String(
"</b></td>");
635 tmpStr += QLatin1String(
"<td>") +
636 i18nc(
"<beginTime> - <endTime>",
"%1 - %2",
639 QLatin1String(
"</td>");
641 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Date:") + QLatin1String(
"</b></td>");
642 tmpStr += QLatin1String(
"<td>") +
643 i18nc(
"date as string",
"%1",
645 QLatin1String(
"</td>");
647 tmpStr += QLatin1String(
"</tr><tr>");
648 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Time:") + QLatin1String(
"</b></td>");
649 if (event->hasEndDate() && startDt != endDt) {
650 tmpStr += QLatin1String(
"<td>") +
651 i18nc(
"<beginTime> - <endTime>",
"%1 - %2",
654 QLatin1String(
"</td>");
656 tmpStr += QLatin1String(
"<td>") +
658 QLatin1String(
"</td>");
662 tmpStr += QLatin1String(
"</tr>");
665 if (!durStr.isEmpty()) {
666 tmpStr += QLatin1String(
"<tr>");
667 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Duration:") + QLatin1String(
"</b></td>");
668 tmpStr += QLatin1String(
"<td>") + durStr + QLatin1String(
"</td>");
669 tmpStr += QLatin1String(
"</tr>");
672 if (event->recurs() ||
event->hasRecurrenceId()) {
673 tmpStr += QLatin1String(
"<tr>");
674 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Recurrence:") + QLatin1String(
"</b></td>");
677 if (event->hasRecurrenceId()) {
678 str = i18n(
"Exception");
683 tmpStr += QLatin1String(
"<td>") + str +
684 QLatin1String(
"</td>");
685 tmpStr += QLatin1String(
"</tr>");
688 const bool isBirthday =
event->customProperty(
"KABC",
"BIRTHDAY") == QLatin1String(
"YES");
689 const bool isAnniversary =
event->customProperty(
"KABC",
"ANNIVERSARY") == QLatin1String(
"YES");
691 if (isBirthday || isAnniversary) {
692 tmpStr += QLatin1String(
"<tr>");
694 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Anniversary:") + QLatin1String(
"</b></td>");
696 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Birthday:") + QLatin1String(
"</b></td>");
698 tmpStr += QLatin1String(
"<td>") + displayViewFormatBirthday(event) + QLatin1String(
"</td>");
699 tmpStr += QLatin1String(
"</tr>");
700 tmpStr += QLatin1String(
"</table>");
704 if (!event->description().isEmpty()) {
706 if (!event->descriptionIsRich() &&
707 !
event->description().startsWith(QLatin1String(
"<!DOCTYPE HTML")))
709 descStr = string2HTML(event->description());
711 if (!event->description().startsWith(QLatin1String(
"<!DOCTYPE HTML"))) {
712 descStr =
event->richDescription();
714 descStr =
event->description();
717 tmpStr += QLatin1String(
"<tr>");
718 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Description:") + QLatin1String(
"</b></td>");
719 tmpStr += QLatin1String(
"<td>") + descStr + QLatin1String(
"</td>");
720 tmpStr += QLatin1String(
"</tr>");
725 int reminderCount =
event->alarms().count();
726 if (reminderCount > 0 && event->hasEnabledAlarms()) {
727 tmpStr += QLatin1String(
"<tr>");
728 tmpStr += QLatin1String(
"<td><b>") +
729 i18np(
"Reminder:",
"Reminders:", reminderCount) +
730 QLatin1String(
"</b></td>");
731 tmpStr += QLatin1String(
"<td>") +
reminderStringList(event).join(QLatin1String(
"<br>")) + QLatin1String(
"</td>");
732 tmpStr += QLatin1String(
"</tr>");
735 tmpStr += displayViewFormatAttendees(calendar, event);
737 int categoryCount =
event->categories().count();
738 if (categoryCount > 0) {
739 tmpStr += QLatin1String(
"<tr>");
740 tmpStr += QLatin1String(
"<td><b>");
741 tmpStr += i18np(
"Category:",
"Categories:", categoryCount) +
742 QLatin1String(
"</b></td>");
743 tmpStr += QLatin1String(
"<td>") + displayViewFormatCategories(event) + QLatin1String(
"</td>");
744 tmpStr += QLatin1String(
"</tr>");
747 int attachmentCount =
event->attachments().count();
748 if (attachmentCount > 0) {
749 tmpStr += QLatin1String(
"<tr>");
750 tmpStr += QLatin1String(
"<td><b>") +
751 i18np(
"Attachment:",
"Attachments:", attachmentCount) +
752 QLatin1String(
"</b></td>");
753 tmpStr += QLatin1String(
"<td>") + displayViewFormatAttachments(event) + QLatin1String(
"</td>");
754 tmpStr += QLatin1String(
"</tr>");
756 tmpStr += QLatin1String(
"</table>");
758 tmpStr += QLatin1String(
"<p><em>") + displayViewFormatCreationDate(event, spec) + QLatin1String(
"</em>");
763 static QString displayViewFormatTodo(
const Calendar::Ptr &calendar,
const QString &sourceName,
765 const QDate &ocurrenceDueDate, KDateTime::Spec spec)
768 kDebug() <<
"IncidenceFormatter::displayViewFormatTodo was called without to-do, quitting";
772 QString tmpStr = displayViewFormatHeader(todo);
774 tmpStr += QLatin1String(
"<table>");
775 tmpStr += QLatin1String(
"<col width=\"25%\"/>");
776 tmpStr += QLatin1String(
"<col width=\"75%\"/>");
778 const QString calStr = calendar ?
resourceString(calendar, todo) : sourceName;
779 if (!calStr.isEmpty()) {
780 tmpStr += QLatin1String(
"<tr>");
781 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Calendar:") + QLatin1String(
"</b></td>");
782 tmpStr += QLatin1String(
"<td>") + calStr + QLatin1String(
"</td>");
783 tmpStr += QLatin1String(
"</tr>");
786 if (!todo->location().isEmpty()) {
787 tmpStr += QLatin1String(
"<tr>");
788 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Location:") + QLatin1String(
"</b></td>");
789 tmpStr += QLatin1String(
"<td>") + todo->richLocation() + QLatin1String(
"</td>");
790 tmpStr += QLatin1String(
"</tr>");
793 const bool hastStartDate = todo->hasStartDate();
794 const bool hasDueDate = todo->hasDueDate();
797 KDateTime startDt = todo->dtStart(
true );
798 if (todo->recurs() && ocurrenceDueDate.isValid()) {
801 const int length = startDt.daysTo(todo->dtDue(
true ));
803 startDt.setDate(ocurrenceDueDate.addDays(-length));
805 kError() <<
"DTSTART is bigger than DTDUE, todo->uid() is " << todo->uid();
806 startDt.setDate(ocurrenceDueDate);
809 kError() <<
"To-do is recurring but has no DTDUE set, todo->uid() is " << todo->uid();
810 startDt.setDate(ocurrenceDueDate);
813 tmpStr += QLatin1String(
"<tr>");
814 tmpStr += QLatin1String(
"<td><b>") +
815 i18nc(
"to-do start date/time",
"Start:") +
816 QLatin1String(
"</b></td>");
817 tmpStr += QLatin1String(
"<td>") +
819 QLatin1String(
"</td>");
820 tmpStr += QLatin1String(
"</tr>");
824 KDateTime dueDt = todo->dtDue();
825 if (todo->recurs()) {
826 if (ocurrenceDueDate.isValid()) {
827 KDateTime kdt(ocurrenceDueDate, QTime(0, 0, 0), KSystemTimeZones::local());
828 kdt = kdt.addSecs(-1);
829 dueDt.setDate(todo->recurrence()->getNextDateTime(kdt).date());
832 tmpStr += QLatin1String(
"<tr>");
833 tmpStr += QLatin1String(
"<td><b>") +
834 i18nc(
"to-do due date/time",
"Due:") +
835 QLatin1String(
"</b></td>");
836 tmpStr += QLatin1String(
"<td>") +
838 QLatin1String(
"</td>");
839 tmpStr += QLatin1String(
"</tr>");
843 if (!durStr.isEmpty()) {
844 tmpStr += QLatin1String(
"<tr>");
845 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Duration:") + QLatin1String(
"</b></td>");
846 tmpStr += QLatin1String(
"<td>") + durStr + QLatin1String(
"</td>");
847 tmpStr += QLatin1String(
"</tr>");
850 if (todo->recurs() || todo->hasRecurrenceId()) {
851 tmpStr += QLatin1String(
"<tr>");
852 tmpStr += QLatin1String(
"<td><b>")+ i18n(
"Recurrence:") + QLatin1String(
"</b></td>");
854 if (todo->hasRecurrenceId()) {
855 str = i18n(
"Exception");
859 tmpStr += QLatin1String(
"<td>") +
861 QLatin1String(
"</td>");
862 tmpStr += QLatin1String(
"</tr>");
865 if (!todo->description().isEmpty()) {
866 tmpStr += QLatin1String(
"<tr>");
867 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Description:") + QLatin1String(
"</b></td>");
868 tmpStr += QLatin1String(
"<td>") + todo->richDescription() + QLatin1String(
"</td>");
869 tmpStr += QLatin1String(
"</tr>");
874 int reminderCount = todo->alarms().count();
875 if (reminderCount > 0 && todo->hasEnabledAlarms()) {
876 tmpStr += QLatin1String(
"<tr>");
877 tmpStr += QLatin1String(
"<td><b>") +
878 i18np(
"Reminder:",
"Reminders:", reminderCount) +
879 QLatin1String(
"</b></td>");
880 tmpStr += QLatin1String(
"<td>") +
reminderStringList(todo).join(QLatin1String(
"<br>")) + QLatin1String(
"</td>");
881 tmpStr += QLatin1String(
"</tr>");
884 tmpStr += displayViewFormatAttendees(calendar, todo);
886 int categoryCount = todo->categories().count();
887 if (categoryCount > 0) {
888 tmpStr += QLatin1String(
"<tr>");
889 tmpStr += QLatin1String(
"<td><b>") +
890 i18np(
"Category:",
"Categories:", categoryCount) +
891 QLatin1String(
"</b></td>");
892 tmpStr += QLatin1String(
"<td>") + displayViewFormatCategories(todo) + QLatin1String(
"</td>");
893 tmpStr += QLatin1String(
"</tr>");
896 if (todo->priority() > 0) {
897 tmpStr += QLatin1String(
"<tr>");
898 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Priority:") + QLatin1String(
"</b></td>");
899 tmpStr += QLatin1String(
"<td>");
900 tmpStr += QString::number(todo->priority());
901 tmpStr += QLatin1String(
"</td>");
902 tmpStr += QLatin1String(
"</tr>");
905 tmpStr += QLatin1String(
"<tr>");
906 if (todo->isCompleted()) {
907 tmpStr += QLatin1String(
"<td><b>") + i18nc(
"Completed: date",
"Completed:") + QLatin1String(
"</b></td>");
908 tmpStr += QLatin1String(
"<td>");
911 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Percent Done:") + QLatin1String(
"</b></td>");
912 tmpStr += QLatin1String(
"<td>");
913 tmpStr += i18n(
"%1%", todo->percentComplete());
915 tmpStr += QLatin1String(
"</td>");
916 tmpStr += QLatin1String(
"</tr>");
918 int attachmentCount = todo->attachments().count();
919 if (attachmentCount > 0) {
920 tmpStr += QLatin1String(
"<tr>");
921 tmpStr += QLatin1String(
"<td><b>") +
922 i18np(
"Attachment:",
"Attachments:", attachmentCount) +
923 QLatin1String(
"</b></td>");
924 tmpStr += QLatin1String(
"<td>") + displayViewFormatAttachments(todo) + QLatin1String(
"</td>");
925 tmpStr += QLatin1String(
"</tr>");
927 tmpStr += QLatin1String(
"</table>");
929 tmpStr += QLatin1String(
"<p><em>")+ displayViewFormatCreationDate(todo, spec) + QLatin1String(
"</em>");
934 static QString displayViewFormatJournal(
const Calendar::Ptr &calendar,
const QString &sourceName,
941 QString tmpStr = displayViewFormatHeader(journal);
943 tmpStr += QLatin1String(
"<table>");
944 tmpStr += QLatin1String(
"<col width=\"25%\"/>");
945 tmpStr += QLatin1String(
"<col width=\"75%\"/>");
947 const QString calStr = calendar ?
resourceString(calendar, journal) : sourceName;
948 if (!calStr.isEmpty()) {
949 tmpStr += QLatin1String(
"<tr>");
950 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Calendar:") + QLatin1String(
"</b></td>");
951 tmpStr += QLatin1String(
"<td>") + calStr + QLatin1String(
"</td>");
952 tmpStr += QLatin1String(
"</tr>");
955 tmpStr += QLatin1String(
"<tr>");
956 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Date:") + QLatin1String(
"</b></td>");
957 tmpStr += QLatin1String(
"<td>") +
959 QLatin1String(
"</td>");
960 tmpStr += QLatin1String(
"</tr>");
962 if (!journal->description().isEmpty()) {
963 tmpStr += QLatin1String(
"<tr>");
964 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Description:") + QLatin1String(
"</b></td>");
965 tmpStr += QLatin1String(
"<td>") + journal->richDescription() + QLatin1String(
"</td>");
966 tmpStr += QLatin1String(
"</tr>");
969 int categoryCount = journal->categories().count();
970 if (categoryCount > 0) {
971 tmpStr += QLatin1String(
"<tr>");
972 tmpStr += QLatin1String(
"<td><b>") +
973 i18np(
"Category:",
"Categories:", categoryCount) +
974 QLatin1String(
"</b></td>");
975 tmpStr += QLatin1String(
"<td>") + displayViewFormatCategories(journal) + QLatin1String(
"</td>");
976 tmpStr += QLatin1String(
"</tr>");
979 tmpStr += QLatin1String(
"</table>");
981 tmpStr += QLatin1String(
"<p><em>") + displayViewFormatCreationDate(journal, spec) + QLatin1String(
"</em>");
986 static QString displayViewFormatFreeBusy(
const Calendar::Ptr &calendar,
const QString &sourceName,
990 Q_UNUSED(sourceName);
997 QLatin1String(
"h2"), i18n(
"Free/Busy information for %1", fb->organizer()->fullName())));
999 tmpStr += htmlAddTag(QLatin1String(
"h4"),
1000 i18n(
"Busy times in date range %1 - %2:",
1005 htmlAddTag(QLatin1String(
"em"),
1006 htmlAddTag(QLatin1String(
"b"), i18nc(
"tag for busy periods list",
"Busy:")));
1008 Period::List periods = fb->busyPeriods();
1009 Period::List::iterator it;
1010 for (it = periods.begin(); it != periods.end(); ++it) {
1012 if (per.hasDuration()) {
1013 int dur = per.duration().asSeconds();
1016 cont += i18ncp(
"hours part of duration",
"1 hour ",
"%1 hours ", dur / 3600);
1020 cont += i18ncp(
"minutes part duration",
"1 minute ",
"%1 minutes ", dur / 60);
1024 cont += i18ncp(
"seconds part of duration",
"1 second",
"%1 seconds", dur);
1026 text += i18nc(
"startDate for duration",
"%1 for %2",
1029 text += QLatin1String(
"<br>");
1031 if (per.start().date() == per.end().date()) {
1032 text += i18nc(
"date, fromTime - toTime ",
"%1, %2 - %3",
1037 text += i18nc(
"fromDateTime - toDateTime",
"%1 - %2",
1041 text += QLatin1String(
"<br>");
1044 tmpStr += htmlAddTag(QLatin1String(
"p"), text);
1050 class KCalUtils::IncidenceFormatter::EventViewerVisitor :
public Visitor
1053 EventViewerVisitor()
1054 : mCalendar(0), mSpec(KDateTime::Spec()), mResult(QLatin1String(
"")) {}
1056 bool act(
const Calendar::Ptr &calendar, IncidenceBase::Ptr incidence,
const QDate &date,
1057 KDateTime::Spec spec=KDateTime::Spec())
1059 mCalendar = calendar;
1060 mSourceName.clear();
1063 mResult = QLatin1String(
"");
1064 return incidence->accept(*
this, incidence);
1067 bool act(
const QString &sourceName, IncidenceBase::Ptr incidence,
const QDate &date,
1068 KDateTime::Spec spec=KDateTime::Spec())
1070 mSourceName = sourceName;
1073 mResult = QLatin1String(
"");
1074 return incidence->accept(*
this, incidence);
1077 QString result()
const {
1084 mResult = displayViewFormatEvent(mCalendar, mSourceName, event, mDate, mSpec);
1085 return !mResult.isEmpty();
1089 mResult = displayViewFormatTodo(mCalendar, mSourceName, todo, mDate, mSpec);
1090 return !mResult.isEmpty();
1094 mResult = displayViewFormatJournal(mCalendar, mSourceName, journal, mSpec);
1095 return !mResult.isEmpty();
1099 mResult = displayViewFormatFreeBusy(mCalendar, mSourceName, fb, mSpec);
1100 return !mResult.isEmpty();
1105 QString mSourceName;
1107 KDateTime::Spec mSpec;
1113 const IncidenceBase::Ptr &incidence,
1115 KDateTime::Spec spec)
1121 EventViewerVisitor v;
1122 if (v.act(calendar, incidence, date, spec)) {
1130 const IncidenceBase::Ptr &incidence,
1132 KDateTime::Spec spec)
1138 EventViewerVisitor v;
1139 if (v.act(sourceName, incidence, date, spec)) {
1150 static QString cleanHtml(
const QString &html)
1152 QRegExp rx(QLatin1String(
"<body[^>]*>(.*)</body>"), Qt::CaseInsensitive);
1154 QString body = rx.cap(1);
1156 return Qt::escape(body.remove(QRegExp(QLatin1String(
"<[^>]*>"))).trimmed());
1159 static QString invitationSummary(
const Incidence::Ptr &incidence,
bool noHtmlMode)
1161 QString summaryStr = i18n(
"Summary unspecified");
1162 if (!incidence->summary().isEmpty()) {
1163 if (!incidence->summaryIsRich()) {
1164 summaryStr = Qt::escape(incidence->summary());
1166 summaryStr = incidence->richSummary();
1168 summaryStr = cleanHtml(summaryStr);
1175 static QString invitationLocation(
const Incidence::Ptr &incidence,
bool noHtmlMode)
1177 QString locationStr = i18n(
"Location unspecified");
1178 if (!incidence->location().isEmpty()) {
1179 if (!incidence->locationIsRich()) {
1180 locationStr = Qt::escape(incidence->location());
1182 locationStr = incidence->richLocation();
1184 locationStr = cleanHtml(locationStr);
1191 static QString eventStartTimeStr(
const Event::Ptr &event)
1194 if (!event->allDay()) {
1195 tmp = i18nc(
"%1: Start Date, %2: Start Time",
"%1 %2",
1196 dateToString(event->dtStart(),
true, KSystemTimeZones::local()),
1197 timeToString(event->dtStart(),
true, KSystemTimeZones::local()));
1199 tmp = i18nc(
"%1: Start Date",
"%1 (all day)",
1200 dateToString(event->dtStart(),
true, KSystemTimeZones::local()));
1205 static QString eventEndTimeStr(
const Event::Ptr &event)
1208 if (event->hasEndDate() &&
event->dtEnd().isValid()) {
1209 if (!event->allDay()) {
1210 tmp = i18nc(
"%1: End Date, %2: End Time",
"%1 %2",
1211 dateToString(event->dtEnd(),
true, KSystemTimeZones::local()),
1212 timeToString(event->dtEnd(),
true, KSystemTimeZones::local()));
1214 tmp = i18nc(
"%1: End Date",
"%1 (all day)",
1215 dateToString(event->dtEnd(),
true, KSystemTimeZones::local()));
1221 static QString htmlInvitationDetailsBegin()
1223 QString dir = (QApplication::isRightToLeft() ? QLatin1String(
"rtl") : QLatin1String(
"ltr"));
1224 return QString::fromLatin1(
"<div dir=\"%1\">\n").arg(dir);
1227 static QString htmlInvitationDetailsEnd()
1229 return QLatin1String(
"</div>\n");
1232 static QString htmlInvitationDetailsTableBegin()
1235 return QLatin1String(
"<table cellspacing=\"4\" style=\"border-width:4px; border-style:groove\">");
1239 static QString htmlInvitationDetailsTableEnd()
1241 return QLatin1String(
"</table>\n");
1244 static QString diffColor()
1249 return QColor(Qt::red).name();
1252 static QString noteColor()
1255 return qApp->palette().color(QPalette::Active, QPalette::Highlight).name();
1258 static QString htmlRow(
const QString &title,
const QString &value)
1260 if (!value.isEmpty()) {
1261 return QLatin1String(
"<tr><td>") + title + QLatin1String(
"</td><td>") + value + QLatin1String(
"</td></tr>\n");
1267 static QString htmlRow(
const QString &title,
const QString &value,
const QString &oldvalue)
1270 if (value.isEmpty()) {
1275 if (oldvalue.isEmpty() || value == oldvalue) {
1276 return htmlRow(title, value);
1280 QString color = diffColor();
1281 QString newtitle = QLatin1String(
"<font color=\"") + color + QLatin1String(
"\">") + title + QLatin1String(
"</font>");
1282 QString newvalue = QLatin1String(
"<font color=\"") + color + QLatin1String(
"\">") + value + QLatin1String(
"</font>") +
1283 QLatin1String(
" ")+
1284 QLatin1String(
"(<strike>") + oldvalue + QLatin1String(
"</strike>");
1285 return htmlRow(newtitle, newvalue);
1289 static Attendee::Ptr findDelegatedFromMyAttendee(
const Incidence::Ptr &incidence)
1298 QString delegatorName, delegatorEmail;
1300 Attendee::List::ConstIterator it;
1301 for (it = attendees.constBegin(); it != attendees.constEnd(); ++it) {
1303 KPIMUtils::extractEmailAddressAndName(a->delegator(), delegatorEmail, delegatorName);
1304 if (thatIsMe(delegatorEmail)) {
1313 static Attendee::Ptr findMyAttendee(
const Incidence::Ptr &incidence)
1323 Attendee::List::ConstIterator it;
1324 for (it = attendees.constBegin(); it != attendees.constEnd(); ++it) {
1326 if (thatIsMe(a->email())) {
1335 static Attendee::Ptr findAttendee(
const Incidence::Ptr &incidence,
1336 const QString &email)
1346 Attendee::List::ConstIterator it;
1347 for (it = attendees.constBegin(); it != attendees.constEnd(); ++it) {
1349 if (email == a->email()) {
1357 static bool rsvpRequested(
const Incidence::Ptr &incidence)
1367 Attendee::List::ConstIterator it;
1368 for (it = attendees.constBegin(); it != attendees.constEnd(); ++it) {
1369 if (it == attendees.constBegin()) {
1370 rsvp = (*it)->RSVP();
1372 if ((*it)->RSVP() != rsvp) {
1381 static QString rsvpRequestedStr(
bool rsvpRequested,
const QString &role)
1383 if (rsvpRequested) {
1384 if (role.isEmpty()) {
1385 return i18n(
"Your response is requested");
1387 return i18n(
"Your response as <b>%1</b> is requested", role);
1390 if (role.isEmpty()) {
1391 return i18n(
"No response is necessary");
1393 return i18n(
"No response as <b>%1</b> is necessary", role);
1398 static QString myStatusStr(Incidence::Ptr incidence)
1404 ret = i18n(
"(<b>Note</b>: the Organizer preset your response to <b>%1</b>)",
1405 Stringify::attendeeStatus(a->status()));
1410 static QString invitationNote(
const QString &title,
const QString ¬e,
1411 const QString &tag,
const QString &color)
1414 if (!note.isEmpty()) {
1415 noteStr += QLatin1String(
"<table border=\"0\" style=\"margin-top:4px;\">");
1416 noteStr += QLatin1String(
"<tr><center><td>");
1417 if (!color.isEmpty()) {
1418 noteStr += QLatin1String(
"<font color=\"") + color + QLatin1String(
"\">");
1420 if (!title.isEmpty()) {
1421 if (!tag.isEmpty()) {
1422 noteStr += htmlAddTag(tag, title);
1427 noteStr += QLatin1String(
" )") + note;
1428 if (!color.isEmpty()) {
1429 noteStr += QLatin1String(
"</font>");
1431 noteStr += QLatin1String(
"</td></center></tr>");
1432 noteStr += QLatin1String(
"</table>");
1437 static QString invitationPerson(
const QString &email,
const QString &name,
const QString &uid,
1438 const QString &comment)
1440 QPair<QString, QString> s = searchNameAndUid(email, name, uid);
1441 const QString printName = s.first;
1442 const QString printUid = s.second;
1444 QString personString;
1446 if (!printUid.isEmpty()) {
1447 personString = htmlAddUidLink(email, printName, printUid);
1450 personString = (printName.isEmpty() ? email : printName);
1452 if (!comment.isEmpty()) {
1453 personString = i18nc(
"name (comment)",
"%1 (%2)", personString, comment);
1455 personString += QLatin1Char(
'\n');
1458 if (!email.isEmpty()) {
1459 personString += QLatin1String(
" ") + htmlAddMailtoLink(email, printName);
1461 personString += QLatin1Char(
'\n');
1463 return personString;
1466 static QString invitationDetailsIncidence(
const Incidence::Ptr &incidence,
bool noHtmlMode)
1474 QStringList comments;
1476 if (incidence->comments().isEmpty()) {
1477 if (!incidence->description().isEmpty()) {
1479 if (!incidence->descriptionIsRich() &&
1480 !incidence->description().startsWith(QLatin1String(
"<!DOCTYPE HTML"))) {
1481 comments << string2HTML(incidence->description());
1483 if (!incidence->description().startsWith(QLatin1String(
"<!DOCTYPE HTML"))) {
1484 comments << incidence->richDescription();
1486 comments << incidence->description();
1489 comments[0] = cleanHtml(comments[0]);
1491 comments[0] = htmlAddTag(QLatin1String(
"p"), comments[0]);
1497 foreach(
const QString &c, incidence->comments()) {
1500 if (!Qt::mightBeRichText(c)) {
1501 comments << string2HTML(c);
1504 comments << cleanHtml(cleanHtml(QLatin1String(
"<body>") + c +QLatin1String(
"</body>")));
1511 if (!incidence->description().isEmpty()) {
1513 if (!incidence->descriptionIsRich() &&
1514 !incidence->description().startsWith(QLatin1String(
"<!DOCTYPE HTML"))) {
1515 descr = string2HTML(incidence->description());
1517 if (!incidence->description().startsWith(QLatin1String(
"<!DOCTYPE HTML"))) {
1518 descr = incidence->richDescription();
1520 descr = incidence->description();
1523 descr = cleanHtml(descr);
1525 descr = htmlAddTag(QLatin1String(
"p"), descr);
1530 if (!descr.isEmpty()) {
1531 html += QLatin1String(
"<p>");
1532 html += QLatin1String(
"<table border=\"0\" style=\"margin-top:4px;\">");
1533 html += QLatin1String(
"<tr><td><center>") +
1534 htmlAddTag(QLatin1String(
"u"), i18n(
"Description:")) +
1535 QLatin1String(
"</center></td></tr>");
1536 html += QLatin1String(
"<tr><td>") + descr + QLatin1String(
"</td></tr>");
1537 html += QLatin1String(
"</table>");
1540 if (!comments.isEmpty()) {
1541 html += QLatin1String(
"<p>");
1542 html += QLatin1String(
"<table border=\"0\" style=\"margin-top:4px;\">");
1543 html += QLatin1String(
"<tr><td><center>") +
1544 htmlAddTag(QLatin1String(
"u"), i18n(
"Comments:")) +
1545 QLatin1String(
"</center></td></tr>");
1546 html += QLatin1String(
"<tr><td>");
1547 if (comments.count() > 1) {
1548 html += QLatin1String(
"<ul>");
1549 for (
int i=0; i < comments.count(); ++i) {
1550 html += QLatin1String(
"<li>") + comments[i] + QLatin1String(
"</li>");
1552 html += QLatin1String(
"</ul>");
1554 html += comments[0];
1556 html += QLatin1String(
"</td></tr>");
1557 html += QLatin1String(
"</table>");
1562 static QString invitationDetailsEvent(
const Event::Ptr &event,
bool noHtmlMode,
1563 KDateTime::Spec spec)
1570 QString html = htmlInvitationDetailsBegin();
1571 html += htmlInvitationDetailsTableBegin();
1574 html += htmlRow(i18n(
"What:"), invitationSummary(event, noHtmlMode));
1575 html += htmlRow(i18n(
"Where:"), invitationLocation(event, noHtmlMode));
1578 if (event->dtStart().date() ==
event->dtEnd().date()) {
1579 html += htmlRow(i18n(
"Date:"),
dateToString(event->dtStart(),
false, spec));
1580 if (!event->allDay()) {
1581 html += htmlRow(i18n(
"Time:"),
1583 QLatin1String(
" - ") +
1587 html += htmlRow(i18nc(
"starting date",
"From:"),
1589 if (!event->allDay()) {
1590 html += htmlRow(i18nc(
"starting time",
"At:"),
1593 if (event->hasEndDate()) {
1594 html += htmlRow(i18nc(
"ending date",
"To:"),
1596 if (!event->allDay()) {
1597 html += htmlRow(i18nc(
"ending time",
"At:"),
1601 html += htmlRow(i18nc(
"ending date",
"To:"), i18n(
"no end date specified"));
1609 if (event->recurs()) {
1613 html += htmlInvitationDetailsTableEnd();
1614 html += invitationDetailsIncidence(event, noHtmlMode);
1615 html += htmlInvitationDetailsEnd();
1622 KDateTime::Spec spec)
1625 return invitationDetailsEvent(event, noHtmlMode, spec);
1632 html += QLatin1String(
"<br>");
1633 html += invitationNote(QString(),
1634 i18n(
"Please respond again to the original proposal."),
1635 QString(), noteColor());
1638 html += htmlInvitationDetailsBegin();
1639 html += htmlInvitationDetailsTableBegin();
1641 html += htmlRow(i18n(
"What:"),
1642 invitationSummary(event, noHtmlMode),
1643 invitationSummary(oldevent, noHtmlMode));
1645 html += htmlRow(i18n(
"Where:"),
1646 invitationLocation(event, noHtmlMode),
1647 invitationLocation(oldevent, noHtmlMode));
1650 if (event->dtStart().date() ==
event->dtEnd().date()) {
1651 html += htmlRow(i18n(
"Date:"),
1654 QString spanStr, oldspanStr;
1655 if (!event->allDay()) {
1657 QLatin1String(
" - ") +
1660 if (!oldevent->allDay()) {
1661 oldspanStr =
timeToString(oldevent->dtStart(),
true, spec) +
1662 QLatin1String(
" - ") +
1665 html += htmlRow(i18n(
"Time:"), spanStr, oldspanStr);
1667 html += htmlRow(i18nc(
"Starting date of an event",
"From:"),
1670 QString startStr, oldstartStr;
1671 if (!event->allDay()) {
1674 if (!oldevent->allDay()) {
1675 oldstartStr =
timeToString(oldevent->dtStart(),
true, spec);
1677 html += htmlRow(i18nc(
"Starting time of an event",
"At:"), startStr, oldstartStr);
1678 if (event->hasEndDate()) {
1679 html += htmlRow(i18nc(
"Ending date of an event",
"To:"),
1682 QString endStr, oldendStr;
1683 if (!event->allDay()) {
1686 if (!oldevent->allDay()) {
1687 oldendStr =
timeToString(oldevent->dtEnd(),
true, spec);
1689 html += htmlRow(i18nc(
"Starting time of an event",
"At:"), endStr, oldendStr);
1691 QString endStr = i18n(
"no end date specified");
1693 if (!oldevent->hasEndDate()) {
1694 oldendStr = i18n(
"no end date specified");
1696 oldendStr =
dateTimeToString(oldevent->dtEnd(), oldevent->allDay(),
false);
1698 html += htmlRow(i18nc(
"Ending date of an event",
"To:"), endStr, oldendStr);
1704 QString recurStr, oldrecurStr;
1705 if (event->recurs() || oldevent->recurs()) {
1709 html += htmlRow(i18n(
"Recurrence:"), recurStr, oldrecurStr);
1711 html += htmlInvitationDetailsTableEnd();
1712 html += invitationDetailsIncidence(event, noHtmlMode);
1713 html += htmlInvitationDetailsEnd();
1718 static QString invitationDetailsTodo(
const Todo::Ptr &todo,
bool noHtmlMode,
1719 KDateTime::Spec spec)
1726 QString html = htmlInvitationDetailsBegin();
1727 html += htmlInvitationDetailsTableBegin();
1730 html += htmlRow(i18n(
"What:"), invitationSummary(todo, noHtmlMode));
1731 html += htmlRow(i18n(
"Where:"), invitationLocation(todo, noHtmlMode));
1733 if (todo->hasStartDate()) {
1734 html += htmlRow(i18n(
"Start Date:"),
dateToString(todo->dtStart(),
false, spec));
1735 if (!todo->allDay()) {
1736 html += htmlRow(i18n(
"Start Time:"),
timeToString(todo->dtStart(),
false, spec));
1739 if (todo->hasDueDate()) {
1740 html += htmlRow(i18n(
"Due Date:"),
dateToString(todo->dtDue(),
false, spec));
1741 if (!todo->allDay()) {
1742 html += htmlRow(i18n(
"Due Time:"),
timeToString(todo->dtDue(),
false, spec));
1745 html += htmlRow(i18n(
"Due Date:"), i18nc(
"Due Date: None",
"None"));
1752 if (todo->percentComplete() > 0) {
1753 html += htmlRow(i18n(
"Percent Done:"), i18n(
"%1%", todo->percentComplete()));
1757 if (todo->recurs()) {
1761 html += htmlInvitationDetailsTableEnd();
1762 html += invitationDetailsIncidence(todo, noHtmlMode);
1763 html += htmlInvitationDetailsEnd();
1768 static QString invitationDetailsTodo(
const Todo::Ptr &todo,
const Todo::Ptr &oldtodo,
1770 KDateTime::Spec spec)
1773 return invitationDetailsTodo(todo, noHtmlMode, spec);
1780 html += QLatin1String(
"<br>");
1781 html += invitationNote(QString(),
1782 i18n(
"Please respond again to the original proposal."),
1783 QString(), noteColor());
1786 html += htmlInvitationDetailsBegin();
1787 html += htmlInvitationDetailsTableBegin();
1789 html += htmlRow(i18n(
"What:"),
1790 invitationSummary(todo, noHtmlMode),
1791 invitationSummary(todo, noHtmlMode));
1793 html += htmlRow(i18n(
"Where:"),
1794 invitationLocation(todo, noHtmlMode),
1795 invitationLocation(oldtodo, noHtmlMode));
1797 if (todo->hasStartDate()) {
1798 html += htmlRow(i18n(
"Start Date:"),
1801 QString startTimeStr, oldstartTimeStr;
1802 if (!todo->allDay() || !oldtodo->allDay()) {
1803 startTimeStr = todo->allDay() ?
1804 i18n(
"All day") :
timeToString(todo->dtStart(), false, spec);
1805 oldstartTimeStr = oldtodo->allDay() ?
1806 i18n(
"All day") :
timeToString(oldtodo->dtStart(), false, spec);
1808 html += htmlRow(i18n(
"Start Time:"), startTimeStr, oldstartTimeStr);
1810 if (todo->hasDueDate()) {
1811 html += htmlRow(i18n(
"Due Date:"),
1814 QString endTimeStr, oldendTimeStr;
1815 if (!todo->allDay() || !oldtodo->allDay()) {
1816 endTimeStr = todo->allDay() ?
1817 i18n(
"All day") :
timeToString(todo->dtDue(), false, spec);
1818 oldendTimeStr = oldtodo->allDay() ?
1819 i18n(
"All day") :
timeToString(oldtodo->dtDue(), false, spec);
1821 html += htmlRow(i18n(
"Due Time:"), endTimeStr, oldendTimeStr);
1823 QString dueStr = i18nc(
"Due Date: None",
"None");
1825 if (!oldtodo->hasDueDate()) {
1826 olddueStr = i18nc(
"Due Date: None",
"None");
1830 html += htmlRow(i18n(
"Due Date:"), dueStr, olddueStr);
1835 QString completionStr, oldcompletionStr;
1836 if (todo->percentComplete() > 0 || oldtodo->percentComplete() > 0) {
1837 completionStr = i18n(
"%1%", todo->percentComplete());
1838 oldcompletionStr = i18n(
"%1%", oldtodo->percentComplete());
1840 html += htmlRow(i18n(
"Percent Done:"), completionStr, oldcompletionStr);
1842 QString recurStr, oldrecurStr;
1843 if (todo->recurs() || oldtodo->recurs()) {
1847 html += htmlRow(i18n(
"Recurrence:"), recurStr, oldrecurStr);
1849 html += htmlInvitationDetailsTableEnd();
1850 html += invitationDetailsIncidence(todo, noHtmlMode);
1852 html += htmlInvitationDetailsEnd();
1857 static QString invitationDetailsJournal(
const Journal::Ptr &journal,
bool noHtmlMode,
1858 KDateTime::Spec spec)
1864 QString html = htmlInvitationDetailsBegin();
1865 html += htmlInvitationDetailsTableBegin();
1867 html += htmlRow(i18n(
"Summary:"), invitationSummary(journal, noHtmlMode));
1868 html += htmlRow(i18n(
"Date:"),
dateToString(journal->dtStart(),
false, spec));
1870 html += htmlInvitationDetailsTableEnd();
1871 html += invitationDetailsIncidence(journal, noHtmlMode);
1872 html += htmlInvitationDetailsEnd();
1877 static QString invitationDetailsJournal(
const Journal::Ptr &journal,
1879 bool noHtmlMode, KDateTime::Spec spec)
1882 return invitationDetailsJournal(journal, noHtmlMode, spec);
1885 QString html = htmlInvitationDetailsBegin();
1886 html += htmlInvitationDetailsTableBegin();
1888 html += htmlRow(i18n(
"What:"),
1889 invitationSummary(journal, noHtmlMode),
1890 invitationSummary(oldjournal, noHtmlMode));
1892 html += htmlRow(i18n(
"Date:"),
1896 html += htmlInvitationDetailsTableEnd();
1897 html += invitationDetailsIncidence(journal, noHtmlMode);
1898 html += htmlInvitationDetailsEnd();
1903 static QString invitationDetailsFreeBusy(
const FreeBusy::Ptr &fb,
bool noHtmlMode,
1904 KDateTime::Spec spec)
1906 Q_UNUSED(noHtmlMode);
1912 QString html = htmlInvitationDetailsTableBegin();
1914 html += htmlRow(i18n(
"Person:"), fb->organizer()->fullName());
1915 html += htmlRow(i18n(
"Start date:"),
dateToString(fb->dtStart(),
true, spec));
1916 html += htmlRow(i18n(
"End date:"),
dateToString(fb->dtEnd(),
true, spec));
1918 html += QLatin1String(
"<tr><td colspan=2><hr></td></tr>\n");
1919 html += QLatin1String(
"<tr><td colspan=2>Busy periods given in this free/busy object:</td></tr>\n");
1921 Period::List periods = fb->busyPeriods();
1922 Period::List::iterator it;
1923 for (it = periods.begin(); it != periods.end(); ++it) {
1925 if (per.hasDuration()) {
1926 int dur = per.duration().asSeconds();
1929 cont += i18ncp(
"hours part of duration",
"1 hour ",
"%1 hours ", dur / 3600);
1933 cont += i18ncp(
"minutes part of duration",
"1 minute",
"%1 minutes ", dur / 60);
1937 cont += i18ncp(
"seconds part of duration",
"1 second",
"%1 seconds", dur);
1939 html += htmlRow(QString(),
1940 i18nc(
"startDate for duration",
"%1 for %2",
1942 per.start().dateTime(), KLocale::LongDate),
1946 if (per.start().date() == per.end().date()) {
1947 cont = i18nc(
"date, fromTime - toTime ",
"%1, %2 - %3",
1948 KGlobal::locale()->
formatDate(per.start().date()),
1949 KGlobal::locale()->formatTime(per.start().time()),
1950 KGlobal::locale()->formatTime(per.end().time()));
1952 cont = i18nc(
"fromDateTime - toDateTime",
"%1 - %2",
1954 per.start().dateTime(), KLocale::LongDate),
1955 KGlobal::locale()->formatDateTime(
1956 per.end().dateTime(), KLocale::LongDate));
1959 html += htmlRow(QString(), cont);
1963 html += htmlInvitationDetailsTableEnd();
1968 bool noHtmlMode, KDateTime::Spec spec)
1971 return invitationDetailsFreeBusy(fb, noHtmlMode, spec);
1974 static bool replyMeansCounter(
const Incidence::Ptr &incidence)
1976 Q_UNUSED(incidence);
1994 static QString invitationHeaderEvent(
const Event::Ptr &event,
1995 const Incidence::Ptr &existingIncidence,
1998 if (!msg || !event) {
2002 switch (msg->method()) {
2004 return i18n(
"This invitation has been published");
2006 if (existingIncidence && event->revision() > 0) {
2007 QString orgStr = organizerName(event, sender);
2008 if (senderIsOrganizer(event, sender)) {
2009 return i18n(
"This invitation has been updated by the organizer %1", orgStr);
2011 return i18n(
"This invitation has been updated by %1 as a representative of %2",
2015 if (iamOrganizer(event)) {
2016 return i18n(
"I created this invitation");
2018 QString orgStr = organizerName(event, sender);
2019 if (senderIsOrganizer(event, sender)) {
2020 return i18n(
"You received an invitation from %1", orgStr);
2022 return i18n(
"You received an invitation from %1 as a representative of %2",
2027 return i18n(
"This invitation was refreshed");
2029 if (iamOrganizer(event)) {
2030 return i18n(
"This invitation has been canceled");
2032 return i18n(
"The organizer has revoked the invitation");
2035 return i18n(
"Addition to the invitation");
2038 if (replyMeansCounter(event)) {
2039 return i18n(
"%1 makes this counter proposal", firstAttendeeName(event, sender));
2043 if (attendees.count() == 0) {
2044 kDebug() <<
"No attendees in the iCal reply!";
2047 if (attendees.count() != 1) {
2048 kDebug() <<
"Warning: attendeecount in the reply should be 1"
2049 <<
"but is" << attendees.count();
2051 QString attendeeName = firstAttendeeName(event, sender);
2053 QString delegatorName, dummy;
2055 KPIMUtils::extractEmailAddressAndName(attendee->delegator(), dummy, delegatorName);
2056 if (delegatorName.isEmpty()) {
2057 delegatorName = attendee->delegator();
2060 switch (attendee->status()) {
2062 return i18n(
"%1 indicates this invitation still needs some action", attendeeName);
2064 if (event->revision() > 0) {
2065 if (!sender.isEmpty()) {
2066 return i18n(
"This invitation has been updated by attendee %1", sender);
2068 return i18n(
"This invitation has been updated by an attendee");
2071 if (delegatorName.isEmpty()) {
2072 return i18n(
"%1 accepts this invitation", attendeeName);
2074 return i18n(
"%1 accepts this invitation on behalf of %2",
2075 attendeeName, delegatorName);
2079 if (delegatorName.isEmpty()) {
2080 return i18n(
"%1 tentatively accepts this invitation", attendeeName);
2082 return i18n(
"%1 tentatively accepts this invitation on behalf of %2",
2083 attendeeName, delegatorName);
2086 if (delegatorName.isEmpty()) {
2087 return i18n(
"%1 declines this invitation", attendeeName);
2089 return i18n(
"%1 declines this invitation on behalf of %2",
2090 attendeeName, delegatorName);
2094 QString delegate, dummy;
2095 KPIMUtils::extractEmailAddressAndName(attendee->delegate(), dummy, delegate);
2096 if (delegate.isEmpty()) {
2097 delegate = attendee->delegate();
2099 if (!delegate.isEmpty()) {
2100 return i18n(
"%1 has delegated this invitation to %2", attendeeName, delegate);
2102 return i18n(
"%1 has delegated this invitation", attendeeName);
2106 return i18n(
"This invitation is now completed");
2108 return i18n(
"%1 is still processing the invitation", attendeeName);
2109 case Attendee::None:
2110 return i18n(
"Unknown response to this invitation");
2115 return i18n(
"%1 makes this counter proposal",
2116 firstAttendeeName(event, i18n(
"Sender")));
2120 QString orgStr = organizerName(event, sender);
2121 if (senderIsOrganizer(event, sender)) {
2122 return i18n(
"%1 declines your counter proposal", orgStr);
2124 return i18n(
"%1 declines your counter proposal on behalf of %2", sender, orgStr);
2129 return i18n(
"Error: Event iTIP message with unknown method");
2131 kError() <<
"encountered an iTIP method that we do not support";
2135 static QString invitationHeaderTodo(
const Todo::Ptr &todo,
2136 const Incidence::Ptr &existingIncidence,
2139 if (!msg || !todo) {
2143 switch (msg->method()) {
2145 return i18n(
"This to-do has been published");
2147 if (existingIncidence && todo->revision() > 0) {
2148 QString orgStr = organizerName(todo, sender);
2149 if (senderIsOrganizer(todo, sender)) {
2150 return i18n(
"This to-do has been updated by the organizer %1", orgStr);
2152 return i18n(
"This to-do has been updated by %1 as a representative of %2",
2156 if (iamOrganizer(todo)) {
2157 return i18n(
"I created this to-do");
2159 QString orgStr = organizerName(todo, sender);
2160 if (senderIsOrganizer(todo, sender)) {
2161 return i18n(
"You have been assigned this to-do by %1", orgStr);
2163 return i18n(
"You have been assigned this to-do by %1 as a representative of %2",
2169 return i18n(
"This to-do was refreshed");
2171 if (iamOrganizer(todo)) {
2172 return i18n(
"This to-do was canceled");
2174 return i18n(
"The organizer has revoked this to-do");
2177 return i18n(
"Addition to the to-do");
2180 if (replyMeansCounter(todo)) {
2181 return i18n(
"%1 makes this counter proposal", firstAttendeeName(todo, sender));
2185 if (attendees.count() == 0) {
2186 kDebug() <<
"No attendees in the iCal reply!";
2189 if (attendees.count() != 1) {
2190 kDebug() <<
"Warning: attendeecount in the reply should be 1"
2191 <<
"but is" << attendees.count();
2193 QString attendeeName = firstAttendeeName(todo, sender);
2195 QString delegatorName, dummy;
2197 KPIMUtils::extractEmailAddressAndName(attendee->delegate(), dummy, delegatorName);
2198 if (delegatorName.isEmpty()) {
2199 delegatorName = attendee->delegator();
2202 switch (attendee->status()) {
2204 return i18n(
"%1 indicates this to-do assignment still needs some action",
2207 if (todo->revision() > 0) {
2208 if (!sender.isEmpty()) {
2209 if (todo->isCompleted()) {
2210 return i18n(
"This to-do has been completed by assignee %1", sender);
2212 return i18n(
"This to-do has been updated by assignee %1", sender);
2215 if (todo->isCompleted()) {
2216 return i18n(
"This to-do has been completed by an assignee");
2218 return i18n(
"This to-do has been updated by an assignee");
2222 if (delegatorName.isEmpty()) {
2223 return i18n(
"%1 accepts this to-do", attendeeName);
2225 return i18n(
"%1 accepts this to-do on behalf of %2",
2226 attendeeName, delegatorName);
2230 if (delegatorName.isEmpty()) {
2231 return i18n(
"%1 tentatively accepts this to-do", attendeeName);
2233 return i18n(
"%1 tentatively accepts this to-do on behalf of %2",
2234 attendeeName, delegatorName);
2237 if (delegatorName.isEmpty()) {
2238 return i18n(
"%1 declines this to-do", attendeeName);
2240 return i18n(
"%1 declines this to-do on behalf of %2",
2241 attendeeName, delegatorName);
2245 QString delegate, dummy;
2246 KPIMUtils::extractEmailAddressAndName(attendee->delegate(), dummy, delegate);
2247 if (delegate.isEmpty()) {
2248 delegate = attendee->delegate();
2250 if (!delegate.isEmpty()) {
2251 return i18n(
"%1 has delegated this to-do to %2", attendeeName, delegate);
2253 return i18n(
"%1 has delegated this to-do", attendeeName);
2257 return i18n(
"The request for this to-do is now completed");
2259 return i18n(
"%1 is still processing the to-do", attendeeName);
2260 case Attendee::None:
2261 return i18n(
"Unknown response to this to-do");
2266 return i18n(
"%1 makes this counter proposal", firstAttendeeName(todo, sender));
2270 QString orgStr = organizerName(todo, sender);
2271 if (senderIsOrganizer(todo, sender)) {
2272 return i18n(
"%1 declines the counter proposal", orgStr);
2274 return i18n(
"%1 declines the counter proposal on behalf of %2", sender, orgStr);
2279 return i18n(
"Error: To-do iTIP message with unknown method");
2281 kError() <<
"encountered an iTIP method that we do not support";
2285 static QString invitationHeaderJournal(
const Journal::Ptr &journal,
2288 if (!msg || !journal) {
2292 switch (msg->method()) {
2294 return i18n(
"This journal has been published");
2296 return i18n(
"You have been assigned this journal");
2298 return i18n(
"This journal was refreshed");
2300 return i18n(
"This journal was canceled");
2302 return i18n(
"Addition to the journal");
2305 if (replyMeansCounter(journal)) {
2306 return i18n(
"Sender makes this counter proposal");
2310 if (attendees.count() == 0) {
2311 kDebug() <<
"No attendees in the iCal reply!";
2314 if (attendees.count() != 1) {
2315 kDebug() <<
"Warning: attendeecount in the reply should be 1 "
2316 <<
"but is " << attendees.count();
2320 switch (attendee->status()) {
2322 return i18n(
"Sender indicates this journal assignment still needs some action");
2324 return i18n(
"Sender accepts this journal");
2326 return i18n(
"Sender tentatively accepts this journal");
2328 return i18n(
"Sender declines this journal");
2330 return i18n(
"Sender has delegated this request for the journal");
2332 return i18n(
"The request for this journal is now completed");
2334 return i18n(
"Sender is still processing the invitation");
2335 case Attendee::None:
2336 return i18n(
"Unknown response to this journal");
2341 return i18n(
"Sender makes this counter proposal");
2343 return i18n(
"Sender declines the counter proposal");
2345 return i18n(
"Error: Journal iTIP message with unknown method");
2347 kError() <<
"encountered an iTIP method that we do not support";
2351 static QString invitationHeaderFreeBusy(
const FreeBusy::Ptr &fb,
2358 switch (msg->method()) {
2360 return i18n(
"This free/busy list has been published");
2362 return i18n(
"The free/busy list has been requested");
2364 return i18n(
"This free/busy list was refreshed");
2366 return i18n(
"This free/busy list was canceled");
2368 return i18n(
"Addition to the free/busy list");
2370 return i18n(
"Reply to the free/busy list");
2372 return i18n(
"Sender makes this counter proposal");
2374 return i18n(
"Sender declines the counter proposal");
2376 return i18n(
"Error: Free/Busy iTIP message with unknown method");
2378 kError() <<
"encountered an iTIP method that we do not support";
2383 static QString invitationAttendeeList(
const Incidence::Ptr &incidence)
2389 if (incidence->type() == Incidence::TypeTodo) {
2390 tmpStr += i18n(
"Assignees");
2392 tmpStr += i18n(
"Invitation List");
2397 if (!attendees.isEmpty()) {
2398 QStringList comments;
2399 Attendee::List::ConstIterator it;
2400 for (it = attendees.constBegin(); it != attendees.constEnd(); ++it) {
2402 if (!iamAttendee(a)) {
2405 tmpStr += QLatin1String(
"<table border=\"1\" cellpadding=\"1\" cellspacing=\"0\">");
2407 tmpStr += QLatin1String(
"<tr>");
2408 tmpStr += QLatin1String(
"<td>");
2410 if (attendeeIsOrganizer(incidence, a)) {
2411 comments << i18n(
"organizer");
2413 if (!a->delegator().isEmpty()) {
2414 comments << i18n(
" (delegated by %1)", a->delegator());
2416 if (!a->delegate().isEmpty()) {
2417 comments << i18n(
" (delegated to %1)", a->delegate());
2419 tmpStr += invitationPerson(a->email(), a->name(), QString(), comments.join(QLatin1String(
",")));
2420 tmpStr += QLatin1String(
"</td>");
2421 tmpStr += QLatin1String(
"</tr>");
2426 tmpStr += QLatin1String(
"</table>");
2434 static QString invitationRsvpList(
const Incidence::Ptr &incidence,
const Attendee::Ptr &sender)
2440 if (incidence->type() == Incidence::TypeTodo) {
2441 tmpStr += i18n(
"Assignees");
2443 tmpStr += i18n(
"Invitation List");
2448 if (!attendees.isEmpty()) {
2449 QStringList comments;
2450 Attendee::List::ConstIterator it;
2451 for (it = attendees.constBegin(); it != attendees.constEnd(); ++it) {
2453 if (!attendeeIsOrganizer(incidence, a)) {
2454 QString statusStr = Stringify::attendeeStatus(a->status());
2455 if (sender && (a->email() == sender->email())) {
2458 if (a->status() != sender->status()) {
2459 statusStr = i18n(
"%1 (<i>unrecorded</i>)",
2460 Stringify::attendeeStatus(sender->status()));
2466 tmpStr += QLatin1String(
"<table border=\"1\" cellpadding=\"1\" cellspacing=\"0\">");
2468 tmpStr += QLatin1String(
"<tr>");
2469 tmpStr += QLatin1String(
"<td>");
2471 if (iamAttendee(a)) {
2472 comments << i18n(
"myself");
2474 if (!a->delegator().isEmpty()) {
2475 comments << i18n(
" (delegated by %1)", a->delegator());
2477 if (!a->delegate().isEmpty()) {
2478 comments << i18n(
" (delegated to %1)", a->delegate());
2480 tmpStr += invitationPerson(a->email(), a->name(), QString(), comments.join(QLatin1String(
",")));
2481 tmpStr += QLatin1String(
"</td>");
2482 tmpStr += QLatin1String(
"<td>")+ statusStr + QLatin1String(
"</td>");
2483 tmpStr += QLatin1String(
"</tr>");
2488 tmpStr += QLatin1String(
"</table>");
2490 tmpStr += QLatin1String(
"<i> ") + i18nc(
"no attendees",
"None") + QLatin1String(
"</i>");
2496 static QString invitationAttachments(InvitationFormatterHelper *helper,
2497 const Incidence::Ptr &incidence)
2504 if (incidence->type() == Incidence::TypeFreeBusy) {
2510 if (!attachments.isEmpty()) {
2511 tmpStr += i18n(
"Attached Documents:") + QLatin1String(
"<ol>");
2513 Attachment::List::ConstIterator it;
2514 for (it = attachments.constBegin(); it != attachments.constEnd(); ++it) {
2516 tmpStr += QLatin1String(
"<li>");
2518 KMimeType::Ptr
mimeType = KMimeType::mimeType(a->mimeType());
2519 const QString iconStr = (mimeType ?
2520 mimeType->iconName(a->uri()) :
2521 QLatin1String(
"application-octet-stream"));
2522 const QString iconPath = KIconLoader::global()->iconPath(iconStr, KIconLoader::Small);
2523 if (!iconPath.isEmpty()) {
2524 tmpStr += QLatin1String(
"<img valign=\"top\" src=\"") + iconPath + QLatin1String(
"\">");
2526 tmpStr += helper->makeLink(QLatin1String(
"ATTACH:") + QLatin1String(a->label().toUtf8().toBase64()), a->label());
2527 tmpStr += QLatin1String(
"</li>");
2529 tmpStr += QLatin1String(
"</ol>");
2536 class KCalUtils::IncidenceFormatter::ScheduleMessageVisitor :
public Visitor
2539 ScheduleMessageVisitor() : mMessage(0) {
2540 mResult = QLatin1String(
"");
2542 bool act(
const IncidenceBase::Ptr &incidence,
2543 const Incidence::Ptr &existingIncidence,
2546 mExistingIncidence = existingIncidence;
2549 return incidence->accept(*
this, incidence);
2551 QString result()
const {
2557 Incidence::Ptr mExistingIncidence;
2562 class KCalUtils::IncidenceFormatter::InvitationHeaderVisitor :
2563 public IncidenceFormatter::ScheduleMessageVisitor
2568 mResult = invitationHeaderEvent(event, mExistingIncidence, mMessage, mSender);
2569 return !mResult.isEmpty();
2573 mResult = invitationHeaderTodo(todo, mExistingIncidence, mMessage, mSender);
2574 return !mResult.isEmpty();
2578 mResult = invitationHeaderJournal(journal, mMessage);
2579 return !mResult.isEmpty();
2583 mResult = invitationHeaderFreeBusy(fb, mMessage);
2584 return !mResult.isEmpty();
2588 class KCalUtils::IncidenceFormatter::InvitationBodyVisitor
2589 :
public IncidenceFormatter::ScheduleMessageVisitor
2592 InvitationBodyVisitor(
bool noHtmlMode, KDateTime::Spec spec)
2593 : ScheduleMessageVisitor(), mNoHtmlMode(noHtmlMode), mSpec(spec) {}
2599 mResult = invitationDetailsEvent(event, oldevent, mMessage, mNoHtmlMode, mSpec);
2600 return !mResult.isEmpty();
2605 mResult = invitationDetailsTodo(todo, oldtodo, mMessage, mNoHtmlMode, mSpec);
2606 return !mResult.isEmpty();
2611 mResult = invitationDetailsJournal(journal, oldjournal, mNoHtmlMode, mSpec);
2612 return !mResult.isEmpty();
2616 mResult = invitationDetailsFreeBusy(fb,
FreeBusy::Ptr(), mNoHtmlMode, mSpec);
2617 return !mResult.isEmpty();
2622 KDateTime::Spec mSpec;
2626 InvitationFormatterHelper::InvitationFormatterHelper()
2631 InvitationFormatterHelper::~InvitationFormatterHelper()
2635 QString InvitationFormatterHelper::generateLinkURL(
const QString &
id)
2641 class IncidenceFormatter::IncidenceCompareVisitor :
public Visitor
2644 IncidenceCompareVisitor() {}
2645 bool act(
const IncidenceBase::Ptr &incidence,
2646 const Incidence::Ptr &existingIncidence)
2648 if (!existingIncidence) {
2651 Incidence::Ptr inc = incidence.staticCast<
Incidence>();
2652 if (!inc || !existingIncidence ||
2653 inc->revision() <= existingIncidence->revision()) {
2656 mExistingIncidence = existingIncidence;
2657 return incidence->
accept(*
this, incidence);
2660 QString result()
const
2662 if (mChanges.isEmpty()) {
2665 QString html = QLatin1String(
"<div align=\"left\"><ul><li>");
2666 html += mChanges.join(QLatin1String(
"</li><li>"));
2667 html += QLatin1String(
"</li><ul></div>");
2674 compareEvents(event, mExistingIncidence.dynamicCast<
Event>());
2675 compareIncidences(event, mExistingIncidence);
2676 return !mChanges.isEmpty();
2680 compareTodos(todo, mExistingIncidence.dynamicCast<
Todo>());
2681 compareIncidences(todo, mExistingIncidence);
2682 return !mChanges.isEmpty();
2686 compareIncidences(journal, mExistingIncidence);
2687 return !mChanges.isEmpty();
2692 return !mChanges.isEmpty();
2696 void compareEvents(
const Event::Ptr &newEvent,
2699 if (!oldEvent || !newEvent) {
2702 if (oldEvent->dtStart() != newEvent->dtStart() ||
2703 oldEvent->allDay() != newEvent->allDay()) {
2704 mChanges += i18n(
"The invitation starting time has been changed from %1 to %2",
2705 eventStartTimeStr(oldEvent), eventStartTimeStr(newEvent));
2707 if (oldEvent->dtEnd() != newEvent->dtEnd() ||
2708 oldEvent->allDay() != newEvent->allDay()) {
2709 mChanges += i18n(
"The invitation ending time has been changed from %1 to %2",
2710 eventEndTimeStr(oldEvent), eventEndTimeStr(newEvent));
2714 void compareTodos(
const Todo::Ptr &newTodo,
2717 if (!oldTodo || !newTodo) {
2721 if (!oldTodo->isCompleted() && newTodo->isCompleted()) {
2722 mChanges += i18n(
"The to-do has been completed");
2724 if (oldTodo->isCompleted() && !newTodo->isCompleted()) {
2725 mChanges += i18n(
"The to-do is no longer completed");
2727 if (oldTodo->percentComplete() != newTodo->percentComplete()) {
2728 const QString oldPer = i18n(
"%1%", oldTodo->percentComplete());
2729 const QString newPer = i18n(
"%1%", newTodo->percentComplete());
2730 mChanges += i18n(
"The task completed percentage has changed from %1 to %2",
2734 if (!oldTodo->hasStartDate() && newTodo->hasStartDate()) {
2735 mChanges += i18n(
"A to-do starting time has been added");
2737 if (oldTodo->hasStartDate() && !newTodo->hasStartDate()) {
2738 mChanges += i18n(
"The to-do starting time has been removed");
2740 if (oldTodo->hasStartDate() && newTodo->hasStartDate() &&
2741 oldTodo->dtStart() != newTodo->dtStart()) {
2742 mChanges += i18n(
"The to-do starting time has been changed from %1 to %2",
2747 if (!oldTodo->hasDueDate() && newTodo->hasDueDate()) {
2748 mChanges += i18n(
"A to-do due time has been added");
2750 if (oldTodo->hasDueDate() && !newTodo->hasDueDate()) {
2751 mChanges += i18n(
"The to-do due time has been removed");
2753 if (oldTodo->hasDueDate() && newTodo->hasDueDate() &&
2754 oldTodo->dtDue() != newTodo->dtDue()) {
2755 mChanges += i18n(
"The to-do due time has been changed from %1 to %2",
2761 void compareIncidences(
const Incidence::Ptr &newInc,
2762 const Incidence::Ptr &oldInc)
2764 if (!oldInc || !newInc) {
2768 if (oldInc->summary() != newInc->summary()) {
2769 mChanges += i18n(
"The summary has been changed to: \"%1\"",
2770 newInc->richSummary());
2773 if (oldInc->location() != newInc->location()) {
2774 mChanges += i18n(
"The location has been changed to: \"%1\"",
2775 newInc->richLocation());
2778 if (oldInc->description() != newInc->description()) {
2779 mChanges += i18n(
"The description has been changed to: \"%1\"",
2780 newInc->richDescription());
2785 for (Attendee::List::ConstIterator it = newAttendees.constBegin();
2786 it != newAttendees.constEnd(); ++it) {
2787 Attendee::Ptr oldAtt = oldInc->attendeeByMail((*it)->email());
2789 mChanges += i18n(
"Attendee %1 has been added", (*it)->fullName());
2791 if (oldAtt->status() != (*it)->status()) {
2792 mChanges += i18n(
"The status of attendee %1 has been changed to: %2",
2793 (*it)->fullName(), Stringify::attendeeStatus((*it)->status()));
2798 for (Attendee::List::ConstIterator it = oldAttendees.constBegin();
2799 it != oldAttendees.constEnd(); ++it) {
2800 if (!attendeeIsOrganizer(oldInc, (*it))) {
2801 Attendee::Ptr newAtt = newInc->attendeeByMail((*it)->email());
2803 mChanges += i18n(
"Attendee %1 has been removed", (*it)->fullName());
2810 Incidence::Ptr mExistingIncidence;
2811 QStringList mChanges;
2815 QString InvitationFormatterHelper::makeLink(
const QString &
id,
const QString &text)
2817 if (!
id.startsWith(QLatin1String(
"ATTACH:"))) {
2818 QString res = QString::fromLatin1(
"<a href=\"%1\"><font size=\"-1\"><b>%2</b></font></a>").
2819 arg(generateLinkURL(
id), text);
2823 QString res = QString::fromLatin1(
"<a href=\"%1\">%2</a>").
2824 arg(generateLinkURL(
id), text);
2831 static bool incidenceOwnedByMe(
const Calendar::Ptr &calendar,
2832 const Incidence::Ptr &incidence)
2835 Q_UNUSED(incidence);
2839 static QString inviteButton(InvitationFormatterHelper *helper,
2840 const QString &
id,
const QString &text)
2847 html += QLatin1String(
"<td style=\"border-width:2px;border-style:outset\">");
2848 if (!
id.isEmpty()) {
2849 html += helper->makeLink(
id, text);
2853 html += QLatin1String(
"</td>");
2857 static QString inviteLink(InvitationFormatterHelper *helper,
2858 const QString &
id,
const QString &text)
2862 if (helper && !
id.isEmpty()) {
2863 html += helper->makeLink(
id, text);
2870 static QString responseButtons(
const Incidence::Ptr &incidence,
2871 bool rsvpReq,
bool rsvpRec,
2872 InvitationFormatterHelper *helper)
2879 if (!rsvpReq && (incidence && incidence->revision() == 0)) {
2881 html += inviteButton(helper, QLatin1String(
"record"), i18n(
"Record"));
2884 html += inviteButton(helper, QLatin1String(
"delete"), i18n(
"Move to Trash"));
2889 html += inviteButton(helper, QLatin1String(
"accept"),
2890 i18nc(
"accept invitation",
"Accept"));
2893 html += inviteButton(helper, QLatin1String(
"accept_conditionally"),
2894 i18nc(
"Accept invitation conditionally",
"Accept cond."));
2897 html += inviteButton(helper, QLatin1String(
"counter"),
2898 i18nc(
"invitation counter proposal",
"Counter proposal"));
2901 html += inviteButton(helper, QLatin1String(
"decline"),
2902 i18nc(
"decline invitation",
"Decline"));
2905 if (!rsvpRec || (incidence && incidence->revision() > 0)) {
2907 html += inviteButton(helper, QLatin1String(
"delegate"),
2908 i18nc(
"delegate inviation to another",
"Delegate"));
2911 html += inviteButton(helper, QLatin1String(
"forward"), i18nc(
"forward request to another",
"Forward"));
2914 if (incidence && incidence->type() == Incidence::TypeEvent) {
2915 html += inviteButton(helper, QLatin1String(
"check_calendar"),
2916 i18nc(
"look for scheduling conflicts",
"Check my calendar"));
2922 static QString counterButtons(
const Incidence::Ptr &incidence,
2923 InvitationFormatterHelper *helper)
2931 html += inviteButton(helper, QLatin1String(
"accept_counter"), i18n(
"Accept"));
2934 html += inviteButton(helper, QLatin1String(
"decline_counter"), i18n(
"Decline"));
2938 if (incidence->type() == Incidence::TypeTodo) {
2939 html += inviteButton(helper, QLatin1String(
"check_calendar"), i18n(
"Check my to-do list"));
2941 html += inviteButton(helper, QLatin1String(
"check_calendar"), i18n(
"Check my calendar"));
2947 static QString recordButtons(
const Incidence::Ptr &incidence,
2948 InvitationFormatterHelper *helper)
2956 if (incidence->type() == Incidence::TypeTodo) {
2957 html += inviteLink(helper, QLatin1String(
"reply"),
2958 i18n(
"Record invitation in my to-do list"));
2960 html += inviteLink(helper, QLatin1String(
"reply"),
2961 i18n(
"Record invitation in my calendar"));
2967 static QString recordResponseButtons(
const Incidence::Ptr &incidence,
2968 InvitationFormatterHelper *helper)
2976 if (incidence->type() == Incidence::TypeTodo) {
2977 html += inviteLink(helper, QLatin1String(
"reply"),
2978 i18n(
"Record response in my to-do list"));
2980 html += inviteLink(helper, QLatin1String(
"reply"),
2981 i18n(
"Record response in my calendar"));
2987 static QString cancelButtons(
const Incidence::Ptr &incidence,
2988 InvitationFormatterHelper *helper)
2997 if (incidence->type() == Incidence::TypeTodo) {
2998 html += inviteButton(helper, QLatin1String(
"cancel"),
2999 i18n(
"Remove invitation from my to-do list"));
3001 html += inviteButton(helper, QLatin1String(
"cancel"),
3002 i18n(
"Remove invitation from my calendar"));
3013 static QString formatICalInvitationHelper(QString invitation,
3015 InvitationFormatterHelper *helper,
3017 KDateTime::Spec spec,
3018 const QString &sender,
3019 bool outlookCompareStyle)
3021 if (invitation.isEmpty()) {
3031 kDebug() <<
"Failed to parse the scheduling message";
3037 IncidenceBase::Ptr incBase = msg->event();
3039 incBase->shiftTimes(mCalendar->timeSpec(), KDateTime::Spec::LocalZone());
3042 Incidence::Ptr existingIncidence;
3043 if (incBase && helper->calendar()) {
3044 existingIncidence = helper->calendar()->incidence(incBase->uid());
3046 if (!incidenceOwnedByMe(helper->calendar(), existingIncidence)) {
3047 existingIncidence.clear();
3049 if (!existingIncidence) {
3050 const Incidence::List list = helper->calendar()->incidences();
3051 for (Incidence::List::ConstIterator it = list.begin(), end = list.end(); it != end; ++it) {
3052 if ((*it)->schedulingID() == incBase->uid() &&
3053 incidenceOwnedByMe(helper->calendar(), *it)) {
3054 existingIncidence = *it;
3061 Incidence::Ptr inc = incBase.staticCast<
Incidence>();
3065 int incRevision = 0;
3066 if (inc && inc->type() != Incidence::TypeFreeBusy) {
3067 incRevision = inc->revision();
3071 QString html = QLatin1String(
"<div align=\"center\" style=\"border:solid 1px;\">");
3073 IncidenceFormatter::InvitationHeaderVisitor headerVisitor;
3075 if (!headerVisitor.act(inc, existingIncidence, msg, sender)) {
3078 html += htmlAddTag(QLatin1String(
"h3"), headerVisitor.result());
3080 if (outlookCompareStyle ||
3083 IncidenceFormatter::InvitationBodyVisitor bodyVisitor(noHtmlMode, spec);
3087 if (inc && existingIncidence &&
3088 incRevision < existingIncidence->revision()) {
3089 bodyOk = bodyVisitor.act(existingIncidence, inc, msg, sender);
3091 bodyOk = bodyVisitor.act(inc, existingIncidence, msg, sender);
3094 bodyOk = bodyVisitor.act(inc, Incidence::Ptr(), msg, sender);
3097 html += bodyVisitor.result();
3103 InvitationBodyVisitor bodyVisitor(noHtmlMode, spec);
3104 if (!bodyVisitor.act(inc, Incidence::Ptr(), msg, sender)) {
3107 html += bodyVisitor.result();
3110 IncidenceFormatter::IncidenceCompareVisitor compareVisitor;
3111 if (compareVisitor.act(inc, existingIncidence)) {
3112 html += QLatin1String(
"<p align=\"left\">");
3113 if (senderIsOrganizer(inc, sender)) {
3114 html += i18n(
"The following changes have been made by the organizer:");
3115 }
else if (!sender.isEmpty()) {
3116 html += i18n(
"The following changes have been made by %1:", sender);
3118 html += i18n(
"The following changes have been made:");
3120 html += QLatin1String(
"</p>");
3121 html += compareVisitor.result();
3125 IncidenceCompareVisitor compareVisitor;
3126 if (compareVisitor.act(inc, existingIncidence)) {
3127 html += QLatin1String(
"<p align=\"left\">");
3128 if (!sender.isEmpty()) {
3129 html += i18n(
"The following changes have been made by %1:", sender);
3131 html += i18n(
"The following changes have been made by an attendee:");
3133 html += QLatin1String(
"</p>");
3134 html += compareVisitor.result();
3140 bool myInc = iamOrganizer(inc);
3143 bool rsvpRec =
false;
3146 Incidence::Ptr rsvpIncidence = existingIncidence;
3147 if (!rsvpIncidence && inc && incRevision > 0) {
3148 rsvpIncidence = inc;
3150 if (rsvpIncidence) {
3151 ea = findMyAttendee(rsvpIncidence);
3154 (ea->status() == Attendee::Accepted ||
3155 ea->status() == Attendee::Declined ||
3156 ea->status() == Attendee::Tentative)) {
3163 bool isDelegated =
false;
3166 if (!inc->attendees().isEmpty()) {
3167 a = inc->attendees().first();
3171 isDelegated = (a->status() == Attendee::Delegated);
3172 role = Stringify::attendeeRole(a->role());
3176 bool rsvpReq = rsvpRequested(inc);
3179 if (rsvpRec && inc) {
3180 if (incRevision == 0) {
3181 tStr = i18n(
"Your <b>%1</b> response has been recorded",
3182 Stringify::attendeeStatus(ea->status()));
3184 tStr = i18n(
"Your status for this invitation is <b>%1</b>",
3185 Stringify::attendeeStatus(ea->status()));
3189 tStr = i18n(
"This invitation was canceled");
3190 }
else if (msg->method() ==
iTIPAdd) {
3191 tStr = i18n(
"This invitation was accepted");
3194 tStr = rsvpRequestedStr(rsvpReq, role);
3197 tStr = rsvpRequestedStr(rsvpReq, role);
3199 tStr = i18n(
"Awaiting delegation response");
3202 html += QLatin1String(
"<br>");
3203 html += QLatin1String(
"<i><u>") + tStr + QLatin1String(
"</u></i>");
3208 if (inc && incRevision == 0) {
3209 QString statStr = myStatusStr(inc);
3210 if (!statStr.isEmpty()) {
3211 html += QLatin1String(
"<br>");
3212 html += QLatin1String(
"<i>") + statStr + QLatin1String(
"</i>");
3219 html += QLatin1String(
"<p>");
3220 html += QLatin1String(
"<table border=\"0\" align=\"center\" cellspacing=\"4\"><tr>");
3222 switch (msg->method()) {
3228 if (inc && incRevision > 0 && (existingIncidence || !helper->calendar())) {
3229 html += recordButtons(inc, helper);
3234 html += responseButtons(inc, rsvpReq, rsvpRec, helper);
3236 html += responseButtons(inc,
false,
false, helper);
3243 html += cancelButtons(inc, helper);
3253 if (replyMeansCounter(inc)) {
3254 html += QLatin1String(
"<tr>") + counterButtons(inc, helper) + QLatin1String(
"</tr>");
3263 a = findDelegatedFromMyAttendee(inc);
3265 if (a->status() != Attendee::Accepted ||
3266 a->status() != Attendee::Tentative) {
3267 html += responseButtons(inc, rsvpReq, rsvpRec, helper);
3273 if (!inc->attendees().isEmpty()) {
3274 a = inc->attendees().first();
3276 if (a && helper->calendar()) {
3277 ea = findAttendee(existingIncidence, a->email());
3280 if (ea && (ea->status() != Attendee::NeedsAction) && (ea->status() == a->status())) {
3281 const QString tStr = i18n(
"The <b>%1</b> response has been recorded",
3282 Stringify::attendeeStatus(ea->status()));
3283 html += inviteButton(helper, QString(), htmlAddTag(QLatin1String(
"i"), tStr));
3286 html += recordResponseButtons(inc, helper);
3294 html += counterButtons(inc, helper);
3298 html += responseButtons(inc, rsvpReq, rsvpRec, helper);
3306 html += QLatin1String(
"</tr></table>");
3310 html += invitationRsvpList(existingIncidence, a);
3312 html += invitationAttendeeList(inc);
3316 html += QLatin1String(
"</div>");
3319 html += invitationAttachments(helper, inc);
3327 InvitationFormatterHelper *helper,
3328 bool outlookCompareStyle)
3330 return formatICalInvitationHelper(invitation, calendar, helper,
false,
3331 KSystemTimeZones::local(), QString(),
3332 outlookCompareStyle);
3337 InvitationFormatterHelper *helper,
3338 const QString &sender,
3339 bool outlookCompareStyle)
3341 return formatICalInvitationHelper(invitation, calendar, helper,
true,
3342 KSystemTimeZones::local(), sender,
3343 outlookCompareStyle);
3351 class KCalUtils::IncidenceFormatter::ToolTipVisitor :
public Visitor
3355 : mRichText(true), mSpec(KDateTime::Spec()), mResult(QLatin1String(
"")) {}
3358 const IncidenceBase::Ptr &incidence,
3359 const QDate &date=QDate(),
bool richText=
true,
3360 KDateTime::Spec spec=KDateTime::Spec())
3362 mCalendar = calendar;
3365 mRichText = richText;
3367 mResult = QLatin1String(
"");
3368 return incidence ? incidence->accept(*
this, incidence) :
false;
3371 bool act(
const QString &location,
const IncidenceBase::Ptr &incidence,
3372 const QDate &date=QDate(),
bool richText=
true,
3373 KDateTime::Spec spec=KDateTime::Spec())
3375 mLocation = location;
3377 mRichText = richText;
3379 mResult = QLatin1String(
"");
3380 return incidence ? incidence->accept(*
this, incidence) :
false;
3383 QString result()
const {
3393 QString dateRangeText(
const Event::Ptr &event,
const QDate &date);
3394 QString dateRangeText(
const Todo::Ptr &todo,
const QDate &date);
3398 QString generateToolTip(
const Incidence::Ptr &incidence, QString dtRangeText);
3405 KDateTime::Spec mSpec;
3409 QString IncidenceFormatter::ToolTipVisitor::dateRangeText(
const Event::Ptr &event,
3416 KDateTime startDt =
event->dtStart();
3417 KDateTime endDt =
event->dtEnd();
3418 if (event->recurs()) {
3419 if (date.isValid()) {
3420 KDateTime kdt(date, QTime(0, 0, 0), KSystemTimeZones::local());
3421 int diffDays = startDt.daysTo(kdt);
3422 kdt = kdt.addSecs(-1);
3423 startDt.setDate(event->recurrence()->getNextDateTime(kdt).date());
3424 if (event->hasEndDate()) {
3425 endDt = endDt.addDays(diffDays);
3426 if (startDt > endDt) {
3427 startDt.setDate(event->recurrence()->getPreviousDateTime(kdt).date());
3428 endDt = startDt.addDays(event->dtStart().daysTo(event->dtEnd()));
3434 if (event->isMultiDay()) {
3436 ret += QLatin1String(
"<br>") + i18nc(
"Event start",
"<i>From:</i> %1", tmp);
3439 ret += QLatin1String(
"<br>") + i18nc(
"Event end",
"<i>To:</i> %1", tmp);
3443 ret += QLatin1String(
"<br>") +
3444 i18n(
"<i>Date:</i> %1",
dateToString(startDt,
false, mSpec));
3445 if (!event->allDay()) {
3446 const QString dtStartTime =
timeToString(startDt,
true, mSpec);
3447 const QString dtEndTime =
timeToString(endDt,
true, mSpec);
3448 if (dtStartTime == dtEndTime) {
3450 tmp = QLatin1String(
"<br>") +
3451 i18nc(
"time for event",
"<i>Time:</i> %1",
3454 tmp = QLatin1String(
"<br>") +
3455 i18nc(
"time range for event",
3456 "<i>Time:</i> %1 - %2",
3457 dtStartTime, dtEndTime);
3462 return ret.replace(QLatin1Char(
' '), QLatin1String(
" "));
3465 QString IncidenceFormatter::ToolTipVisitor::dateRangeText(
const Todo::Ptr &todo,
3470 if (todo->hasStartDate()) {
3471 KDateTime startDt = todo->dtStart();
3472 if (todo->recurs() && date.isValid()) {
3473 startDt.setDate(date);
3475 ret += QLatin1String(
"<br>") +
3476 i18n(
"<i>Start:</i> %1",
dateToString(startDt,
false, mSpec));
3479 if (todo->hasDueDate()) {
3480 KDateTime dueDt = todo->dtDue();
3481 if (todo->recurs() && date.isValid()) {
3482 KDateTime kdt(date, QTime(0, 0, 0), KSystemTimeZones::local());
3483 kdt = kdt.addSecs(-1);
3484 dueDt.setDate(todo->recurrence()->getNextDateTime(kdt).date());
3486 ret += QLatin1String(
"<br>") +
3487 i18n(
"<i>Due:</i> %1",
3493 if (todo->priority() > 0) {
3494 ret += QLatin1String(
"<br>");
3495 ret += QLatin1String(
"<i>") + i18n(
"Priority:") + QLatin1String(
"</i>") + QLatin1String(
" ");
3496 ret += QString::number(todo->priority());
3499 ret += QLatin1String(
"<br>");
3500 if (todo->isCompleted()) {
3501 ret += QLatin1String(
"<i>") + i18nc(
"Completed: date",
"Completed:") + QLatin1String(
"</i>") + QLatin1String(
" ");
3504 ret += QLatin1String(
"<i>")+ i18n(
"Percent Done:") + QLatin1String(
"</i>") + QLatin1String(
" ");
3505 ret += i18n(
"%1%", todo->percentComplete());
3508 return ret.replace(QLatin1Char(
' '), QLatin1String(
" "));
3511 QString IncidenceFormatter::ToolTipVisitor::dateRangeText(
const Journal::Ptr &journal)
3515 if (journal->dtStart().isValid()) {
3516 ret += QLatin1String(
"<br>") +
3517 i18n(
"<i>Date:</i> %1",
dateToString(journal->dtStart(),
false, mSpec));
3519 return ret.replace(QLatin1Char(
' '), QLatin1String(
" "));
3522 QString IncidenceFormatter::ToolTipVisitor::dateRangeText(
const FreeBusy::Ptr &fb)
3526 ret = QLatin1String(
"<br>") +
3527 i18n(
"<i>Period start:</i> %1",
3529 ret += QLatin1String(
"<br>") +
3530 i18n(
"<i>Period start:</i> %1",
3532 return ret.replace(QLatin1Char(
' '), QLatin1String(
" "));
3537 mResult = generateToolTip(event, dateRangeText(event, mDate));
3538 return !mResult.isEmpty();
3543 mResult = generateToolTip(todo, dateRangeText(todo, mDate));
3544 return !mResult.isEmpty();
3549 mResult = generateToolTip(journal, dateRangeText(journal));
3550 return !mResult.isEmpty();
3556 mResult = QLatin1String(
"<qt><b>") +
3557 i18n(
"Free/Busy information for %1", fb->organizer()->fullName()) +
3558 QLatin1String(
"</b>");
3559 mResult += dateRangeText(fb);
3560 mResult += QLatin1String(
"</qt>");
3561 return !mResult.isEmpty();
3564 static QString tooltipPerson(
const QString &email,
const QString &name,
Attendee::PartStat status)
3567 const QString printName = searchName(email, name);
3570 const QString iconPath = rsvpStatusIconPath(status);
3573 QString personString;
3574 if (!iconPath.isEmpty()) {
3575 personString += QLatin1String(
"<img valign=\"top\" src=\"") + iconPath + QLatin1String(
"\">") + QLatin1String(
" ");
3577 if (status != Attendee::None) {
3578 personString += i18nc(
"attendee name (attendee status)",
"%1 (%2)",
3579 printName.isEmpty() ? email : printName,
3580 Stringify::attendeeStatus(status));
3582 personString += i18n(
"%1", printName.isEmpty() ? email : printName);
3584 return personString;
3587 static QString tooltipFormatOrganizer(
const QString &email,
const QString &name)
3590 const QString printName = searchName(email, name);
3593 const QString iconPath =
3594 KIconLoader::global()->iconPath(QLatin1String(
"meeting-organizer"), KIconLoader::Small);
3597 QString personString;
3598 personString += QLatin1String(
"<img valign=\"top\" src=\"") + iconPath + QLatin1String(
"\">") + QLatin1String(
" ");
3599 personString += (printName.isEmpty() ? email : printName);
3600 return personString;
3603 static QString tooltipFormatAttendeeRoleList(
const Incidence::Ptr &incidence,
3607 const QString etc = i18nc(
"elipsis",
"...");
3611 Attendee::List::ConstIterator it;
3614 for (it = attendees.constBegin(); it != attendees.constEnd(); ++it) {
3616 if (a->role() != role) {
3620 if (attendeeIsOrganizer(incidence, a)) {
3624 if (i == maxNumAtts) {
3625 tmpStr += QLatin1String(
" ") + etc;
3628 tmpStr += QLatin1String(
" ") + tooltipPerson(a->email(), a->name(),
3629 showStatus ? a->status() : Attendee::None);
3630 if (!a->delegator().isEmpty()) {
3631 tmpStr += i18n(
" (delegated by %1)", a->delegator());
3633 if (!a->delegate().isEmpty()) {
3634 tmpStr += i18n(
" (delegated to %1)", a->delegate());
3636 tmpStr += QLatin1String(
"<br>");
3639 if (tmpStr.endsWith(QLatin1String(
"<br>"))) {
3645 static QString tooltipFormatAttendees(
const Calendar::Ptr &calendar,
3646 const Incidence::Ptr &incidence)
3648 QString tmpStr, str;
3651 int attendeeCount = incidence->attendees().count();
3652 if (attendeeCount > 1 ||
3653 (attendeeCount == 1 &&
3654 !attendeeIsOrganizer(incidence, incidence->attendees().first()))) {
3655 tmpStr += QLatin1String(
"<i>") + i18n(
"Organizer:") + QLatin1String(
"</i>") + QLatin1String(
"<br>");
3656 tmpStr += QLatin1String(
" ") + tooltipFormatOrganizer(incidence->organizer()->email(),
3657 incidence->organizer()->name());
3662 const bool showStatus = attendeeCount > 0 && incOrganizerOwnsCalendar(calendar, incidence);
3665 str = tooltipFormatAttendeeRoleList(incidence, Attendee::Chair, showStatus);
3666 if (!str.isEmpty()) {
3667 tmpStr += QLatin1String(
"<br><i>") + i18n(
"Chair:") + QLatin1String(
"</i>") + QLatin1String(
"<br>");
3672 str = tooltipFormatAttendeeRoleList(incidence, Attendee::ReqParticipant, showStatus);
3673 if (!str.isEmpty()) {
3674 tmpStr += QLatin1String(
"<br><i>") + i18n(
"Required Participants:") + QLatin1String(
"</i>") + QLatin1String(
"<br>");
3679 str = tooltipFormatAttendeeRoleList(incidence, Attendee::OptParticipant, showStatus);
3680 if (!str.isEmpty()) {
3681 tmpStr += QLatin1String(
"<br><i>") + i18n(
"Optional Participants:") + QLatin1String(
"</i>") + QLatin1String(
"<br>");
3686 str = tooltipFormatAttendeeRoleList(incidence, Attendee::NonParticipant, showStatus);
3687 if (!str.isEmpty()) {
3688 tmpStr += QLatin1String(
"<br><i>") + i18n(
"Observers:") + QLatin1String(
"</i>") + QLatin1String(
"<br>");
3695 QString IncidenceFormatter::ToolTipVisitor::generateToolTip(
const Incidence::Ptr &incidence,
3696 QString dtRangeText)
3698 int maxDescLen = 120;
3705 QString tmp = QLatin1String(
"<qt>");
3708 tmp += QLatin1String(
"<b>") + incidence->richSummary() + QLatin1String(
"</b>");
3709 tmp += QLatin1String(
"<hr>");
3711 QString calStr = mLocation;
3715 if (!calStr.isEmpty()) {
3716 tmp += QLatin1String(
"<i>") + i18n(
"Calendar:") + QLatin1String(
"</i>") + QLatin1String(
" ");
3722 if (!incidence->location().isEmpty()) {
3723 tmp += QLatin1String(
"<br>");
3724 tmp += QLatin1String(
"<i>") + i18n(
"Location:") + QLatin1String(
"</i>") + QLatin1String(
" ");
3725 tmp += incidence->richLocation();
3729 if (!durStr.isEmpty()) {
3730 tmp += QLatin1String(
"<br>");
3731 tmp += QLatin1String(
"<i>") + i18n(
"Duration:") + QLatin1String(
"</i>") + QLatin1String(
" ");
3735 if (incidence->recurs()) {
3736 tmp += QLatin1String(
"<br>");
3737 tmp += QLatin1String(
"<i>") + i18n(
"Recurrence:") + QLatin1String(
"</i>") + QLatin1String(
" ");
3741 if (incidence->hasRecurrenceId()) {
3742 tmp += QLatin1String(
"<br>");
3743 tmp += QLatin1String(
"<i>") + i18n(
"Recurrence:") + QLatin1String(
"</i>") + QLatin1String(
" ");
3744 tmp += i18n(
"Exception");
3747 if (!incidence->description().isEmpty()) {
3748 QString desc(incidence->description());
3749 if (!incidence->descriptionIsRich()) {
3750 if (desc.length() > maxDescLen) {
3751 desc = desc.left(maxDescLen) + i18nc(
"elipsis",
"...");
3753 desc = Qt::escape(desc).replace(QLatin1Char(
'\n'), QLatin1String(
"<br>"));
3757 tmp += QLatin1String(
"<hr>");
3758 tmp += QLatin1String(
"<i>") + i18n(
"Description:") + QLatin1String(
"</i>") + QLatin1String(
"<br>");
3760 tmp += QLatin1String(
"<hr>");
3763 int reminderCount = incidence->alarms().count();
3764 if (reminderCount > 0 && incidence->hasEnabledAlarms()) {
3765 tmp += QLatin1String(
"<br>");
3766 tmp += QLatin1String(
"<i>") + i18np(
"Reminder:",
"Reminders:", reminderCount) + QLatin1String(
"</i>") + QLatin1String(
" ");
3770 tmp += QLatin1String(
"<br>");
3771 tmp += tooltipFormatAttendees(mCalendar, incidence);
3773 int categoryCount = incidence->categories().count();
3774 if (categoryCount > 0) {
3775 tmp += QLatin1String(
"<br>");
3776 tmp += QLatin1String(
"<i>") + i18np(
"Category:",
"Categories:", categoryCount) + QLatin1String(
"</i>") +QLatin1String(
" ");
3777 tmp += incidence->categories().join(QLatin1String(
", "));
3780 tmp += QLatin1String(
"</qt>");
3786 const IncidenceBase::Ptr &incidence,
3789 KDateTime::Spec spec)
3792 if (incidence && v.act(sourceName, incidence, date, richText, spec)) {
3804 static QString mailBodyIncidence(
const Incidence::Ptr &incidence)
3807 if (!incidence->summary().isEmpty()) {
3808 body += i18n(
"Summary: %1\n", incidence->richSummary());
3810 if (!incidence->organizer()->isEmpty()) {
3811 body += i18n(
"Organizer: %1\n", incidence->organizer()->fullName());
3813 if (!incidence->location().isEmpty()) {
3814 body += i18n(
"Location: %1\n", incidence->richLocation());
3821 class KCalUtils::IncidenceFormatter::MailBodyVisitor :
public Visitor
3825 : mSpec(KDateTime::Spec()), mResult(QLatin1String(
"")) {}
3827 bool act(IncidenceBase::Ptr incidence, KDateTime::Spec spec=KDateTime::Spec())
3830 mResult = QLatin1String(
"");
3831 return incidence ? incidence->accept(*
this, incidence) :
false;
3833 QString result()
const
3844 mResult = i18n(
"This is a Free Busy Object");
3845 return !mResult.isEmpty();
3848 KDateTime::Spec mSpec;
3854 QString recurrence[]= {
3855 i18nc(
"no recurrence",
"None"),
3856 i18nc(
"event recurs by minutes",
"Minutely"),
3857 i18nc(
"event recurs by hours",
"Hourly"),
3858 i18nc(
"event recurs by days",
"Daily"),
3859 i18nc(
"event recurs by weeks",
"Weekly"),
3860 i18nc(
"event recurs same position (e.g. first monday) each month",
"Monthly Same Position"),
3861 i18nc(
"event recurs same day each month",
"Monthly Same Day"),
3862 i18nc(
"event recurs same month each year",
"Yearly Same Month"),
3863 i18nc(
"event recurs same day each year",
"Yearly Same Day"),
3864 i18nc(
"event recurs same position (e.g. first monday) each year",
"Yearly Same Position")
3867 mResult = mailBodyIncidence(event);
3868 mResult += i18n(
"Start Date: %1\n",
dateToString(event->dtStart(),
true, mSpec));
3869 if (!event->allDay()) {
3870 mResult += i18n(
"Start Time: %1\n",
timeToString(event->dtStart(),
true, mSpec));
3872 if (event->dtStart() !=
event->dtEnd()) {
3873 mResult += i18n(
"End Date: %1\n",
dateToString(event->dtEnd(),
true, mSpec));
3875 if (!event->allDay()) {
3876 mResult += i18n(
"End Time: %1\n",
timeToString(event->dtEnd(),
true, mSpec));
3878 if (event->recurs()) {
3881 mResult += i18n(
"Recurs: %1\n", recurrence[ recur->
recurrenceType() ]);
3882 mResult += i18n(
"Frequency: %1\n", event->recurrence()->frequency());
3885 mResult += i18np(
"Repeats once",
"Repeats %1 times", recur->
duration());
3886 mResult += QLatin1Char(
'\n');
3891 if (event->allDay()) {
3892 endstr = KGlobal::locale()->formatDate(recur->
endDate());
3894 endstr = KGlobal::locale()->formatDateTime(recur->
endDateTime().dateTime());
3896 mResult += i18n(
"Repeat until: %1\n", endstr);
3898 mResult += i18n(
"Repeats forever\n");
3903 if (!event->description().isEmpty()) {
3905 if (event->descriptionIsRich() ||
3906 event->description().startsWith(QLatin1String(
"<!DOCTYPE HTML")))
3908 descStr = cleanHtml(event->description());
3910 descStr =
event->description();
3912 if (!descStr.isEmpty()) {
3913 mResult += i18n(
"Details:\n%1\n", descStr);
3916 return !mResult.isEmpty();
3921 mResult = mailBodyIncidence(todo);
3923 if (todo->hasStartDate() && todo->dtStart().isValid()) {
3924 mResult += i18n(
"Start Date: %1\n",
dateToString(todo->dtStart(
false),
true, mSpec));
3925 if (!todo->allDay()) {
3926 mResult += i18n(
"Start Time: %1\n",
timeToString(todo->dtStart(
false),
true, mSpec));
3929 if (todo->hasDueDate() && todo->dtDue().isValid()) {
3930 mResult += i18n(
"Due Date: %1\n",
dateToString(todo->dtDue(),
true, mSpec));
3931 if (!todo->allDay()) {
3932 mResult += i18n(
"Due Time: %1\n",
timeToString(todo->dtDue(),
true, mSpec));
3935 QString details = todo->richDescription();
3936 if (!details.isEmpty()) {
3937 mResult += i18n(
"Details:\n%1\n", details);
3939 return !mResult.isEmpty();
3944 mResult = mailBodyIncidence(journal);
3945 mResult += i18n(
"Date: %1\n",
dateToString(journal->dtStart(),
true, mSpec));
3946 if (!journal->allDay()) {
3947 mResult += i18n(
"Time: %1\n",
timeToString(journal->dtStart(),
true, mSpec));
3949 if (!journal->description().isEmpty()) {
3950 mResult += i18n(
"Text of the journal:\n%1\n", journal->richDescription());
3952 return !mResult.isEmpty();
3957 KDateTime::Spec spec)
3964 if (v.act(incidence, spec)) {
3971 static QString recurEnd(
const Incidence::Ptr &incidence)
3974 if (incidence->allDay()) {
3975 endstr = KGlobal::locale()->formatDate(incidence->recurrence()->endDate());
3977 endstr = KGlobal::locale()->formatDateTime(incidence->recurrence()->endDateTime());
3989 if (incidence->hasRecurrenceId()) {
3990 return QLatin1String(
"Recurrence exception");
3993 if (!incidence->recurs()) {
3994 return i18n(
"No recurrence");
3996 static QStringList dayList;
3997 if (dayList.isEmpty()) {
3998 dayList.append(i18n(
"31st Last"));
3999 dayList.append(i18n(
"30th Last"));
4000 dayList.append(i18n(
"29th Last"));
4001 dayList.append(i18n(
"28th Last"));
4002 dayList.append(i18n(
"27th Last"));
4003 dayList.append(i18n(
"26th Last"));
4004 dayList.append(i18n(
"25th Last"));
4005 dayList.append(i18n(
"24th Last"));
4006 dayList.append(i18n(
"23rd Last"));
4007 dayList.append(i18n(
"22nd Last"));
4008 dayList.append(i18n(
"21st Last"));
4009 dayList.append(i18n(
"20th Last"));
4010 dayList.append(i18n(
"19th Last"));
4011 dayList.append(i18n(
"18th Last"));
4012 dayList.append(i18n(
"17th Last"));
4013 dayList.append(i18n(
"16th Last"));
4014 dayList.append(i18n(
"15th Last"));
4015 dayList.append(i18n(
"14th Last"));
4016 dayList.append(i18n(
"13th Last"));
4017 dayList.append(i18n(
"12th Last"));
4018 dayList.append(i18n(
"11th Last"));
4019 dayList.append(i18n(
"10th Last"));
4020 dayList.append(i18n(
"9th Last"));
4021 dayList.append(i18n(
"8th Last"));
4022 dayList.append(i18n(
"7th Last"));
4023 dayList.append(i18n(
"6th Last"));
4024 dayList.append(i18n(
"5th Last"));
4025 dayList.append(i18n(
"4th Last"));
4026 dayList.append(i18n(
"3rd Last"));
4027 dayList.append(i18n(
"2nd Last"));
4028 dayList.append(i18nc(
"last day of the month",
"Last"));
4029 dayList.append(i18nc(
"unknown day of the month",
"unknown"));
4030 dayList.append(i18n(
"1st"));
4031 dayList.append(i18n(
"2nd"));
4032 dayList.append(i18n(
"3rd"));
4033 dayList.append(i18n(
"4th"));
4034 dayList.append(i18n(
"5th"));
4035 dayList.append(i18n(
"6th"));
4036 dayList.append(i18n(
"7th"));
4037 dayList.append(i18n(
"8th"));
4038 dayList.append(i18n(
"9th"));
4039 dayList.append(i18n(
"10th"));
4040 dayList.append(i18n(
"11th"));
4041 dayList.append(i18n(
"12th"));
4042 dayList.append(i18n(
"13th"));
4043 dayList.append(i18n(
"14th"));
4044 dayList.append(i18n(
"15th"));
4045 dayList.append(i18n(
"16th"));
4046 dayList.append(i18n(
"17th"));
4047 dayList.append(i18n(
"18th"));
4048 dayList.append(i18n(
"19th"));
4049 dayList.append(i18n(
"20th"));
4050 dayList.append(i18n(
"21st"));
4051 dayList.append(i18n(
"22nd"));
4052 dayList.append(i18n(
"23rd"));
4053 dayList.append(i18n(
"24th"));
4054 dayList.append(i18n(
"25th"));
4055 dayList.append(i18n(
"26th"));
4056 dayList.append(i18n(
"27th"));
4057 dayList.append(i18n(
"28th"));
4058 dayList.append(i18n(
"29th"));
4059 dayList.append(i18n(
"30th"));
4060 dayList.append(i18n(
"31st"));
4063 const int weekStart = KGlobal::locale()->weekStartDay();
4065 const KCalendarSystem *calSys = KGlobal::locale()->calendar();
4069 QString txt, recurStr;
4070 static QString noRecurrence = i18n(
"No recurrence");
4072 case Recurrence::rNone:
4073 return noRecurrence;
4075 case Recurrence::rMinutely:
4077 recurStr = i18np(
"Recurs every minute until %2",
4078 "Recurs every %1 minutes until %2",
4079 recur->
frequency(), recurEnd(incidence));
4081 recurStr += i18nc(
"number of occurrences",
4082 " (<numid>%1</numid> occurrences)",
4086 recurStr = i18np(
"Recurs every minute",
4087 "Recurs every %1 minutes", recur->
frequency());
4091 case Recurrence::rHourly:
4093 recurStr = i18np(
"Recurs hourly until %2",
4094 "Recurs every %1 hours until %2",
4095 recur->
frequency(), recurEnd(incidence));
4097 recurStr += i18nc(
"number of occurrences",
4098 " (<numid>%1</numid> occurrences)",
4102 recurStr = i18np(
"Recurs hourly",
"Recurs every %1 hours", recur->
frequency());
4106 case Recurrence::rDaily:
4108 recurStr = i18np(
"Recurs daily until %2",
4109 "Recurs every %1 days until %2",
4110 recur->
frequency(), recurEnd(incidence));
4112 recurStr += i18nc(
"number of occurrences",
4113 " (<numid>%1</numid> occurrences)",
4117 recurStr = i18np(
"Recurs daily",
"Recurs every %1 days", recur->
frequency());
4121 case Recurrence::rWeekly:
4123 bool addSpace =
false;
4124 for (
int i = 0; i < 7; ++i) {
4125 if (recur->
days().testBit((i + weekStart + 6) % 7)) {
4127 dayNames.append(i18nc(
"separator for list of days",
", "));
4129 dayNames.append(calSys->weekDayName(((i + weekStart + 6) % 7) + 1,
4130 KCalendarSystem::ShortDayName));
4134 if (dayNames.isEmpty()) {
4135 dayNames = i18nc(
"Recurs weekly on no days",
"no days");
4138 recurStr = i18ncp(
"Recurs weekly on [list of days] until end-date",
4139 "Recurs weekly on %2 until %3",
4140 "Recurs every <numid>%1</numid> weeks on %2 until %3",
4141 recur->
frequency(), dayNames, recurEnd(incidence));
4143 recurStr += i18nc(
"number of occurrences",
4144 " (<numid>%1</numid> occurrences)",
4148 recurStr = i18ncp(
"Recurs weekly on [list of days]",
4149 "Recurs weekly on %2",
4150 "Recurs every <numid>%1</numid> weeks on %2",
4155 case Recurrence::rMonthlyPos:
4160 recurStr = i18ncp(
"Recurs every N months on the [2nd|3rd|...]"
4161 " weekdayname until end-date",
4162 "Recurs every month on the %2 %3 until %4",
4163 "Recurs every <numid>%1</numid> months on the %2 %3 until %4",
4165 dayList[rule.pos() + 31],
4166 calSys->weekDayName(rule.day(), KCalendarSystem::LongDayName),
4167 recurEnd(incidence));
4169 recurStr += i18nc(
"number of occurrences",
4170 " (<numid>%1</numid> occurrences)",
4174 recurStr = i18ncp(
"Recurs every N months on the [2nd|3rd|...] weekdayname",
4175 "Recurs every month on the %2 %3",
4176 "Recurs every %1 months on the %2 %3",
4178 dayList[rule.pos() + 31],
4179 calSys->weekDayName(rule.day(), KCalendarSystem::LongDayName));
4184 case Recurrence::rMonthlyDay:
4189 recurStr = i18ncp(
"Recurs monthly on the [1st|2nd|...] day until end-date",
4190 "Recurs monthly on the %2 day until %3",
4191 "Recurs every %1 months on the %2 day until %3",
4194 recurEnd(incidence));
4196 recurStr += i18nc(
"number of occurrences",
4197 " (<numid>%1</numid> occurrences)",
4201 recurStr = i18ncp(
"Recurs monthly on the [1st|2nd|...] day",
4202 "Recurs monthly on the %2 day",
4203 "Recurs every <numid>%1</numid> month on the %2 day",
4205 dayList[days + 31]);
4210 case Recurrence::rYearlyMonth:
4214 recurStr = i18ncp(
"Recurs Every N years on month-name [1st|2nd|...]"
4216 "Recurs yearly on %2 %3 until %4",
4217 "Recurs every %1 years on %2 %3 until %4",
4221 recurEnd(incidence));
4223 recurStr += i18nc(
"number of occurrences",
4224 " (<numid>%1</numid> occurrences)",
4230 recurStr = i18ncp(
"Recurs Every N years on month-name [1st|2nd|...]",
4231 "Recurs yearly on %2 %3",
4232 "Recurs every %1 years on %2 %3",
4239 recurStr = i18nc(
"Recurs Every year on month-name [1st|2nd|...]",
4240 "Recurs yearly on %1 %2",
4243 dayList[ recur->
startDate().day() + 31 ]);
4245 recurStr = i18nc(
"Recurs Every year on month-name [1st|2nd|...]",
4246 "Recurs yearly on %1 %2",
4247 calSys->monthName(recur->
startDate().month(),
4249 dayList[ recur->
startDate().day() + 31 ]);
4255 case Recurrence::rYearlyDay:
4256 if (!recur->
yearDays().isEmpty()) {
4258 recurStr = i18ncp(
"Recurs every N years on day N until end-date",
4259 "Recurs every year on day <numid>%2</numid> until %3",
4260 "Recurs every <numid>%1</numid> years"
4261 " on day <numid>%2</numid> until %3",
4264 recurEnd(incidence));
4266 recurStr += i18nc(
"number of occurrences",
4267 " (<numid>%1</numid> occurrences)",
4271 recurStr = i18ncp(
"Recurs every N YEAR[S] on day N",
4272 "Recurs every year on day <numid>%2</numid>",
4273 "Recurs every <numid>%1</numid> years"
4274 " on day <numid>%2</numid>",
4279 case Recurrence::rYearlyPos:
4284 recurStr = i18ncp(
"Every N years on the [2nd|3rd|...] weekdayname "
4285 "of monthname until end-date",
4286 "Every year on the %2 %3 of %4 until %5",
4287 "Every <numid>%1</numid> years on the %2 %3 of %4"
4290 dayList[rule.pos() + 31],
4291 calSys->weekDayName(rule.day(), KCalendarSystem::LongDayName),
4293 recurEnd(incidence));
4295 recurStr += i18nc(
"number of occurrences",
4296 " (<numid>%1</numid> occurrences)",
4300 recurStr = i18ncp(
"Every N years on the [2nd|3rd|...] weekdayname "
4302 "Every year on the %2 %3 of %4",
4303 "Every <numid>%1</numid> years on the %2 %3 of %4",
4305 dayList[rule.pos() + 31],
4306 calSys->weekDayName(rule.day(), KCalendarSystem::LongDayName),
4314 if (recurStr.isEmpty()) {
4315 recurStr = i18n(
"Incidence recurs");
4320 DateTimeList::ConstIterator il;
4322 for (il = l.constBegin(); il != l.constEnd(); ++il) {
4324 case Recurrence::rMinutely:
4325 exStr << i18n(
"minute %1", (*il).time().minute());
4327 case Recurrence::rHourly:
4328 exStr << KGlobal::locale()->formatTime((*il).time());
4330 case Recurrence::rDaily:
4331 exStr << KGlobal::locale()->formatDate((*il).date(), KLocale::ShortDate);
4333 case Recurrence::rWeekly:
4334 exStr << calSys->weekDayName((*il).date(), KCalendarSystem::ShortDayName);
4336 case Recurrence::rMonthlyPos:
4337 exStr << KGlobal::locale()->formatDate((*il).date(), KLocale::ShortDate);
4339 case Recurrence::rMonthlyDay:
4340 exStr << KGlobal::locale()->formatDate((*il).date(), KLocale::ShortDate);
4342 case Recurrence::rYearlyMonth:
4343 exStr << calSys->monthName((*il).date(), KCalendarSystem::LongName);
4345 case Recurrence::rYearlyDay:
4346 exStr << KGlobal::locale()->formatDate((*il).date(), KLocale::ShortDate);
4348 case Recurrence::rYearlyPos:
4349 exStr << KGlobal::locale()->formatDate((*il).date(), KLocale::ShortDate);
4355 DateList::ConstIterator dl;
4356 for (dl = d.constBegin(); dl != d.constEnd(); ++dl) {
4358 case Recurrence::rDaily:
4359 exStr << KGlobal::locale()->formatDate((*dl), KLocale::ShortDate);
4361 case Recurrence::rWeekly:
4364 if (exStr.isEmpty()) {
4365 exStr << i18np(
"1 day",
"%1 days", recur->exDates().count());
4368 case Recurrence::rMonthlyPos:
4369 exStr << KGlobal::locale()->formatDate((*dl), KLocale::ShortDate);
4371 case Recurrence::rMonthlyDay:
4372 exStr << KGlobal::locale()->formatDate((*dl), KLocale::ShortDate);
4374 case Recurrence::rYearlyMonth:
4375 exStr << calSys->monthName((*dl), KCalendarSystem::LongName);
4377 case Recurrence::rYearlyDay:
4378 exStr << KGlobal::locale()->formatDate((*dl), KLocale::ShortDate);
4380 case Recurrence::rYearlyPos:
4381 exStr << KGlobal::locale()->formatDate((*dl), KLocale::ShortDate);
4386 if (!exStr.isEmpty()) {
4387 recurStr = i18n(
"%1 (excluding %2)", recurStr, exStr.join(QLatin1String(
",")));
4395 const KDateTime::Spec &spec)
4397 if (spec.isValid()) {
4400 if (spec.timeZone() != KSystemTimeZones::local()) {
4401 timeZone = QLatin1Char(
' ') + spec.timeZone().name();
4404 return KGlobal::locale()->formatTime(date.toTimeSpec(spec).time(), !shortfmt) + timeZone;
4406 return KGlobal::locale()->formatTime(date.time(), !shortfmt);
4412 const KDateTime::Spec &spec)
4414 if (spec.isValid()) {
4417 if (spec.timeZone() != KSystemTimeZones::local()) {
4418 timeZone = QLatin1Char(
' ') + spec.timeZone().name();
4422 KGlobal::locale()->formatDate(date.toTimeSpec(spec).date(),
4423 (shortfmt ? KLocale::ShortDate : KLocale::LongDate)) +
4427 KGlobal::locale()->formatDate(date.date(),
4428 (shortfmt ? KLocale::ShortDate : KLocale::LongDate));
4435 const KDateTime::Spec &spec)
4441 if (spec.isValid()) {
4443 if (spec.timeZone() != KSystemTimeZones::local()) {
4444 timeZone = QLatin1Char(
' ') + spec.timeZone().name();
4447 return KGlobal::locale()->formatDateTime(
4448 date.toTimeSpec(spec).dateTime(),
4449 (shortfmt ? KLocale::ShortDate : KLocale::LongDate)) + timeZone;
4451 return KGlobal::locale()->formatDateTime(
4453 (shortfmt ? KLocale::ShortDate : KLocale::LongDate));
4458 const Incidence::Ptr &incidence)
4461 Q_UNUSED(incidence);
4465 static QString secs2Duration(
int secs)
4468 int days = secs / 86400;
4470 tmp += i18np(
"1 day",
"%1 days", days);
4471 tmp += QLatin1Char(
' ');
4472 secs -= (days * 86400);
4474 int hours = secs / 3600;
4476 tmp += i18np(
"1 hour",
"%1 hours", hours);
4477 tmp += QLatin1Char(
' ');
4478 secs -= (hours * 3600);
4480 int mins = secs / 60;
4482 tmp += i18np(
"1 minute",
"%1 minutes", mins);
4490 if (incidence->type() == Incidence::TypeEvent) {
4492 if (event->hasEndDate()) {
4493 if (!event->allDay()) {
4494 tmp = secs2Duration(event->dtStart().secsTo(event->dtEnd()));
4496 tmp = i18np(
"1 day",
"%1 days",
4497 event->dtStart().date().daysTo(event->dtEnd().date()) + 1);
4500 tmp = i18n(
"forever");
4502 }
else if (incidence->type() == Incidence::TypeTodo) {
4504 if (todo->hasDueDate()) {
4505 if (todo->hasStartDate()) {
4506 if (!todo->allDay()) {
4507 tmp = secs2Duration(todo->dtStart().secsTo(todo->dtDue()));
4509 tmp = i18np(
"1 day",
"%1 days",
4510 todo->dtStart().date().daysTo(todo->dtDue().date()) + 1);
4528 Alarm::List::ConstIterator it;
4529 for (it = alarms.constBegin(); it != alarms.constEnd(); ++it) {
4532 QString remStr, atStr, offsetStr;
4533 if (alarm->hasTime()) {
4535 if (alarm->time().isValid()) {
4536 atStr = KGlobal::locale()->formatDateTime(alarm->time());
4538 }
else if (alarm->hasStartOffset()) {
4539 offset = alarm->startOffset().asSeconds();
4542 offsetStr = i18nc(
"N days/hours/minutes before the start datetime",
4543 "%1 before the start", secs2Duration(offset));
4544 }
else if (offset > 0) {
4545 offsetStr = i18nc(
"N days/hours/minutes after the start datetime",
4546 "%1 after the start", secs2Duration(offset));
4548 if (incidence->dtStart().isValid()) {
4549 atStr = KGlobal::locale()->formatDateTime(incidence->dtStart());
4552 }
else if (alarm->hasEndOffset()) {
4553 offset = alarm->endOffset().asSeconds();
4556 if (incidence->type() == Incidence::TypeTodo) {
4557 offsetStr = i18nc(
"N days/hours/minutes before the due datetime",
4558 "%1 before the to-do is due", secs2Duration(offset));
4560 offsetStr = i18nc(
"N days/hours/minutes before the end datetime",
4561 "%1 before the end", secs2Duration(offset));
4563 }
else if (offset > 0) {
4564 if (incidence->type() == Incidence::TypeTodo) {
4565 offsetStr = i18nc(
"N days/hours/minutes after the due datetime",
4566 "%1 after the to-do is due", secs2Duration(offset));
4568 offsetStr = i18nc(
"N days/hours/minutes after the end datetime",
4569 "%1 after the end", secs2Duration(offset));
4572 if (incidence->type() == Incidence::TypeTodo) {
4574 if (t->dtDue().isValid()) {
4575 atStr = KGlobal::locale()->formatDateTime(t->dtDue());
4579 if (e->dtEnd().isValid()) {
4580 atStr = KGlobal::locale()->formatDateTime(e->dtEnd());
4586 if (!atStr.isEmpty()) {
4587 remStr = i18nc(
"reminder occurs at datetime",
"at %1", atStr);
4593 if (alarm->repeatCount() > 0) {
4594 QString countStr = i18np(
"repeats once",
"repeats %1 times", alarm->repeatCount());
4595 QString intervalStr = i18nc(
"interval is N days/hours/minutes",
4597 secs2Duration(alarm->snoozeTime().asSeconds()));
4598 QString repeatStr = i18nc(
"(repeat string, interval string)",
4599 "(%1, %2)", countStr, intervalStr);
4600 remStr = remStr + QLatin1Char(
' ') + repeatStr;
4603 reminderStringList << remStr;
QSharedPointer< Attachment > Ptr
QSharedPointer< Alarm > Ptr
virtual bool visit(Event::Ptr event)
QSharedPointer< Event > Ptr
QList< int > yearDays() const
KCALUTILS_EXPORT QString formatDate(const KDateTime &dt, bool shortfmt=true, const KDateTime::Spec &spec=KDateTime::Spec())
Build a QString date representation of a KDateTime object.
QList< int > yearDates() const
KCALUTILS_EXPORT QString formatDateTime(const KDateTime &dt, bool dateOnly=false, bool shortfmt=true, const KDateTime::Spec &spec=KDateTime::Spec())
Build a QString date/time representation of a KDateTime object.
QSharedPointer< ScheduleMessage > Ptr
virtual bool accept(Visitor &v, IncidenceBase::Ptr incidence)
KCALUTILS_EXPORT QString mimeType()
Mime-type of iCalendar.
QSharedPointer< MemoryCalendar > Ptr
This file is part of the API for handling calendar data and provides static functions for formatting ...
QList< int > monthDays() const
KCALUTILS_EXPORT QString errorMessage(const KCalCore::Exception &exception)
Build a translated message representing an exception.
QList< int > yearMonths() const
QSharedPointer< Calendar > Ptr
QSharedPointer< Attendee > Ptr
KCALUTILS_EXPORT QString todoCompletedDateTime(const KCalCore::Todo::Ptr &todo, bool shortfmt=false)
Returns string containing the date/time when the to-do was completed, formatted according to the user...
QSharedPointer< FreeBusy > Ptr
ushort recurrenceType() const
QSharedPointer< Todo > Ptr
KDateTime endDateTime() const
QSharedPointer< Journal > Ptr
QList< RecurrenceRule::WDayPos > monthPositions() const
QList< RecurrenceRule::WDayPos > yearPositions() const