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>
67 using namespace IncidenceFormatter;
74 static QString string2HTML(
const QString &str)
78 return KPIMUtils::LinkLocator::convertToHtml(str);
81 static KPIMIdentities::IdentityManager *s_identityManager = 0;
85 struct RAIIIdentityManager{
89 s_identityManager =
new KPIMIdentities::IdentityManager(
true);
92 ~RAIIIdentityManager()
94 delete s_identityManager;
95 s_identityManager = 0;
101 static bool thatIsMe(
const QString &email)
103 return s_identityManager ? s_identityManager->thatIsMe(email)
104 : KPIMIdentities::IdentityManager(
true).thatIsMe(email);
110 return thatIsMe(attendee->email());
113 static bool iamPerson(
const Person &person)
116 return thatIsMe(person.
email());
119 static QString htmlAddLink(
const QString &ref,
const QString &text,
122 QString tmpStr(QLatin1String(
"<a href=\"") + ref + QLatin1String(
"\">") + text + QLatin1String(
"</a>"));
124 tmpStr += QLatin1Char(
'\n');
129 static QString htmlAddMailtoLink(
const QString &email,
const QString &name)
133 if (!email.isEmpty()) {
134 Person person(name, email);
135 if (!iamPerson(person)) {
136 QString path = person.
fullName().simplified();
137 if (path.isEmpty() || path.startsWith(QLatin1Char(
'"'))) {
141 mailto.setProtocol(QLatin1String(
"mailto"));
142 mailto.setPath(path);
145 static const QString iconPath =
146 KIconLoader::global()->iconPath(QLatin1String(
"mail-message-new"), KIconLoader::Small);
147 str = htmlAddLink(mailto.url(), QLatin1String(
"<img valign=\"top\" src=\"") + iconPath + QLatin1String(
"\">"));
153 static QString htmlAddUidLink(
const QString &email,
const QString &name,
const QString &uid)
157 if (!uid.isEmpty()) {
159 if (name.isEmpty()) {
161 str += htmlAddLink(QLatin1String(
"uid:") + uid, email);
163 str += htmlAddLink(QLatin1String(
"uid:") + uid, name);
169 static QString htmlAddTag(
const QString &tag,
const QString &text)
171 int numLineBreaks = text.count(QLatin1String(
"\n"));
172 QString str = QLatin1Char(
'<') + tag + QLatin1Char(
'>');
173 QString tmpText = text;
174 QString tmpStr = str;
175 if (numLineBreaks >= 0) {
176 if (numLineBreaks > 0) {
179 for (
int i = 0; i <= numLineBreaks; ++i) {
180 pos = tmpText.indexOf(QLatin1String(
"\n"));
181 tmp = tmpText.left(pos);
182 tmpText = tmpText.right(tmpText.length() - pos - 1);
183 tmpStr += tmp + QLatin1String(
"<br>");
189 tmpStr += QLatin1String(
"</") + tag + QLatin1Char(
'>');
193 static QPair<QString, QString> searchNameAndUid(
const QString &email,
const QString &name,
199 QPair<QString, QString>s;
202 if (!email.isEmpty() && (name.isEmpty() || uid.isEmpty())) {
208 static QString searchName(
const QString &email,
const QString &name)
210 const QString printName = name.isEmpty() ? email : name;
222 return thatIsMe(incidence->organizer()->email());
225 static bool senderIsOrganizer(
Incidence::Ptr incidence,
const QString &sender)
229 if (!incidence || sender.isEmpty()) {
234 QString senderName, senderEmail;
235 if (KPIMUtils::extractEmailAddressAndName(sender, senderEmail, senderName)) {
237 if (incidence->organizer()->email() != senderEmail &&
238 incidence->organizer()->name() != senderName) {
247 if (incidence && attendee &&
248 (incidence->organizer()->email() == attendee->email())) {
255 static QString organizerName(
const Incidence::Ptr incidence,
const QString &defName)
258 if (!defName.isEmpty()) {
261 tName = i18n(
"Organizer Unknown");
266 name = incidence->organizer()->name();
267 if (name.isEmpty()) {
268 name = incidence->organizer()->email();
271 if (name.isEmpty()) {
277 static QString firstAttendeeName(
const Incidence::Ptr &incidence,
const QString &defName)
280 if (!defName.isEmpty()) {
283 tName = i18n(
"Sender");
289 if (attendees.count() > 0) {
291 name = attendee->name();
292 if (name.isEmpty()) {
293 name = attendee->email();
297 if (name.isEmpty()) {
308 iconPath = KIconLoader::global()->iconPath(QLatin1String(
"dialog-ok-apply"), KIconLoader::Small);
311 iconPath = KIconLoader::global()->iconPath(QLatin1String(
"dialog-cancel"), KIconLoader::Small);
314 iconPath = KIconLoader::global()->iconPath(QLatin1String(
"help-about"), KIconLoader::Small);
317 iconPath = KIconLoader::global()->iconPath(QLatin1String(
"help-about"), KIconLoader::Small);
320 iconPath = KIconLoader::global()->iconPath(QLatin1String(
"dialog-ok"), KIconLoader::Small);
323 iconPath = KIconLoader::global()->iconPath(QLatin1String(
"mail-forward"), KIconLoader::Small);
326 iconPath = KIconLoader::global()->iconPath(QLatin1String(
"mail-mark-read"), KIconLoader::Small);
340 static QString displayViewFormatPerson(
const QString &email,
const QString &name,
341 const QString &uid,
const QString &iconPath)
344 QPair<QString, QString> s = searchNameAndUid(email, name, uid);
345 const QString printName = s.first;
346 const QString printUid = s.second;
348 QString personString;
349 if (!iconPath.isEmpty()) {
350 personString += QLatin1String(
"<img valign=\"top\" src=\"") + iconPath + QLatin1String(
"\">") + QLatin1String(
" ");
354 if (!printUid.isEmpty()) {
355 personString += htmlAddUidLink(email, printName, printUid);
358 personString += (printName.isEmpty() ? email : printName);
361 #ifndef KDEPIM_MOBILE_UI
363 if (!email.isEmpty()) {
364 personString += QLatin1String(
" ") + htmlAddMailtoLink(email, printName);
371 static QString displayViewFormatPerson(
const QString &email,
const QString &name,
374 return displayViewFormatPerson(email, name, uid, rsvpStatusIconPath(status));
377 static bool incOrganizerOwnsCalendar(
const Calendar::Ptr &calendar,
384 return iamOrganizer(incidence);
391 Attendee::List::ConstIterator it;
394 for (it = attendees.constBegin(); it != attendees.constEnd(); ++it) {
396 if (a->role() != role) {
400 if (attendeeIsOrganizer(incidence, a)) {
404 tmpStr += displayViewFormatPerson(a->email(), a->name(), a->uid(),
405 showStatus ? a->status() : Attendee::None);
406 if (!a->delegator().isEmpty()) {
407 tmpStr += i18n(
" (delegated by %1)", a->delegator());
409 if (!a->delegate().isEmpty()) {
410 tmpStr += i18n(
" (delegated to %1)", a->delegate());
412 tmpStr += QLatin1String(
"<br>");
414 if (tmpStr.endsWith(QLatin1String(
"<br>"))) {
425 int attendeeCount = incidence->attendees().count();
426 if (attendeeCount > 1 ||
427 (attendeeCount == 1 &&
428 !attendeeIsOrganizer(incidence, incidence->attendees().first()))) {
430 QPair<QString, QString> s = searchNameAndUid(incidence->organizer()->email(),
431 incidence->organizer()->name(),
433 tmpStr += QLatin1String(
"<tr>");
434 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Organizer:") + QLatin1String(
"</b></td>");
435 const QString iconPath =
436 KIconLoader::global()->iconPath(QLatin1String(
"meeting-organizer"), KIconLoader::Small);
437 tmpStr += QLatin1String(
"<td>") + displayViewFormatPerson(incidence->organizer()->email(),
438 s.first, s.second, iconPath) +
439 QLatin1String(
"</td>");
440 tmpStr += QLatin1String(
"</tr>");
445 bool showStatus = incOrganizerOwnsCalendar(calendar, incidence);
448 str = displayViewFormatAttendeeRoleList(incidence,
Attendee::Chair, showStatus);
449 if (!str.isEmpty()) {
450 tmpStr += QLatin1String(
"<tr>");
451 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Chair:") + QLatin1String(
"</b></td>");
452 tmpStr += QLatin1String(
"<td>") + str + QLatin1String(
"</td>");
453 tmpStr += QLatin1String(
"</tr>");
458 if (!str.isEmpty()) {
459 tmpStr += QLatin1String(
"<tr>");
460 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Required Participants:") + QLatin1String(
"</b></td>");
461 tmpStr += QLatin1String(
"<td>") + str + QLatin1String(
"</td>");
462 tmpStr += QLatin1String(
"</tr>");
467 if (!str.isEmpty()) {
468 tmpStr += QLatin1String(
"<tr>");
469 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Optional Participants:") + QLatin1String(
"</b></td>");
470 tmpStr += QLatin1String(
"<td>") + str + QLatin1String(
"</td>");
471 tmpStr += QLatin1String(
"</tr>");
476 if (!str.isEmpty()) {
477 tmpStr += QLatin1String(
"<tr>");
478 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Observers:") + QLatin1String(
"</b></td>");
479 tmpStr += QLatin1String(
"<td>") + str + QLatin1String(
"</td>");
480 tmpStr += QLatin1String(
"</tr>");
486 static QString displayViewFormatAttachments(
Incidence::Ptr incidence)
490 Attachment::List::ConstIterator it;
492 for (it = as.constBegin(); it != as.constEnd(); ++it) {
494 if ((*it)->isUri()) {
496 if ((*it)->uri().startsWith(QLatin1String(
"kmail:"))) {
497 name = i18n(
"Show mail");
499 if ((*it)->label().isEmpty()) {
502 name = (*it)->label();
505 tmpStr += htmlAddLink((*it)->uri(), name);
507 tmpStr += htmlAddLink(QString::fromLatin1(
"ATTACH:%1").
508 arg(QString::fromUtf8((*it)->label().toUtf8().toBase64())),
511 if (count < as.count()) {
512 tmpStr += QLatin1String(
"<br>");
518 static QString displayViewFormatCategories(
Incidence::Ptr incidence)
521 return incidence->categories().join(QLatin1String(
", "));
524 static QString displayViewFormatCreationDate(
Incidence::Ptr incidence, KDateTime::Spec spec)
526 KDateTime kdt = incidence->created().toTimeSpec(spec);
527 return i18n(
"Creation date: %1",
dateTimeToString(incidence->created(),
false,
true, spec));
530 static QString displayViewFormatBirthday(
Event::Ptr event)
535 if (event->customProperty(
"KABC",
"BIRTHDAY") != QLatin1String(
"YES") &&
536 event->customProperty(
"KABC",
"ANNIVERSARY") != QLatin1String(
"YES")) {
540 const QString uid_1 =
event->customProperty(
"KABC",
"UID-1");
541 const QString name_1 =
event->customProperty(
"KABC",
"NAME-1");
542 const QString email_1=
event->customProperty(
"KABC",
"EMAIL-1");
546 const QString tmpStr = displayViewFormatPerson(p->email(), name_1, uid_1, QString());
552 QString tmpStr = QLatin1String(
"<table><tr>");
555 KIconLoader *iconLoader = KIconLoader::global();
556 tmpStr += QLatin1String(
"<td>");
559 if (incidence->customProperty(
"KABC",
"BIRTHDAY") == QLatin1String(
"YES")) {
560 iconPath = iconLoader->iconPath(QLatin1String(
"view-calendar-birthday"), KIconLoader::Small);
561 }
else if (incidence->customProperty(
"KABC",
"ANNIVERSARY") == QLatin1String(
"YES")) {
562 iconPath = iconLoader->iconPath(QLatin1String(
"view-calendar-wedding-anniversary"), KIconLoader::Small);
564 iconPath = iconLoader->iconPath(incidence->iconName(), KIconLoader::Small);
566 tmpStr += QLatin1String(
"<img valign=\"top\" src=\"") + iconPath + QLatin1String(
"\">");
568 if (incidence->hasEnabledAlarms()) {
569 tmpStr += QLatin1String(
"<img valign=\"top\" src=\"") +
570 iconLoader->iconPath(QLatin1String(
"preferences-desktop-notification-bell"), KIconLoader::Small) +
571 QLatin1String(
"\">");
573 if (incidence->recurs()) {
574 tmpStr += QLatin1String(
"<img valign=\"top\" src=\"") +
575 iconLoader->iconPath(QLatin1String(
"edit-redo"), KIconLoader::Small) +
576 QLatin1String(
"\">");
578 if (incidence->isReadOnly()) {
579 tmpStr += QLatin1String(
"<img valign=\"top\" src=\"") +
580 iconLoader->iconPath(QLatin1String(
"object-locked"), KIconLoader::Small) +
581 QLatin1String(
"\">");
583 tmpStr += QLatin1String(
"</td>");
585 tmpStr += QLatin1String(
"<td>");
586 tmpStr += QLatin1String(
"<b><u>") + incidence->richSummary() + QLatin1String(
"</u></b>");
587 tmpStr += QLatin1String(
"</td>");
589 tmpStr += QLatin1String(
"</tr></table>");
594 static QString displayViewFormatEvent(
const Calendar::Ptr calendar,
const QString &sourceName,
596 const QDate &date, KDateTime::Spec spec)
602 QString tmpStr = displayViewFormatHeader(event);
604 tmpStr += QLatin1String(
"<table>");
605 tmpStr += QLatin1String(
"<col width=\"25%\"/>");
606 tmpStr += QLatin1String(
"<col width=\"75%\"/>");
608 const QString calStr = calendar ?
resourceString(calendar, event) : sourceName;
609 if (!calStr.isEmpty()) {
610 tmpStr += QLatin1String(
"<tr>");
611 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Calendar:") + QLatin1String(
"</b></td>");
612 tmpStr += QLatin1String(
"<td>") + calStr + QLatin1String(
"</td>");
613 tmpStr += QLatin1String(
"</tr>");
616 if (!event->location().isEmpty()) {
617 tmpStr += QLatin1String(
"<tr>");
618 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Location:") + QLatin1String(
"</b></td>");
619 tmpStr += QLatin1String(
"<td>") +
event->richLocation() + QLatin1String(
"</td>");
620 tmpStr +=QLatin1String(
"</tr>");
623 KDateTime startDt =
event->dtStart();
624 KDateTime endDt =
event->dtEnd();
625 if (event->recurs()) {
626 if (date.isValid()) {
627 KDateTime kdt(date, QTime(0, 0, 0), KSystemTimeZones::local());
628 int diffDays = startDt.daysTo(kdt);
629 kdt = kdt.addSecs(-1);
630 startDt.setDate(event->recurrence()->getNextDateTime(kdt).date());
631 if (event->hasEndDate()) {
632 endDt = endDt.addDays(diffDays);
633 if (startDt > endDt) {
634 startDt.setDate(event->recurrence()->getPreviousDateTime(kdt).date());
635 endDt = startDt.addDays(event->dtStart().daysTo(event->dtEnd()));
641 tmpStr += QLatin1String(
"<tr>");
642 if (event->allDay()) {
643 if (event->isMultiDay()) {
644 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Date:") + QLatin1String(
"</b></td>");
645 tmpStr += QLatin1String(
"<td>") +
646 i18nc(
"<beginTime> - <endTime>",
"%1 - %2",
649 QLatin1String(
"</td>");
651 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Date:") + QLatin1String(
"</b></td>");
652 tmpStr += QLatin1String(
"<td>") +
653 i18nc(
"date as string",
"%1",
655 QLatin1String(
"</td>");
658 if (event->isMultiDay()) {
659 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Date:") + QLatin1String(
"</b></td>");
660 tmpStr += QLatin1String(
"<td>") +
661 i18nc(
"<beginTime> - <endTime>",
"%1 - %2",
664 QLatin1String(
"</td>");
666 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Date:") + QLatin1String(
"</b></td>");
667 tmpStr += QLatin1String(
"<td>") +
668 i18nc(
"date as string",
"%1",
670 QLatin1String(
"</td>");
672 tmpStr += QLatin1String(
"</tr><tr>");
673 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Time:") + QLatin1String(
"</b></td>");
674 if (event->hasEndDate() && startDt != endDt) {
675 tmpStr += QLatin1String(
"<td>") +
676 i18nc(
"<beginTime> - <endTime>",
"%1 - %2",
679 QLatin1String(
"</td>");
681 tmpStr += QLatin1String(
"<td>") +
683 QLatin1String(
"</td>");
687 tmpStr += QLatin1String(
"</tr>");
690 if (!durStr.isEmpty()) {
691 tmpStr += QLatin1String(
"<tr>");
692 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Duration:") + QLatin1String(
"</b></td>");
693 tmpStr += QLatin1String(
"<td>") + durStr + QLatin1String(
"</td>");
694 tmpStr += QLatin1String(
"</tr>");
697 if (event->recurs() ||
event->hasRecurrenceId()) {
698 tmpStr += QLatin1String(
"<tr>");
699 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Recurrence:") + QLatin1String(
"</b></td>");
702 if (event->hasRecurrenceId()) {
703 str = i18n(
"Exception");
708 tmpStr += QLatin1String(
"<td>") + str +
709 QLatin1String(
"</td>");
710 tmpStr += QLatin1String(
"</tr>");
713 const bool isBirthday =
event->customProperty(
"KABC",
"BIRTHDAY") == QLatin1String(
"YES");
714 const bool isAnniversary =
event->customProperty(
"KABC",
"ANNIVERSARY") == QLatin1String(
"YES");
716 if (isBirthday || isAnniversary) {
717 tmpStr += QLatin1String(
"<tr>");
719 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Anniversary:") + QLatin1String(
"</b></td>");
721 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Birthday:") + QLatin1String(
"</b></td>");
723 tmpStr += QLatin1String(
"<td>") + displayViewFormatBirthday(event) + QLatin1String(
"</td>");
724 tmpStr += QLatin1String(
"</tr>");
725 tmpStr += QLatin1String(
"</table>");
729 if (!event->description().isEmpty()) {
731 if (!event->descriptionIsRich() &&
732 !
event->description().startsWith(QLatin1String(
"<!DOCTYPE HTML")))
734 descStr = string2HTML(event->description());
736 if (!event->description().startsWith(QLatin1String(
"<!DOCTYPE HTML"))) {
737 descStr =
event->richDescription();
739 descStr =
event->description();
742 tmpStr += QLatin1String(
"<tr>");
743 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Description:") + QLatin1String(
"</b></td>");
744 tmpStr += QLatin1String(
"<td>") + descStr + QLatin1String(
"</td>");
745 tmpStr += QLatin1String(
"</tr>");
750 int reminderCount =
event->alarms().count();
751 if (reminderCount > 0 && event->hasEnabledAlarms()) {
752 tmpStr += QLatin1String(
"<tr>");
753 tmpStr += QLatin1String(
"<td><b>") +
754 i18np(
"Reminder:",
"Reminders:", reminderCount) +
755 QLatin1String(
"</b></td>");
756 tmpStr += QLatin1String(
"<td>") +
reminderStringList(event).join(QLatin1String(
"<br>")) + QLatin1String(
"</td>");
757 tmpStr += QLatin1String(
"</tr>");
760 tmpStr += displayViewFormatAttendees(calendar, event);
762 int categoryCount =
event->categories().count();
763 if (categoryCount > 0) {
764 tmpStr += QLatin1String(
"<tr>");
765 tmpStr += QLatin1String(
"<td><b>");
766 tmpStr += i18np(
"Category:",
"Categories:", categoryCount) +
767 QLatin1String(
"</b></td>");
768 tmpStr += QLatin1String(
"<td>") + displayViewFormatCategories(event) + QLatin1String(
"</td>");
769 tmpStr += QLatin1String(
"</tr>");
772 int attachmentCount =
event->attachments().count();
773 if (attachmentCount > 0) {
774 tmpStr += QLatin1String(
"<tr>");
775 tmpStr += QLatin1String(
"<td><b>") +
776 i18np(
"Attachment:",
"Attachments:", attachmentCount) +
777 QLatin1String(
"</b></td>");
778 tmpStr += QLatin1String(
"<td>") + displayViewFormatAttachments(event) + QLatin1String(
"</td>");
779 tmpStr += QLatin1String(
"</tr>");
781 tmpStr += QLatin1String(
"</table>");
783 tmpStr += QLatin1String(
"<p><em>") + displayViewFormatCreationDate(event, spec) + QLatin1String(
"</em>");
788 static QString displayViewFormatTodo(
const Calendar::Ptr &calendar,
const QString &sourceName,
790 const QDate &ocurrenceDueDate, KDateTime::Spec spec)
793 kDebug() <<
"IncidenceFormatter::displayViewFormatTodo was called without to-do, quitting";
797 QString tmpStr = displayViewFormatHeader(todo);
799 tmpStr += QLatin1String(
"<table>");
800 tmpStr += QLatin1String(
"<col width=\"25%\"/>");
801 tmpStr += QLatin1String(
"<col width=\"75%\"/>");
803 const QString calStr = calendar ?
resourceString(calendar, todo) : sourceName;
804 if (!calStr.isEmpty()) {
805 tmpStr += QLatin1String(
"<tr>");
806 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Calendar:") + QLatin1String(
"</b></td>");
807 tmpStr += QLatin1String(
"<td>") + calStr + QLatin1String(
"</td>");
808 tmpStr += QLatin1String(
"</tr>");
811 if (!todo->location().isEmpty()) {
812 tmpStr += QLatin1String(
"<tr>");
813 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Location:") + QLatin1String(
"</b></td>");
814 tmpStr += QLatin1String(
"<td>") + todo->richLocation() + QLatin1String(
"</td>");
815 tmpStr += QLatin1String(
"</tr>");
818 const bool hastStartDate = todo->hasStartDate();
819 const bool hasDueDate = todo->hasDueDate();
822 KDateTime startDt = todo->dtStart(
true );
823 if (todo->recurs() && ocurrenceDueDate.isValid()) {
826 const int length = startDt.daysTo(todo->dtDue(
true ));
828 startDt.setDate(ocurrenceDueDate.addDays(-length));
830 kError() <<
"DTSTART is bigger than DTDUE, todo->uid() is " << todo->uid();
831 startDt.setDate(ocurrenceDueDate);
834 kError() <<
"To-do is recurring but has no DTDUE set, todo->uid() is " << todo->uid();
835 startDt.setDate(ocurrenceDueDate);
838 tmpStr += QLatin1String(
"<tr>");
839 tmpStr += QLatin1String(
"<td><b>") +
840 i18nc(
"to-do start date/time",
"Start:") +
841 QLatin1String(
"</b></td>");
842 tmpStr += QLatin1String(
"<td>") +
844 QLatin1String(
"</td>");
845 tmpStr += QLatin1String(
"</tr>");
849 KDateTime dueDt = todo->dtDue();
850 if (todo->recurs()) {
851 if (ocurrenceDueDate.isValid()) {
852 KDateTime kdt(ocurrenceDueDate, QTime(0, 0, 0), KSystemTimeZones::local());
853 kdt = kdt.addSecs(-1);
854 dueDt.setDate(todo->recurrence()->getNextDateTime(kdt).date());
857 tmpStr += QLatin1String(
"<tr>");
858 tmpStr += QLatin1String(
"<td><b>") +
859 i18nc(
"to-do due date/time",
"Due:") +
860 QLatin1String(
"</b></td>");
861 tmpStr += QLatin1String(
"<td>") +
863 QLatin1String(
"</td>");
864 tmpStr += QLatin1String(
"</tr>");
868 if (!durStr.isEmpty()) {
869 tmpStr += QLatin1String(
"<tr>");
870 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Duration:") + QLatin1String(
"</b></td>");
871 tmpStr += QLatin1String(
"<td>") + durStr + QLatin1String(
"</td>");
872 tmpStr += QLatin1String(
"</tr>");
875 if (todo->recurs() || todo->hasRecurrenceId()) {
876 tmpStr += QLatin1String(
"<tr>");
877 tmpStr += QLatin1String(
"<td><b>")+ i18n(
"Recurrence:") + QLatin1String(
"</b></td>");
879 if (todo->hasRecurrenceId()) {
880 str = i18n(
"Exception");
884 tmpStr += QLatin1String(
"<td>") +
886 QLatin1String(
"</td>");
887 tmpStr += QLatin1String(
"</tr>");
890 if (!todo->description().isEmpty()) {
891 tmpStr += QLatin1String(
"<tr>");
892 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Description:") + QLatin1String(
"</b></td>");
893 tmpStr += QLatin1String(
"<td>") + todo->richDescription() + QLatin1String(
"</td>");
894 tmpStr += QLatin1String(
"</tr>");
899 int reminderCount = todo->alarms().count();
900 if (reminderCount > 0 && todo->hasEnabledAlarms()) {
901 tmpStr += QLatin1String(
"<tr>");
902 tmpStr += QLatin1String(
"<td><b>") +
903 i18np(
"Reminder:",
"Reminders:", reminderCount) +
904 QLatin1String(
"</b></td>");
905 tmpStr += QLatin1String(
"<td>") +
reminderStringList(todo).join(QLatin1String(
"<br>")) + QLatin1String(
"</td>");
906 tmpStr += QLatin1String(
"</tr>");
909 tmpStr += displayViewFormatAttendees(calendar, todo);
911 int categoryCount = todo->categories().count();
912 if (categoryCount > 0) {
913 tmpStr += QLatin1String(
"<tr>");
914 tmpStr += QLatin1String(
"<td><b>") +
915 i18np(
"Category:",
"Categories:", categoryCount) +
916 QLatin1String(
"</b></td>");
917 tmpStr += QLatin1String(
"<td>") + displayViewFormatCategories(todo) + QLatin1String(
"</td>");
918 tmpStr += QLatin1String(
"</tr>");
921 if (todo->priority() > 0) {
922 tmpStr += QLatin1String(
"<tr>");
923 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Priority:") + QLatin1String(
"</b></td>");
924 tmpStr += QLatin1String(
"<td>");
925 tmpStr += QString::number(todo->priority());
926 tmpStr += QLatin1String(
"</td>");
927 tmpStr += QLatin1String(
"</tr>");
930 tmpStr += QLatin1String(
"<tr>");
931 if (todo->isCompleted()) {
932 tmpStr += QLatin1String(
"<td><b>") + i18nc(
"Completed: date",
"Completed:") + QLatin1String(
"</b></td>");
933 tmpStr += QLatin1String(
"<td>");
936 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Percent Done:") + QLatin1String(
"</b></td>");
937 tmpStr += QLatin1String(
"<td>");
938 tmpStr += i18n(
"%1%", todo->percentComplete());
940 tmpStr += QLatin1String(
"</td>");
941 tmpStr += QLatin1String(
"</tr>");
943 int attachmentCount = todo->attachments().count();
944 if (attachmentCount > 0) {
945 tmpStr += QLatin1String(
"<tr>");
946 tmpStr += QLatin1String(
"<td><b>") +
947 i18np(
"Attachment:",
"Attachments:", attachmentCount) +
948 QLatin1String(
"</b></td>");
949 tmpStr += QLatin1String(
"<td>") + displayViewFormatAttachments(todo) + QLatin1String(
"</td>");
950 tmpStr += QLatin1String(
"</tr>");
952 tmpStr += QLatin1String(
"</table>");
954 tmpStr += QLatin1String(
"<p><em>")+ displayViewFormatCreationDate(todo, spec) + QLatin1String(
"</em>");
959 static QString displayViewFormatJournal(
const Calendar::Ptr &calendar,
const QString &sourceName,
966 QString tmpStr = displayViewFormatHeader(journal);
968 tmpStr += QLatin1String(
"<table>");
969 tmpStr += QLatin1String(
"<col width=\"25%\"/>");
970 tmpStr += QLatin1String(
"<col width=\"75%\"/>");
972 const QString calStr = calendar ?
resourceString(calendar, journal) : sourceName;
973 if (!calStr.isEmpty()) {
974 tmpStr += QLatin1String(
"<tr>");
975 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Calendar:") + QLatin1String(
"</b></td>");
976 tmpStr += QLatin1String(
"<td>") + calStr + QLatin1String(
"</td>");
977 tmpStr += QLatin1String(
"</tr>");
980 tmpStr += QLatin1String(
"<tr>");
981 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Date:") + QLatin1String(
"</b></td>");
982 tmpStr += QLatin1String(
"<td>") +
984 QLatin1String(
"</td>");
985 tmpStr += QLatin1String(
"</tr>");
987 if (!journal->description().isEmpty()) {
988 tmpStr += QLatin1String(
"<tr>");
989 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Description:") + QLatin1String(
"</b></td>");
990 tmpStr += QLatin1String(
"<td>") + journal->richDescription() + QLatin1String(
"</td>");
991 tmpStr += QLatin1String(
"</tr>");
994 int categoryCount = journal->categories().count();
995 if (categoryCount > 0) {
996 tmpStr += QLatin1String(
"<tr>");
997 tmpStr += QLatin1String(
"<td><b>") +
998 i18np(
"Category:",
"Categories:", categoryCount) +
999 QLatin1String(
"</b></td>");
1000 tmpStr += QLatin1String(
"<td>") + displayViewFormatCategories(journal) + QLatin1String(
"</td>");
1001 tmpStr += QLatin1String(
"</tr>");
1004 tmpStr += QLatin1String(
"</table>");
1006 tmpStr += QLatin1String(
"<p><em>") + displayViewFormatCreationDate(journal, spec) + QLatin1String(
"</em>");
1011 static QString displayViewFormatFreeBusy(
const Calendar::Ptr &calendar,
const QString &sourceName,
1015 Q_UNUSED(sourceName);
1022 QLatin1String(
"h2"), i18n(
"Free/Busy information for %1", fb->organizer()->fullName())));
1024 tmpStr += htmlAddTag(QLatin1String(
"h4"),
1025 i18n(
"Busy times in date range %1 - %2:",
1030 htmlAddTag(QLatin1String(
"em"),
1031 htmlAddTag(QLatin1String(
"b"), i18nc(
"tag for busy periods list",
"Busy:")));
1034 Period::List::iterator it;
1035 for (it = periods.begin(); it != periods.end(); ++it) {
1041 cont += i18ncp(
"hours part of duration",
"1 hour ",
"%1 hours ", dur / 3600);
1045 cont += i18ncp(
"minutes part duration",
"1 minute ",
"%1 minutes ", dur / 60);
1049 cont += i18ncp(
"seconds part of duration",
"1 second",
"%1 seconds", dur);
1051 text += i18nc(
"startDate for duration",
"%1 for %2",
1054 text += QLatin1String(
"<br>");
1056 if (per.
start().date() == per.
end().date()) {
1057 text += i18nc(
"date, fromTime - toTime ",
"%1, %2 - %3",
1062 text += i18nc(
"fromDateTime - toDateTime",
"%1 - %2",
1066 text += QLatin1String(
"<br>");
1069 tmpStr += htmlAddTag(QLatin1String(
"p"), text);
1075 class KCalUtils::IncidenceFormatter::EventViewerVisitor :
public Visitor
1078 EventViewerVisitor()
1079 : mCalendar(0), mSpec(KDateTime::Spec()), mResult(QLatin1String(
"")) {}
1082 KDateTime::Spec spec=KDateTime::Spec())
1084 mCalendar = calendar;
1085 mSourceName.clear();
1088 mResult = QLatin1String(
"");
1089 return incidence->accept(*
this, incidence);
1093 KDateTime::Spec spec=KDateTime::Spec())
1095 mSourceName = sourceName;
1098 mResult = QLatin1String(
"");
1099 return incidence->accept(*
this, incidence);
1102 QString result()
const {
1109 mResult = displayViewFormatEvent(mCalendar, mSourceName, event, mDate, mSpec);
1110 return !mResult.isEmpty();
1114 mResult = displayViewFormatTodo(mCalendar, mSourceName, todo, mDate, mSpec);
1115 return !mResult.isEmpty();
1119 mResult = displayViewFormatJournal(mCalendar, mSourceName, journal, mSpec);
1120 return !mResult.isEmpty();
1124 mResult = displayViewFormatFreeBusy(mCalendar, mSourceName, fb, mSpec);
1125 return !mResult.isEmpty();
1130 QString mSourceName;
1132 KDateTime::Spec mSpec;
1140 KDateTime::Spec spec)
1146 EventViewerVisitor v;
1147 if (v.act(calendar, incidence, date, spec)) {
1157 KDateTime::Spec spec)
1163 EventViewerVisitor v;
1164 if (v.act(sourceName, incidence, date, spec)) {
1175 static QString cleanHtml(
const QString &html)
1177 QRegExp rx(QLatin1String(
"<body[^>]*>(.*)</body>"), Qt::CaseInsensitive);
1179 QString body = rx.cap(1);
1181 return Qt::escape(body.remove(QRegExp(QLatin1String(
"<[^>]*>"))).trimmed());
1184 static QString invitationSummary(
const Incidence::Ptr &incidence,
bool noHtmlMode)
1186 QString summaryStr = i18n(
"Summary unspecified");
1187 if (!incidence->summary().isEmpty()) {
1188 if (!incidence->summaryIsRich()) {
1189 summaryStr = Qt::escape(incidence->summary());
1191 summaryStr = incidence->richSummary();
1193 summaryStr = cleanHtml(summaryStr);
1200 static QString invitationLocation(
const Incidence::Ptr &incidence,
bool noHtmlMode)
1202 QString locationStr = i18n(
"Location unspecified");
1203 if (!incidence->location().isEmpty()) {
1204 if (!incidence->locationIsRich()) {
1205 locationStr = Qt::escape(incidence->location());
1207 locationStr = incidence->richLocation();
1209 locationStr = cleanHtml(locationStr);
1216 static QString eventStartTimeStr(
const Event::Ptr &event)
1219 if (!event->allDay()) {
1220 tmp = i18nc(
"%1: Start Date, %2: Start Time",
"%1 %2",
1221 dateToString(event->dtStart(),
true, KSystemTimeZones::local()),
1222 timeToString(event->dtStart(),
true, KSystemTimeZones::local()));
1224 tmp = i18nc(
"%1: Start Date",
"%1 (all day)",
1225 dateToString(event->dtStart(),
true, KSystemTimeZones::local()));
1230 static QString eventEndTimeStr(
const Event::Ptr &event)
1233 if (event->hasEndDate() &&
event->dtEnd().isValid()) {
1234 if (!event->allDay()) {
1235 tmp = i18nc(
"%1: End Date, %2: End Time",
"%1 %2",
1236 dateToString(event->dtEnd(),
true, KSystemTimeZones::local()),
1237 timeToString(event->dtEnd(),
true, KSystemTimeZones::local()));
1239 tmp = i18nc(
"%1: End Date",
"%1 (all day)",
1240 dateToString(event->dtEnd(),
true, KSystemTimeZones::local()));
1246 static QString htmlInvitationDetailsBegin()
1248 QString dir = (QApplication::isRightToLeft() ? QLatin1String(
"rtl") : QLatin1String(
"ltr"));
1249 return QString::fromLatin1(
"<div dir=\"%1\">\n").arg(dir);
1252 static QString htmlInvitationDetailsEnd()
1254 return QLatin1String(
"</div>\n");
1257 static QString htmlInvitationDetailsTableBegin()
1260 return QLatin1String(
"<table cellspacing=\"4\" style=\"border-width:4px; border-style:groove\">");
1264 static QString htmlInvitationDetailsTableEnd()
1266 return QLatin1String(
"</table>\n");
1269 static QString diffColor()
1274 return QColor(Qt::red).name();
1277 static QString noteColor()
1280 return qApp->palette().color(QPalette::Active, QPalette::Highlight).name();
1283 static QString htmlRow(
const QString &title,
const QString &value)
1285 if (!value.isEmpty()) {
1286 return QLatin1String(
"<tr><td>") + title + QLatin1String(
"</td><td>") + value + QLatin1String(
"</td></tr>\n");
1292 static QString htmlRow(
const QString &title,
const QString &value,
const QString &oldvalue)
1295 if (value.isEmpty()) {
1300 if (oldvalue.isEmpty() || value == oldvalue) {
1301 return htmlRow(title, value);
1305 QString color = diffColor();
1306 QString newtitle = QLatin1String(
"<font color=\"") + color + QLatin1String(
"\">") + title + QLatin1String(
"</font>");
1307 QString newvalue = QLatin1String(
"<font color=\"") + color + QLatin1String(
"\">") + value + QLatin1String(
"</font>") +
1308 QLatin1String(
" ")+
1309 QLatin1String(
"(<strike>") + oldvalue + QLatin1String(
"</strike>");
1310 return htmlRow(newtitle, newvalue);
1323 RAIIIdentityManager raiiHelper;
1324 QString delegatorName, delegatorEmail;
1326 Attendee::List::ConstIterator it;
1327 for (it = attendees.constBegin(); it != attendees.constEnd(); ++it) {
1329 KPIMUtils::extractEmailAddressAndName(a->delegator(), delegatorEmail, delegatorName);
1330 if (thatIsMe(delegatorEmail)) {
1348 RAIIIdentityManager raiiHelper;
1350 Attendee::List::ConstIterator it;
1351 for (it = attendees.constBegin(); it != attendees.constEnd(); ++it) {
1353 if (thatIsMe(a->email())) {
1363 const QString &email)
1372 RAIIIdentityManager raiiHelper;
1374 Attendee::List::ConstIterator it;
1375 for (it = attendees.constBegin(); it != attendees.constEnd(); ++it) {
1377 if (email == a->email()) {
1395 Attendee::List::ConstIterator it;
1396 for (it = attendees.constBegin(); it != attendees.constEnd(); ++it) {
1397 if (it == attendees.constBegin()) {
1398 rsvp = (*it)->RSVP();
1400 if ((*it)->RSVP() != rsvp) {
1409 static QString rsvpRequestedStr(
bool rsvpRequested,
const QString &role)
1411 if (rsvpRequested) {
1412 if (role.isEmpty()) {
1413 return i18n(
"Your response is requested");
1415 return i18n(
"Your response as <b>%1</b> is requested", role);
1418 if (role.isEmpty()) {
1419 return i18n(
"No response is necessary");
1421 return i18n(
"No response as <b>%1</b> is necessary", role);
1432 ret = i18n(
"(<b>Note</b>: the Organizer preset your response to <b>%1</b>)",
1433 Stringify::attendeeStatus(a->status()));
1438 static QString invitationNote(
const QString &title,
const QString ¬e,
1439 const QString &tag,
const QString &color)
1442 if (!note.isEmpty()) {
1443 noteStr += QLatin1String(
"<table border=\"0\" style=\"margin-top:4px;\">");
1444 noteStr += QLatin1String(
"<tr><center><td>");
1445 if (!color.isEmpty()) {
1446 noteStr += QLatin1String(
"<font color=\"") + color + QLatin1String(
"\">");
1448 if (!title.isEmpty()) {
1449 if (!tag.isEmpty()) {
1450 noteStr += htmlAddTag(tag, title);
1455 noteStr += QLatin1String(
" )") + note;
1456 if (!color.isEmpty()) {
1457 noteStr += QLatin1String(
"</font>");
1459 noteStr += QLatin1String(
"</td></center></tr>");
1460 noteStr += QLatin1String(
"</table>");
1465 static QString invitationPerson(
const QString &email,
const QString &name,
const QString &uid,
1466 const QString &comment)
1468 QPair<QString, QString> s = searchNameAndUid(email, name, uid);
1469 const QString printName = s.first;
1470 const QString printUid = s.second;
1472 QString personString;
1474 if (!printUid.isEmpty()) {
1475 personString = htmlAddUidLink(email, printName, printUid);
1478 personString = (printName.isEmpty() ? email : printName);
1480 if (!comment.isEmpty()) {
1481 personString = i18nc(
"name (comment)",
"%1 (%2)", personString, comment);
1483 personString += QLatin1Char(
'\n');
1486 if (!email.isEmpty()) {
1487 personString += QLatin1String(
" ") + htmlAddMailtoLink(email, printName);
1489 personString += QLatin1Char(
'\n');
1491 return personString;
1494 static QString invitationDetailsIncidence(
const Incidence::Ptr &incidence,
bool noHtmlMode)
1502 QStringList comments;
1504 if (incidence->comments().isEmpty()) {
1505 if (!incidence->description().isEmpty()) {
1507 if (!incidence->descriptionIsRich() &&
1508 !incidence->description().startsWith(QLatin1String(
"<!DOCTYPE HTML"))) {
1509 comments << string2HTML(incidence->description());
1511 if (!incidence->description().startsWith(QLatin1String(
"<!DOCTYPE HTML"))) {
1512 comments << incidence->richDescription();
1514 comments << incidence->description();
1517 comments[0] = cleanHtml(comments[0]);
1519 comments[0] = htmlAddTag(QLatin1String(
"p"), comments[0]);
1525 foreach(
const QString &c, incidence->comments()) {
1528 if (!Qt::mightBeRichText(c)) {
1529 comments << string2HTML(c);
1532 comments << cleanHtml(cleanHtml(QLatin1String(
"<body>") + c +QLatin1String(
"</body>")));
1539 if (!incidence->description().isEmpty()) {
1541 if (!incidence->descriptionIsRich() &&
1542 !incidence->description().startsWith(QLatin1String(
"<!DOCTYPE HTML"))) {
1543 descr = string2HTML(incidence->description());
1545 if (!incidence->description().startsWith(QLatin1String(
"<!DOCTYPE HTML"))) {
1546 descr = incidence->richDescription();
1548 descr = incidence->description();
1551 descr = cleanHtml(descr);
1553 descr = htmlAddTag(QLatin1String(
"p"), descr);
1558 if (!descr.isEmpty()) {
1559 html += QLatin1String(
"<p>");
1560 html += QLatin1String(
"<table border=\"0\" style=\"margin-top:4px;\">");
1561 html += QLatin1String(
"<tr><td><center>") +
1562 htmlAddTag(QLatin1String(
"u"), i18n(
"Description:")) +
1563 QLatin1String(
"</center></td></tr>");
1564 html += QLatin1String(
"<tr><td>") + descr + QLatin1String(
"</td></tr>");
1565 html += QLatin1String(
"</table>");
1568 if (!comments.isEmpty()) {
1569 html += QLatin1String(
"<p>");
1570 html += QLatin1String(
"<table border=\"0\" style=\"margin-top:4px;\">");
1571 html += QLatin1String(
"<tr><td><center>") +
1572 htmlAddTag(QLatin1String(
"u"), i18n(
"Comments:")) +
1573 QLatin1String(
"</center></td></tr>");
1574 html += QLatin1String(
"<tr><td>");
1575 if (comments.count() > 1) {
1576 html += QLatin1String(
"<ul>");
1577 for (
int i=0; i < comments.count(); ++i) {
1578 html += QLatin1String(
"<li>") + comments[i] + QLatin1String(
"</li>");
1580 html += QLatin1String(
"</ul>");
1582 html += comments[0];
1584 html += QLatin1String(
"</td></tr>");
1585 html += QLatin1String(
"</table>");
1590 static QString invitationDetailsEvent(
const Event::Ptr &event,
bool noHtmlMode,
1591 KDateTime::Spec spec)
1598 QString html = htmlInvitationDetailsBegin();
1599 html += htmlInvitationDetailsTableBegin();
1602 html += htmlRow(i18n(
"What:"), invitationSummary(event, noHtmlMode));
1603 html += htmlRow(i18n(
"Where:"), invitationLocation(event, noHtmlMode));
1606 if (event->dtStart().date() ==
event->dtEnd().date()) {
1607 html += htmlRow(i18n(
"Date:"),
dateToString(event->dtStart(),
false, spec));
1608 if (!event->allDay()) {
1609 html += htmlRow(i18n(
"Time:"),
1611 QLatin1String(
" - ") +
1615 html += htmlRow(i18nc(
"starting date",
"From:"),
1617 if (!event->allDay()) {
1618 html += htmlRow(i18nc(
"starting time",
"At:"),
1621 if (event->hasEndDate()) {
1622 html += htmlRow(i18nc(
"ending date",
"To:"),
1624 if (!event->allDay()) {
1625 html += htmlRow(i18nc(
"ending time",
"At:"),
1629 html += htmlRow(i18nc(
"ending date",
"To:"), i18n(
"no end date specified"));
1637 if (event->recurs()) {
1641 html += htmlInvitationDetailsTableEnd();
1642 html += invitationDetailsIncidence(event, noHtmlMode);
1643 html += htmlInvitationDetailsEnd();
1650 KDateTime::Spec spec)
1653 return invitationDetailsEvent(event, noHtmlMode, spec);
1659 if (message->method() == iTIPDeclineCounter) {
1660 html += QLatin1String(
"<br>");
1661 html += invitationNote(QString(),
1662 i18n(
"Please respond again to the original proposal."),
1663 QString(), noteColor());
1666 html += htmlInvitationDetailsBegin();
1667 html += htmlInvitationDetailsTableBegin();
1669 html += htmlRow(i18n(
"What:"),
1670 invitationSummary(event, noHtmlMode),
1671 invitationSummary(oldevent, noHtmlMode));
1673 html += htmlRow(i18n(
"Where:"),
1674 invitationLocation(event, noHtmlMode),
1675 invitationLocation(oldevent, noHtmlMode));
1678 if (event->dtStart().date() ==
event->dtEnd().date()) {
1679 html += htmlRow(i18n(
"Date:"),
1682 QString spanStr, oldspanStr;
1683 if (!event->allDay()) {
1685 QLatin1String(
" - ") +
1688 if (!oldevent->allDay()) {
1689 oldspanStr =
timeToString(oldevent->dtStart(),
true, spec) +
1690 QLatin1String(
" - ") +
1693 html += htmlRow(i18n(
"Time:"), spanStr, oldspanStr);
1695 html += htmlRow(i18nc(
"Starting date of an event",
"From:"),
1698 QString startStr, oldstartStr;
1699 if (!event->allDay()) {
1702 if (!oldevent->allDay()) {
1703 oldstartStr =
timeToString(oldevent->dtStart(),
true, spec);
1705 html += htmlRow(i18nc(
"Starting time of an event",
"At:"), startStr, oldstartStr);
1706 if (event->hasEndDate()) {
1707 html += htmlRow(i18nc(
"Ending date of an event",
"To:"),
1710 QString endStr, oldendStr;
1711 if (!event->allDay()) {
1714 if (!oldevent->allDay()) {
1715 oldendStr =
timeToString(oldevent->dtEnd(),
true, spec);
1717 html += htmlRow(i18nc(
"Starting time of an event",
"At:"), endStr, oldendStr);
1719 QString endStr = i18n(
"no end date specified");
1721 if (!oldevent->hasEndDate()) {
1722 oldendStr = i18n(
"no end date specified");
1724 oldendStr =
dateTimeToString(oldevent->dtEnd(), oldevent->allDay(),
false);
1726 html += htmlRow(i18nc(
"Ending date of an event",
"To:"), endStr, oldendStr);
1732 QString recurStr, oldrecurStr;
1733 if (event->recurs() || oldevent->recurs()) {
1737 html += htmlRow(i18n(
"Recurrence:"), recurStr, oldrecurStr);
1739 html += htmlInvitationDetailsTableEnd();
1740 html += invitationDetailsIncidence(event, noHtmlMode);
1741 html += htmlInvitationDetailsEnd();
1746 static QString invitationDetailsTodo(
const Todo::Ptr &todo,
bool noHtmlMode,
1747 KDateTime::Spec spec)
1754 QString html = htmlInvitationDetailsBegin();
1755 html += htmlInvitationDetailsTableBegin();
1758 html += htmlRow(i18n(
"What:"), invitationSummary(todo, noHtmlMode));
1759 html += htmlRow(i18n(
"Where:"), invitationLocation(todo, noHtmlMode));
1761 if (todo->hasStartDate()) {
1762 html += htmlRow(i18n(
"Start Date:"),
dateToString(todo->dtStart(),
false, spec));
1763 if (!todo->allDay()) {
1764 html += htmlRow(i18n(
"Start Time:"),
timeToString(todo->dtStart(),
false, spec));
1767 if (todo->hasDueDate()) {
1768 html += htmlRow(i18n(
"Due Date:"),
dateToString(todo->dtDue(),
false, spec));
1769 if (!todo->allDay()) {
1770 html += htmlRow(i18n(
"Due Time:"),
timeToString(todo->dtDue(),
false, spec));
1773 html += htmlRow(i18n(
"Due Date:"), i18nc(
"Due Date: None",
"None"));
1780 if (todo->percentComplete() > 0) {
1781 html += htmlRow(i18n(
"Percent Done:"), i18n(
"%1%", todo->percentComplete()));
1785 if (todo->recurs()) {
1789 html += htmlInvitationDetailsTableEnd();
1790 html += invitationDetailsIncidence(todo, noHtmlMode);
1791 html += htmlInvitationDetailsEnd();
1796 static QString invitationDetailsTodo(
const Todo::Ptr &todo,
const Todo::Ptr &oldtodo,
1798 KDateTime::Spec spec)
1801 return invitationDetailsTodo(todo, noHtmlMode, spec);
1807 if (message->method() == iTIPDeclineCounter) {
1808 html += QLatin1String(
"<br>");
1809 html += invitationNote(QString(),
1810 i18n(
"Please respond again to the original proposal."),
1811 QString(), noteColor());
1814 html += htmlInvitationDetailsBegin();
1815 html += htmlInvitationDetailsTableBegin();
1817 html += htmlRow(i18n(
"What:"),
1818 invitationSummary(todo, noHtmlMode),
1819 invitationSummary(todo, noHtmlMode));
1821 html += htmlRow(i18n(
"Where:"),
1822 invitationLocation(todo, noHtmlMode),
1823 invitationLocation(oldtodo, noHtmlMode));
1825 if (todo->hasStartDate()) {
1826 html += htmlRow(i18n(
"Start Date:"),
1829 QString startTimeStr, oldstartTimeStr;
1830 if (!todo->allDay() || !oldtodo->allDay()) {
1831 startTimeStr = todo->allDay() ?
1832 i18n(
"All day") :
timeToString(todo->dtStart(), false, spec);
1833 oldstartTimeStr = oldtodo->allDay() ?
1834 i18n(
"All day") :
timeToString(oldtodo->dtStart(), false, spec);
1836 html += htmlRow(i18n(
"Start Time:"), startTimeStr, oldstartTimeStr);
1838 if (todo->hasDueDate()) {
1839 html += htmlRow(i18n(
"Due Date:"),
1842 QString endTimeStr, oldendTimeStr;
1843 if (!todo->allDay() || !oldtodo->allDay()) {
1844 endTimeStr = todo->allDay() ?
1845 i18n(
"All day") :
timeToString(todo->dtDue(), false, spec);
1846 oldendTimeStr = oldtodo->allDay() ?
1847 i18n(
"All day") :
timeToString(oldtodo->dtDue(), false, spec);
1849 html += htmlRow(i18n(
"Due Time:"), endTimeStr, oldendTimeStr);
1851 QString dueStr = i18nc(
"Due Date: None",
"None");
1853 if (!oldtodo->hasDueDate()) {
1854 olddueStr = i18nc(
"Due Date: None",
"None");
1858 html += htmlRow(i18n(
"Due Date:"), dueStr, olddueStr);
1863 QString completionStr, oldcompletionStr;
1864 if (todo->percentComplete() > 0 || oldtodo->percentComplete() > 0) {
1865 completionStr = i18n(
"%1%", todo->percentComplete());
1866 oldcompletionStr = i18n(
"%1%", oldtodo->percentComplete());
1868 html += htmlRow(i18n(
"Percent Done:"), completionStr, oldcompletionStr);
1870 QString recurStr, oldrecurStr;
1871 if (todo->recurs() || oldtodo->recurs()) {
1875 html += htmlRow(i18n(
"Recurrence:"), recurStr, oldrecurStr);
1877 html += htmlInvitationDetailsTableEnd();
1878 html += invitationDetailsIncidence(todo, noHtmlMode);
1880 html += htmlInvitationDetailsEnd();
1885 static QString invitationDetailsJournal(
const Journal::Ptr &journal,
bool noHtmlMode,
1886 KDateTime::Spec spec)
1892 QString html = htmlInvitationDetailsBegin();
1893 html += htmlInvitationDetailsTableBegin();
1895 html += htmlRow(i18n(
"Summary:"), invitationSummary(journal, noHtmlMode));
1896 html += htmlRow(i18n(
"Date:"),
dateToString(journal->dtStart(),
false, spec));
1898 html += htmlInvitationDetailsTableEnd();
1899 html += invitationDetailsIncidence(journal, noHtmlMode);
1900 html += htmlInvitationDetailsEnd();
1905 static QString invitationDetailsJournal(
const Journal::Ptr &journal,
1907 bool noHtmlMode, KDateTime::Spec spec)
1910 return invitationDetailsJournal(journal, noHtmlMode, spec);
1913 QString html = htmlInvitationDetailsBegin();
1914 html += htmlInvitationDetailsTableBegin();
1916 html += htmlRow(i18n(
"What:"),
1917 invitationSummary(journal, noHtmlMode),
1918 invitationSummary(oldjournal, noHtmlMode));
1920 html += htmlRow(i18n(
"Date:"),
1924 html += htmlInvitationDetailsTableEnd();
1925 html += invitationDetailsIncidence(journal, noHtmlMode);
1926 html += htmlInvitationDetailsEnd();
1931 static QString invitationDetailsFreeBusy(
const FreeBusy::Ptr &fb,
bool noHtmlMode,
1932 KDateTime::Spec spec)
1934 Q_UNUSED(noHtmlMode);
1940 QString html = htmlInvitationDetailsTableBegin();
1942 html += htmlRow(i18n(
"Person:"), fb->organizer()->fullName());
1943 html += htmlRow(i18n(
"Start date:"),
dateToString(fb->dtStart(),
true, spec));
1944 html += htmlRow(i18n(
"End date:"),
dateToString(fb->dtEnd(),
true, spec));
1946 html += QLatin1String(
"<tr><td colspan=2><hr></td></tr>\n");
1947 html += QLatin1String(
"<tr><td colspan=2>Busy periods given in this free/busy object:</td></tr>\n");
1950 Period::List::iterator it;
1951 for (it = periods.begin(); it != periods.end(); ++it) {
1957 cont += i18ncp(
"hours part of duration",
"1 hour ",
"%1 hours ", dur / 3600);
1961 cont += i18ncp(
"minutes part of duration",
"1 minute",
"%1 minutes ", dur / 60);
1965 cont += i18ncp(
"seconds part of duration",
"1 second",
"%1 seconds", dur);
1967 html += htmlRow(QString(),
1968 i18nc(
"startDate for duration",
"%1 for %2",
1970 per.
start().dateTime(), KLocale::LongDate),
1974 if (per.
start().date() == per.
end().date()) {
1975 cont = i18nc(
"date, fromTime - toTime ",
"%1, %2 - %3",
1977 KGlobal::locale()->formatTime(per.
start().time()),
1978 KGlobal::locale()->formatTime(per.
end().time()));
1980 cont = i18nc(
"fromDateTime - toDateTime",
"%1 - %2",
1982 per.
start().dateTime(), KLocale::LongDate),
1983 KGlobal::locale()->formatDateTime(
1984 per.
end().dateTime(), KLocale::LongDate));
1987 html += htmlRow(QString(), cont);
1991 html += htmlInvitationDetailsTableEnd();
1996 bool noHtmlMode, KDateTime::Spec spec)
1999 return invitationDetailsFreeBusy(fb, noHtmlMode, spec);
2004 Q_UNUSED(incidence);
2022 static QString invitationHeaderEvent(
const Event::Ptr &event,
2026 if (!msg || !event) {
2030 switch (msg->method()) {
2032 return i18n(
"This invitation has been published");
2034 if (existingIncidence && event->revision() > 0) {
2035 QString orgStr = organizerName(event, sender);
2036 if (senderIsOrganizer(event, sender)) {
2037 return i18n(
"This invitation has been updated by the organizer %1", orgStr);
2039 return i18n(
"This invitation has been updated by %1 as a representative of %2",
2043 if (iamOrganizer(event)) {
2044 return i18n(
"I created this invitation");
2046 QString orgStr = organizerName(event, sender);
2047 if (senderIsOrganizer(event, sender)) {
2048 return i18n(
"You received an invitation from %1", orgStr);
2050 return i18n(
"You received an invitation from %1 as a representative of %2",
2055 return i18n(
"This invitation was refreshed");
2057 if (iamOrganizer(event)) {
2058 return i18n(
"This invitation has been canceled");
2060 return i18n(
"The organizer has revoked the invitation");
2063 return i18n(
"Addition to the invitation");
2066 if (replyMeansCounter(event)) {
2067 return i18n(
"%1 makes this counter proposal", firstAttendeeName(event, sender));
2071 if (attendees.count() == 0) {
2072 kDebug() <<
"No attendees in the iCal reply!";
2075 if (attendees.count() != 1) {
2076 kDebug() <<
"Warning: attendeecount in the reply should be 1"
2077 <<
"but is" << attendees.count();
2079 QString attendeeName = firstAttendeeName(event, sender);
2081 QString delegatorName, dummy;
2083 KPIMUtils::extractEmailAddressAndName(attendee->delegator(), dummy, delegatorName);
2084 if (delegatorName.isEmpty()) {
2085 delegatorName = attendee->delegator();
2088 switch (attendee->status()) {
2090 return i18n(
"%1 indicates this invitation still needs some action", attendeeName);
2092 if (event->revision() > 0) {
2093 if (!sender.isEmpty()) {
2094 return i18n(
"This invitation has been updated by attendee %1", sender);
2096 return i18n(
"This invitation has been updated by an attendee");
2099 if (delegatorName.isEmpty()) {
2100 return i18n(
"%1 accepts this invitation", attendeeName);
2102 return i18n(
"%1 accepts this invitation on behalf of %2",
2103 attendeeName, delegatorName);
2107 if (delegatorName.isEmpty()) {
2108 return i18n(
"%1 tentatively accepts this invitation", attendeeName);
2110 return i18n(
"%1 tentatively accepts this invitation on behalf of %2",
2111 attendeeName, delegatorName);
2114 if (delegatorName.isEmpty()) {
2115 return i18n(
"%1 declines this invitation", attendeeName);
2117 return i18n(
"%1 declines this invitation on behalf of %2",
2118 attendeeName, delegatorName);
2122 QString delegate, dummy;
2123 KPIMUtils::extractEmailAddressAndName(attendee->delegate(), dummy, delegate);
2124 if (delegate.isEmpty()) {
2125 delegate = attendee->delegate();
2127 if (!delegate.isEmpty()) {
2128 return i18n(
"%1 has delegated this invitation to %2", attendeeName, delegate);
2130 return i18n(
"%1 has delegated this invitation", attendeeName);
2134 return i18n(
"This invitation is now completed");
2136 return i18n(
"%1 is still processing the invitation", attendeeName);
2137 case Attendee::None:
2138 return i18n(
"Unknown response to this invitation");
2143 return i18n(
"%1 makes this counter proposal",
2144 firstAttendeeName(event, i18n(
"Sender")));
2146 case iTIPDeclineCounter:
2148 QString orgStr = organizerName(event, sender);
2149 if (senderIsOrganizer(event, sender)) {
2150 return i18n(
"%1 declines your counter proposal", orgStr);
2152 return i18n(
"%1 declines your counter proposal on behalf of %2", sender, orgStr);
2157 return i18n(
"Error: Event iTIP message with unknown method");
2159 kError() <<
"encountered an iTIP method that we do not support";
2163 static QString invitationHeaderTodo(
const Todo::Ptr &todo,
2167 if (!msg || !todo) {
2171 switch (msg->method()) {
2173 return i18n(
"This to-do has been published");
2175 if (existingIncidence && todo->revision() > 0) {
2176 QString orgStr = organizerName(todo, sender);
2177 if (senderIsOrganizer(todo, sender)) {
2178 return i18n(
"This to-do has been updated by the organizer %1", orgStr);
2180 return i18n(
"This to-do has been updated by %1 as a representative of %2",
2184 if (iamOrganizer(todo)) {
2185 return i18n(
"I created this to-do");
2187 QString orgStr = organizerName(todo, sender);
2188 if (senderIsOrganizer(todo, sender)) {
2189 return i18n(
"You have been assigned this to-do by %1", orgStr);
2191 return i18n(
"You have been assigned this to-do by %1 as a representative of %2",
2197 return i18n(
"This to-do was refreshed");
2199 if (iamOrganizer(todo)) {
2200 return i18n(
"This to-do was canceled");
2202 return i18n(
"The organizer has revoked this to-do");
2205 return i18n(
"Addition to the to-do");
2208 if (replyMeansCounter(todo)) {
2209 return i18n(
"%1 makes this counter proposal", firstAttendeeName(todo, sender));
2213 if (attendees.count() == 0) {
2214 kDebug() <<
"No attendees in the iCal reply!";
2217 if (attendees.count() != 1) {
2218 kDebug() <<
"Warning: attendeecount in the reply should be 1"
2219 <<
"but is" << attendees.count();
2221 QString attendeeName = firstAttendeeName(todo, sender);
2223 QString delegatorName, dummy;
2225 KPIMUtils::extractEmailAddressAndName(attendee->delegate(), dummy, delegatorName);
2226 if (delegatorName.isEmpty()) {
2227 delegatorName = attendee->delegator();
2230 switch (attendee->status()) {
2232 return i18n(
"%1 indicates this to-do assignment still needs some action",
2235 if (todo->revision() > 0) {
2236 if (!sender.isEmpty()) {
2237 if (todo->isCompleted()) {
2238 return i18n(
"This to-do has been completed by assignee %1", sender);
2240 return i18n(
"This to-do has been updated by assignee %1", sender);
2243 if (todo->isCompleted()) {
2244 return i18n(
"This to-do has been completed by an assignee");
2246 return i18n(
"This to-do has been updated by an assignee");
2250 if (delegatorName.isEmpty()) {
2251 return i18n(
"%1 accepts this to-do", attendeeName);
2253 return i18n(
"%1 accepts this to-do on behalf of %2",
2254 attendeeName, delegatorName);
2258 if (delegatorName.isEmpty()) {
2259 return i18n(
"%1 tentatively accepts this to-do", attendeeName);
2261 return i18n(
"%1 tentatively accepts this to-do on behalf of %2",
2262 attendeeName, delegatorName);
2265 if (delegatorName.isEmpty()) {
2266 return i18n(
"%1 declines this to-do", attendeeName);
2268 return i18n(
"%1 declines this to-do on behalf of %2",
2269 attendeeName, delegatorName);
2273 QString delegate, dummy;
2274 KPIMUtils::extractEmailAddressAndName(attendee->delegate(), dummy, delegate);
2275 if (delegate.isEmpty()) {
2276 delegate = attendee->delegate();
2278 if (!delegate.isEmpty()) {
2279 return i18n(
"%1 has delegated this to-do to %2", attendeeName, delegate);
2281 return i18n(
"%1 has delegated this to-do", attendeeName);
2285 return i18n(
"The request for this to-do is now completed");
2287 return i18n(
"%1 is still processing the to-do", attendeeName);
2288 case Attendee::None:
2289 return i18n(
"Unknown response to this to-do");
2294 return i18n(
"%1 makes this counter proposal", firstAttendeeName(todo, sender));
2296 case iTIPDeclineCounter:
2298 QString orgStr = organizerName(todo, sender);
2299 if (senderIsOrganizer(todo, sender)) {
2300 return i18n(
"%1 declines the counter proposal", orgStr);
2302 return i18n(
"%1 declines the counter proposal on behalf of %2", sender, orgStr);
2307 return i18n(
"Error: To-do iTIP message with unknown method");
2309 kError() <<
"encountered an iTIP method that we do not support";
2313 static QString invitationHeaderJournal(
const Journal::Ptr &journal,
2316 if (!msg || !journal) {
2320 switch (msg->method()) {
2322 return i18n(
"This journal has been published");
2324 return i18n(
"You have been assigned this journal");
2326 return i18n(
"This journal was refreshed");
2328 return i18n(
"This journal was canceled");
2330 return i18n(
"Addition to the journal");
2333 if (replyMeansCounter(journal)) {
2334 return i18n(
"Sender makes this counter proposal");
2338 if (attendees.count() == 0) {
2339 kDebug() <<
"No attendees in the iCal reply!";
2342 if (attendees.count() != 1) {
2343 kDebug() <<
"Warning: attendeecount in the reply should be 1 "
2344 <<
"but is " << attendees.count();
2348 switch (attendee->status()) {
2350 return i18n(
"Sender indicates this journal assignment still needs some action");
2352 return i18n(
"Sender accepts this journal");
2354 return i18n(
"Sender tentatively accepts this journal");
2356 return i18n(
"Sender declines this journal");
2358 return i18n(
"Sender has delegated this request for the journal");
2360 return i18n(
"The request for this journal is now completed");
2362 return i18n(
"Sender is still processing the invitation");
2363 case Attendee::None:
2364 return i18n(
"Unknown response to this journal");
2369 return i18n(
"Sender makes this counter proposal");
2370 case iTIPDeclineCounter:
2371 return i18n(
"Sender declines the counter proposal");
2373 return i18n(
"Error: Journal iTIP message with unknown method");
2375 kError() <<
"encountered an iTIP method that we do not support";
2379 static QString invitationHeaderFreeBusy(
const FreeBusy::Ptr &fb,
2386 switch (msg->method()) {
2388 return i18n(
"This free/busy list has been published");
2390 return i18n(
"The free/busy list has been requested");
2392 return i18n(
"This free/busy list was refreshed");
2394 return i18n(
"This free/busy list was canceled");
2396 return i18n(
"Addition to the free/busy list");
2398 return i18n(
"Reply to the free/busy list");
2400 return i18n(
"Sender makes this counter proposal");
2401 case iTIPDeclineCounter:
2402 return i18n(
"Sender declines the counter proposal");
2404 return i18n(
"Error: Free/Busy iTIP message with unknown method");
2406 kError() <<
"encountered an iTIP method that we do not support";
2411 static QString invitationAttendeeList(
const Incidence::Ptr &incidence)
2413 RAIIIdentityManager raiiHelper;
2420 tmpStr += i18n(
"Assignees");
2422 tmpStr += i18n(
"Invitation List");
2427 if (!attendees.isEmpty()) {
2428 QStringList comments;
2429 Attendee::List::ConstIterator it;
2430 for (it = attendees.constBegin(); it != attendees.constEnd(); ++it) {
2432 if (!iamAttendee(a)) {
2435 tmpStr += QLatin1String(
"<table border=\"1\" cellpadding=\"1\" cellspacing=\"0\">");
2437 tmpStr += QLatin1String(
"<tr>");
2438 tmpStr += QLatin1String(
"<td>");
2440 if (attendeeIsOrganizer(incidence, a)) {
2441 comments << i18n(
"organizer");
2443 if (!a->delegator().isEmpty()) {
2444 comments << i18n(
" (delegated by %1)", a->delegator());
2446 if (!a->delegate().isEmpty()) {
2447 comments << i18n(
" (delegated to %1)", a->delegate());
2449 tmpStr += invitationPerson(a->email(), a->name(), QString(), comments.join(QLatin1String(
",")));
2450 tmpStr += QLatin1String(
"</td>");
2451 tmpStr += QLatin1String(
"</tr>");
2456 tmpStr += QLatin1String(
"</table>");
2471 tmpStr += i18n(
"Assignees");
2473 tmpStr += i18n(
"Invitation List");
2478 if (!attendees.isEmpty()) {
2479 QStringList comments;
2480 Attendee::List::ConstIterator it;
2481 for (it = attendees.constBegin(); it != attendees.constEnd(); ++it) {
2483 if (!attendeeIsOrganizer(incidence, a)) {
2484 QString statusStr = Stringify::attendeeStatus(a->status());
2485 if (sender && (a->email() == sender->email())) {
2488 if (a->status() != sender->status()) {
2489 statusStr = i18n(
"%1 (<i>unrecorded</i>)",
2490 Stringify::attendeeStatus(sender->status()));
2496 tmpStr += QLatin1String(
"<table border=\"1\" cellpadding=\"1\" cellspacing=\"0\">");
2498 tmpStr += QLatin1String(
"<tr>");
2499 tmpStr += QLatin1String(
"<td>");
2501 if (iamAttendee(a)) {
2502 comments << i18n(
"myself");
2504 if (!a->delegator().isEmpty()) {
2505 comments << i18n(
" (delegated by %1)", a->delegator());
2507 if (!a->delegate().isEmpty()) {
2508 comments << i18n(
" (delegated to %1)", a->delegate());
2510 tmpStr += invitationPerson(a->email(), a->name(), QString(), comments.join(QLatin1String(
",")));
2511 tmpStr += QLatin1String(
"</td>");
2512 tmpStr += QLatin1String(
"<td>")+ statusStr + QLatin1String(
"</td>");
2513 tmpStr += QLatin1String(
"</tr>");
2518 tmpStr += QLatin1String(
"</table>");
2520 tmpStr += QLatin1String(
"<i> ") + i18nc(
"no attendees",
"None") + QLatin1String(
"</i>");
2526 static QString invitationAttachments(InvitationFormatterHelper *helper,
2540 if (!attachments.isEmpty()) {
2541 tmpStr += i18n(
"Attached Documents:") + QLatin1String(
"<ol>");
2543 Attachment::List::ConstIterator it;
2544 for (it = attachments.constBegin(); it != attachments.constEnd(); ++it) {
2546 tmpStr += QLatin1String(
"<li>");
2548 KMimeType::Ptr
mimeType = KMimeType::mimeType(a->mimeType());
2549 const QString iconStr = (mimeType ?
2550 mimeType->iconName(a->uri()) :
2551 QLatin1String(
"application-octet-stream"));
2552 const QString iconPath = KIconLoader::global()->iconPath(iconStr, KIconLoader::Small);
2553 if (!iconPath.isEmpty()) {
2554 tmpStr += QLatin1String(
"<img valign=\"top\" src=\"") + iconPath + QLatin1String(
"\">");
2556 tmpStr += helper->makeLink(QLatin1String(
"ATTACH:") + QLatin1String(a->label().toUtf8().toBase64()), a->label());
2557 tmpStr += QLatin1String(
"</li>");
2559 tmpStr += QLatin1String(
"</ol>");
2566 class KCalUtils::IncidenceFormatter::ScheduleMessageVisitor :
public Visitor
2569 ScheduleMessageVisitor() : mMessage(0) {
2570 mResult = QLatin1String(
"");
2576 mExistingIncidence = existingIncidence;
2579 return incidence->accept(*
this, incidence);
2581 QString result()
const {
2592 class KCalUtils::IncidenceFormatter::InvitationHeaderVisitor :
2593 public IncidenceFormatter::ScheduleMessageVisitor
2598 mResult = invitationHeaderEvent(event, mExistingIncidence, mMessage, mSender);
2599 return !mResult.isEmpty();
2603 mResult = invitationHeaderTodo(todo, mExistingIncidence, mMessage, mSender);
2604 return !mResult.isEmpty();
2608 mResult = invitationHeaderJournal(journal, mMessage);
2609 return !mResult.isEmpty();
2613 mResult = invitationHeaderFreeBusy(fb, mMessage);
2614 return !mResult.isEmpty();
2618 class KCalUtils::IncidenceFormatter::InvitationBodyVisitor
2619 :
public IncidenceFormatter::ScheduleMessageVisitor
2622 InvitationBodyVisitor(
bool noHtmlMode, KDateTime::Spec spec)
2623 : ScheduleMessageVisitor(), mNoHtmlMode(noHtmlMode), mSpec(spec) {}
2629 mResult = invitationDetailsEvent(event, oldevent, mMessage, mNoHtmlMode, mSpec);
2630 return !mResult.isEmpty();
2635 mResult = invitationDetailsTodo(todo, oldtodo, mMessage, mNoHtmlMode, mSpec);
2636 return !mResult.isEmpty();
2641 mResult = invitationDetailsJournal(journal, oldjournal, mNoHtmlMode, mSpec);
2642 return !mResult.isEmpty();
2646 mResult = invitationDetailsFreeBusy(fb,
FreeBusy::Ptr(), mNoHtmlMode, mSpec);
2647 return !mResult.isEmpty();
2652 KDateTime::Spec mSpec;
2656 InvitationFormatterHelper::InvitationFormatterHelper()
2661 InvitationFormatterHelper::~InvitationFormatterHelper()
2665 QString InvitationFormatterHelper::generateLinkURL(
const QString &
id)
2671 class IncidenceFormatter::IncidenceCompareVisitor :
public Visitor
2674 IncidenceCompareVisitor() {}
2678 if (!existingIncidence) {
2682 if (!inc || !existingIncidence ||
2683 inc->revision() <= existingIncidence->revision()) {
2686 mExistingIncidence = existingIncidence;
2687 return incidence->
accept(*
this, incidence);
2690 QString result()
const
2692 if (mChanges.isEmpty()) {
2695 QString html = QLatin1String(
"<div align=\"left\"><ul><li>");
2696 html += mChanges.join(QLatin1String(
"</li><li>"));
2697 html += QLatin1String(
"</li><ul></div>");
2704 compareEvents(event, mExistingIncidence.dynamicCast<
Event>());
2705 compareIncidences(event, mExistingIncidence);
2706 return !mChanges.isEmpty();
2710 compareTodos(todo, mExistingIncidence.dynamicCast<
Todo>());
2711 compareIncidences(todo, mExistingIncidence);
2712 return !mChanges.isEmpty();
2716 compareIncidences(journal, mExistingIncidence);
2717 return !mChanges.isEmpty();
2722 return !mChanges.isEmpty();
2726 void compareEvents(
const Event::Ptr &newEvent,
2729 if (!oldEvent || !newEvent) {
2732 if (oldEvent->dtStart() != newEvent->dtStart() ||
2733 oldEvent->allDay() != newEvent->allDay()) {
2734 mChanges += i18n(
"The invitation starting time has been changed from %1 to %2",
2735 eventStartTimeStr(oldEvent), eventStartTimeStr(newEvent));
2737 if (oldEvent->dtEnd() != newEvent->dtEnd() ||
2738 oldEvent->allDay() != newEvent->allDay()) {
2739 mChanges += i18n(
"The invitation ending time has been changed from %1 to %2",
2740 eventEndTimeStr(oldEvent), eventEndTimeStr(newEvent));
2744 void compareTodos(
const Todo::Ptr &newTodo,
2747 if (!oldTodo || !newTodo) {
2751 if (!oldTodo->isCompleted() && newTodo->isCompleted()) {
2752 mChanges += i18n(
"The to-do has been completed");
2754 if (oldTodo->isCompleted() && !newTodo->isCompleted()) {
2755 mChanges += i18n(
"The to-do is no longer completed");
2757 if (oldTodo->percentComplete() != newTodo->percentComplete()) {
2758 const QString oldPer = i18n(
"%1%", oldTodo->percentComplete());
2759 const QString newPer = i18n(
"%1%", newTodo->percentComplete());
2760 mChanges += i18n(
"The task completed percentage has changed from %1 to %2",
2764 if (!oldTodo->hasStartDate() && newTodo->hasStartDate()) {
2765 mChanges += i18n(
"A to-do starting time has been added");
2767 if (oldTodo->hasStartDate() && !newTodo->hasStartDate()) {
2768 mChanges += i18n(
"The to-do starting time has been removed");
2770 if (oldTodo->hasStartDate() && newTodo->hasStartDate() &&
2771 oldTodo->dtStart() != newTodo->dtStart()) {
2772 mChanges += i18n(
"The to-do starting time has been changed from %1 to %2",
2777 if (!oldTodo->hasDueDate() && newTodo->hasDueDate()) {
2778 mChanges += i18n(
"A to-do due time has been added");
2780 if (oldTodo->hasDueDate() && !newTodo->hasDueDate()) {
2781 mChanges += i18n(
"The to-do due time has been removed");
2783 if (oldTodo->hasDueDate() && newTodo->hasDueDate() &&
2784 oldTodo->dtDue() != newTodo->dtDue()) {
2785 mChanges += i18n(
"The to-do due time has been changed from %1 to %2",
2794 if (!oldInc || !newInc) {
2798 if (oldInc->summary() != newInc->summary()) {
2799 mChanges += i18n(
"The summary has been changed to: \"%1\"",
2800 newInc->richSummary());
2803 if (oldInc->location() != newInc->location()) {
2804 mChanges += i18n(
"The location has been changed to: \"%1\"",
2805 newInc->richLocation());
2808 if (oldInc->description() != newInc->description()) {
2809 mChanges += i18n(
"The description has been changed to: \"%1\"",
2810 newInc->richDescription());
2815 for (Attendee::List::ConstIterator it = newAttendees.constBegin();
2816 it != newAttendees.constEnd(); ++it) {
2817 Attendee::Ptr oldAtt = oldInc->attendeeByMail((*it)->email());
2819 mChanges += i18n(
"Attendee %1 has been added", (*it)->fullName());
2821 if (oldAtt->status() != (*it)->status()) {
2822 mChanges += i18n(
"The status of attendee %1 has been changed to: %2",
2823 (*it)->fullName(), Stringify::attendeeStatus((*it)->status()));
2828 for (Attendee::List::ConstIterator it = oldAttendees.constBegin();
2829 it != oldAttendees.constEnd(); ++it) {
2830 if (!attendeeIsOrganizer(oldInc, (*it))) {
2831 Attendee::Ptr newAtt = newInc->attendeeByMail((*it)->email());
2833 mChanges += i18n(
"Attendee %1 has been removed", (*it)->fullName());
2841 QStringList mChanges;
2845 QString InvitationFormatterHelper::makeLink(
const QString &
id,
const QString &text)
2847 if (!
id.startsWith(QLatin1String(
"ATTACH:"))) {
2848 QString res = QString::fromLatin1(
"<a href=\"%1\"><font size=\"-1\"><b>%2</b></font></a>").
2849 arg(generateLinkURL(
id), text);
2853 QString res = QString::fromLatin1(
"<a href=\"%1\">%2</a>").
2854 arg(generateLinkURL(
id), text);
2861 static bool incidenceOwnedByMe(
const Calendar::Ptr &calendar,
2865 Q_UNUSED(incidence);
2869 static QString inviteButton(InvitationFormatterHelper *helper,
2870 const QString &
id,
const QString &text)
2877 html += QLatin1String(
"<td style=\"border-width:2px;border-style:outset\">");
2878 if (!
id.isEmpty()) {
2879 html += helper->makeLink(
id, text);
2883 html += QLatin1String(
"</td>");
2887 static QString inviteLink(InvitationFormatterHelper *helper,
2888 const QString &
id,
const QString &text)
2892 if (helper && !
id.isEmpty()) {
2893 html += helper->makeLink(
id, text);
2901 bool rsvpReq,
bool rsvpRec,
2902 InvitationFormatterHelper *helper)
2909 if (!rsvpReq && (incidence && incidence->revision() == 0)) {
2911 html += inviteButton(helper, QLatin1String(
"record"), i18n(
"Record"));
2914 html += inviteButton(helper, QLatin1String(
"delete"), i18n(
"Move to Trash"));
2919 html += inviteButton(helper, QLatin1String(
"accept"),
2920 i18nc(
"accept invitation",
"Accept"));
2923 html += inviteButton(helper, QLatin1String(
"accept_conditionally"),
2924 i18nc(
"Accept invitation conditionally",
"Accept cond."));
2927 html += inviteButton(helper, QLatin1String(
"counter"),
2928 i18nc(
"invitation counter proposal",
"Counter proposal"));
2931 html += inviteButton(helper, QLatin1String(
"decline"),
2932 i18nc(
"decline invitation",
"Decline"));
2935 if (!rsvpRec || (incidence && incidence->revision() > 0)) {
2937 html += inviteButton(helper, QLatin1String(
"delegate"),
2938 i18nc(
"delegate inviation to another",
"Delegate"));
2941 html += inviteButton(helper, QLatin1String(
"forward"), i18nc(
"forward request to another",
"Forward"));
2944 if (incidence && incidence->type() == Incidence::TypeEvent) {
2945 html += inviteButton(helper, QLatin1String(
"check_calendar"),
2946 i18nc(
"look for scheduling conflicts",
"Check my calendar"));
2953 InvitationFormatterHelper *helper)
2961 html += inviteButton(helper, QLatin1String(
"accept_counter"), i18n(
"Accept"));
2964 html += inviteButton(helper, QLatin1String(
"decline_counter"), i18n(
"Decline"));
2968 if (incidence->type() == Incidence::TypeTodo) {
2969 html += inviteButton(helper, QLatin1String(
"check_calendar"), i18n(
"Check my to-do list"));
2971 html += inviteButton(helper, QLatin1String(
"check_calendar"), i18n(
"Check my calendar"));
2978 InvitationFormatterHelper *helper)
2986 if (incidence->type() == Incidence::TypeTodo) {
2987 html += inviteLink(helper, QLatin1String(
"reply"),
2988 i18n(
"Record invitation in my to-do list"));
2990 html += inviteLink(helper, QLatin1String(
"reply"),
2991 i18n(
"Record invitation in my calendar"));
2997 static QString recordResponseButtons(
const Incidence::Ptr &incidence,
2998 InvitationFormatterHelper *helper)
3006 if (incidence->type() == Incidence::TypeTodo) {
3007 html += inviteLink(helper, QLatin1String(
"reply"),
3008 i18n(
"Record response in my to-do list"));
3010 html += inviteLink(helper, QLatin1String(
"reply"),
3011 i18n(
"Record response in my calendar"));
3018 InvitationFormatterHelper *helper)
3027 if (incidence->type() == Incidence::TypeTodo) {
3028 html += inviteButton(helper, QLatin1String(
"cancel"),
3029 i18n(
"Remove invitation from my to-do list"));
3031 html += inviteButton(helper, QLatin1String(
"cancel"),
3032 i18n(
"Remove invitation from my calendar"));
3043 static QString formatICalInvitationHelper(QString invitation,
3045 InvitationFormatterHelper *helper,
3047 KDateTime::Spec spec,
3048 const QString &sender,
3049 bool outlookCompareStyle)
3051 if (invitation.isEmpty()) {
3061 kDebug() <<
"Failed to parse the scheduling message";
3069 incBase->shiftTimes(mCalendar->timeSpec(), KDateTime::Spec::LocalZone());
3073 if (incBase && helper->calendar()) {
3074 existingIncidence = helper->calendar()->incidence(incBase->uid());
3076 if (!incidenceOwnedByMe(helper->calendar(), existingIncidence)) {
3077 existingIncidence.clear();
3079 if (!existingIncidence) {
3081 for (Incidence::List::ConstIterator it = list.begin(), end = list.end(); it != end; ++it) {
3082 if ((*it)->schedulingID() == incBase->uid() &&
3083 incidenceOwnedByMe(helper->calendar(), *it)) {
3084 existingIncidence = *it;
3095 int incRevision = 0;
3096 if (inc && inc->type() != Incidence::TypeFreeBusy) {
3101 QString html = QLatin1String(
"<div align=\"center\" style=\"border:solid 1px;\">");
3103 IncidenceFormatter::InvitationHeaderVisitor headerVisitor;
3105 if (!headerVisitor.act(inc, existingIncidence, msg, sender)) {
3108 html += htmlAddTag(QLatin1String(
"h3"), headerVisitor.result());
3110 if (outlookCompareStyle ||
3111 msg->method() == iTIPDeclineCounter) {
3113 IncidenceFormatter::InvitationBodyVisitor bodyVisitor(noHtmlMode, spec);
3115 if (msg->method() == iTIPRequest || msg->method() == iTIPReply ||
3116 msg->method() == iTIPDeclineCounter) {
3117 if (inc && existingIncidence &&
3118 incRevision < existingIncidence->revision()) {
3119 bodyOk = bodyVisitor.act(existingIncidence, inc, msg, sender);
3121 bodyOk = bodyVisitor.act(inc, existingIncidence, msg, sender);
3127 html += bodyVisitor.result();
3133 InvitationBodyVisitor bodyVisitor(noHtmlMode, spec);
3137 html += bodyVisitor.result();
3139 if (msg->method() == iTIPRequest) {
3140 IncidenceFormatter::IncidenceCompareVisitor compareVisitor;
3141 if (compareVisitor.act(inc, existingIncidence)) {
3142 html += QLatin1String(
"<p align=\"left\">");
3143 if (senderIsOrganizer(inc, sender)) {
3144 html += i18n(
"The following changes have been made by the organizer:");
3145 }
else if (!sender.isEmpty()) {
3146 html += i18n(
"The following changes have been made by %1:", sender);
3148 html += i18n(
"The following changes have been made:");
3150 html += QLatin1String(
"</p>");
3151 html += compareVisitor.result();
3154 if (msg->method() == iTIPReply) {
3155 IncidenceCompareVisitor compareVisitor;
3156 if (compareVisitor.act(inc, existingIncidence)) {
3157 html += QLatin1String(
"<p align=\"left\">");
3158 if (!sender.isEmpty()) {
3159 html += i18n(
"The following changes have been made by %1:", sender);
3161 html += i18n(
"The following changes have been made by an attendee:");
3163 html += QLatin1String(
"</p>");
3164 html += compareVisitor.result();
3170 bool myInc = iamOrganizer(inc);
3173 bool rsvpRec =
false;
3177 if (!rsvpIncidence && inc && incRevision > 0) {
3178 rsvpIncidence = inc;
3180 if (rsvpIncidence) {
3181 ea = findMyAttendee(rsvpIncidence);
3184 (ea->status() == Attendee::Accepted ||
3185 ea->status() == Attendee::Declined ||
3186 ea->status() == Attendee::Tentative)) {
3193 bool isDelegated =
false;
3196 if (!inc->attendees().isEmpty()) {
3197 a = inc->attendees().first();
3201 isDelegated = (a->status() == Attendee::Delegated);
3202 role = Stringify::attendeeRole(a->role());
3206 bool rsvpReq = rsvpRequested(inc);
3209 if (rsvpRec && inc) {
3210 if (incRevision == 0) {
3211 tStr = i18n(
"Your <b>%1</b> response has been recorded",
3212 Stringify::attendeeStatus(ea->status()));
3214 tStr = i18n(
"Your status for this invitation is <b>%1</b>",
3215 Stringify::attendeeStatus(ea->status()));
3218 }
else if (msg->method() == iTIPCancel) {
3219 tStr = i18n(
"This invitation was canceled");
3220 }
else if (msg->method() == iTIPAdd) {
3221 tStr = i18n(
"This invitation was accepted");
3222 }
else if (msg->method() == iTIPDeclineCounter) {
3224 tStr = rsvpRequestedStr(rsvpReq, role);
3227 tStr = rsvpRequestedStr(rsvpReq, role);
3229 tStr = i18n(
"Awaiting delegation response");
3232 html += QLatin1String(
"<br>");
3233 html += QLatin1String(
"<i><u>") + tStr + QLatin1String(
"</u></i>");
3238 if (inc && incRevision == 0) {
3239 QString statStr = myStatusStr(inc);
3240 if (!statStr.isEmpty()) {
3241 html += QLatin1String(
"<br>");
3242 html += QLatin1String(
"<i>") + statStr + QLatin1String(
"</i>");
3249 html += QLatin1String(
"<p>");
3250 html += QLatin1String(
"<table border=\"0\" align=\"center\" cellspacing=\"4\"><tr>");
3252 switch (msg->method()) {
3258 if (inc && incRevision > 0 && (existingIncidence || !helper->calendar())) {
3259 html += recordButtons(inc, helper);
3264 html += responseButtons(inc, rsvpReq, rsvpRec, helper);
3266 html += responseButtons(inc,
false,
false, helper);
3273 html += cancelButtons(inc, helper);
3283 if (replyMeansCounter(inc)) {
3284 html += QLatin1String(
"<tr>") + counterButtons(inc, helper) + QLatin1String(
"</tr>");
3293 a = findDelegatedFromMyAttendee(inc);
3295 if (a->status() != Attendee::Accepted ||
3296 a->status() != Attendee::Tentative) {
3297 html += responseButtons(inc, rsvpReq, rsvpRec, helper);
3303 if (!inc->attendees().isEmpty()) {
3304 a = inc->attendees().first();
3306 if (a && helper->calendar()) {
3307 ea = findAttendee(existingIncidence, a->email());
3310 if (ea && (ea->status() != Attendee::NeedsAction) && (ea->status() == a->status())) {
3311 const QString tStr = i18n(
"The <b>%1</b> response has been recorded",
3312 Stringify::attendeeStatus(ea->status()));
3313 html += inviteButton(helper, QString(), htmlAddTag(QLatin1String(
"i"), tStr));
3316 html += recordResponseButtons(inc, helper);
3324 html += counterButtons(inc, helper);
3327 case iTIPDeclineCounter:
3328 html += responseButtons(inc, rsvpReq, rsvpRec, helper);
3336 html += QLatin1String(
"</tr></table>");
3340 html += invitationRsvpList(existingIncidence, a);
3342 html += invitationAttendeeList(inc);
3346 html += QLatin1String(
"</div>");
3349 html += invitationAttachments(helper, inc);
3357 InvitationFormatterHelper *helper,
3358 bool outlookCompareStyle)
3360 return formatICalInvitationHelper(invitation, calendar, helper,
false,
3361 KSystemTimeZones::local(), QString(),
3362 outlookCompareStyle);
3367 InvitationFormatterHelper *helper,
3368 const QString &sender,
3369 bool outlookCompareStyle)
3371 return formatICalInvitationHelper(invitation, calendar, helper,
true,
3372 KSystemTimeZones::local(), sender,
3373 outlookCompareStyle);
3381 class KCalUtils::IncidenceFormatter::ToolTipVisitor :
public Visitor
3385 : mRichText(true), mSpec(KDateTime::Spec()), mResult(QLatin1String(
"")) {}
3389 const QDate &date=QDate(),
bool richText=
true,
3390 KDateTime::Spec spec=KDateTime::Spec())
3392 mCalendar = calendar;
3395 mRichText = richText;
3397 mResult = QLatin1String(
"");
3398 return incidence ? incidence->accept(*
this, incidence) :
false;
3402 const QDate &date=QDate(),
bool richText=
true,
3403 KDateTime::Spec spec=KDateTime::Spec())
3405 mLocation = location;
3407 mRichText = richText;
3409 mResult = QLatin1String(
"");
3410 return incidence ? incidence->accept(*
this, incidence) :
false;
3413 QString result()
const {
3423 QString dateRangeText(
const Event::Ptr &event,
const QDate &date);
3424 QString dateRangeText(
const Todo::Ptr &todo,
const QDate &date);
3428 QString generateToolTip(
const Incidence::Ptr &incidence, QString dtRangeText);
3435 KDateTime::Spec mSpec;
3439 QString IncidenceFormatter::ToolTipVisitor::dateRangeText(
const Event::Ptr &event,
3446 KDateTime startDt =
event->
dtStart();
3447 KDateTime endDt =
event->dtEnd();
3448 if (event->recurs()) {
3449 if (date.isValid()) {
3450 KDateTime kdt(date, QTime(0, 0, 0), KSystemTimeZones::local());
3451 int diffDays = startDt.daysTo(kdt);
3452 kdt = kdt.addSecs(-1);
3453 startDt.setDate(event->recurrence()->getNextDateTime(kdt).date());
3454 if (event->hasEndDate()) {
3455 endDt = endDt.addDays(diffDays);
3456 if (startDt > endDt) {
3457 startDt.setDate(event->recurrence()->getPreviousDateTime(kdt).date());
3458 endDt = startDt.addDays(event->dtStart().daysTo(event->dtEnd()));
3464 if (event->isMultiDay()) {
3466 ret += QLatin1String(
"<br>") + i18nc(
"Event start",
"<i>From:</i> %1", tmp);
3469 ret += QLatin1String(
"<br>") + i18nc(
"Event end",
"<i>To:</i> %1", tmp);
3473 ret += QLatin1String(
"<br>") +
3474 i18n(
"<i>Date:</i> %1",
dateToString(startDt,
false, mSpec));
3475 if (!event->allDay()) {
3476 const QString dtStartTime =
timeToString(startDt,
true, mSpec);
3477 const QString dtEndTime =
timeToString(endDt,
true, mSpec);
3478 if (dtStartTime == dtEndTime) {
3480 tmp = QLatin1String(
"<br>") +
3481 i18nc(
"time for event",
"<i>Time:</i> %1",
3484 tmp = QLatin1String(
"<br>") +
3485 i18nc(
"time range for event",
3486 "<i>Time:</i> %1 - %2",
3487 dtStartTime, dtEndTime);
3492 return ret.replace(QLatin1Char(
' '), QLatin1String(
" "));
3495 QString IncidenceFormatter::ToolTipVisitor::dateRangeText(
const Todo::Ptr &todo,
3500 if (todo->hasStartDate()) {
3501 KDateTime startDt = todo->dtStart();
3502 if (todo->recurs() && date.isValid()) {
3503 startDt.setDate(date);
3505 ret += QLatin1String(
"<br>") +
3506 i18n(
"<i>Start:</i> %1",
dateToString(startDt,
false, mSpec));
3509 if (todo->hasDueDate()) {
3510 KDateTime dueDt = todo->dtDue();
3511 if (todo->recurs() && date.isValid()) {
3512 KDateTime kdt(date, QTime(0, 0, 0), KSystemTimeZones::local());
3513 kdt = kdt.addSecs(-1);
3514 dueDt.setDate(todo->recurrence()->getNextDateTime(kdt).date());
3516 ret += QLatin1String(
"<br>") +
3517 i18n(
"<i>Due:</i> %1",
3523 if (todo->priority() > 0) {
3524 ret += QLatin1String(
"<br>");
3525 ret += QLatin1String(
"<i>") + i18n(
"Priority:") + QLatin1String(
"</i>") + QLatin1String(
" ");
3526 ret += QString::number(todo->priority());
3529 ret += QLatin1String(
"<br>");
3530 if (todo->isCompleted()) {
3531 ret += QLatin1String(
"<i>") + i18nc(
"Completed: date",
"Completed:") + QLatin1String(
"</i>") + QLatin1String(
" ");
3534 ret += QLatin1String(
"<i>")+ i18n(
"Percent Done:") + QLatin1String(
"</i>") + QLatin1String(
" ");
3535 ret += i18n(
"%1%", todo->percentComplete());
3538 return ret.replace(QLatin1Char(
' '), QLatin1String(
" "));
3541 QString IncidenceFormatter::ToolTipVisitor::dateRangeText(
const Journal::Ptr &journal)
3545 if (journal->dtStart().isValid()) {
3546 ret += QLatin1String(
"<br>") +
3547 i18n(
"<i>Date:</i> %1",
dateToString(journal->dtStart(),
false, mSpec));
3549 return ret.replace(QLatin1Char(
' '), QLatin1String(
" "));
3552 QString IncidenceFormatter::ToolTipVisitor::dateRangeText(
const FreeBusy::Ptr &fb)
3556 ret = QLatin1String(
"<br>") +
3557 i18n(
"<i>Period start:</i> %1",
3559 ret += QLatin1String(
"<br>") +
3560 i18n(
"<i>Period start:</i> %1",
3562 return ret.replace(QLatin1Char(
' '), QLatin1String(
" "));
3567 mResult = generateToolTip(event, dateRangeText(event, mDate));
3568 return !mResult.isEmpty();
3573 mResult = generateToolTip(todo, dateRangeText(todo, mDate));
3574 return !mResult.isEmpty();
3579 mResult = generateToolTip(journal, dateRangeText(journal));
3580 return !mResult.isEmpty();
3586 mResult = QLatin1String(
"<qt><b>") +
3587 i18n(
"Free/Busy information for %1", fb->organizer()->fullName()) +
3588 QLatin1String(
"</b>");
3589 mResult += dateRangeText(fb);
3590 mResult += QLatin1String(
"</qt>");
3591 return !mResult.isEmpty();
3594 static QString tooltipPerson(
const QString &email,
const QString &name,
Attendee::PartStat status)
3597 const QString printName = searchName(email, name);
3600 const QString iconPath = rsvpStatusIconPath(status);
3603 QString personString;
3604 if (!iconPath.isEmpty()) {
3605 personString += QLatin1String(
"<img valign=\"top\" src=\"") + iconPath + QLatin1String(
"\">") + QLatin1String(
" ");
3607 if (status != Attendee::None) {
3608 personString += i18nc(
"attendee name (attendee status)",
"%1 (%2)",
3609 printName.isEmpty() ? email : printName,
3610 Stringify::attendeeStatus(status));
3612 personString += i18n(
"%1", printName.isEmpty() ? email : printName);
3614 return personString;
3617 static QString tooltipFormatOrganizer(
const QString &email,
const QString &name)
3620 const QString printName = searchName(email, name);
3623 const QString iconPath =
3624 KIconLoader::global()->iconPath(QLatin1String(
"meeting-organizer"), KIconLoader::Small);
3627 QString personString;
3628 personString += QLatin1String(
"<img valign=\"top\" src=\"") + iconPath + QLatin1String(
"\">") + QLatin1String(
" ");
3629 personString += (printName.isEmpty() ? email : printName);
3630 return personString;
3633 static QString tooltipFormatAttendeeRoleList(
const Incidence::Ptr &incidence,
3637 const QString etc = i18nc(
"elipsis",
"...");
3641 Attendee::List::ConstIterator it;
3644 for (it = attendees.constBegin(); it != attendees.constEnd(); ++it) {
3646 if (a->role() != role) {
3650 if (attendeeIsOrganizer(incidence, a)) {
3654 if (i == maxNumAtts) {
3655 tmpStr += QLatin1String(
" ") + etc;
3658 tmpStr += QLatin1String(
" ") + tooltipPerson(a->email(), a->name(),
3659 showStatus ? a->status() : Attendee::None);
3660 if (!a->delegator().isEmpty()) {
3661 tmpStr += i18n(
" (delegated by %1)", a->delegator());
3663 if (!a->delegate().isEmpty()) {
3664 tmpStr += i18n(
" (delegated to %1)", a->delegate());
3666 tmpStr += QLatin1String(
"<br>");
3669 if (tmpStr.endsWith(QLatin1String(
"<br>"))) {
3675 static QString tooltipFormatAttendees(
const Calendar::Ptr &calendar,
3678 QString tmpStr, str;
3681 int attendeeCount = incidence->attendees().count();
3682 if (attendeeCount > 1 ||
3683 (attendeeCount == 1 &&
3684 !attendeeIsOrganizer(incidence, incidence->attendees().first()))) {
3685 tmpStr += QLatin1String(
"<i>") + i18n(
"Organizer:") + QLatin1String(
"</i>") + QLatin1String(
"<br>");
3686 tmpStr += QLatin1String(
" ") + tooltipFormatOrganizer(incidence->organizer()->email(),
3687 incidence->organizer()->name());
3692 const bool showStatus = attendeeCount > 0 && incOrganizerOwnsCalendar(calendar, incidence);
3695 str = tooltipFormatAttendeeRoleList(incidence, Attendee::Chair, showStatus);
3696 if (!str.isEmpty()) {
3697 tmpStr += QLatin1String(
"<br><i>") + i18n(
"Chair:") + QLatin1String(
"</i>") + QLatin1String(
"<br>");
3702 str = tooltipFormatAttendeeRoleList(incidence, Attendee::ReqParticipant, showStatus);
3703 if (!str.isEmpty()) {
3704 tmpStr += QLatin1String(
"<br><i>") + i18n(
"Required Participants:") + QLatin1String(
"</i>") + QLatin1String(
"<br>");
3709 str = tooltipFormatAttendeeRoleList(incidence, Attendee::OptParticipant, showStatus);
3710 if (!str.isEmpty()) {
3711 tmpStr += QLatin1String(
"<br><i>") + i18n(
"Optional Participants:") + QLatin1String(
"</i>") + QLatin1String(
"<br>");
3716 str = tooltipFormatAttendeeRoleList(incidence, Attendee::NonParticipant, showStatus);
3717 if (!str.isEmpty()) {
3718 tmpStr += QLatin1String(
"<br><i>") + i18n(
"Observers:") + QLatin1String(
"</i>") + QLatin1String(
"<br>");
3725 QString IncidenceFormatter::ToolTipVisitor::generateToolTip(
const Incidence::Ptr &incidence,
3726 QString dtRangeText)
3728 int maxDescLen = 120;
3735 QString tmp = QLatin1String(
"<qt>");
3738 tmp += QLatin1String(
"<b>") + incidence->richSummary() + QLatin1String(
"</b>");
3739 tmp += QLatin1String(
"<hr>");
3741 QString calStr = mLocation;
3745 if (!calStr.isEmpty()) {
3746 tmp += QLatin1String(
"<i>") + i18n(
"Calendar:") + QLatin1String(
"</i>") + QLatin1String(
" ");
3752 if (!incidence->location().isEmpty()) {
3753 tmp += QLatin1String(
"<br>");
3754 tmp += QLatin1String(
"<i>") + i18n(
"Location:") + QLatin1String(
"</i>") + QLatin1String(
" ");
3755 tmp += incidence->richLocation();
3759 if (!durStr.isEmpty()) {
3760 tmp += QLatin1String(
"<br>");
3761 tmp += QLatin1String(
"<i>") + i18n(
"Duration:") + QLatin1String(
"</i>") + QLatin1String(
" ");
3765 if (incidence->recurs()) {
3766 tmp += QLatin1String(
"<br>");
3767 tmp += QLatin1String(
"<i>") + i18n(
"Recurrence:") + QLatin1String(
"</i>") + QLatin1String(
" ");
3771 if (incidence->hasRecurrenceId()) {
3772 tmp += QLatin1String(
"<br>");
3773 tmp += QLatin1String(
"<i>") + i18n(
"Recurrence:") + QLatin1String(
"</i>") + QLatin1String(
" ");
3774 tmp += i18n(
"Exception");
3777 if (!incidence->description().isEmpty()) {
3778 QString desc(incidence->description());
3779 if (!incidence->descriptionIsRich()) {
3780 if (desc.length() > maxDescLen) {
3781 desc = desc.left(maxDescLen) + i18nc(
"elipsis",
"...");
3783 desc = Qt::escape(desc).replace(QLatin1Char(
'\n'), QLatin1String(
"<br>"));
3787 tmp += QLatin1String(
"<hr>");
3788 tmp += QLatin1String(
"<i>") + i18n(
"Description:") + QLatin1String(
"</i>") + QLatin1String(
"<br>");
3790 tmp += QLatin1String(
"<hr>");
3793 int reminderCount = incidence->alarms().count();
3794 if (reminderCount > 0 && incidence->hasEnabledAlarms()) {
3795 tmp += QLatin1String(
"<br>");
3796 tmp += QLatin1String(
"<i>") + i18np(
"Reminder:",
"Reminders:", reminderCount) + QLatin1String(
"</i>") + QLatin1String(
" ");
3800 tmp += QLatin1String(
"<br>");
3801 tmp += tooltipFormatAttendees(mCalendar, incidence);
3803 int categoryCount = incidence->categories().count();
3804 if (categoryCount > 0) {
3805 tmp += QLatin1String(
"<br>");
3806 tmp += QLatin1String(
"<i>") + i18np(
"Category:",
"Categories:", categoryCount) + QLatin1String(
"</i>") +QLatin1String(
" ");
3807 tmp += incidence->categories().join(QLatin1String(
", "));
3810 tmp += QLatin1String(
"</qt>");
3819 KDateTime::Spec spec)
3822 if (incidence && v.act(sourceName, incidence, date, richText, spec)) {
3834 static QString mailBodyIncidence(
const Incidence::Ptr &incidence)
3837 if (!incidence->summary().isEmpty()) {
3838 body += i18n(
"Summary: %1\n", incidence->richSummary());
3840 if (!incidence->organizer()->isEmpty()) {
3841 body += i18n(
"Organizer: %1\n", incidence->organizer()->fullName());
3843 if (!incidence->location().isEmpty()) {
3844 body += i18n(
"Location: %1\n", incidence->richLocation());
3851 class KCalUtils::IncidenceFormatter::MailBodyVisitor :
public Visitor
3855 : mSpec(KDateTime::Spec()), mResult(QLatin1String(
"")) {}
3860 mResult = QLatin1String(
"");
3861 return incidence ? incidence->accept(*
this, incidence) :
false;
3863 QString result()
const
3874 mResult = i18n(
"This is a Free Busy Object");
3875 return !mResult.isEmpty();
3878 KDateTime::Spec mSpec;
3884 QString recurrence[]= {
3885 i18nc(
"no recurrence",
"None"),
3886 i18nc(
"event recurs by minutes",
"Minutely"),
3887 i18nc(
"event recurs by hours",
"Hourly"),
3888 i18nc(
"event recurs by days",
"Daily"),
3889 i18nc(
"event recurs by weeks",
"Weekly"),
3890 i18nc(
"event recurs same position (e.g. first monday) each month",
"Monthly Same Position"),
3891 i18nc(
"event recurs same day each month",
"Monthly Same Day"),
3892 i18nc(
"event recurs same month each year",
"Yearly Same Month"),
3893 i18nc(
"event recurs same day each year",
"Yearly Same Day"),
3894 i18nc(
"event recurs same position (e.g. first monday) each year",
"Yearly Same Position")
3897 mResult = mailBodyIncidence(event);
3898 mResult += i18n(
"Start Date: %1\n",
dateToString(event->dtStart(),
true, mSpec));
3899 if (!event->allDay()) {
3900 mResult += i18n(
"Start Time: %1\n",
timeToString(event->dtStart(),
true, mSpec));
3902 if (event->dtStart() !=
event->dtEnd()) {
3903 mResult += i18n(
"End Date: %1\n",
dateToString(event->dtEnd(),
true, mSpec));
3905 if (!event->allDay()) {
3906 mResult += i18n(
"End Time: %1\n",
timeToString(event->dtEnd(),
true, mSpec));
3908 if (event->recurs()) {
3911 mResult += i18n(
"Recurs: %1\n", recurrence[ recur->
recurrenceType() ]);
3912 mResult += i18n(
"Frequency: %1\n", event->recurrence()->frequency());
3915 mResult += i18np(
"Repeats once",
"Repeats %1 times", recur->
duration());
3916 mResult += QLatin1Char(
'\n');
3921 if (event->allDay()) {
3922 endstr = KGlobal::locale()->formatDate(recur->
endDate());
3924 endstr = KGlobal::locale()->formatDateTime(recur->
endDateTime().dateTime());
3926 mResult += i18n(
"Repeat until: %1\n", endstr);
3928 mResult += i18n(
"Repeats forever\n");
3933 if (!event->description().isEmpty()) {
3935 if (event->descriptionIsRich() ||
3936 event->description().startsWith(QLatin1String(
"<!DOCTYPE HTML")))
3938 descStr = cleanHtml(event->description());
3940 descStr =
event->description();
3942 if (!descStr.isEmpty()) {
3943 mResult += i18n(
"Details:\n%1\n", descStr);
3946 return !mResult.isEmpty();
3951 mResult = mailBodyIncidence(todo);
3953 if (todo->hasStartDate() && todo->dtStart().isValid()) {
3954 mResult += i18n(
"Start Date: %1\n",
dateToString(todo->dtStart(
false),
true, mSpec));
3955 if (!todo->allDay()) {
3956 mResult += i18n(
"Start Time: %1\n",
timeToString(todo->dtStart(
false),
true, mSpec));
3959 if (todo->hasDueDate() && todo->dtDue().isValid()) {
3960 mResult += i18n(
"Due Date: %1\n",
dateToString(todo->dtDue(),
true, mSpec));
3961 if (!todo->allDay()) {
3962 mResult += i18n(
"Due Time: %1\n",
timeToString(todo->dtDue(),
true, mSpec));
3965 QString details = todo->richDescription();
3966 if (!details.isEmpty()) {
3967 mResult += i18n(
"Details:\n%1\n", details);
3969 return !mResult.isEmpty();
3974 mResult = mailBodyIncidence(journal);
3975 mResult += i18n(
"Date: %1\n",
dateToString(journal->dtStart(),
true, mSpec));
3976 if (!journal->allDay()) {
3977 mResult += i18n(
"Time: %1\n",
timeToString(journal->dtStart(),
true, mSpec));
3979 if (!journal->description().isEmpty()) {
3980 mResult += i18n(
"Text of the journal:\n%1\n", journal->richDescription());
3982 return !mResult.isEmpty();
3987 KDateTime::Spec spec)
3994 if (v.act(incidence, spec)) {
4004 if (incidence->allDay()) {
4005 endstr = KGlobal::locale()->formatDate(incidence->recurrence()->endDate());
4007 endstr = KGlobal::locale()->formatDateTime(incidence->recurrence()->endDateTime());
4019 if (incidence->hasRecurrenceId()) {
4020 return QLatin1String(
"Recurrence exception");
4023 if (!incidence->recurs()) {
4024 return i18n(
"No recurrence");
4026 static QStringList dayList;
4027 if (dayList.isEmpty()) {
4028 dayList.append(i18n(
"31st Last"));
4029 dayList.append(i18n(
"30th Last"));
4030 dayList.append(i18n(
"29th Last"));
4031 dayList.append(i18n(
"28th Last"));
4032 dayList.append(i18n(
"27th Last"));
4033 dayList.append(i18n(
"26th Last"));
4034 dayList.append(i18n(
"25th Last"));
4035 dayList.append(i18n(
"24th Last"));
4036 dayList.append(i18n(
"23rd Last"));
4037 dayList.append(i18n(
"22nd Last"));
4038 dayList.append(i18n(
"21st Last"));
4039 dayList.append(i18n(
"20th Last"));
4040 dayList.append(i18n(
"19th Last"));
4041 dayList.append(i18n(
"18th Last"));
4042 dayList.append(i18n(
"17th Last"));
4043 dayList.append(i18n(
"16th Last"));
4044 dayList.append(i18n(
"15th Last"));
4045 dayList.append(i18n(
"14th Last"));
4046 dayList.append(i18n(
"13th Last"));
4047 dayList.append(i18n(
"12th Last"));
4048 dayList.append(i18n(
"11th Last"));
4049 dayList.append(i18n(
"10th Last"));
4050 dayList.append(i18n(
"9th Last"));
4051 dayList.append(i18n(
"8th Last"));
4052 dayList.append(i18n(
"7th Last"));
4053 dayList.append(i18n(
"6th Last"));
4054 dayList.append(i18n(
"5th Last"));
4055 dayList.append(i18n(
"4th Last"));
4056 dayList.append(i18n(
"3rd Last"));
4057 dayList.append(i18n(
"2nd Last"));
4058 dayList.append(i18nc(
"last day of the month",
"Last"));
4059 dayList.append(i18nc(
"unknown day of the month",
"unknown"));
4060 dayList.append(i18n(
"1st"));
4061 dayList.append(i18n(
"2nd"));
4062 dayList.append(i18n(
"3rd"));
4063 dayList.append(i18n(
"4th"));
4064 dayList.append(i18n(
"5th"));
4065 dayList.append(i18n(
"6th"));
4066 dayList.append(i18n(
"7th"));
4067 dayList.append(i18n(
"8th"));
4068 dayList.append(i18n(
"9th"));
4069 dayList.append(i18n(
"10th"));
4070 dayList.append(i18n(
"11th"));
4071 dayList.append(i18n(
"12th"));
4072 dayList.append(i18n(
"13th"));
4073 dayList.append(i18n(
"14th"));
4074 dayList.append(i18n(
"15th"));
4075 dayList.append(i18n(
"16th"));
4076 dayList.append(i18n(
"17th"));
4077 dayList.append(i18n(
"18th"));
4078 dayList.append(i18n(
"19th"));
4079 dayList.append(i18n(
"20th"));
4080 dayList.append(i18n(
"21st"));
4081 dayList.append(i18n(
"22nd"));
4082 dayList.append(i18n(
"23rd"));
4083 dayList.append(i18n(
"24th"));
4084 dayList.append(i18n(
"25th"));
4085 dayList.append(i18n(
"26th"));
4086 dayList.append(i18n(
"27th"));
4087 dayList.append(i18n(
"28th"));
4088 dayList.append(i18n(
"29th"));
4089 dayList.append(i18n(
"30th"));
4090 dayList.append(i18n(
"31st"));
4093 const int weekStart = KGlobal::locale()->weekStartDay();
4095 const KCalendarSystem *calSys = KGlobal::locale()->calendar();
4099 QString txt, recurStr;
4100 static QString noRecurrence = i18n(
"No recurrence");
4102 case Recurrence::rNone:
4103 return noRecurrence;
4105 case Recurrence::rMinutely:
4107 recurStr = i18np(
"Recurs every minute until %2",
4108 "Recurs every %1 minutes until %2",
4109 recur->
frequency(), recurEnd(incidence));
4111 recurStr += i18nc(
"number of occurrences",
4112 " (<numid>%1</numid> occurrences)",
4116 recurStr = i18np(
"Recurs every minute",
4117 "Recurs every %1 minutes", recur->
frequency());
4121 case Recurrence::rHourly:
4123 recurStr = i18np(
"Recurs hourly until %2",
4124 "Recurs every %1 hours until %2",
4125 recur->
frequency(), recurEnd(incidence));
4127 recurStr += i18nc(
"number of occurrences",
4128 " (<numid>%1</numid> occurrences)",
4132 recurStr = i18np(
"Recurs hourly",
"Recurs every %1 hours", recur->
frequency());
4136 case Recurrence::rDaily:
4138 recurStr = i18np(
"Recurs daily until %2",
4139 "Recurs every %1 days until %2",
4140 recur->
frequency(), recurEnd(incidence));
4142 recurStr += i18nc(
"number of occurrences",
4143 " (<numid>%1</numid> occurrences)",
4147 recurStr = i18np(
"Recurs daily",
"Recurs every %1 days", recur->
frequency());
4151 case Recurrence::rWeekly:
4153 bool addSpace =
false;
4154 for (
int i = 0; i < 7; ++i) {
4155 if (recur->
days().testBit((i + weekStart + 6) % 7)) {
4157 dayNames.append(i18nc(
"separator for list of days",
", "));
4159 dayNames.append(calSys->weekDayName(((i + weekStart + 6) % 7) + 1,
4160 KCalendarSystem::ShortDayName));
4164 if (dayNames.isEmpty()) {
4165 dayNames = i18nc(
"Recurs weekly on no days",
"no days");
4168 recurStr = i18ncp(
"Recurs weekly on [list of days] until end-date",
4169 "Recurs weekly on %2 until %3",
4170 "Recurs every <numid>%1</numid> weeks on %2 until %3",
4171 recur->
frequency(), dayNames, recurEnd(incidence));
4173 recurStr += i18nc(
"number of occurrences",
4174 " (<numid>%1</numid> occurrences)",
4178 recurStr = i18ncp(
"Recurs weekly on [list of days]",
4179 "Recurs weekly on %2",
4180 "Recurs every <numid>%1</numid> weeks on %2",
4185 case Recurrence::rMonthlyPos:
4190 recurStr = i18ncp(
"Recurs every N months on the [2nd|3rd|...]"
4191 " weekdayname until end-date",
4192 "Recurs every month on the %2 %3 until %4",
4193 "Recurs every <numid>%1</numid> months on the %2 %3 until %4",
4195 dayList[rule.pos() + 31],
4196 calSys->weekDayName(rule.day(), KCalendarSystem::LongDayName),
4197 recurEnd(incidence));
4199 recurStr += i18nc(
"number of occurrences",
4200 " (<numid>%1</numid> occurrences)",
4204 recurStr = i18ncp(
"Recurs every N months on the [2nd|3rd|...] weekdayname",
4205 "Recurs every month on the %2 %3",
4206 "Recurs every %1 months on the %2 %3",
4208 dayList[rule.pos() + 31],
4209 calSys->weekDayName(rule.day(), KCalendarSystem::LongDayName));
4214 case Recurrence::rMonthlyDay:
4219 recurStr = i18ncp(
"Recurs monthly on the [1st|2nd|...] day until end-date",
4220 "Recurs monthly on the %2 day until %3",
4221 "Recurs every %1 months on the %2 day until %3",
4224 recurEnd(incidence));
4226 recurStr += i18nc(
"number of occurrences",
4227 " (<numid>%1</numid> occurrences)",
4231 recurStr = i18ncp(
"Recurs monthly on the [1st|2nd|...] day",
4232 "Recurs monthly on the %2 day",
4233 "Recurs every <numid>%1</numid> month on the %2 day",
4235 dayList[days + 31]);
4240 case Recurrence::rYearlyMonth:
4244 recurStr = i18ncp(
"Recurs Every N years on month-name [1st|2nd|...]"
4246 "Recurs yearly on %2 %3 until %4",
4247 "Recurs every %1 years on %2 %3 until %4",
4251 recurEnd(incidence));
4253 recurStr += i18nc(
"number of occurrences",
4254 " (<numid>%1</numid> occurrences)",
4260 recurStr = i18ncp(
"Recurs Every N years on month-name [1st|2nd|...]",
4261 "Recurs yearly on %2 %3",
4262 "Recurs every %1 years on %2 %3",
4269 recurStr = i18nc(
"Recurs Every year on month-name [1st|2nd|...]",
4270 "Recurs yearly on %1 %2",
4273 dayList[ recur->
startDate().day() + 31 ]);
4275 recurStr = i18nc(
"Recurs Every year on month-name [1st|2nd|...]",
4276 "Recurs yearly on %1 %2",
4277 calSys->monthName(recur->
startDate().month(),
4279 dayList[ recur->
startDate().day() + 31 ]);
4285 case Recurrence::rYearlyDay:
4286 if (!recur->
yearDays().isEmpty()) {
4288 recurStr = i18ncp(
"Recurs every N years on day N until end-date",
4289 "Recurs every year on day <numid>%2</numid> until %3",
4290 "Recurs every <numid>%1</numid> years"
4291 " on day <numid>%2</numid> until %3",
4294 recurEnd(incidence));
4296 recurStr += i18nc(
"number of occurrences",
4297 " (<numid>%1</numid> occurrences)",
4301 recurStr = i18ncp(
"Recurs every N YEAR[S] on day N",
4302 "Recurs every year on day <numid>%2</numid>",
4303 "Recurs every <numid>%1</numid> years"
4304 " on day <numid>%2</numid>",
4309 case Recurrence::rYearlyPos:
4314 recurStr = i18ncp(
"Every N years on the [2nd|3rd|...] weekdayname "
4315 "of monthname until end-date",
4316 "Every year on the %2 %3 of %4 until %5",
4317 "Every <numid>%1</numid> years on the %2 %3 of %4"
4320 dayList[rule.pos() + 31],
4321 calSys->weekDayName(rule.day(), KCalendarSystem::LongDayName),
4323 recurEnd(incidence));
4325 recurStr += i18nc(
"number of occurrences",
4326 " (<numid>%1</numid> occurrences)",
4330 recurStr = i18ncp(
"Every N years on the [2nd|3rd|...] weekdayname "
4332 "Every year on the %2 %3 of %4",
4333 "Every <numid>%1</numid> years on the %2 %3 of %4",
4335 dayList[rule.pos() + 31],
4336 calSys->weekDayName(rule.day(), KCalendarSystem::LongDayName),
4344 if (recurStr.isEmpty()) {
4345 recurStr = i18n(
"Incidence recurs");
4350 DateTimeList::ConstIterator il;
4352 for (il = l.constBegin(); il != l.constEnd(); ++il) {
4354 case Recurrence::rMinutely:
4355 exStr << i18n(
"minute %1", (*il).time().minute());
4357 case Recurrence::rHourly:
4358 exStr << KGlobal::locale()->formatTime((*il).time());
4360 case Recurrence::rDaily:
4361 exStr << KGlobal::locale()->formatDate((*il).date(), KLocale::ShortDate);
4363 case Recurrence::rWeekly:
4364 exStr << calSys->weekDayName((*il).date(), KCalendarSystem::ShortDayName);
4366 case Recurrence::rMonthlyPos:
4367 exStr << KGlobal::locale()->formatDate((*il).date(), KLocale::ShortDate);
4369 case Recurrence::rMonthlyDay:
4370 exStr << KGlobal::locale()->formatDate((*il).date(), KLocale::ShortDate);
4372 case Recurrence::rYearlyMonth:
4373 exStr << calSys->monthName((*il).date(), KCalendarSystem::LongName);
4375 case Recurrence::rYearlyDay:
4376 exStr << KGlobal::locale()->formatDate((*il).date(), KLocale::ShortDate);
4378 case Recurrence::rYearlyPos:
4379 exStr << KGlobal::locale()->formatDate((*il).date(), KLocale::ShortDate);
4385 DateList::ConstIterator dl;
4386 for (dl = d.constBegin(); dl != d.constEnd(); ++dl) {
4388 case Recurrence::rDaily:
4389 exStr << KGlobal::locale()->formatDate((*dl), KLocale::ShortDate);
4391 case Recurrence::rWeekly:
4394 if (exStr.isEmpty()) {
4395 exStr << i18np(
"1 day",
"%1 days", recur->exDates().count());
4398 case Recurrence::rMonthlyPos:
4399 exStr << KGlobal::locale()->formatDate((*dl), KLocale::ShortDate);
4401 case Recurrence::rMonthlyDay:
4402 exStr << KGlobal::locale()->formatDate((*dl), KLocale::ShortDate);
4404 case Recurrence::rYearlyMonth:
4405 exStr << calSys->monthName((*dl), KCalendarSystem::LongName);
4407 case Recurrence::rYearlyDay:
4408 exStr << KGlobal::locale()->formatDate((*dl), KLocale::ShortDate);
4410 case Recurrence::rYearlyPos:
4411 exStr << KGlobal::locale()->formatDate((*dl), KLocale::ShortDate);
4416 if (!exStr.isEmpty()) {
4417 recurStr = i18n(
"%1 (excluding %2)", recurStr, exStr.join(QLatin1String(
",")));
4425 const KDateTime::Spec &spec)
4427 if (spec.isValid()) {
4430 if (spec.timeZone() != KSystemTimeZones::local()) {
4431 timeZone = QLatin1Char(
' ') + spec.timeZone().name();
4434 return KGlobal::locale()->formatTime(date.toTimeSpec(spec).time(), !shortfmt) + timeZone;
4436 return KGlobal::locale()->formatTime(date.time(), !shortfmt);
4442 const KDateTime::Spec &spec)
4444 if (spec.isValid()) {
4447 if (spec.timeZone() != KSystemTimeZones::local()) {
4448 timeZone = QLatin1Char(
' ') + spec.timeZone().name();
4452 KGlobal::locale()->formatDate(date.toTimeSpec(spec).date(),
4453 (shortfmt ? KLocale::ShortDate : KLocale::LongDate)) +
4457 KGlobal::locale()->formatDate(date.date(),
4458 (shortfmt ? KLocale::ShortDate : KLocale::LongDate));
4465 const KDateTime::Spec &spec)
4471 if (spec.isValid()) {
4473 if (spec.timeZone() != KSystemTimeZones::local()) {
4474 timeZone = QLatin1Char(
' ') + spec.timeZone().name();
4477 return KGlobal::locale()->formatDateTime(
4478 date.toTimeSpec(spec).dateTime(),
4479 (shortfmt ? KLocale::ShortDate : KLocale::LongDate)) + timeZone;
4481 return KGlobal::locale()->formatDateTime(
4483 (shortfmt ? KLocale::ShortDate : KLocale::LongDate));
4491 Q_UNUSED(incidence);
4495 static QString secs2Duration(
int secs)
4498 int days = secs / 86400;
4500 tmp += i18np(
"1 day",
"%1 days", days);
4501 tmp += QLatin1Char(
' ');
4502 secs -= (days * 86400);
4504 int hours = secs / 3600;
4506 tmp += i18np(
"1 hour",
"%1 hours", hours);
4507 tmp += QLatin1Char(
' ');
4508 secs -= (hours * 3600);
4510 int mins = secs / 60;
4512 tmp += i18np(
"1 minute",
"%1 minutes", mins);
4520 if (incidence->type() == Incidence::TypeEvent) {
4522 if (event->hasEndDate()) {
4523 if (!event->allDay()) {
4524 tmp = secs2Duration(event->dtStart().secsTo(event->dtEnd()));
4526 tmp = i18np(
"1 day",
"%1 days",
4527 event->dtStart().date().daysTo(event->dtEnd().date()) + 1);
4530 tmp = i18n(
"forever");
4532 }
else if (incidence->type() == Incidence::TypeTodo) {
4534 if (todo->hasDueDate()) {
4535 if (todo->hasStartDate()) {
4536 if (!todo->allDay()) {
4537 tmp = secs2Duration(todo->dtStart().secsTo(todo->dtDue()));
4539 tmp = i18np(
"1 day",
"%1 days",
4540 todo->dtStart().date().daysTo(todo->dtDue().date()) + 1);
4558 Alarm::List::ConstIterator it;
4559 for (it = alarms.constBegin(); it != alarms.constEnd(); ++it) {
4562 QString remStr, atStr, offsetStr;
4563 if (alarm->hasTime()) {
4565 if (alarm->time().isValid()) {
4566 atStr = KGlobal::locale()->formatDateTime(alarm->time());
4568 }
else if (alarm->hasStartOffset()) {
4569 offset = alarm->startOffset().asSeconds();
4572 offsetStr = i18nc(
"N days/hours/minutes before the start datetime",
4573 "%1 before the start", secs2Duration(offset));
4574 }
else if (offset > 0) {
4575 offsetStr = i18nc(
"N days/hours/minutes after the start datetime",
4576 "%1 after the start", secs2Duration(offset));
4578 if (incidence->dtStart().isValid()) {
4579 atStr = KGlobal::locale()->formatDateTime(incidence->dtStart());
4582 }
else if (alarm->hasEndOffset()) {
4583 offset = alarm->endOffset().asSeconds();
4586 if (incidence->type() == Incidence::TypeTodo) {
4587 offsetStr = i18nc(
"N days/hours/minutes before the due datetime",
4588 "%1 before the to-do is due", secs2Duration(offset));
4590 offsetStr = i18nc(
"N days/hours/minutes before the end datetime",
4591 "%1 before the end", secs2Duration(offset));
4593 }
else if (offset > 0) {
4594 if (incidence->type() == Incidence::TypeTodo) {
4595 offsetStr = i18nc(
"N days/hours/minutes after the due datetime",
4596 "%1 after the to-do is due", secs2Duration(offset));
4598 offsetStr = i18nc(
"N days/hours/minutes after the end datetime",
4599 "%1 after the end", secs2Duration(offset));
4602 if (incidence->type() == Incidence::TypeTodo) {
4604 if (t->dtDue().isValid()) {
4605 atStr = KGlobal::locale()->formatDateTime(t->dtDue());
4609 if (e->dtEnd().isValid()) {
4610 atStr = KGlobal::locale()->formatDateTime(e->dtEnd());
4616 if (!atStr.isEmpty()) {
4617 remStr = i18nc(
"reminder occurs at datetime",
"at %1", atStr);
4623 if (alarm->repeatCount() > 0) {
4624 QString countStr = i18np(
"repeats once",
"repeats %1 times", alarm->repeatCount());
4625 QString intervalStr = i18nc(
"interval is N days/hours/minutes",
4627 secs2Duration(alarm->snoozeTime().asSeconds()));
4628 QString repeatStr = i18nc(
"(repeat string, interval string)",
4629 "(%1, %2)", countStr, intervalStr);
4630 remStr = remStr + QLatin1Char(
' ') + repeatStr;
4633 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< Incidence > Ptr
QSharedPointer< ScheduleMessage > Ptr
virtual bool accept(Visitor &v, IncidenceBase::Ptr incidence)
KCALUTILS_EXPORT QString mimeType()
Mime-type of iCalendar.
Duration duration() const
QSharedPointer< MemoryCalendar > Ptr
QSharedPointer< IncidenceBase > 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
static Person::Ptr fromFullName(const QString &fullName)
QSharedPointer< Calendar > Ptr
QSharedPointer< Person > 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
virtual KDateTime dtStart() const