45 #include <kcalcore/visitor.h> 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 QString uid_1 =
event->customProperty(
"KABC",
"UID-1");
541 QString name_1 =
event->customProperty(
"KABC",
"NAME-1");
542 QString email_1=
event->customProperty(
"KABC",
"EMAIL-1");
544 QString tmpStr = displayViewFormatPerson(email_1, name_1, uid_1, QString());
550 QString tmpStr = QLatin1String(
"<table><tr>");
553 KIconLoader *iconLoader = KIconLoader::global();
554 tmpStr += QLatin1String(
"<td>");
557 if (incidence->customProperty(
"KABC",
"BIRTHDAY") == QLatin1String(
"YES")) {
558 iconPath = iconLoader->iconPath(QLatin1String(
"view-calendar-birthday"), KIconLoader::Small);
559 }
else if (incidence->customProperty(
"KABC",
"ANNIVERSARY") == QLatin1String(
"YES")) {
560 iconPath = iconLoader->iconPath(QLatin1String(
"view-calendar-wedding-anniversary"), KIconLoader::Small);
562 iconPath = iconLoader->iconPath(incidence->iconName(), KIconLoader::Small);
564 tmpStr += QLatin1String(
"<img valign=\"top\" src=\"") + iconPath + QLatin1String(
"\">");
566 if (incidence->hasEnabledAlarms()) {
567 tmpStr += QLatin1String(
"<img valign=\"top\" src=\"") +
568 iconLoader->iconPath(QLatin1String(
"preferences-desktop-notification-bell"), KIconLoader::Small) +
569 QLatin1String(
"\">");
571 if (incidence->recurs()) {
572 tmpStr += QLatin1String(
"<img valign=\"top\" src=\"") +
573 iconLoader->iconPath(QLatin1String(
"edit-redo"), KIconLoader::Small) +
574 QLatin1String(
"\">");
576 if (incidence->isReadOnly()) {
577 tmpStr += QLatin1String(
"<img valign=\"top\" src=\"") +
578 iconLoader->iconPath(QLatin1String(
"object-locked"), KIconLoader::Small) +
579 QLatin1String(
"\">");
581 tmpStr += QLatin1String(
"</td>");
583 tmpStr += QLatin1String(
"<td>");
584 tmpStr += QLatin1String(
"<b><u>") + incidence->richSummary() + QLatin1String(
"</u></b>");
585 tmpStr += QLatin1String(
"</td>");
587 tmpStr += QLatin1String(
"</tr></table>");
592 static QString displayViewFormatEvent(
const Calendar::Ptr calendar,
const QString &sourceName,
594 const QDate &date, KDateTime::Spec spec)
600 QString tmpStr = displayViewFormatHeader(event);
602 tmpStr += QLatin1String(
"<table>");
603 tmpStr += QLatin1String(
"<col width=\"25%\"/>");
604 tmpStr += QLatin1String(
"<col width=\"75%\"/>");
606 const QString calStr = calendar ?
resourceString(calendar, event) : sourceName;
607 if (!calStr.isEmpty()) {
608 tmpStr += QLatin1String(
"<tr>");
609 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Calendar:") + QLatin1String(
"</b></td>");
610 tmpStr += QLatin1String(
"<td>") + calStr + QLatin1String(
"</td>");
611 tmpStr += QLatin1String(
"</tr>");
614 if (!event->location().isEmpty()) {
615 tmpStr += QLatin1String(
"<tr>");
616 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Location:") + QLatin1String(
"</b></td>");
617 tmpStr += QLatin1String(
"<td>") +
event->richLocation() + QLatin1String(
"</td>");
618 tmpStr +=QLatin1String(
"</tr>");
621 KDateTime startDt =
event->dtStart();
622 KDateTime endDt =
event->dtEnd();
623 if (event->recurs()) {
624 if (date.isValid()) {
625 KDateTime kdt(date, QTime(0, 0, 0), KSystemTimeZones::local());
626 int diffDays = startDt.daysTo(kdt);
627 kdt = kdt.addSecs(-1);
628 startDt.setDate(event->recurrence()->getNextDateTime(kdt).date());
629 if (event->hasEndDate()) {
630 endDt = endDt.addDays(diffDays);
631 if (startDt > endDt) {
632 startDt.setDate(event->recurrence()->getPreviousDateTime(kdt).date());
633 endDt = startDt.addDays(event->dtStart().daysTo(event->dtEnd()));
639 tmpStr += QLatin1String(
"<tr>");
640 if (event->allDay()) {
641 if (event->isMultiDay()) {
642 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Date:") + QLatin1String(
"</b></td>");
643 tmpStr += QLatin1String(
"<td>") +
644 i18nc(
"<beginTime> - <endTime>",
"%1 - %2",
647 QLatin1String(
"</td>");
649 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Date:") + QLatin1String(
"</b></td>");
650 tmpStr += QLatin1String(
"<td>") +
651 i18nc(
"date as string",
"%1",
653 QLatin1String(
"</td>");
656 if (event->isMultiDay()) {
657 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Date:") + QLatin1String(
"</b></td>");
658 tmpStr += QLatin1String(
"<td>") +
659 i18nc(
"<beginTime> - <endTime>",
"%1 - %2",
662 QLatin1String(
"</td>");
664 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Date:") + QLatin1String(
"</b></td>");
665 tmpStr += QLatin1String(
"<td>") +
666 i18nc(
"date as string",
"%1",
668 QLatin1String(
"</td>");
670 tmpStr += QLatin1String(
"</tr><tr>");
671 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Time:") + QLatin1String(
"</b></td>");
672 if (event->hasEndDate() && startDt != endDt) {
673 tmpStr += QLatin1String(
"<td>") +
674 i18nc(
"<beginTime> - <endTime>",
"%1 - %2",
677 QLatin1String(
"</td>");
679 tmpStr += QLatin1String(
"<td>") +
681 QLatin1String(
"</td>");
685 tmpStr += QLatin1String(
"</tr>");
688 if (!durStr.isEmpty()) {
689 tmpStr += QLatin1String(
"<tr>");
690 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Duration:") + QLatin1String(
"</b></td>");
691 tmpStr += QLatin1String(
"<td>") + durStr + QLatin1String(
"</td>");
692 tmpStr += QLatin1String(
"</tr>");
695 if (event->recurs() ||
event->hasRecurrenceId()) {
696 tmpStr += QLatin1String(
"<tr>");
697 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Recurrence:") + QLatin1String(
"</b></td>");
700 if (event->hasRecurrenceId()) {
701 str = i18n(
"Exception");
706 tmpStr += QLatin1String(
"<td>") + str +
707 QLatin1String(
"</td>");
708 tmpStr += QLatin1String(
"</tr>");
711 const bool isBirthday =
event->customProperty(
"KABC",
"BIRTHDAY") == QLatin1String(
"YES");
712 const bool isAnniversary =
event->customProperty(
"KABC",
"ANNIVERSARY") == QLatin1String(
"YES");
714 if (isBirthday || isAnniversary) {
715 tmpStr += QLatin1String(
"<tr>");
717 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Anniversary:") + QLatin1String(
"</b></td>");
719 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Birthday:") + QLatin1String(
"</b></td>");
721 tmpStr += QLatin1String(
"<td>") + displayViewFormatBirthday(event) + QLatin1String(
"</td>");
722 tmpStr += QLatin1String(
"</tr>");
723 tmpStr += QLatin1String(
"</table>");
727 if (!event->description().isEmpty()) {
729 if (!event->descriptionIsRich() &&
730 !
event->description().startsWith(QLatin1String(
"<!DOCTYPE HTML")))
732 descStr = string2HTML(event->description());
734 if (!event->description().startsWith(QLatin1String(
"<!DOCTYPE HTML"))) {
735 descStr =
event->richDescription();
737 descStr =
event->description();
740 tmpStr += QLatin1String(
"<tr>");
741 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Description:") + QLatin1String(
"</b></td>");
742 tmpStr += QLatin1String(
"<td>") + descStr + QLatin1String(
"</td>");
743 tmpStr += QLatin1String(
"</tr>");
748 int reminderCount =
event->alarms().count();
749 if (reminderCount > 0 && event->hasEnabledAlarms()) {
750 tmpStr += QLatin1String(
"<tr>");
751 tmpStr += QLatin1String(
"<td><b>") +
752 i18np(
"Reminder:",
"Reminders:", reminderCount) +
753 QLatin1String(
"</b></td>");
754 tmpStr += QLatin1String(
"<td>") +
reminderStringList(event).join(QLatin1String(
"<br>")) + QLatin1String(
"</td>");
755 tmpStr += QLatin1String(
"</tr>");
758 tmpStr += displayViewFormatAttendees(calendar, event);
760 int categoryCount =
event->categories().count();
761 if (categoryCount > 0) {
762 tmpStr += QLatin1String(
"<tr>");
763 tmpStr += QLatin1String(
"<td><b>");
764 tmpStr += i18np(
"Category:",
"Categories:", categoryCount) +
765 QLatin1String(
"</b></td>");
766 tmpStr += QLatin1String(
"<td>") + displayViewFormatCategories(event) + QLatin1String(
"</td>");
767 tmpStr += QLatin1String(
"</tr>");
770 int attachmentCount =
event->attachments().count();
771 if (attachmentCount > 0) {
772 tmpStr += QLatin1String(
"<tr>");
773 tmpStr += QLatin1String(
"<td><b>") +
774 i18np(
"Attachment:",
"Attachments:", attachmentCount) +
775 QLatin1String(
"</b></td>");
776 tmpStr += QLatin1String(
"<td>") + displayViewFormatAttachments(event) + QLatin1String(
"</td>");
777 tmpStr += QLatin1String(
"</tr>");
779 tmpStr += QLatin1String(
"</table>");
781 tmpStr += QLatin1String(
"<p><em>") + displayViewFormatCreationDate(event, spec) + QLatin1String(
"</em>");
786 static QString displayViewFormatTodo(
const Calendar::Ptr &calendar,
const QString &sourceName,
788 const QDate &ocurrenceDueDate, KDateTime::Spec spec)
791 kDebug() <<
"IncidenceFormatter::displayViewFormatTodo was called without to-do, quitting";
795 QString tmpStr = displayViewFormatHeader(todo);
797 tmpStr += QLatin1String(
"<table>");
798 tmpStr += QLatin1String(
"<col width=\"25%\"/>");
799 tmpStr += QLatin1String(
"<col width=\"75%\"/>");
801 const QString calStr = calendar ?
resourceString(calendar, todo) : sourceName;
802 if (!calStr.isEmpty()) {
803 tmpStr += QLatin1String(
"<tr>");
804 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Calendar:") + QLatin1String(
"</b></td>");
805 tmpStr += QLatin1String(
"<td>") + calStr + QLatin1String(
"</td>");
806 tmpStr += QLatin1String(
"</tr>");
809 if (!todo->location().isEmpty()) {
810 tmpStr += QLatin1String(
"<tr>");
811 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Location:") + QLatin1String(
"</b></td>");
812 tmpStr += QLatin1String(
"<td>") + todo->richLocation() + QLatin1String(
"</td>");
813 tmpStr += QLatin1String(
"</tr>");
816 const bool hastStartDate = todo->hasStartDate();
817 const bool hasDueDate = todo->hasDueDate();
820 KDateTime startDt = todo->dtStart(
true );
821 if (todo->recurs() && ocurrenceDueDate.isValid()) {
824 const int length = startDt.daysTo(todo->dtDue(
true ));
826 startDt.setDate(ocurrenceDueDate.addDays(-length));
828 kError() <<
"DTSTART is bigger than DTDUE, todo->uid() is " << todo->uid();
829 startDt.setDate(ocurrenceDueDate);
832 kError() <<
"To-do is recurring but has no DTDUE set, todo->uid() is " << todo->uid();
833 startDt.setDate(ocurrenceDueDate);
836 tmpStr += QLatin1String(
"<tr>");
837 tmpStr += QLatin1String(
"<td><b>") +
838 i18nc(
"to-do start date/time",
"Start:") +
839 QLatin1String(
"</b></td>");
840 tmpStr += QLatin1String(
"<td>") +
842 QLatin1String(
"</td>");
843 tmpStr += QLatin1String(
"</tr>");
847 KDateTime dueDt = todo->dtDue();
848 if (todo->recurs()) {
849 if (ocurrenceDueDate.isValid()) {
850 KDateTime kdt(ocurrenceDueDate, QTime(0, 0, 0), KSystemTimeZones::local());
851 kdt = kdt.addSecs(-1);
852 dueDt.setDate(todo->recurrence()->getNextDateTime(kdt).date());
855 tmpStr += QLatin1String(
"<tr>");
856 tmpStr += QLatin1String(
"<td><b>") +
857 i18nc(
"to-do due date/time",
"Due:") +
858 QLatin1String(
"</b></td>");
859 tmpStr += QLatin1String(
"<td>") +
861 QLatin1String(
"</td>");
862 tmpStr += QLatin1String(
"</tr>");
866 if (!durStr.isEmpty()) {
867 tmpStr += QLatin1String(
"<tr>");
868 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Duration:") + QLatin1String(
"</b></td>");
869 tmpStr += QLatin1String(
"<td>") + durStr + QLatin1String(
"</td>");
870 tmpStr += QLatin1String(
"</tr>");
873 if (todo->recurs() || todo->hasRecurrenceId()) {
874 tmpStr += QLatin1String(
"<tr>");
875 tmpStr += QLatin1String(
"<td><b>")+ i18n(
"Recurrence:") + QLatin1String(
"</b></td>");
877 if (todo->hasRecurrenceId()) {
878 str = i18n(
"Exception");
882 tmpStr += QLatin1String(
"<td>") +
884 QLatin1String(
"</td>");
885 tmpStr += QLatin1String(
"</tr>");
888 if (!todo->description().isEmpty()) {
889 tmpStr += QLatin1String(
"<tr>");
890 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Description:") + QLatin1String(
"</b></td>");
891 tmpStr += QLatin1String(
"<td>") + todo->richDescription() + QLatin1String(
"</td>");
892 tmpStr += QLatin1String(
"</tr>");
897 int reminderCount = todo->alarms().count();
898 if (reminderCount > 0 && todo->hasEnabledAlarms()) {
899 tmpStr += QLatin1String(
"<tr>");
900 tmpStr += QLatin1String(
"<td><b>") +
901 i18np(
"Reminder:",
"Reminders:", reminderCount) +
902 QLatin1String(
"</b></td>");
903 tmpStr += QLatin1String(
"<td>") +
reminderStringList(todo).join(QLatin1String(
"<br>")) + QLatin1String(
"</td>");
904 tmpStr += QLatin1String(
"</tr>");
907 tmpStr += displayViewFormatAttendees(calendar, todo);
909 int categoryCount = todo->categories().count();
910 if (categoryCount > 0) {
911 tmpStr += QLatin1String(
"<tr>");
912 tmpStr += QLatin1String(
"<td><b>") +
913 i18np(
"Category:",
"Categories:", categoryCount) +
914 QLatin1String(
"</b></td>");
915 tmpStr += QLatin1String(
"<td>") + displayViewFormatCategories(todo) + QLatin1String(
"</td>");
916 tmpStr += QLatin1String(
"</tr>");
919 if (todo->priority() > 0) {
920 tmpStr += QLatin1String(
"<tr>");
921 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Priority:") + QLatin1String(
"</b></td>");
922 tmpStr += QLatin1String(
"<td>");
923 tmpStr += QString::number(todo->priority());
924 tmpStr += QLatin1String(
"</td>");
925 tmpStr += QLatin1String(
"</tr>");
928 tmpStr += QLatin1String(
"<tr>");
929 if (todo->isCompleted()) {
930 tmpStr += QLatin1String(
"<td><b>") + i18nc(
"Completed: date",
"Completed:") + QLatin1String(
"</b></td>");
931 tmpStr += QLatin1String(
"<td>");
934 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Percent Done:") + QLatin1String(
"</b></td>");
935 tmpStr += QLatin1String(
"<td>");
936 tmpStr += i18n(
"%1%", todo->percentComplete());
938 tmpStr += QLatin1String(
"</td>");
939 tmpStr += QLatin1String(
"</tr>");
941 int attachmentCount = todo->attachments().count();
942 if (attachmentCount > 0) {
943 tmpStr += QLatin1String(
"<tr>");
944 tmpStr += QLatin1String(
"<td><b>") +
945 i18np(
"Attachment:",
"Attachments:", attachmentCount) +
946 QLatin1String(
"</b></td>");
947 tmpStr += QLatin1String(
"<td>") + displayViewFormatAttachments(todo) + QLatin1String(
"</td>");
948 tmpStr += QLatin1String(
"</tr>");
950 tmpStr += QLatin1String(
"</table>");
952 tmpStr += QLatin1String(
"<p><em>")+ displayViewFormatCreationDate(todo, spec) + QLatin1String(
"</em>");
957 static QString displayViewFormatJournal(
const Calendar::Ptr &calendar,
const QString &sourceName,
964 QString tmpStr = displayViewFormatHeader(journal);
966 tmpStr += QLatin1String(
"<table>");
967 tmpStr += QLatin1String(
"<col width=\"25%\"/>");
968 tmpStr += QLatin1String(
"<col width=\"75%\"/>");
970 const QString calStr = calendar ?
resourceString(calendar, journal) : sourceName;
971 if (!calStr.isEmpty()) {
972 tmpStr += QLatin1String(
"<tr>");
973 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Calendar:") + QLatin1String(
"</b></td>");
974 tmpStr += QLatin1String(
"<td>") + calStr + QLatin1String(
"</td>");
975 tmpStr += QLatin1String(
"</tr>");
978 tmpStr += QLatin1String(
"<tr>");
979 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Date:") + QLatin1String(
"</b></td>");
980 tmpStr += QLatin1String(
"<td>") +
982 QLatin1String(
"</td>");
983 tmpStr += QLatin1String(
"</tr>");
985 if (!journal->description().isEmpty()) {
986 tmpStr += QLatin1String(
"<tr>");
987 tmpStr += QLatin1String(
"<td><b>") + i18n(
"Description:") + QLatin1String(
"</b></td>");
988 tmpStr += QLatin1String(
"<td>") + journal->richDescription() + QLatin1String(
"</td>");
989 tmpStr += QLatin1String(
"</tr>");
992 int categoryCount = journal->categories().count();
993 if (categoryCount > 0) {
994 tmpStr += QLatin1String(
"<tr>");
995 tmpStr += QLatin1String(
"<td><b>") +
996 i18np(
"Category:",
"Categories:", categoryCount) +
997 QLatin1String(
"</b></td>");
998 tmpStr += QLatin1String(
"<td>") + displayViewFormatCategories(journal) + QLatin1String(
"</td>");
999 tmpStr += QLatin1String(
"</tr>");
1002 tmpStr += QLatin1String(
"</table>");
1004 tmpStr += QLatin1String(
"<p><em>") + displayViewFormatCreationDate(journal, spec) + QLatin1String(
"</em>");
1009 static QString displayViewFormatFreeBusy(
const Calendar::Ptr &calendar,
const QString &sourceName,
1013 Q_UNUSED(sourceName);
1020 QLatin1String(
"h2"), i18n(
"Free/Busy information for %1", fb->organizer()->fullName())));
1022 tmpStr += htmlAddTag(QLatin1String(
"h4"),
1023 i18n(
"Busy times in date range %1 - %2:",
1028 htmlAddTag(QLatin1String(
"em"),
1029 htmlAddTag(QLatin1String(
"b"), i18nc(
"tag for busy periods list",
"Busy:")));
1032 Period::List::iterator it;
1033 for (it = periods.begin(); it != periods.end(); ++it) {
1039 cont += i18ncp(
"hours part of duration",
"1 hour ",
"%1 hours ", dur / 3600);
1043 cont += i18ncp(
"minutes part duration",
"1 minute ",
"%1 minutes ", dur / 60);
1047 cont += i18ncp(
"seconds part of duration",
"1 second",
"%1 seconds", dur);
1049 text += i18nc(
"startDate for duration",
"%1 for %2",
1052 text += QLatin1String(
"<br>");
1054 if (per.
start().date() == per.
end().date()) {
1055 text += i18nc(
"date, fromTime - toTime ",
"%1, %2 - %3",
1060 text += i18nc(
"fromDateTime - toDateTime",
"%1 - %2",
1064 text += QLatin1String(
"<br>");
1067 tmpStr += htmlAddTag(QLatin1String(
"p"), text);
1073 class KCalUtils::IncidenceFormatter::EventViewerVisitor :
public Visitor 1076 EventViewerVisitor()
1077 : mCalendar(0), mSpec(KDateTime::Spec()), mResult(QLatin1String(
"")) {}
1080 KDateTime::Spec spec=KDateTime::Spec())
1082 mCalendar = calendar;
1083 mSourceName.clear();
1086 mResult = QLatin1String(
"");
1087 return incidence->accept(*
this, incidence);
1091 KDateTime::Spec spec=KDateTime::Spec())
1093 mSourceName = sourceName;
1096 mResult = QLatin1String(
"");
1097 return incidence->accept(*
this, incidence);
1100 QString result()
const {
1107 mResult = displayViewFormatEvent(mCalendar, mSourceName, event, mDate, mSpec);
1108 return !mResult.isEmpty();
1112 mResult = displayViewFormatTodo(mCalendar, mSourceName, todo, mDate, mSpec);
1113 return !mResult.isEmpty();
1117 mResult = displayViewFormatJournal(mCalendar, mSourceName, journal, mSpec);
1118 return !mResult.isEmpty();
1122 mResult = displayViewFormatFreeBusy(mCalendar, mSourceName, fb, mSpec);
1123 return !mResult.isEmpty();
1128 QString mSourceName;
1130 KDateTime::Spec mSpec;
1138 KDateTime::Spec spec)
1144 EventViewerVisitor v;
1145 if (v.act(calendar, incidence, date, spec)) {
1155 KDateTime::Spec spec)
1161 EventViewerVisitor v;
1162 if (v.act(sourceName, incidence, date, spec)) {
1173 static QString cleanHtml(
const QString &html)
1175 QRegExp rx(QLatin1String(
"<body[^>]*>(.*)</body>"), Qt::CaseInsensitive);
1177 QString body = rx.cap(1);
1179 return Qt::escape(body.remove(QRegExp(QLatin1String(
"<[^>]*>"))).trimmed());
1182 static QString invitationSummary(
const Incidence::Ptr &incidence,
bool noHtmlMode)
1184 QString summaryStr = i18n(
"Summary unspecified");
1185 if (!incidence->summary().isEmpty()) {
1186 if (!incidence->summaryIsRich()) {
1187 summaryStr = Qt::escape(incidence->summary());
1189 summaryStr = incidence->richSummary();
1191 summaryStr = cleanHtml(summaryStr);
1198 static QString invitationLocation(
const Incidence::Ptr &incidence,
bool noHtmlMode)
1200 QString locationStr = i18n(
"Location unspecified");
1201 if (!incidence->location().isEmpty()) {
1202 if (!incidence->locationIsRich()) {
1203 locationStr = Qt::escape(incidence->location());
1205 locationStr = incidence->richLocation();
1207 locationStr = cleanHtml(locationStr);
1214 static QString eventStartTimeStr(
const Event::Ptr &event)
1217 if (!event->allDay()) {
1218 tmp = i18nc(
"%1: Start Date, %2: Start Time",
"%1 %2",
1219 dateToString(event->dtStart(),
true, KSystemTimeZones::local()),
1220 timeToString(event->dtStart(),
true, KSystemTimeZones::local()));
1222 tmp = i18nc(
"%1: Start Date",
"%1 (all day)",
1223 dateToString(event->dtStart(),
true, KSystemTimeZones::local()));
1228 static QString eventEndTimeStr(
const Event::Ptr &event)
1231 if (event->hasEndDate() &&
event->dtEnd().isValid()) {
1232 if (!event->allDay()) {
1233 tmp = i18nc(
"%1: End Date, %2: End Time",
"%1 %2",
1234 dateToString(event->dtEnd(),
true, KSystemTimeZones::local()),
1235 timeToString(event->dtEnd(),
true, KSystemTimeZones::local()));
1237 tmp = i18nc(
"%1: End Date",
"%1 (all day)",
1238 dateToString(event->dtEnd(),
true, KSystemTimeZones::local()));
1244 static QString htmlInvitationDetailsBegin()
1246 QString dir = (QApplication::isRightToLeft() ? QLatin1String(
"rtl") : QLatin1String(
"ltr"));
1247 return QString::fromLatin1(
"<div dir=\"%1\">\n").arg(dir);
1250 static QString htmlInvitationDetailsEnd()
1252 return QLatin1String(
"</div>\n");
1255 static QString htmlInvitationDetailsTableBegin()
1258 return QLatin1String(
"<table cellspacing=\"4\" style=\"border-width:4px; border-style:groove\">");
1262 static QString htmlInvitationDetailsTableEnd()
1264 return QLatin1String(
"</table>\n");
1267 static QString diffColor()
1272 return QColor(Qt::red).name();
1275 static QString noteColor()
1278 return qApp->palette().color(QPalette::Active, QPalette::Highlight).name();
1281 static QString htmlRow(
const QString &title,
const QString &value)
1283 if (!value.isEmpty()) {
1284 return QLatin1String(
"<tr><td>") + title + QLatin1String(
"</td><td>") + value + QLatin1String(
"</td></tr>\n");
1290 static QString htmlRow(
const QString &title,
const QString &value,
const QString &oldvalue)
1293 if (value.isEmpty()) {
1298 if (oldvalue.isEmpty() || value == oldvalue) {
1299 return htmlRow(title, value);
1303 QString color = diffColor();
1304 QString newtitle = QLatin1String(
"<font color=\"") + color + QLatin1String(
"\">") + title + QLatin1String(
"</font>");
1305 QString newvalue = QLatin1String(
"<font color=\"") + color + QLatin1String(
"\">") + value + QLatin1String(
"</font>") +
1306 QLatin1String(
" ")+
1307 QLatin1String(
"(<strike>") + oldvalue + QLatin1String(
"</strike>");
1308 return htmlRow(newtitle, newvalue);
1321 RAIIIdentityManager raiiHelper;
1322 QString delegatorName, delegatorEmail;
1324 Attendee::List::ConstIterator it;
1325 for (it = attendees.constBegin(); it != attendees.constEnd(); ++it) {
1327 KPIMUtils::extractEmailAddressAndName(a->delegator(), delegatorEmail, delegatorName);
1328 if (thatIsMe(delegatorEmail)) {
1346 RAIIIdentityManager raiiHelper;
1348 Attendee::List::ConstIterator it;
1349 for (it = attendees.constBegin(); it != attendees.constEnd(); ++it) {
1351 if (thatIsMe(a->email())) {
1361 const QString &email)
1370 RAIIIdentityManager raiiHelper;
1372 Attendee::List::ConstIterator it;
1373 for (it = attendees.constBegin(); it != attendees.constEnd(); ++it) {
1375 if (email == a->email()) {
1393 Attendee::List::ConstIterator it;
1394 for (it = attendees.constBegin(); it != attendees.constEnd(); ++it) {
1395 if (it == attendees.constBegin()) {
1396 rsvp = (*it)->RSVP();
1398 if ((*it)->RSVP() != rsvp) {
1407 static QString rsvpRequestedStr(
bool rsvpRequested,
const QString &role)
1409 if (rsvpRequested) {
1410 if (role.isEmpty()) {
1411 return i18n(
"Your response is requested");
1413 return i18n(
"Your response as <b>%1</b> is requested", role);
1416 if (role.isEmpty()) {
1417 return i18n(
"No response is necessary");
1419 return i18n(
"No response as <b>%1</b> is necessary", role);
1430 ret = i18n(
"(<b>Note</b>: the Organizer preset your response to <b>%1</b>)",
1431 Stringify::attendeeStatus(a->status()));
1436 static QString invitationNote(
const QString &title,
const QString ¬e,
1437 const QString &tag,
const QString &color)
1440 if (!note.isEmpty()) {
1441 noteStr += QLatin1String(
"<table border=\"0\" style=\"margin-top:4px;\">");
1442 noteStr += QLatin1String(
"<tr><center><td>");
1443 if (!color.isEmpty()) {
1444 noteStr += QLatin1String(
"<font color=\"") + color + QLatin1String(
"\">");
1446 if (!title.isEmpty()) {
1447 if (!tag.isEmpty()) {
1448 noteStr += htmlAddTag(tag, title);
1453 noteStr += QLatin1String(
" )") + note;
1454 if (!color.isEmpty()) {
1455 noteStr += QLatin1String(
"</font>");
1457 noteStr += QLatin1String(
"</td></center></tr>");
1458 noteStr += QLatin1String(
"</table>");
1463 static QString invitationPerson(
const QString &email,
const QString &name,
const QString &uid,
1464 const QString &comment)
1466 QPair<QString, QString> s = searchNameAndUid(email, name, uid);
1467 const QString printName = s.first;
1468 const QString printUid = s.second;
1470 QString personString;
1472 if (!printUid.isEmpty()) {
1473 personString = htmlAddUidLink(email, printName, printUid);
1476 personString = (printName.isEmpty() ? email : printName);
1478 if (!comment.isEmpty()) {
1479 personString = i18nc(
"name (comment)",
"%1 (%2)", personString, comment);
1481 personString += QLatin1Char(
'\n');
1484 if (!email.isEmpty()) {
1485 personString += QLatin1String(
" ") + htmlAddMailtoLink(email, printName);
1487 personString += QLatin1Char(
'\n');
1489 return personString;
1492 static QString invitationDetailsIncidence(
const Incidence::Ptr &incidence,
bool noHtmlMode)
1500 QStringList comments;
1502 if (incidence->comments().isEmpty()) {
1503 if (!incidence->description().isEmpty()) {
1505 if (!incidence->descriptionIsRich() &&
1506 !incidence->description().startsWith(QLatin1String(
"<!DOCTYPE HTML"))) {
1507 comments << string2HTML(incidence->description());
1509 if (!incidence->description().startsWith(QLatin1String(
"<!DOCTYPE HTML"))) {
1510 comments << incidence->richDescription();
1512 comments << incidence->description();
1515 comments[0] = cleanHtml(comments[0]);
1517 comments[0] = htmlAddTag(QLatin1String(
"p"), comments[0]);
1523 foreach(
const QString &c, incidence->comments()) {
1526 if (!Qt::mightBeRichText(c)) {
1527 comments << string2HTML(c);
1530 comments << cleanHtml(cleanHtml(QLatin1String(
"<body>") + c +QLatin1String(
"</body>")));
1537 if (!incidence->description().isEmpty()) {
1539 if (!incidence->descriptionIsRich() &&
1540 !incidence->description().startsWith(QLatin1String(
"<!DOCTYPE HTML"))) {
1541 descr = string2HTML(incidence->description());
1543 if (!incidence->description().startsWith(QLatin1String(
"<!DOCTYPE HTML"))) {
1544 descr = incidence->richDescription();
1546 descr = incidence->description();
1549 descr = cleanHtml(descr);
1551 descr = htmlAddTag(QLatin1String(
"p"), descr);
1556 if (!descr.isEmpty()) {
1557 html += QLatin1String(
"<p>");
1558 html += QLatin1String(
"<table border=\"0\" style=\"margin-top:4px;\">");
1559 html += QLatin1String(
"<tr><td><center>") +
1560 htmlAddTag(QLatin1String(
"u"), i18n(
"Description:")) +
1561 QLatin1String(
"</center></td></tr>");
1562 html += QLatin1String(
"<tr><td>") + descr + QLatin1String(
"</td></tr>");
1563 html += QLatin1String(
"</table>");
1566 if (!comments.isEmpty()) {
1567 html += QLatin1String(
"<p>");
1568 html += QLatin1String(
"<table border=\"0\" style=\"margin-top:4px;\">");
1569 html += QLatin1String(
"<tr><td><center>") +
1570 htmlAddTag(QLatin1String(
"u"), i18n(
"Comments:")) +
1571 QLatin1String(
"</center></td></tr>");
1572 html += QLatin1String(
"<tr><td>");
1573 if (comments.count() > 1) {
1574 html += QLatin1String(
"<ul>");
1575 for (
int i=0; i < comments.count(); ++i) {
1576 html += QLatin1String(
"<li>") + comments[i] + QLatin1String(
"</li>");
1578 html += QLatin1String(
"</ul>");
1580 html += comments[0];
1582 html += QLatin1String(
"</td></tr>");
1583 html += QLatin1String(
"</table>");
1588 static QString invitationDetailsEvent(
const Event::Ptr &event,
bool noHtmlMode,
1589 KDateTime::Spec spec)
1596 QString html = htmlInvitationDetailsBegin();
1597 html += htmlInvitationDetailsTableBegin();
1600 html += htmlRow(i18n(
"What:"), invitationSummary(event, noHtmlMode));
1601 html += htmlRow(i18n(
"Where:"), invitationLocation(event, noHtmlMode));
1604 if (event->dtStart().date() ==
event->dtEnd().date()) {
1605 html += htmlRow(i18n(
"Date:"),
dateToString(event->dtStart(),
false, spec));
1606 if (!event->allDay()) {
1607 html += htmlRow(i18n(
"Time:"),
1609 QLatin1String(
" - ") +
1613 html += htmlRow(i18nc(
"starting date",
"From:"),
1615 if (!event->allDay()) {
1616 html += htmlRow(i18nc(
"starting time",
"At:"),
1619 if (event->hasEndDate()) {
1620 html += htmlRow(i18nc(
"ending date",
"To:"),
1622 if (!event->allDay()) {
1623 html += htmlRow(i18nc(
"ending time",
"At:"),
1627 html += htmlRow(i18nc(
"ending date",
"To:"), i18n(
"no end date specified"));
1635 if (event->recurs()) {
1639 html += htmlInvitationDetailsTableEnd();
1640 html += invitationDetailsIncidence(event, noHtmlMode);
1641 html += htmlInvitationDetailsEnd();
1648 KDateTime::Spec spec)
1651 return invitationDetailsEvent(event, noHtmlMode, spec);
1658 html += QLatin1String(
"<br>");
1659 html += invitationNote(QString(),
1660 i18n(
"Please respond again to the original proposal."),
1661 QString(), noteColor());
1664 html += htmlInvitationDetailsBegin();
1665 html += htmlInvitationDetailsTableBegin();
1667 html += htmlRow(i18n(
"What:"),
1668 invitationSummary(event, noHtmlMode),
1669 invitationSummary(oldevent, noHtmlMode));
1671 html += htmlRow(i18n(
"Where:"),
1672 invitationLocation(event, noHtmlMode),
1673 invitationLocation(oldevent, noHtmlMode));
1676 if (event->dtStart().date() ==
event->dtEnd().date()) {
1677 html += htmlRow(i18n(
"Date:"),
1680 QString spanStr, oldspanStr;
1681 if (!event->allDay()) {
1683 QLatin1String(
" - ") +
1686 if (!oldevent->allDay()) {
1687 oldspanStr =
timeToString(oldevent->dtStart(),
true, spec) +
1688 QLatin1String(
" - ") +
1691 html += htmlRow(i18n(
"Time:"), spanStr, oldspanStr);
1693 html += htmlRow(i18nc(
"Starting date of an event",
"From:"),
1696 QString startStr, oldstartStr;
1697 if (!event->allDay()) {
1700 if (!oldevent->allDay()) {
1701 oldstartStr =
timeToString(oldevent->dtStart(),
true, spec);
1703 html += htmlRow(i18nc(
"Starting time of an event",
"At:"), startStr, oldstartStr);
1704 if (event->hasEndDate()) {
1705 html += htmlRow(i18nc(
"Ending date of an event",
"To:"),
1708 QString endStr, oldendStr;
1709 if (!event->allDay()) {
1712 if (!oldevent->allDay()) {
1713 oldendStr =
timeToString(oldevent->dtEnd(),
true, spec);
1715 html += htmlRow(i18nc(
"Starting time of an event",
"At:"), endStr, oldendStr);
1717 QString endStr = i18n(
"no end date specified");
1719 if (!oldevent->hasEndDate()) {
1720 oldendStr = i18n(
"no end date specified");
1722 oldendStr =
dateTimeToString(oldevent->dtEnd(), oldevent->allDay(),
false);
1724 html += htmlRow(i18nc(
"Ending date of an event",
"To:"), endStr, oldendStr);
1730 QString recurStr, oldrecurStr;
1731 if (event->recurs() || oldevent->recurs()) {
1735 html += htmlRow(i18n(
"Recurrence:"), recurStr, oldrecurStr);
1737 html += htmlInvitationDetailsTableEnd();
1738 html += invitationDetailsIncidence(event, noHtmlMode);
1739 html += htmlInvitationDetailsEnd();
1744 static QString invitationDetailsTodo(
const Todo::Ptr &todo,
bool noHtmlMode,
1745 KDateTime::Spec spec)
1752 QString html = htmlInvitationDetailsBegin();
1753 html += htmlInvitationDetailsTableBegin();
1756 html += htmlRow(i18n(
"What:"), invitationSummary(todo, noHtmlMode));
1757 html += htmlRow(i18n(
"Where:"), invitationLocation(todo, noHtmlMode));
1759 if (todo->hasStartDate()) {
1760 html += htmlRow(i18n(
"Start Date:"),
dateToString(todo->dtStart(),
false, spec));
1761 if (!todo->allDay()) {
1762 html += htmlRow(i18n(
"Start Time:"),
timeToString(todo->dtStart(),
false, spec));
1765 if (todo->hasDueDate()) {
1766 html += htmlRow(i18n(
"Due Date:"),
dateToString(todo->dtDue(),
false, spec));
1767 if (!todo->allDay()) {
1768 html += htmlRow(i18n(
"Due Time:"),
timeToString(todo->dtDue(),
false, spec));
1771 html += htmlRow(i18n(
"Due Date:"), i18nc(
"Due Date: None",
"None"));
1778 if (todo->percentComplete() > 0) {
1779 html += htmlRow(i18n(
"Percent Done:"), i18n(
"%1%", todo->percentComplete()));
1783 if (todo->recurs()) {
1787 html += htmlInvitationDetailsTableEnd();
1788 html += invitationDetailsIncidence(todo, noHtmlMode);
1789 html += htmlInvitationDetailsEnd();
1794 static QString invitationDetailsTodo(
const Todo::Ptr &todo,
const Todo::Ptr &oldtodo,
1796 KDateTime::Spec spec)
1799 return invitationDetailsTodo(todo, noHtmlMode, spec);
1806 html += QLatin1String(
"<br>");
1807 html += invitationNote(QString(),
1808 i18n(
"Please respond again to the original proposal."),
1809 QString(), noteColor());
1812 html += htmlInvitationDetailsBegin();
1813 html += htmlInvitationDetailsTableBegin();
1815 html += htmlRow(i18n(
"What:"),
1816 invitationSummary(todo, noHtmlMode),
1817 invitationSummary(todo, noHtmlMode));
1819 html += htmlRow(i18n(
"Where:"),
1820 invitationLocation(todo, noHtmlMode),
1821 invitationLocation(oldtodo, noHtmlMode));
1823 if (todo->hasStartDate()) {
1824 html += htmlRow(i18n(
"Start Date:"),
1827 QString startTimeStr, oldstartTimeStr;
1828 if (!todo->allDay() || !oldtodo->allDay()) {
1829 startTimeStr = todo->allDay() ?
1830 i18n(
"All day") :
timeToString(todo->dtStart(), false, spec);
1831 oldstartTimeStr = oldtodo->allDay() ?
1832 i18n(
"All day") :
timeToString(oldtodo->dtStart(), false, spec);
1834 html += htmlRow(i18n(
"Start Time:"), startTimeStr, oldstartTimeStr);
1836 if (todo->hasDueDate()) {
1837 html += htmlRow(i18n(
"Due Date:"),
1840 QString endTimeStr, oldendTimeStr;
1841 if (!todo->allDay() || !oldtodo->allDay()) {
1842 endTimeStr = todo->allDay() ?
1843 i18n(
"All day") :
timeToString(todo->dtDue(), false, spec);
1844 oldendTimeStr = oldtodo->allDay() ?
1845 i18n(
"All day") :
timeToString(oldtodo->dtDue(), false, spec);
1847 html += htmlRow(i18n(
"Due Time:"), endTimeStr, oldendTimeStr);
1849 QString dueStr = i18nc(
"Due Date: None",
"None");
1851 if (!oldtodo->hasDueDate()) {
1852 olddueStr = i18nc(
"Due Date: None",
"None");
1856 html += htmlRow(i18n(
"Due Date:"), dueStr, olddueStr);
1861 QString completionStr, oldcompletionStr;
1862 if (todo->percentComplete() > 0 || oldtodo->percentComplete() > 0) {
1863 completionStr = i18n(
"%1%", todo->percentComplete());
1864 oldcompletionStr = i18n(
"%1%", oldtodo->percentComplete());
1866 html += htmlRow(i18n(
"Percent Done:"), completionStr, oldcompletionStr);
1868 QString recurStr, oldrecurStr;
1869 if (todo->recurs() || oldtodo->recurs()) {
1873 html += htmlRow(i18n(
"Recurrence:"), recurStr, oldrecurStr);
1875 html += htmlInvitationDetailsTableEnd();
1876 html += invitationDetailsIncidence(todo, noHtmlMode);
1878 html += htmlInvitationDetailsEnd();
1883 static QString invitationDetailsJournal(
const Journal::Ptr &journal,
bool noHtmlMode,
1884 KDateTime::Spec spec)
1890 QString html = htmlInvitationDetailsBegin();
1891 html += htmlInvitationDetailsTableBegin();
1893 html += htmlRow(i18n(
"Summary:"), invitationSummary(journal, noHtmlMode));
1894 html += htmlRow(i18n(
"Date:"),
dateToString(journal->dtStart(),
false, spec));
1896 html += htmlInvitationDetailsTableEnd();
1897 html += invitationDetailsIncidence(journal, noHtmlMode);
1898 html += htmlInvitationDetailsEnd();
1903 static QString invitationDetailsJournal(
const Journal::Ptr &journal,
1905 bool noHtmlMode, KDateTime::Spec spec)
1908 return invitationDetailsJournal(journal, noHtmlMode, spec);
1911 QString html = htmlInvitationDetailsBegin();
1912 html += htmlInvitationDetailsTableBegin();
1914 html += htmlRow(i18n(
"What:"),
1915 invitationSummary(journal, noHtmlMode),
1916 invitationSummary(oldjournal, noHtmlMode));
1918 html += htmlRow(i18n(
"Date:"),
1922 html += htmlInvitationDetailsTableEnd();
1923 html += invitationDetailsIncidence(journal, noHtmlMode);
1924 html += htmlInvitationDetailsEnd();
1929 static QString invitationDetailsFreeBusy(
const FreeBusy::Ptr &fb,
bool noHtmlMode,
1930 KDateTime::Spec spec)
1932 Q_UNUSED(noHtmlMode);
1938 QString html = htmlInvitationDetailsTableBegin();
1940 html += htmlRow(i18n(
"Person:"), fb->organizer()->fullName());
1941 html += htmlRow(i18n(
"Start date:"),
dateToString(fb->dtStart(),
true, spec));
1942 html += htmlRow(i18n(
"End date:"),
dateToString(fb->dtEnd(),
true, spec));
1944 html += QLatin1String(
"<tr><td colspan=2><hr></td></tr>\n");
1945 html += QLatin1String(
"<tr><td colspan=2>Busy periods given in this free/busy object:</td></tr>\n");
1948 Period::List::iterator it;
1949 for (it = periods.begin(); it != periods.end(); ++it) {
1955 cont += i18ncp(
"hours part of duration",
"1 hour ",
"%1 hours ", dur / 3600);
1959 cont += i18ncp(
"minutes part of duration",
"1 minute",
"%1 minutes ", dur / 60);
1963 cont += i18ncp(
"seconds part of duration",
"1 second",
"%1 seconds", dur);
1965 html += htmlRow(QString(),
1966 i18nc(
"startDate for duration",
"%1 for %2",
1968 per.
start().dateTime(), KLocale::LongDate),
1972 if (per.
start().date() == per.
end().date()) {
1973 cont = i18nc(
"date, fromTime - toTime ",
"%1, %2 - %3",
1975 KGlobal::locale()->formatTime(per.
start().time()),
1976 KGlobal::locale()->formatTime(per.
end().time()));
1978 cont = i18nc(
"fromDateTime - toDateTime",
"%1 - %2",
1980 per.
start().dateTime(), KLocale::LongDate),
1981 KGlobal::locale()->formatDateTime(
1982 per.
end().dateTime(), KLocale::LongDate));
1985 html += htmlRow(QString(), cont);
1989 html += htmlInvitationDetailsTableEnd();
1994 bool noHtmlMode, KDateTime::Spec spec)
1997 return invitationDetailsFreeBusy(fb, noHtmlMode, spec);
2002 Q_UNUSED(incidence);
2020 static QString invitationHeaderEvent(
const Event::Ptr &event,
2024 if (!msg || !event) {
2028 switch (msg->method()) {
2030 return i18n(
"This invitation has been published");
2032 if (existingIncidence && event->revision() > 0) {
2033 QString orgStr = organizerName(event, sender);
2034 if (senderIsOrganizer(event, sender)) {
2035 return i18n(
"This invitation has been updated by the organizer %1", orgStr);
2037 return i18n(
"This invitation has been updated by %1 as a representative of %2",
2041 if (iamOrganizer(event)) {
2042 return i18n(
"I created this invitation");
2044 QString orgStr = organizerName(event, sender);
2045 if (senderIsOrganizer(event, sender)) {
2046 return i18n(
"You received an invitation from %1", orgStr);
2048 return i18n(
"You received an invitation from %1 as a representative of %2",
2053 return i18n(
"This invitation was refreshed");
2055 if (iamOrganizer(event)) {
2056 return i18n(
"This invitation has been canceled");
2058 return i18n(
"The organizer has revoked the invitation");
2061 return i18n(
"Addition to the invitation");
2064 if (replyMeansCounter(event)) {
2065 return i18n(
"%1 makes this counter proposal", firstAttendeeName(event, sender));
2069 if (attendees.count() == 0) {
2070 kDebug() <<
"No attendees in the iCal reply!";
2073 if (attendees.count() != 1) {
2074 kDebug() <<
"Warning: attendeecount in the reply should be 1" 2075 <<
"but is" << attendees.count();
2077 QString attendeeName = firstAttendeeName(event, sender);
2079 QString delegatorName, dummy;
2081 KPIMUtils::extractEmailAddressAndName(attendee->delegator(), dummy, delegatorName);
2082 if (delegatorName.isEmpty()) {
2083 delegatorName = attendee->delegator();
2086 switch (attendee->status()) {
2088 return i18n(
"%1 indicates this invitation still needs some action", attendeeName);
2090 if (event->revision() > 0) {
2091 if (!sender.isEmpty()) {
2092 return i18n(
"This invitation has been updated by attendee %1", sender);
2094 return i18n(
"This invitation has been updated by an attendee");
2097 if (delegatorName.isEmpty()) {
2098 return i18n(
"%1 accepts this invitation", attendeeName);
2100 return i18n(
"%1 accepts this invitation on behalf of %2",
2101 attendeeName, delegatorName);
2105 if (delegatorName.isEmpty()) {
2106 return i18n(
"%1 tentatively accepts this invitation", attendeeName);
2108 return i18n(
"%1 tentatively accepts this invitation on behalf of %2",
2109 attendeeName, delegatorName);
2112 if (delegatorName.isEmpty()) {
2113 return i18n(
"%1 declines this invitation", attendeeName);
2115 return i18n(
"%1 declines this invitation on behalf of %2",
2116 attendeeName, delegatorName);
2120 QString delegate, dummy;
2121 KPIMUtils::extractEmailAddressAndName(attendee->delegate(), dummy, delegate);
2122 if (delegate.isEmpty()) {
2123 delegate = attendee->delegate();
2125 if (!delegate.isEmpty()) {
2126 return i18n(
"%1 has delegated this invitation to %2", attendeeName, delegate);
2128 return i18n(
"%1 has delegated this invitation", attendeeName);
2132 return i18n(
"This invitation is now completed");
2134 return i18n(
"%1 is still processing the invitation", attendeeName);
2135 case Attendee::None:
2136 return i18n(
"Unknown response to this invitation");
2141 return i18n(
"%1 makes this counter proposal",
2142 firstAttendeeName(event, i18n(
"Sender")));
2146 QString orgStr = organizerName(event, sender);
2147 if (senderIsOrganizer(event, sender)) {
2148 return i18n(
"%1 declines your counter proposal", orgStr);
2150 return i18n(
"%1 declines your counter proposal on behalf of %2", sender, orgStr);
2155 return i18n(
"Error: Event iTIP message with unknown method");
2157 kError() <<
"encountered an iTIP method that we do not support";
2161 static QString invitationHeaderTodo(
const Todo::Ptr &todo,
2165 if (!msg || !todo) {
2169 switch (msg->method()) {
2171 return i18n(
"This to-do has been published");
2173 if (existingIncidence && todo->revision() > 0) {
2174 QString orgStr = organizerName(todo, sender);
2175 if (senderIsOrganizer(todo, sender)) {
2176 return i18n(
"This to-do has been updated by the organizer %1", orgStr);
2178 return i18n(
"This to-do has been updated by %1 as a representative of %2",
2182 if (iamOrganizer(todo)) {
2183 return i18n(
"I created this to-do");
2185 QString orgStr = organizerName(todo, sender);
2186 if (senderIsOrganizer(todo, sender)) {
2187 return i18n(
"You have been assigned this to-do by %1", orgStr);
2189 return i18n(
"You have been assigned this to-do by %1 as a representative of %2",
2195 return i18n(
"This to-do was refreshed");
2197 if (iamOrganizer(todo)) {
2198 return i18n(
"This to-do was canceled");
2200 return i18n(
"The organizer has revoked this to-do");
2203 return i18n(
"Addition to the to-do");
2206 if (replyMeansCounter(todo)) {
2207 return i18n(
"%1 makes this counter proposal", firstAttendeeName(todo, sender));
2211 if (attendees.count() == 0) {
2212 kDebug() <<
"No attendees in the iCal reply!";
2215 if (attendees.count() != 1) {
2216 kDebug() <<
"Warning: attendeecount in the reply should be 1" 2217 <<
"but is" << attendees.count();
2219 QString attendeeName = firstAttendeeName(todo, sender);
2221 QString delegatorName, dummy;
2223 KPIMUtils::extractEmailAddressAndName(attendee->delegate(), dummy, delegatorName);
2224 if (delegatorName.isEmpty()) {
2225 delegatorName = attendee->delegator();
2228 switch (attendee->status()) {
2230 return i18n(
"%1 indicates this to-do assignment still needs some action",
2233 if (todo->revision() > 0) {
2234 if (!sender.isEmpty()) {
2235 if (todo->isCompleted()) {
2236 return i18n(
"This to-do has been completed by assignee %1", sender);
2238 return i18n(
"This to-do has been updated by assignee %1", sender);
2241 if (todo->isCompleted()) {
2242 return i18n(
"This to-do has been completed by an assignee");
2244 return i18n(
"This to-do has been updated by an assignee");
2248 if (delegatorName.isEmpty()) {
2249 return i18n(
"%1 accepts this to-do", attendeeName);
2251 return i18n(
"%1 accepts this to-do on behalf of %2",
2252 attendeeName, delegatorName);
2256 if (delegatorName.isEmpty()) {
2257 return i18n(
"%1 tentatively accepts this to-do", attendeeName);
2259 return i18n(
"%1 tentatively accepts this to-do on behalf of %2",
2260 attendeeName, delegatorName);
2263 if (delegatorName.isEmpty()) {
2264 return i18n(
"%1 declines this to-do", attendeeName);
2266 return i18n(
"%1 declines this to-do on behalf of %2",
2267 attendeeName, delegatorName);
2271 QString delegate, dummy;
2272 KPIMUtils::extractEmailAddressAndName(attendee->delegate(), dummy, delegate);
2273 if (delegate.isEmpty()) {
2274 delegate = attendee->delegate();
2276 if (!delegate.isEmpty()) {
2277 return i18n(
"%1 has delegated this to-do to %2", attendeeName, delegate);
2279 return i18n(
"%1 has delegated this to-do", attendeeName);
2283 return i18n(
"The request for this to-do is now completed");
2285 return i18n(
"%1 is still processing the to-do", attendeeName);
2286 case Attendee::None:
2287 return i18n(
"Unknown response to this to-do");
2292 return i18n(
"%1 makes this counter proposal", firstAttendeeName(todo, sender));
2296 QString orgStr = organizerName(todo, sender);
2297 if (senderIsOrganizer(todo, sender)) {
2298 return i18n(
"%1 declines the counter proposal", orgStr);
2300 return i18n(
"%1 declines the counter proposal on behalf of %2", sender, orgStr);
2305 return i18n(
"Error: To-do iTIP message with unknown method");
2307 kError() <<
"encountered an iTIP method that we do not support";
2311 static QString invitationHeaderJournal(
const Journal::Ptr &journal,
2314 if (!msg || !journal) {
2318 switch (msg->method()) {
2320 return i18n(
"This journal has been published");
2322 return i18n(
"You have been assigned this journal");
2324 return i18n(
"This journal was refreshed");
2326 return i18n(
"This journal was canceled");
2328 return i18n(
"Addition to the journal");
2331 if (replyMeansCounter(journal)) {
2332 return i18n(
"Sender makes this counter proposal");
2336 if (attendees.count() == 0) {
2337 kDebug() <<
"No attendees in the iCal reply!";
2340 if (attendees.count() != 1) {
2341 kDebug() <<
"Warning: attendeecount in the reply should be 1 " 2342 <<
"but is " << attendees.count();
2346 switch (attendee->status()) {
2348 return i18n(
"Sender indicates this journal assignment still needs some action");
2350 return i18n(
"Sender accepts this journal");
2352 return i18n(
"Sender tentatively accepts this journal");
2354 return i18n(
"Sender declines this journal");
2356 return i18n(
"Sender has delegated this request for the journal");
2358 return i18n(
"The request for this journal is now completed");
2360 return i18n(
"Sender is still processing the invitation");
2361 case Attendee::None:
2362 return i18n(
"Unknown response to this journal");
2367 return i18n(
"Sender makes this counter proposal");
2369 return i18n(
"Sender declines the counter proposal");
2371 return i18n(
"Error: Journal iTIP message with unknown method");
2373 kError() <<
"encountered an iTIP method that we do not support";
2377 static QString invitationHeaderFreeBusy(
const FreeBusy::Ptr &fb,
2384 switch (msg->method()) {
2386 return i18n(
"This free/busy list has been published");
2388 return i18n(
"The free/busy list has been requested");
2390 return i18n(
"This free/busy list was refreshed");
2392 return i18n(
"This free/busy list was canceled");
2394 return i18n(
"Addition to the free/busy list");
2396 return i18n(
"Reply to the free/busy list");
2398 return i18n(
"Sender makes this counter proposal");
2400 return i18n(
"Sender declines the counter proposal");
2402 return i18n(
"Error: Free/Busy iTIP message with unknown method");
2404 kError() <<
"encountered an iTIP method that we do not support";
2409 static QString invitationAttendeeList(
const Incidence::Ptr &incidence)
2411 RAIIIdentityManager raiiHelper;
2418 tmpStr += i18n(
"Assignees");
2420 tmpStr += i18n(
"Invitation List");
2425 if (!attendees.isEmpty()) {
2426 QStringList comments;
2427 Attendee::List::ConstIterator it;
2428 for (it = attendees.constBegin(); it != attendees.constEnd(); ++it) {
2430 if (!iamAttendee(a)) {
2433 tmpStr += QLatin1String(
"<table border=\"1\" cellpadding=\"1\" cellspacing=\"0\">");
2435 tmpStr += QLatin1String(
"<tr>");
2436 tmpStr += QLatin1String(
"<td>");
2438 if (attendeeIsOrganizer(incidence, a)) {
2439 comments << i18n(
"organizer");
2441 if (!a->delegator().isEmpty()) {
2442 comments << i18n(
" (delegated by %1)", a->delegator());
2444 if (!a->delegate().isEmpty()) {
2445 comments << i18n(
" (delegated to %1)", a->delegate());
2447 tmpStr += invitationPerson(a->email(), a->name(), QString(), comments.join(QLatin1String(
",")));
2448 tmpStr += QLatin1String(
"</td>");
2449 tmpStr += QLatin1String(
"</tr>");
2454 tmpStr += QLatin1String(
"</table>");
2469 tmpStr += i18n(
"Assignees");
2471 tmpStr += i18n(
"Invitation List");
2476 if (!attendees.isEmpty()) {
2477 QStringList comments;
2478 Attendee::List::ConstIterator it;
2479 for (it = attendees.constBegin(); it != attendees.constEnd(); ++it) {
2481 if (!attendeeIsOrganizer(incidence, a)) {
2482 QString statusStr = Stringify::attendeeStatus(a->status());
2483 if (sender && (a->email() == sender->email())) {
2486 if (a->status() != sender->status()) {
2487 statusStr = i18n(
"%1 (<i>unrecorded</i>)",
2488 Stringify::attendeeStatus(sender->status()));
2494 tmpStr += QLatin1String(
"<table border=\"1\" cellpadding=\"1\" cellspacing=\"0\">");
2496 tmpStr += QLatin1String(
"<tr>");
2497 tmpStr += QLatin1String(
"<td>");
2499 if (iamAttendee(a)) {
2500 comments << i18n(
"myself");
2502 if (!a->delegator().isEmpty()) {
2503 comments << i18n(
" (delegated by %1)", a->delegator());
2505 if (!a->delegate().isEmpty()) {
2506 comments << i18n(
" (delegated to %1)", a->delegate());
2508 tmpStr += invitationPerson(a->email(), a->name(), QString(), comments.join(QLatin1String(
",")));
2509 tmpStr += QLatin1String(
"</td>");
2510 tmpStr += QLatin1String(
"<td>")+ statusStr + QLatin1String(
"</td>");
2511 tmpStr += QLatin1String(
"</tr>");
2516 tmpStr += QLatin1String(
"</table>");
2518 tmpStr += QLatin1String(
"<i> ") + i18nc(
"no attendees",
"None") + QLatin1String(
"</i>");
2524 static QString invitationAttachments(InvitationFormatterHelper *helper,
2538 if (!attachments.isEmpty()) {
2539 tmpStr += i18n(
"Attached Documents:") + QLatin1String(
"<ol>");
2541 Attachment::List::ConstIterator it;
2542 for (it = attachments.constBegin(); it != attachments.constEnd(); ++it) {
2544 tmpStr += QLatin1String(
"<li>");
2546 KMimeType::Ptr
mimeType = KMimeType::mimeType(a->mimeType());
2547 const QString iconStr = (mimeType ?
2548 mimeType->iconName(a->uri()) :
2549 QLatin1String(
"application-octet-stream"));
2550 const QString iconPath = KIconLoader::global()->iconPath(iconStr, KIconLoader::Small);
2551 if (!iconPath.isEmpty()) {
2552 tmpStr += QLatin1String(
"<img valign=\"top\" src=\"") + iconPath + QLatin1String(
"\">");
2554 tmpStr += helper->makeLink(QLatin1String(
"ATTACH:") + QLatin1String(a->label().toUtf8().toBase64()), a->label());
2555 tmpStr += QLatin1String(
"</li>");
2557 tmpStr += QLatin1String(
"</ol>");
2564 class KCalUtils::IncidenceFormatter::ScheduleMessageVisitor :
public Visitor 2567 ScheduleMessageVisitor() : mMessage(0) {
2568 mResult = QLatin1String(
"");
2574 mExistingIncidence = existingIncidence;
2577 return incidence->accept(*
this, incidence);
2579 QString result()
const {
2590 class KCalUtils::IncidenceFormatter::InvitationHeaderVisitor :
2591 public IncidenceFormatter::ScheduleMessageVisitor
2596 mResult = invitationHeaderEvent(event, mExistingIncidence, mMessage, mSender);
2597 return !mResult.isEmpty();
2601 mResult = invitationHeaderTodo(todo, mExistingIncidence, mMessage, mSender);
2602 return !mResult.isEmpty();
2606 mResult = invitationHeaderJournal(journal, mMessage);
2607 return !mResult.isEmpty();
2611 mResult = invitationHeaderFreeBusy(fb, mMessage);
2612 return !mResult.isEmpty();
2616 class KCalUtils::IncidenceFormatter::InvitationBodyVisitor
2617 :
public IncidenceFormatter::ScheduleMessageVisitor
2620 InvitationBodyVisitor(
bool noHtmlMode, KDateTime::Spec spec)
2621 : ScheduleMessageVisitor(), mNoHtmlMode(noHtmlMode), mSpec(spec) {}
2627 mResult = invitationDetailsEvent(event, oldevent, mMessage, mNoHtmlMode, mSpec);
2628 return !mResult.isEmpty();
2633 mResult = invitationDetailsTodo(todo, oldtodo, mMessage, mNoHtmlMode, mSpec);
2634 return !mResult.isEmpty();
2639 mResult = invitationDetailsJournal(journal, oldjournal, mNoHtmlMode, mSpec);
2640 return !mResult.isEmpty();
2644 mResult = invitationDetailsFreeBusy(fb,
FreeBusy::Ptr(), mNoHtmlMode, mSpec);
2645 return !mResult.isEmpty();
2650 KDateTime::Spec mSpec;
2654 InvitationFormatterHelper::InvitationFormatterHelper()
2659 InvitationFormatterHelper::~InvitationFormatterHelper()
2663 QString InvitationFormatterHelper::generateLinkURL(
const QString &
id)
2669 class IncidenceFormatter::IncidenceCompareVisitor :
public Visitor 2672 IncidenceCompareVisitor() {}
2676 if (!existingIncidence) {
2680 if (!inc || !existingIncidence ||
2681 inc->revision() <= existingIncidence->revision()) {
2684 mExistingIncidence = existingIncidence;
2685 return incidence->
accept(*
this, incidence);
2688 QString result()
const 2690 if (mChanges.isEmpty()) {
2693 QString html = QLatin1String(
"<div align=\"left\"><ul><li>");
2694 html += mChanges.join(QLatin1String(
"</li><li>"));
2695 html += QLatin1String(
"</li><ul></div>");
2702 compareEvents(event, mExistingIncidence.dynamicCast<
Event>());
2703 compareIncidences(event, mExistingIncidence);
2704 return !mChanges.isEmpty();
2708 compareTodos(todo, mExistingIncidence.dynamicCast<
Todo>());
2709 compareIncidences(todo, mExistingIncidence);
2710 return !mChanges.isEmpty();
2714 compareIncidences(journal, mExistingIncidence);
2715 return !mChanges.isEmpty();
2720 return !mChanges.isEmpty();
2724 void compareEvents(
const Event::Ptr &newEvent,
2727 if (!oldEvent || !newEvent) {
2730 if (oldEvent->dtStart() != newEvent->dtStart() ||
2731 oldEvent->allDay() != newEvent->allDay()) {
2732 mChanges += i18n(
"The invitation starting time has been changed from %1 to %2",
2733 eventStartTimeStr(oldEvent), eventStartTimeStr(newEvent));
2735 if (oldEvent->dtEnd() != newEvent->dtEnd() ||
2736 oldEvent->allDay() != newEvent->allDay()) {
2737 mChanges += i18n(
"The invitation ending time has been changed from %1 to %2",
2738 eventEndTimeStr(oldEvent), eventEndTimeStr(newEvent));
2742 void compareTodos(
const Todo::Ptr &newTodo,
2745 if (!oldTodo || !newTodo) {
2749 if (!oldTodo->isCompleted() && newTodo->isCompleted()) {
2750 mChanges += i18n(
"The to-do has been completed");
2752 if (oldTodo->isCompleted() && !newTodo->isCompleted()) {
2753 mChanges += i18n(
"The to-do is no longer completed");
2755 if (oldTodo->percentComplete() != newTodo->percentComplete()) {
2756 const QString oldPer = i18n(
"%1%", oldTodo->percentComplete());
2757 const QString newPer = i18n(
"%1%", newTodo->percentComplete());
2758 mChanges += i18n(
"The task completed percentage has changed from %1 to %2",
2762 if (!oldTodo->hasStartDate() && newTodo->hasStartDate()) {
2763 mChanges += i18n(
"A to-do starting time has been added");
2765 if (oldTodo->hasStartDate() && !newTodo->hasStartDate()) {
2766 mChanges += i18n(
"The to-do starting time has been removed");
2768 if (oldTodo->hasStartDate() && newTodo->hasStartDate() &&
2769 oldTodo->dtStart() != newTodo->dtStart()) {
2770 mChanges += i18n(
"The to-do starting time has been changed from %1 to %2",
2775 if (!oldTodo->hasDueDate() && newTodo->hasDueDate()) {
2776 mChanges += i18n(
"A to-do due time has been added");
2778 if (oldTodo->hasDueDate() && !newTodo->hasDueDate()) {
2779 mChanges += i18n(
"The to-do due time has been removed");
2781 if (oldTodo->hasDueDate() && newTodo->hasDueDate() &&
2782 oldTodo->dtDue() != newTodo->dtDue()) {
2783 mChanges += i18n(
"The to-do due time has been changed from %1 to %2",
2792 if (!oldInc || !newInc) {
2796 if (oldInc->summary() != newInc->summary()) {
2797 mChanges += i18n(
"The summary has been changed to: \"%1\"",
2798 newInc->richSummary());
2801 if (oldInc->location() != newInc->location()) {
2802 mChanges += i18n(
"The location has been changed to: \"%1\"",
2803 newInc->richLocation());
2806 if (oldInc->description() != newInc->description()) {
2807 mChanges += i18n(
"The description has been changed to: \"%1\"",
2808 newInc->richDescription());
2813 for (Attendee::List::ConstIterator it = newAttendees.constBegin();
2814 it != newAttendees.constEnd(); ++it) {
2815 Attendee::Ptr oldAtt = oldInc->attendeeByMail((*it)->email());
2817 mChanges += i18n(
"Attendee %1 has been added", (*it)->fullName());
2819 if (oldAtt->status() != (*it)->status()) {
2820 mChanges += i18n(
"The status of attendee %1 has been changed to: %2",
2821 (*it)->fullName(), Stringify::attendeeStatus((*it)->status()));
2826 for (Attendee::List::ConstIterator it = oldAttendees.constBegin();
2827 it != oldAttendees.constEnd(); ++it) {
2828 if (!attendeeIsOrganizer(oldInc, (*it))) {
2829 Attendee::Ptr newAtt = newInc->attendeeByMail((*it)->email());
2831 mChanges += i18n(
"Attendee %1 has been removed", (*it)->fullName());
2839 QStringList mChanges;
2843 QString InvitationFormatterHelper::makeLink(
const QString &
id,
const QString &text)
2845 if (!
id.startsWith(QLatin1String(
"ATTACH:"))) {
2846 QString res = QString::fromLatin1(
"<a href=\"%1\"><font size=\"-1\"><b>%2</b></font></a>").
2847 arg(generateLinkURL(
id), text);
2851 QString res = QString::fromLatin1(
"<a href=\"%1\">%2</a>").
2852 arg(generateLinkURL(
id), text);
2859 static bool incidenceOwnedByMe(
const Calendar::Ptr &calendar,
2863 Q_UNUSED(incidence);
2867 static QString inviteButton(InvitationFormatterHelper *helper,
2868 const QString &
id,
const QString &text)
2875 html += QLatin1String(
"<td style=\"border-width:2px;border-style:outset\">");
2876 if (!
id.isEmpty()) {
2877 html += helper->makeLink(
id, text);
2881 html += QLatin1String(
"</td>");
2885 static QString inviteLink(InvitationFormatterHelper *helper,
2886 const QString &
id,
const QString &text)
2890 if (helper && !
id.isEmpty()) {
2891 html += helper->makeLink(
id, text);
2899 bool rsvpReq,
bool rsvpRec,
2900 InvitationFormatterHelper *helper)
2907 if (!rsvpReq && (incidence && incidence->revision() == 0)) {
2909 html += inviteButton(helper, QLatin1String(
"record"), i18n(
"Record"));
2912 html += inviteButton(helper, QLatin1String(
"delete"), i18n(
"Move to Trash"));
2917 html += inviteButton(helper, QLatin1String(
"accept"),
2918 i18nc(
"accept invitation",
"Accept"));
2921 html += inviteButton(helper, QLatin1String(
"accept_conditionally"),
2922 i18nc(
"Accept invitation conditionally",
"Accept cond."));
2925 html += inviteButton(helper, QLatin1String(
"counter"),
2926 i18nc(
"invitation counter proposal",
"Counter proposal"));
2929 html += inviteButton(helper, QLatin1String(
"decline"),
2930 i18nc(
"decline invitation",
"Decline"));
2933 if (!rsvpRec || (incidence && incidence->revision() > 0)) {
2935 html += inviteButton(helper, QLatin1String(
"delegate"),
2936 i18nc(
"delegate inviation to another",
"Delegate"));
2939 html += inviteButton(helper, QLatin1String(
"forward"), i18nc(
"forward request to another",
"Forward"));
2942 if (incidence && incidence->type() == Incidence::TypeEvent) {
2943 html += inviteButton(helper, QLatin1String(
"check_calendar"),
2944 i18nc(
"look for scheduling conflicts",
"Check my calendar"));
2951 InvitationFormatterHelper *helper)
2959 html += inviteButton(helper, QLatin1String(
"accept_counter"), i18n(
"Accept"));
2962 html += inviteButton(helper, QLatin1String(
"decline_counter"), i18n(
"Decline"));
2966 if (incidence->type() == Incidence::TypeTodo) {
2967 html += inviteButton(helper, QLatin1String(
"check_calendar"), i18n(
"Check my to-do list"));
2969 html += inviteButton(helper, QLatin1String(
"check_calendar"), i18n(
"Check my calendar"));
2976 InvitationFormatterHelper *helper)
2984 if (incidence->type() == Incidence::TypeTodo) {
2985 html += inviteLink(helper, QLatin1String(
"reply"),
2986 i18n(
"Record invitation in my to-do list"));
2988 html += inviteLink(helper, QLatin1String(
"reply"),
2989 i18n(
"Record invitation in my calendar"));
2995 static QString recordResponseButtons(
const Incidence::Ptr &incidence,
2996 InvitationFormatterHelper *helper)
3004 if (incidence->type() == Incidence::TypeTodo) {
3005 html += inviteLink(helper, QLatin1String(
"reply"),
3006 i18n(
"Record response in my to-do list"));
3008 html += inviteLink(helper, QLatin1String(
"reply"),
3009 i18n(
"Record response in my calendar"));
3016 InvitationFormatterHelper *helper)
3025 if (incidence->type() == Incidence::TypeTodo) {
3026 html += inviteButton(helper, QLatin1String(
"cancel"),
3027 i18n(
"Remove invitation from my to-do list"));
3029 html += inviteButton(helper, QLatin1String(
"cancel"),
3030 i18n(
"Remove invitation from my calendar"));
3041 static QString formatICalInvitationHelper(QString invitation,
3043 InvitationFormatterHelper *helper,
3045 KDateTime::Spec spec,
3046 const QString &sender,
3047 bool outlookCompareStyle)
3049 if (invitation.isEmpty()) {
3059 kDebug() <<
"Failed to parse the scheduling message";
3067 incBase->shiftTimes(mCalendar->timeSpec(), KDateTime::Spec::LocalZone());
3071 if (incBase && helper->calendar()) {
3072 existingIncidence = helper->calendar()->incidence(incBase->uid());
3074 if (!incidenceOwnedByMe(helper->calendar(), existingIncidence)) {
3075 existingIncidence.clear();
3077 if (!existingIncidence) {
3079 for (Incidence::List::ConstIterator it = list.begin(), end = list.end(); it != end; ++it) {
3080 if ((*it)->schedulingID() == incBase->uid() &&
3081 incidenceOwnedByMe(helper->calendar(), *it)) {
3082 existingIncidence = *it;
3093 int incRevision = 0;
3094 if (inc && inc->type() != Incidence::TypeFreeBusy) {
3099 QString html = QLatin1String(
"<div align=\"center\" style=\"border:solid 1px;\">");
3101 IncidenceFormatter::InvitationHeaderVisitor headerVisitor;
3103 if (!headerVisitor.act(inc, existingIncidence, msg, sender)) {
3106 html += htmlAddTag(QLatin1String(
"h3"), headerVisitor.result());
3108 if (outlookCompareStyle ||
3111 IncidenceFormatter::InvitationBodyVisitor bodyVisitor(noHtmlMode, spec);
3115 if (inc && existingIncidence &&
3116 incRevision < existingIncidence->revision()) {
3117 bodyOk = bodyVisitor.act(existingIncidence, inc, msg, sender);
3119 bodyOk = bodyVisitor.act(inc, existingIncidence, msg, sender);
3125 html += bodyVisitor.result();
3131 InvitationBodyVisitor bodyVisitor(noHtmlMode, spec);
3135 html += bodyVisitor.result();
3138 IncidenceFormatter::IncidenceCompareVisitor compareVisitor;
3139 if (compareVisitor.act(inc, existingIncidence)) {
3140 html += QLatin1String(
"<p align=\"left\">");
3141 if (senderIsOrganizer(inc, sender)) {
3142 html += i18n(
"The following changes have been made by the organizer:");
3143 }
else if (!sender.isEmpty()) {
3144 html += i18n(
"The following changes have been made by %1:", sender);
3146 html += i18n(
"The following changes have been made:");
3148 html += QLatin1String(
"</p>");
3149 html += compareVisitor.result();
3153 IncidenceCompareVisitor compareVisitor;
3154 if (compareVisitor.act(inc, existingIncidence)) {
3155 html += QLatin1String(
"<p align=\"left\">");
3156 if (!sender.isEmpty()) {
3157 html += i18n(
"The following changes have been made by %1:", sender);
3159 html += i18n(
"The following changes have been made by an attendee:");
3161 html += QLatin1String(
"</p>");
3162 html += compareVisitor.result();
3168 bool myInc = iamOrganizer(inc);
3171 bool rsvpRec =
false;
3175 if (!rsvpIncidence && inc && incRevision > 0) {
3176 rsvpIncidence = inc;
3178 if (rsvpIncidence) {
3179 ea = findMyAttendee(rsvpIncidence);
3182 (ea->status() == Attendee::Accepted ||
3183 ea->status() == Attendee::Declined ||
3184 ea->status() == Attendee::Tentative)) {
3191 bool isDelegated =
false;
3194 if (!inc->attendees().isEmpty()) {
3195 a = inc->attendees().first();
3199 isDelegated = (a->status() == Attendee::Delegated);
3200 role = Stringify::attendeeRole(a->role());
3204 bool rsvpReq = rsvpRequested(inc);
3207 if (rsvpRec && inc) {
3208 if (incRevision == 0) {
3209 tStr = i18n(
"Your <b>%1</b> response has been recorded",
3210 Stringify::attendeeStatus(ea->status()));
3212 tStr = i18n(
"Your status for this invitation is <b>%1</b>",
3213 Stringify::attendeeStatus(ea->status()));
3217 tStr = i18n(
"This invitation was canceled");
3218 }
else if (msg->method() ==
iTIPAdd) {
3219 tStr = i18n(
"This invitation was accepted");
3222 tStr = rsvpRequestedStr(rsvpReq, role);
3225 tStr = rsvpRequestedStr(rsvpReq, role);
3227 tStr = i18n(
"Awaiting delegation response");
3230 html += QLatin1String(
"<br>");
3231 html += QLatin1String(
"<i><u>") + tStr + QLatin1String(
"</u></i>");
3236 if (inc && incRevision == 0) {
3237 QString statStr = myStatusStr(inc);
3238 if (!statStr.isEmpty()) {
3239 html += QLatin1String(
"<br>");
3240 html += QLatin1String(
"<i>") + statStr + QLatin1String(
"</i>");
3247 html += QLatin1String(
"<p>");
3248 html += QLatin1String(
"<table border=\"0\" align=\"center\" cellspacing=\"4\"><tr>");
3250 switch (msg->method()) {
3256 if (inc && incRevision > 0 && (existingIncidence || !helper->calendar())) {
3257 html += recordButtons(inc, helper);
3262 html += responseButtons(inc, rsvpReq, rsvpRec, helper);
3264 html += responseButtons(inc,
false,
false, helper);
3271 html += cancelButtons(inc, helper);
3281 if (replyMeansCounter(inc)) {
3282 html += QLatin1String(
"<tr>") + counterButtons(inc, helper) + QLatin1String(
"</tr>");
3291 a = findDelegatedFromMyAttendee(inc);
3293 if (a->status() != Attendee::Accepted ||
3294 a->status() != Attendee::Tentative) {
3295 html += responseButtons(inc, rsvpReq, rsvpRec, helper);
3301 if (!inc->attendees().isEmpty()) {
3302 a = inc->attendees().first();
3304 if (a && helper->calendar()) {
3305 ea = findAttendee(existingIncidence, a->email());
3308 if (ea && (ea->status() != Attendee::NeedsAction) && (ea->status() == a->status())) {
3309 const QString tStr = i18n(
"The <b>%1</b> response has been recorded",
3310 Stringify::attendeeStatus(ea->status()));
3311 html += inviteButton(helper, QString(), htmlAddTag(QLatin1String(
"i"), tStr));
3314 html += recordResponseButtons(inc, helper);
3322 html += counterButtons(inc, helper);
3326 html += responseButtons(inc, rsvpReq, rsvpRec, helper);
3334 html += QLatin1String(
"</tr></table>");
3338 html += invitationRsvpList(existingIncidence, a);
3340 html += invitationAttendeeList(inc);
3344 html += QLatin1String(
"</div>");
3347 html += invitationAttachments(helper, inc);
3355 InvitationFormatterHelper *helper,
3356 bool outlookCompareStyle)
3358 return formatICalInvitationHelper(invitation, calendar, helper,
false,
3359 KSystemTimeZones::local(), QString(),
3360 outlookCompareStyle);
3365 InvitationFormatterHelper *helper,
3366 const QString &sender,
3367 bool outlookCompareStyle)
3369 return formatICalInvitationHelper(invitation, calendar, helper,
true,
3370 KSystemTimeZones::local(), sender,
3371 outlookCompareStyle);
3379 class KCalUtils::IncidenceFormatter::ToolTipVisitor :
public Visitor 3383 : mRichText(true), mSpec(KDateTime::Spec()), mResult(QLatin1String(
"")) {}
3387 const QDate &date=QDate(),
bool richText=
true,
3388 KDateTime::Spec spec=KDateTime::Spec())
3390 mCalendar = calendar;
3393 mRichText = richText;
3395 mResult = QLatin1String(
"");
3396 return incidence ? incidence->accept(*
this, incidence) :
false;
3400 const QDate &date=QDate(),
bool richText=
true,
3401 KDateTime::Spec spec=KDateTime::Spec())
3403 mLocation = location;
3405 mRichText = richText;
3407 mResult = QLatin1String(
"");
3408 return incidence ? incidence->accept(*
this, incidence) :
false;
3411 QString result()
const {
3421 QString dateRangeText(
const Event::Ptr &event,
const QDate &date);
3422 QString dateRangeText(
const Todo::Ptr &todo,
const QDate &date);
3426 QString generateToolTip(
const Incidence::Ptr &incidence, QString dtRangeText);
3433 KDateTime::Spec mSpec;
3437 QString IncidenceFormatter::ToolTipVisitor::dateRangeText(
const Event::Ptr &event,
3444 KDateTime startDt =
event->
dtStart();
3445 KDateTime endDt =
event->dtEnd();
3446 if (event->recurs()) {
3447 if (date.isValid()) {
3448 KDateTime kdt(date, QTime(0, 0, 0), KSystemTimeZones::local());
3449 int diffDays = startDt.daysTo(kdt);
3450 kdt = kdt.addSecs(-1);
3451 startDt.setDate(event->recurrence()->getNextDateTime(kdt).date());
3452 if (event->hasEndDate()) {
3453 endDt = endDt.addDays(diffDays);
3454 if (startDt > endDt) {
3455 startDt.setDate(event->recurrence()->getPreviousDateTime(kdt).date());
3456 endDt = startDt.addDays(event->dtStart().daysTo(event->dtEnd()));
3462 if (event->isMultiDay()) {
3464 ret += QLatin1String(
"<br>") + i18nc(
"Event start",
"<i>From:</i> %1", tmp);
3467 ret += QLatin1String(
"<br>") + i18nc(
"Event end",
"<i>To:</i> %1", tmp);
3471 ret += QLatin1String(
"<br>") +
3472 i18n(
"<i>Date:</i> %1",
dateToString(startDt,
false, mSpec));
3473 if (!event->allDay()) {
3474 const QString dtStartTime =
timeToString(startDt,
true, mSpec);
3475 const QString dtEndTime =
timeToString(endDt,
true, mSpec);
3476 if (dtStartTime == dtEndTime) {
3478 tmp = QLatin1String(
"<br>") +
3479 i18nc(
"time for event",
"<i>Time:</i> %1",
3482 tmp = QLatin1String(
"<br>") +
3483 i18nc(
"time range for event",
3484 "<i>Time:</i> %1 - %2",
3485 dtStartTime, dtEndTime);
3490 return ret.replace(QLatin1Char(
' '), QLatin1String(
" "));
3493 QString IncidenceFormatter::ToolTipVisitor::dateRangeText(
const Todo::Ptr &todo,
3498 if (todo->hasStartDate()) {
3499 KDateTime startDt = todo->dtStart();
3500 if (todo->recurs() && date.isValid()) {
3501 startDt.setDate(date);
3503 ret += QLatin1String(
"<br>") +
3504 i18n(
"<i>Start:</i> %1",
dateToString(startDt,
false, mSpec));
3507 if (todo->hasDueDate()) {
3508 KDateTime dueDt = todo->dtDue();
3509 if (todo->recurs() && date.isValid()) {
3510 KDateTime kdt(date, QTime(0, 0, 0), KSystemTimeZones::local());
3511 kdt = kdt.addSecs(-1);
3512 dueDt.setDate(todo->recurrence()->getNextDateTime(kdt).date());
3514 ret += QLatin1String(
"<br>") +
3515 i18n(
"<i>Due:</i> %1",
3521 if (todo->priority() > 0) {
3522 ret += QLatin1String(
"<br>");
3523 ret += QLatin1String(
"<i>") + i18n(
"Priority:") + QLatin1String(
"</i>") + QLatin1String(
" ");
3524 ret += QString::number(todo->priority());
3527 ret += QLatin1String(
"<br>");
3528 if (todo->isCompleted()) {
3529 ret += QLatin1String(
"<i>") + i18nc(
"Completed: date",
"Completed:") + QLatin1String(
"</i>") + QLatin1String(
" ");
3532 ret += QLatin1String(
"<i>")+ i18n(
"Percent Done:") + QLatin1String(
"</i>") + QLatin1String(
" ");
3533 ret += i18n(
"%1%", todo->percentComplete());
3536 return ret.replace(QLatin1Char(
' '), QLatin1String(
" "));
3539 QString IncidenceFormatter::ToolTipVisitor::dateRangeText(
const Journal::Ptr &journal)
3543 if (journal->dtStart().isValid()) {
3544 ret += QLatin1String(
"<br>") +
3545 i18n(
"<i>Date:</i> %1",
dateToString(journal->dtStart(),
false, mSpec));
3547 return ret.replace(QLatin1Char(
' '), QLatin1String(
" "));
3550 QString IncidenceFormatter::ToolTipVisitor::dateRangeText(
const FreeBusy::Ptr &fb)
3554 ret = QLatin1String(
"<br>") +
3555 i18n(
"<i>Period start:</i> %1",
3557 ret += QLatin1String(
"<br>") +
3558 i18n(
"<i>Period start:</i> %1",
3560 return ret.replace(QLatin1Char(
' '), QLatin1String(
" "));
3563 bool IncidenceFormatter::ToolTipVisitor::visit(
Event::Ptr event)
3565 mResult = generateToolTip(event, dateRangeText(event, mDate));
3566 return !mResult.isEmpty();
3569 bool IncidenceFormatter::ToolTipVisitor::visit(
Todo::Ptr todo)
3571 mResult = generateToolTip(todo, dateRangeText(todo, mDate));
3572 return !mResult.isEmpty();
3575 bool IncidenceFormatter::ToolTipVisitor::visit(
Journal::Ptr journal)
3577 mResult = generateToolTip(journal, dateRangeText(journal));
3578 return !mResult.isEmpty();
3581 bool IncidenceFormatter::ToolTipVisitor::visit(
FreeBusy::Ptr fb)
3584 mResult = QLatin1String(
"<qt><b>") +
3585 i18n(
"Free/Busy information for %1", fb->organizer()->fullName()) +
3586 QLatin1String(
"</b>");
3587 mResult += dateRangeText(fb);
3588 mResult += QLatin1String(
"</qt>");
3589 return !mResult.isEmpty();
3592 static QString tooltipPerson(
const QString &email,
const QString &name,
Attendee::PartStat status)
3595 const QString printName = searchName(email, name);
3598 const QString iconPath = rsvpStatusIconPath(status);
3601 QString personString;
3602 if (!iconPath.isEmpty()) {
3603 personString += QLatin1String(
"<img valign=\"top\" src=\"") + iconPath + QLatin1String(
"\">") + QLatin1String(
" ");
3605 if (status != Attendee::None) {
3606 personString += i18nc(
"attendee name (attendee status)",
"%1 (%2)",
3607 printName.isEmpty() ? email : printName,
3608 Stringify::attendeeStatus(status));
3610 personString += i18n(
"%1", printName.isEmpty() ? email : printName);
3612 return personString;
3615 static QString tooltipFormatOrganizer(
const QString &email,
const QString &name)
3618 const QString printName = searchName(email, name);
3621 const QString iconPath =
3622 KIconLoader::global()->iconPath(QLatin1String(
"meeting-organizer"), KIconLoader::Small);
3625 QString personString;
3626 personString += QLatin1String(
"<img valign=\"top\" src=\"") + iconPath + QLatin1String(
"\">") + QLatin1String(
" ");
3627 personString += (printName.isEmpty() ? email : printName);
3628 return personString;
3631 static QString tooltipFormatAttendeeRoleList(
const Incidence::Ptr &incidence,
3635 const QString etc = i18nc(
"elipsis",
"...");
3639 Attendee::List::ConstIterator it;
3642 for (it = attendees.constBegin(); it != attendees.constEnd(); ++it) {
3644 if (a->role() != role) {
3648 if (attendeeIsOrganizer(incidence, a)) {
3652 if (i == maxNumAtts) {
3653 tmpStr += QLatin1String(
" ") + etc;
3656 tmpStr += QLatin1String(
" ") + tooltipPerson(a->email(), a->name(),
3657 showStatus ? a->status() : Attendee::None);
3658 if (!a->delegator().isEmpty()) {
3659 tmpStr += i18n(
" (delegated by %1)", a->delegator());
3661 if (!a->delegate().isEmpty()) {
3662 tmpStr += i18n(
" (delegated to %1)", a->delegate());
3664 tmpStr += QLatin1String(
"<br>");
3667 if (tmpStr.endsWith(QLatin1String(
"<br>"))) {
3673 static QString tooltipFormatAttendees(
const Calendar::Ptr &calendar,
3676 QString tmpStr, str;
3679 int attendeeCount = incidence->attendees().count();
3680 if (attendeeCount > 1 ||
3681 (attendeeCount == 1 &&
3682 !attendeeIsOrganizer(incidence, incidence->attendees().first()))) {
3683 tmpStr += QLatin1String(
"<i>") + i18n(
"Organizer:") + QLatin1String(
"</i>") + QLatin1String(
"<br>");
3684 tmpStr += QLatin1String(
" ") + tooltipFormatOrganizer(incidence->organizer()->email(),
3685 incidence->organizer()->name());
3690 const bool showStatus = attendeeCount > 0 && incOrganizerOwnsCalendar(calendar, incidence);
3693 str = tooltipFormatAttendeeRoleList(incidence, Attendee::Chair, showStatus);
3694 if (!str.isEmpty()) {
3695 tmpStr += QLatin1String(
"<br><i>") + i18n(
"Chair:") + QLatin1String(
"</i>") + QLatin1String(
"<br>");
3700 str = tooltipFormatAttendeeRoleList(incidence, Attendee::ReqParticipant, showStatus);
3701 if (!str.isEmpty()) {
3702 tmpStr += QLatin1String(
"<br><i>") + i18n(
"Required Participants:") + QLatin1String(
"</i>") + QLatin1String(
"<br>");
3707 str = tooltipFormatAttendeeRoleList(incidence, Attendee::OptParticipant, showStatus);
3708 if (!str.isEmpty()) {
3709 tmpStr += QLatin1String(
"<br><i>") + i18n(
"Optional Participants:") + QLatin1String(
"</i>") + QLatin1String(
"<br>");
3714 str = tooltipFormatAttendeeRoleList(incidence, Attendee::NonParticipant, showStatus);
3715 if (!str.isEmpty()) {
3716 tmpStr += QLatin1String(
"<br><i>") + i18n(
"Observers:") + QLatin1String(
"</i>") + QLatin1String(
"<br>");
3723 QString IncidenceFormatter::ToolTipVisitor::generateToolTip(
const Incidence::Ptr &incidence,
3724 QString dtRangeText)
3726 int maxDescLen = 120;
3733 QString tmp = QLatin1String(
"<qt>");
3736 tmp += QLatin1String(
"<b>") + incidence->richSummary() + QLatin1String(
"</b>");
3737 tmp += QLatin1String(
"<hr>");
3739 QString calStr = mLocation;
3743 if (!calStr.isEmpty()) {
3744 tmp += QLatin1String(
"<i>") + i18n(
"Calendar:") + QLatin1String(
"</i>") + QLatin1String(
" ");
3750 if (!incidence->location().isEmpty()) {
3751 tmp += QLatin1String(
"<br>");
3752 tmp += QLatin1String(
"<i>") + i18n(
"Location:") + QLatin1String(
"</i>") + QLatin1String(
" ");
3753 tmp += incidence->richLocation();
3757 if (!durStr.isEmpty()) {
3758 tmp += QLatin1String(
"<br>");
3759 tmp += QLatin1String(
"<i>") + i18n(
"Duration:") + QLatin1String(
"</i>") + QLatin1String(
" ");
3763 if (incidence->recurs()) {
3764 tmp += QLatin1String(
"<br>");
3765 tmp += QLatin1String(
"<i>") + i18n(
"Recurrence:") + QLatin1String(
"</i>") + QLatin1String(
" ");
3769 if (incidence->hasRecurrenceId()) {
3770 tmp += QLatin1String(
"<br>");
3771 tmp += QLatin1String(
"<i>") + i18n(
"Recurrence:") + QLatin1String(
"</i>") + QLatin1String(
" ");
3772 tmp += i18n(
"Exception");
3775 if (!incidence->description().isEmpty()) {
3776 QString desc(incidence->description());
3777 if (!incidence->descriptionIsRich()) {
3778 if (desc.length() > maxDescLen) {
3779 desc = desc.left(maxDescLen) + i18nc(
"elipsis",
"...");
3781 desc = Qt::escape(desc).replace(QLatin1Char(
'\n'), QLatin1String(
"<br>"));
3785 tmp += QLatin1String(
"<hr>");
3786 tmp += QLatin1String(
"<i>") + i18n(
"Description:") + QLatin1String(
"</i>") + QLatin1String(
"<br>");
3788 tmp += QLatin1String(
"<hr>");
3791 int reminderCount = incidence->alarms().count();
3792 if (reminderCount > 0 && incidence->hasEnabledAlarms()) {
3793 tmp += QLatin1String(
"<br>");
3794 tmp += QLatin1String(
"<i>") + i18np(
"Reminder:",
"Reminders:", reminderCount) + QLatin1String(
"</i>") + QLatin1String(
" ");
3798 tmp += QLatin1String(
"<br>");
3799 tmp += tooltipFormatAttendees(mCalendar, incidence);
3801 int categoryCount = incidence->categories().count();
3802 if (categoryCount > 0) {
3803 tmp += QLatin1String(
"<br>");
3804 tmp += QLatin1String(
"<i>") + i18np(
"Category:",
"Categories:", categoryCount) + QLatin1String(
"</i>") +QLatin1String(
" ");
3805 tmp += incidence->categories().join(QLatin1String(
", "));
3808 tmp += QLatin1String(
"</qt>");
3817 KDateTime::Spec spec)
3820 if (incidence && v.act(sourceName, incidence, date, richText, spec)) {
3832 static QString mailBodyIncidence(
const Incidence::Ptr &incidence)
3835 if (!incidence->summary().isEmpty()) {
3836 body += i18n(
"Summary: %1\n", incidence->richSummary());
3838 if (!incidence->organizer()->isEmpty()) {
3839 body += i18n(
"Organizer: %1\n", incidence->organizer()->fullName());
3841 if (!incidence->location().isEmpty()) {
3842 body += i18n(
"Location: %1\n", incidence->richLocation());
3849 class KCalUtils::IncidenceFormatter::MailBodyVisitor :
public Visitor 3853 : mSpec(KDateTime::Spec()), mResult(QLatin1String(
"")) {}
3858 mResult = QLatin1String(
"");
3859 return incidence ? incidence->accept(*
this, incidence) :
false;
3861 QString result()
const 3872 mResult = i18n(
"This is a Free Busy Object");
3873 return !mResult.isEmpty();
3876 KDateTime::Spec mSpec;
3880 bool IncidenceFormatter::MailBodyVisitor::visit(
Event::Ptr event)
3882 QString recurrence[]= {
3883 i18nc(
"no recurrence",
"None"),
3884 i18nc(
"event recurs by minutes",
"Minutely"),
3885 i18nc(
"event recurs by hours",
"Hourly"),
3886 i18nc(
"event recurs by days",
"Daily"),
3887 i18nc(
"event recurs by weeks",
"Weekly"),
3888 i18nc(
"event recurs same position (e.g. first monday) each month",
"Monthly Same Position"),
3889 i18nc(
"event recurs same day each month",
"Monthly Same Day"),
3890 i18nc(
"event recurs same month each year",
"Yearly Same Month"),
3891 i18nc(
"event recurs same day each year",
"Yearly Same Day"),
3892 i18nc(
"event recurs same position (e.g. first monday) each year",
"Yearly Same Position")
3895 mResult = mailBodyIncidence(event);
3896 mResult += i18n(
"Start Date: %1\n",
dateToString(event->dtStart(),
true, mSpec));
3897 if (!event->allDay()) {
3898 mResult += i18n(
"Start Time: %1\n",
timeToString(event->dtStart(),
true, mSpec));
3900 if (event->dtStart() !=
event->dtEnd()) {
3901 mResult += i18n(
"End Date: %1\n",
dateToString(event->dtEnd(),
true, mSpec));
3903 if (!event->allDay()) {
3904 mResult += i18n(
"End Time: %1\n",
timeToString(event->dtEnd(),
true, mSpec));
3906 if (event->recurs()) {
3909 mResult += i18n(
"Recurs: %1\n", recurrence[ recur->
recurrenceType() ]);
3910 mResult += i18n(
"Frequency: %1\n", event->recurrence()->frequency());
3913 mResult += i18np(
"Repeats once",
"Repeats %1 times", recur->
duration());
3914 mResult += QLatin1Char(
'\n');
3919 if (event->allDay()) {
3920 endstr = KGlobal::locale()->formatDate(recur->
endDate());
3922 endstr = KGlobal::locale()->formatDateTime(recur->
endDateTime().dateTime());
3924 mResult += i18n(
"Repeat until: %1\n", endstr);
3926 mResult += i18n(
"Repeats forever\n");
3931 if (!event->description().isEmpty()) {
3933 if (event->descriptionIsRich() ||
3934 event->description().startsWith(QLatin1String(
"<!DOCTYPE HTML")))
3936 descStr = cleanHtml(event->description());
3938 descStr =
event->description();
3940 if (!descStr.isEmpty()) {
3941 mResult += i18n(
"Details:\n%1\n", descStr);
3944 return !mResult.isEmpty();
3947 bool IncidenceFormatter::MailBodyVisitor::visit(
Todo::Ptr todo)
3949 mResult = mailBodyIncidence(todo);
3951 if (todo->hasStartDate() && todo->dtStart().isValid()) {
3952 mResult += i18n(
"Start Date: %1\n",
dateToString(todo->dtStart(
false),
true, mSpec));
3953 if (!todo->allDay()) {
3954 mResult += i18n(
"Start Time: %1\n",
timeToString(todo->dtStart(
false),
true, mSpec));
3957 if (todo->hasDueDate() && todo->dtDue().isValid()) {
3958 mResult += i18n(
"Due Date: %1\n",
dateToString(todo->dtDue(),
true, mSpec));
3959 if (!todo->allDay()) {
3960 mResult += i18n(
"Due Time: %1\n",
timeToString(todo->dtDue(),
true, mSpec));
3963 QString details = todo->richDescription();
3964 if (!details.isEmpty()) {
3965 mResult += i18n(
"Details:\n%1\n", details);
3967 return !mResult.isEmpty();
3970 bool IncidenceFormatter::MailBodyVisitor::visit(
Journal::Ptr journal)
3972 mResult = mailBodyIncidence(journal);
3973 mResult += i18n(
"Date: %1\n",
dateToString(journal->dtStart(),
true, mSpec));
3974 if (!journal->allDay()) {
3975 mResult += i18n(
"Time: %1\n",
timeToString(journal->dtStart(),
true, mSpec));
3977 if (!journal->description().isEmpty()) {
3978 mResult += i18n(
"Text of the journal:\n%1\n", journal->richDescription());
3980 return !mResult.isEmpty();
3985 KDateTime::Spec spec)
3992 if (v.act(incidence, spec)) {
4002 if (incidence->allDay()) {
4003 endstr = KGlobal::locale()->formatDate(incidence->recurrence()->endDate());
4005 endstr = KGlobal::locale()->formatDateTime(incidence->recurrence()->endDateTime());
4017 if (incidence->hasRecurrenceId()) {
4018 return QLatin1String(
"Recurrence exception");
4021 if (!incidence->recurs()) {
4022 return i18n(
"No recurrence");
4024 static QStringList dayList;
4025 if (dayList.isEmpty()) {
4026 dayList.append(i18n(
"31st Last"));
4027 dayList.append(i18n(
"30th Last"));
4028 dayList.append(i18n(
"29th Last"));
4029 dayList.append(i18n(
"28th Last"));
4030 dayList.append(i18n(
"27th Last"));
4031 dayList.append(i18n(
"26th Last"));
4032 dayList.append(i18n(
"25th Last"));
4033 dayList.append(i18n(
"24th Last"));
4034 dayList.append(i18n(
"23rd Last"));
4035 dayList.append(i18n(
"22nd Last"));
4036 dayList.append(i18n(
"21st Last"));
4037 dayList.append(i18n(
"20th Last"));
4038 dayList.append(i18n(
"19th Last"));
4039 dayList.append(i18n(
"18th Last"));
4040 dayList.append(i18n(
"17th Last"));
4041 dayList.append(i18n(
"16th Last"));
4042 dayList.append(i18n(
"15th Last"));
4043 dayList.append(i18n(
"14th Last"));
4044 dayList.append(i18n(
"13th Last"));
4045 dayList.append(i18n(
"12th Last"));
4046 dayList.append(i18n(
"11th Last"));
4047 dayList.append(i18n(
"10th Last"));
4048 dayList.append(i18n(
"9th Last"));
4049 dayList.append(i18n(
"8th Last"));
4050 dayList.append(i18n(
"7th Last"));
4051 dayList.append(i18n(
"6th Last"));
4052 dayList.append(i18n(
"5th Last"));
4053 dayList.append(i18n(
"4th Last"));
4054 dayList.append(i18n(
"3rd Last"));
4055 dayList.append(i18n(
"2nd Last"));
4056 dayList.append(i18nc(
"last day of the month",
"Last"));
4057 dayList.append(i18nc(
"unknown day of the month",
"unknown"));
4058 dayList.append(i18n(
"1st"));
4059 dayList.append(i18n(
"2nd"));
4060 dayList.append(i18n(
"3rd"));
4061 dayList.append(i18n(
"4th"));
4062 dayList.append(i18n(
"5th"));
4063 dayList.append(i18n(
"6th"));
4064 dayList.append(i18n(
"7th"));
4065 dayList.append(i18n(
"8th"));
4066 dayList.append(i18n(
"9th"));
4067 dayList.append(i18n(
"10th"));
4068 dayList.append(i18n(
"11th"));
4069 dayList.append(i18n(
"12th"));
4070 dayList.append(i18n(
"13th"));
4071 dayList.append(i18n(
"14th"));
4072 dayList.append(i18n(
"15th"));
4073 dayList.append(i18n(
"16th"));
4074 dayList.append(i18n(
"17th"));
4075 dayList.append(i18n(
"18th"));
4076 dayList.append(i18n(
"19th"));
4077 dayList.append(i18n(
"20th"));
4078 dayList.append(i18n(
"21st"));
4079 dayList.append(i18n(
"22nd"));
4080 dayList.append(i18n(
"23rd"));
4081 dayList.append(i18n(
"24th"));
4082 dayList.append(i18n(
"25th"));
4083 dayList.append(i18n(
"26th"));
4084 dayList.append(i18n(
"27th"));
4085 dayList.append(i18n(
"28th"));
4086 dayList.append(i18n(
"29th"));
4087 dayList.append(i18n(
"30th"));
4088 dayList.append(i18n(
"31st"));
4091 const int weekStart = KGlobal::locale()->weekStartDay();
4093 const KCalendarSystem *calSys = KGlobal::locale()->calendar();
4097 QString txt, recurStr;
4098 static QString noRecurrence = i18n(
"No recurrence");
4100 case Recurrence::rNone:
4101 return noRecurrence;
4103 case Recurrence::rMinutely:
4105 recurStr = i18np(
"Recurs every minute until %2",
4106 "Recurs every %1 minutes until %2",
4107 recur->
frequency(), recurEnd(incidence));
4109 recurStr += i18nc(
"number of occurrences",
4110 " (<numid>%1</numid> occurrences)",
4114 recurStr = i18np(
"Recurs every minute",
4115 "Recurs every %1 minutes", recur->
frequency());
4119 case Recurrence::rHourly:
4121 recurStr = i18np(
"Recurs hourly until %2",
4122 "Recurs every %1 hours until %2",
4123 recur->
frequency(), recurEnd(incidence));
4125 recurStr += i18nc(
"number of occurrences",
4126 " (<numid>%1</numid> occurrences)",
4130 recurStr = i18np(
"Recurs hourly",
"Recurs every %1 hours", recur->
frequency());
4134 case Recurrence::rDaily:
4136 recurStr = i18np(
"Recurs daily until %2",
4137 "Recurs every %1 days until %2",
4138 recur->
frequency(), recurEnd(incidence));
4140 recurStr += i18nc(
"number of occurrences",
4141 " (<numid>%1</numid> occurrences)",
4145 recurStr = i18np(
"Recurs daily",
"Recurs every %1 days", recur->
frequency());
4149 case Recurrence::rWeekly:
4151 bool addSpace =
false;
4152 for (
int i = 0; i < 7; ++i) {
4153 if (recur->
days().testBit((i + weekStart + 6) % 7)) {
4155 dayNames.append(i18nc(
"separator for list of days",
", "));
4157 dayNames.append(calSys->weekDayName(((i + weekStart + 6) % 7) + 1,
4158 KCalendarSystem::ShortDayName));
4162 if (dayNames.isEmpty()) {
4163 dayNames = i18nc(
"Recurs weekly on no days",
"no days");
4166 recurStr = i18ncp(
"Recurs weekly on [list of days] until end-date",
4167 "Recurs weekly on %2 until %3",
4168 "Recurs every <numid>%1</numid> weeks on %2 until %3",
4169 recur->
frequency(), dayNames, recurEnd(incidence));
4171 recurStr += i18nc(
"number of occurrences",
4172 " (<numid>%1</numid> occurrences)",
4176 recurStr = i18ncp(
"Recurs weekly on [list of days]",
4177 "Recurs weekly on %2",
4178 "Recurs every <numid>%1</numid> weeks on %2",
4183 case Recurrence::rMonthlyPos:
4188 recurStr = i18ncp(
"Recurs every N months on the [2nd|3rd|...]" 4189 " weekdayname until end-date",
4190 "Recurs every month on the %2 %3 until %4",
4191 "Recurs every <numid>%1</numid> months on the %2 %3 until %4",
4193 dayList[rule.pos() + 31],
4194 calSys->weekDayName(rule.day(), KCalendarSystem::LongDayName),
4195 recurEnd(incidence));
4197 recurStr += i18nc(
"number of occurrences",
4198 " (<numid>%1</numid> occurrences)",
4202 recurStr = i18ncp(
"Recurs every N months on the [2nd|3rd|...] weekdayname",
4203 "Recurs every month on the %2 %3",
4204 "Recurs every %1 months on the %2 %3",
4206 dayList[rule.pos() + 31],
4207 calSys->weekDayName(rule.day(), KCalendarSystem::LongDayName));
4212 case Recurrence::rMonthlyDay:
4217 recurStr = i18ncp(
"Recurs monthly on the [1st|2nd|...] day until end-date",
4218 "Recurs monthly on the %2 day until %3",
4219 "Recurs every %1 months on the %2 day until %3",
4222 recurEnd(incidence));
4224 recurStr += i18nc(
"number of occurrences",
4225 " (<numid>%1</numid> occurrences)",
4229 recurStr = i18ncp(
"Recurs monthly on the [1st|2nd|...] day",
4230 "Recurs monthly on the %2 day",
4231 "Recurs every <numid>%1</numid> month on the %2 day",
4233 dayList[days + 31]);
4238 case Recurrence::rYearlyMonth:
4242 recurStr = i18ncp(
"Recurs Every N years on month-name [1st|2nd|...]" 4244 "Recurs yearly on %2 %3 until %4",
4245 "Recurs every %1 years on %2 %3 until %4",
4249 recurEnd(incidence));
4251 recurStr += i18nc(
"number of occurrences",
4252 " (<numid>%1</numid> occurrences)",
4258 recurStr = i18ncp(
"Recurs Every N years on month-name [1st|2nd|...]",
4259 "Recurs yearly on %2 %3",
4260 "Recurs every %1 years on %2 %3",
4267 recurStr = i18nc(
"Recurs Every year on month-name [1st|2nd|...]",
4268 "Recurs yearly on %1 %2",
4271 dayList[ recur->
startDate().day() + 31 ]);
4273 recurStr = i18nc(
"Recurs Every year on month-name [1st|2nd|...]",
4274 "Recurs yearly on %1 %2",
4275 calSys->monthName(recur->
startDate().month(),
4277 dayList[ recur->
startDate().day() + 31 ]);
4283 case Recurrence::rYearlyDay:
4284 if (!recur->
yearDays().isEmpty()) {
4286 recurStr = i18ncp(
"Recurs every N years on day N until end-date",
4287 "Recurs every year on day <numid>%2</numid> until %3",
4288 "Recurs every <numid>%1</numid> years" 4289 " on day <numid>%2</numid> until %3",
4292 recurEnd(incidence));
4294 recurStr += i18nc(
"number of occurrences",
4295 " (<numid>%1</numid> occurrences)",
4299 recurStr = i18ncp(
"Recurs every N YEAR[S] on day N",
4300 "Recurs every year on day <numid>%2</numid>",
4301 "Recurs every <numid>%1</numid> years" 4302 " on day <numid>%2</numid>",
4307 case Recurrence::rYearlyPos:
4312 recurStr = i18ncp(
"Every N years on the [2nd|3rd|...] weekdayname " 4313 "of monthname until end-date",
4314 "Every year on the %2 %3 of %4 until %5",
4315 "Every <numid>%1</numid> years on the %2 %3 of %4" 4318 dayList[rule.pos() + 31],
4319 calSys->weekDayName(rule.day(), KCalendarSystem::LongDayName),
4321 recurEnd(incidence));
4323 recurStr += i18nc(
"number of occurrences",
4324 " (<numid>%1</numid> occurrences)",
4328 recurStr = i18ncp(
"Every N years on the [2nd|3rd|...] weekdayname " 4330 "Every year on the %2 %3 of %4",
4331 "Every <numid>%1</numid> years on the %2 %3 of %4",
4333 dayList[rule.pos() + 31],
4334 calSys->weekDayName(rule.day(), KCalendarSystem::LongDayName),
4342 if (recurStr.isEmpty()) {
4343 recurStr = i18n(
"Incidence recurs");
4348 DateTimeList::ConstIterator il;
4350 for (il = l.constBegin(); il != l.constEnd(); ++il) {
4352 case Recurrence::rMinutely:
4353 exStr << i18n(
"minute %1", (*il).time().minute());
4355 case Recurrence::rHourly:
4356 exStr << KGlobal::locale()->formatTime((*il).time());
4358 case Recurrence::rDaily:
4359 exStr << KGlobal::locale()->formatDate((*il).date(), KLocale::ShortDate);
4361 case Recurrence::rWeekly:
4362 exStr << calSys->weekDayName((*il).date(), KCalendarSystem::ShortDayName);
4364 case Recurrence::rMonthlyPos:
4365 exStr << KGlobal::locale()->formatDate((*il).date(), KLocale::ShortDate);
4367 case Recurrence::rMonthlyDay:
4368 exStr << KGlobal::locale()->formatDate((*il).date(), KLocale::ShortDate);
4370 case Recurrence::rYearlyMonth:
4371 exStr << calSys->monthName((*il).date(), KCalendarSystem::LongName);
4373 case Recurrence::rYearlyDay:
4374 exStr << KGlobal::locale()->formatDate((*il).date(), KLocale::ShortDate);
4376 case Recurrence::rYearlyPos:
4377 exStr << KGlobal::locale()->formatDate((*il).date(), KLocale::ShortDate);
4383 DateList::ConstIterator dl;
4384 for (dl = d.constBegin(); dl != d.constEnd(); ++dl) {
4386 case Recurrence::rDaily:
4387 exStr << KGlobal::locale()->formatDate((*dl), KLocale::ShortDate);
4389 case Recurrence::rWeekly:
4392 if (exStr.isEmpty()) {
4393 exStr << i18np(
"1 day",
"%1 days", recur->exDates().count());
4396 case Recurrence::rMonthlyPos:
4397 exStr << KGlobal::locale()->formatDate((*dl), KLocale::ShortDate);
4399 case Recurrence::rMonthlyDay:
4400 exStr << KGlobal::locale()->formatDate((*dl), KLocale::ShortDate);
4402 case Recurrence::rYearlyMonth:
4403 exStr << calSys->monthName((*dl), KCalendarSystem::LongName);
4405 case Recurrence::rYearlyDay:
4406 exStr << KGlobal::locale()->formatDate((*dl), KLocale::ShortDate);
4408 case Recurrence::rYearlyPos:
4409 exStr << KGlobal::locale()->formatDate((*dl), KLocale::ShortDate);
4414 if (!exStr.isEmpty()) {
4415 recurStr = i18n(
"%1 (excluding %2)", recurStr, exStr.join(QLatin1String(
",")));
4423 const KDateTime::Spec &spec)
4425 if (spec.isValid()) {
4428 if (spec.timeZone() != KSystemTimeZones::local()) {
4429 timeZone = QLatin1Char(
' ') + spec.timeZone().name();
4432 return KGlobal::locale()->formatTime(date.toTimeSpec(spec).time(), !shortfmt) + timeZone;
4434 return KGlobal::locale()->formatTime(date.time(), !shortfmt);
4440 const KDateTime::Spec &spec)
4442 if (spec.isValid()) {
4445 if (spec.timeZone() != KSystemTimeZones::local()) {
4446 timeZone = QLatin1Char(
' ') + spec.timeZone().name();
4450 KGlobal::locale()->formatDate(date.toTimeSpec(spec).date(),
4451 (shortfmt ? KLocale::ShortDate : KLocale::LongDate)) +
4455 KGlobal::locale()->formatDate(date.date(),
4456 (shortfmt ? KLocale::ShortDate : KLocale::LongDate));
4463 const KDateTime::Spec &spec)
4469 if (spec.isValid()) {
4471 if (spec.timeZone() != KSystemTimeZones::local()) {
4472 timeZone = QLatin1Char(
' ') + spec.timeZone().name();
4475 return KGlobal::locale()->formatDateTime(
4476 date.toTimeSpec(spec).dateTime(),
4477 (shortfmt ? KLocale::ShortDate : KLocale::LongDate)) + timeZone;
4479 return KGlobal::locale()->formatDateTime(
4481 (shortfmt ? KLocale::ShortDate : KLocale::LongDate));
4489 Q_UNUSED(incidence);
4493 static QString secs2Duration(
int secs)
4496 int days = secs / 86400;
4498 tmp += i18np(
"1 day",
"%1 days", days);
4499 tmp += QLatin1Char(
' ');
4500 secs -= (days * 86400);
4502 int hours = secs / 3600;
4504 tmp += i18np(
"1 hour",
"%1 hours", hours);
4505 tmp += QLatin1Char(
' ');
4506 secs -= (hours * 3600);
4508 int mins = secs / 60;
4510 tmp += i18np(
"1 minute",
"%1 minutes", mins);
4518 if (incidence->type() == Incidence::TypeEvent) {
4520 if (event->hasEndDate()) {
4521 if (!event->allDay()) {
4522 tmp = secs2Duration(event->dtStart().secsTo(event->dtEnd()));
4524 tmp = i18np(
"1 day",
"%1 days",
4525 event->dtStart().date().daysTo(event->dtEnd().date()) + 1);
4528 tmp = i18n(
"forever");
4530 }
else if (incidence->type() == Incidence::TypeTodo) {
4532 if (todo->hasDueDate()) {
4533 if (todo->hasStartDate()) {
4534 if (!todo->allDay()) {
4535 tmp = secs2Duration(todo->dtStart().secsTo(todo->dtDue()));
4537 tmp = i18np(
"1 day",
"%1 days",
4538 todo->dtStart().date().daysTo(todo->dtDue().date()) + 1);
4556 Alarm::List::ConstIterator it;
4557 for (it = alarms.constBegin(); it != alarms.constEnd(); ++it) {
4560 QString remStr, atStr, offsetStr;
4561 if (alarm->hasTime()) {
4563 if (alarm->time().isValid()) {
4564 atStr = KGlobal::locale()->formatDateTime(alarm->time());
4566 }
else if (alarm->hasStartOffset()) {
4567 offset = alarm->startOffset().asSeconds();
4570 offsetStr = i18nc(
"N days/hours/minutes before the start datetime",
4571 "%1 before the start", secs2Duration(offset));
4572 }
else if (offset > 0) {
4573 offsetStr = i18nc(
"N days/hours/minutes after the start datetime",
4574 "%1 after the start", secs2Duration(offset));
4576 if (incidence->dtStart().isValid()) {
4577 atStr = KGlobal::locale()->formatDateTime(incidence->dtStart());
4580 }
else if (alarm->hasEndOffset()) {
4581 offset = alarm->endOffset().asSeconds();
4584 if (incidence->type() == Incidence::TypeTodo) {
4585 offsetStr = i18nc(
"N days/hours/minutes before the due datetime",
4586 "%1 before the to-do is due", secs2Duration(offset));
4588 offsetStr = i18nc(
"N days/hours/minutes before the end datetime",
4589 "%1 before the end", secs2Duration(offset));
4591 }
else if (offset > 0) {
4592 if (incidence->type() == Incidence::TypeTodo) {
4593 offsetStr = i18nc(
"N days/hours/minutes after the due datetime",
4594 "%1 after the to-do is due", secs2Duration(offset));
4596 offsetStr = i18nc(
"N days/hours/minutes after the end datetime",
4597 "%1 after the end", secs2Duration(offset));
4600 if (incidence->type() == Incidence::TypeTodo) {
4602 if (t->dtDue().isValid()) {
4603 atStr = KGlobal::locale()->formatDateTime(t->dtDue());
4607 if (e->dtEnd().isValid()) {
4608 atStr = KGlobal::locale()->formatDateTime(e->dtEnd());
4614 if (!atStr.isEmpty()) {
4615 remStr = i18nc(
"reminder occurs at datetime",
"at %1", atStr);
4621 if (alarm->repeatCount() > 0) {
4622 QString countStr = i18np(
"repeats once",
"repeats %1 times", alarm->repeatCount());
4623 QString intervalStr = i18nc(
"interval is N days/hours/minutes",
4625 secs2Duration(alarm->snoozeTime().asSeconds()));
4626 QString repeatStr = i18nc(
"(repeat string, interval string)",
4627 "(%1, %2)", countStr, intervalStr);
4628 remStr = remStr + QLatin1Char(
' ') + repeatStr;
4631 reminderStringList << remStr;
QSharedPointer< Attachment > Ptr
QList< int > yearDates() const
QSharedPointer< Alarm > Ptr
QList< int > monthDays() const
QSharedPointer< Event > Ptr
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.
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.
QSharedPointer< MemoryCalendar > Ptr
QSharedPointer< IncidenceBase > Ptr
QList< RecurrenceRule::WDayPos > yearPositions() const
This file is part of the API for handling calendar data and provides static functions for formatting ...
KDateTime endDateTime() const
KCALUTILS_EXPORT QString errorMessage(const KCalCore::Exception &exception)
Build a translated message representing an exception.
virtual KDateTime dtStart() const
QList< int > yearDays() const
ushort recurrenceType() const
QSharedPointer< Calendar > Ptr
QSharedPointer< Attendee > Ptr
KCALUTILS_EXPORT QString todoCompletedDateTime(const KCalCore::Todo::Ptr &todo, bool shortfmt=false)
Returns string containing the date/time when the to-do was completed, formatted according to the user...
QSharedPointer< FreeBusy > Ptr
QList< RecurrenceRule::WDayPos > monthPositions() const
QList< int > yearMonths() const
QSharedPointer< Todo > Ptr
QSharedPointer< Journal > Ptr
Duration duration() const